From 78818e7a31c3a8d7bcd4dcf3def5d8af5506551a Mon Sep 17 00:00:00 2001 From: "Pavel V. Talanov" Date: Mon, 5 Aug 2013 20:08:56 +0400 Subject: [PATCH] Use new JetDecompiledData to navigate to declarations in decompiled files --- idea/src/META-INF/plugin.xml | 2 - .../libraries/DecompiledNavigationUtils.java | 124 ++++++++++++++++++ .../JetClsFileDecompiledPsiFileProvider.java | 37 ------ .../libraries/JetClsNavigationPolicy.java | 84 ------------ .../libraries/JetSourceNavigationHelper.java | 28 ++++ .../plugin/references/JetPsiReference.java | 10 ++ 6 files changed, 162 insertions(+), 123 deletions(-) create mode 100644 idea/src/org/jetbrains/jet/plugin/libraries/DecompiledNavigationUtils.java delete mode 100644 idea/src/org/jetbrains/jet/plugin/libraries/JetClsFileDecompiledPsiFileProvider.java delete mode 100644 idea/src/org/jetbrains/jet/plugin/libraries/JetClsNavigationPolicy.java diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 25197088b5a..08b615972a8 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -271,8 +271,6 @@ - - diff --git a/idea/src/org/jetbrains/jet/plugin/libraries/DecompiledNavigationUtils.java b/idea/src/org/jetbrains/jet/plugin/libraries/DecompiledNavigationUtils.java new file mode 100644 index 00000000000..da08778e836 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/libraries/DecompiledNavigationUtils.java @@ -0,0 +1,124 @@ +/* + * Copyright 2010-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.plugin.libraries; + +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.psi.JetDeclaration; +import org.jetbrains.jet.lang.resolve.DescriptorUtils; +import org.jetbrains.jet.lang.resolve.java.PackageClassUtils; +import org.jetbrains.jet.lang.resolve.java.vfilefinder.VirtualFileFinder; +import org.jetbrains.jet.lang.resolve.name.FqName; + +import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getFQName; + +public final class DecompiledNavigationUtils { + + private static final Logger LOG = Logger.getInstance(DecompiledNavigationUtils.class); + + @Nullable + public static JetDeclaration findDeclarationForReference( + @NotNull Project project, + @NotNull DeclarationDescriptor referencedDescriptor + ) { + JetDeclaration declarationFromDecompiledClassFile = getDeclarationFromDecompiledClassFile(project, referencedDescriptor); + if (declarationFromDecompiledClassFile == null) { + return null; + } + return JetSourceNavigationHelper.replaceBySourceDeclarationIfPresent(declarationFromDecompiledClassFile); + } + + @Nullable + private static JetDeclaration getDeclarationFromDecompiledClassFile( + @NotNull Project project, + @NotNull DeclarationDescriptor referencedDescriptor + ) { + DeclarationDescriptor effectiveReferencedDescriptor = getEffectiveReferencedDescriptor(referencedDescriptor); + VirtualFile virtualFile = findVirtualFileContainingDescriptor(project, effectiveReferencedDescriptor); + + if (virtualFile == null || !DecompiledUtils.isKotlinCompiledFile(virtualFile)) return null; + + JetDecompiledData data = JetDecompiledData.getDecompiledData(virtualFile, project); + JetDeclaration jetDeclaration = data.getDeclarationForDescriptor(effectiveReferencedDescriptor); + if (jetDeclaration != null) { + return jetDeclaration; + } + else { + LOG.warn("Could not find an element to navigate to for descriptor " + getFQName(effectiveReferencedDescriptor)); + } + return null; + } + + //TODO: should be done via some generic mechanism + @NotNull + private static DeclarationDescriptor getEffectiveReferencedDescriptor(@NotNull DeclarationDescriptor referencedDescriptor) { + if (referencedDescriptor instanceof VariableDescriptorForObject) { + ClassDescriptor objectClass = ((VariableDescriptorForObject) referencedDescriptor).getObjectClass(); + if (objectClass.getKind() == ClassKind.OBJECT) { + return objectClass; + } + } + return referencedDescriptor; + } + + + /* + Find virtual file which contains the declaration of descriptor we're navigating to. + */ + @Nullable + private static VirtualFile findVirtualFileContainingDescriptor( + @NotNull Project project, + @NotNull DeclarationDescriptor referencedDescriptor + ) { + FqName containerFqName = getContainerFqName(referencedDescriptor); + if (containerFqName == null) { + return null; + } + VirtualFileFinder fileFinder = ServiceManager.getService(project, VirtualFileFinder.class); + VirtualFile virtualFile = fileFinder.find(containerFqName); + if (virtualFile == null) { + return null; + } + return virtualFile; + } + + //TODO: navigate to inner classes + @Nullable + private static FqName getContainerFqName(@NotNull DeclarationDescriptor referencedDescriptor) { + ClassOrNamespaceDescriptor + containerDescriptor = DescriptorUtils.getParentOfType(referencedDescriptor, ClassOrNamespaceDescriptor.class, false); + if (containerDescriptor instanceof NamespaceDescriptor) { + return PackageClassUtils.getPackageClassFqName(getFQName(containerDescriptor).toSafe()); + } + if (containerDescriptor instanceof ClassDescriptor) { + ClassKind classKind = ((ClassDescriptor) containerDescriptor).getKind(); + if (classKind == ClassKind.CLASS_OBJECT || classKind == ClassKind.ENUM_ENTRY) { + return getContainerFqName(containerDescriptor.getContainingDeclaration()); + } + return getFQName(containerDescriptor).toSafe(); + } + return null; + } + + private DecompiledNavigationUtils() { + } +} diff --git a/idea/src/org/jetbrains/jet/plugin/libraries/JetClsFileDecompiledPsiFileProvider.java b/idea/src/org/jetbrains/jet/plugin/libraries/JetClsFileDecompiledPsiFileProvider.java deleted file mode 100644 index f6fdf3b423f..00000000000 --- a/idea/src/org/jetbrains/jet/plugin/libraries/JetClsFileDecompiledPsiFileProvider.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2010-2013 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.jet.plugin.libraries; - -import com.intellij.openapi.project.DumbService; -import com.intellij.psi.ClsFileDecompiledPsiFileProvider; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiJavaFile; -import com.intellij.psi.impl.compiled.ClsFileImpl; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class JetClsFileDecompiledPsiFileProvider implements ClsFileDecompiledPsiFileProvider { - @Nullable - @Override - public PsiFile getDecompiledPsiFile(@NotNull PsiJavaFile psiFile) { - ClsFileImpl clsFile = (ClsFileImpl)psiFile; - if (JetDecompiledData.isKotlinFile(clsFile) && !DumbService.isDumb(psiFile.getProject())) { - return JetDecompiledData.getDecompiledData(clsFile).getJetFile(); - } - return null; - } -} diff --git a/idea/src/org/jetbrains/jet/plugin/libraries/JetClsNavigationPolicy.java b/idea/src/org/jetbrains/jet/plugin/libraries/JetClsNavigationPolicy.java deleted file mode 100644 index 3b118790c4a..00000000000 --- a/idea/src/org/jetbrains/jet/plugin/libraries/JetClsNavigationPolicy.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2010-2013 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.jet.plugin.libraries; - -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiElement; -import com.intellij.psi.impl.compiled.*; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.psi.*; - -public class JetClsNavigationPolicy implements ClsCustomNavigationPolicy { - @Override - @Nullable - public PsiElement getNavigationElement(@NotNull ClsClassImpl clsClass) { - return getNavigationElementForMember(clsClass); - } - - @Override - @Nullable - public PsiElement getNavigationElement(@NotNull ClsMethodImpl clsMethod) { - return getNavigationElementForMember(clsMethod); - } - - @Override - @Nullable - public PsiElement getNavigationElement(@NotNull ClsFieldImpl clsField) { - return getNavigationElementForMember(clsField); - } - - @Nullable - private static PsiElement getNavigationElementForMember(@NotNull ClsMemberImpl clsMember) { - VirtualFile virtualFile = clsMember.getContainingFile().getVirtualFile(); - if (virtualFile == null || !JetDecompiledData.isKotlinFile(clsMember.getProject(), virtualFile)) { - return null; - } - - JetDecompiledData decompiledData = JetDecompiledData.getDecompiledData((ClsFileImpl) clsMember.getContainingFile()); - JetDeclaration decompiledDeclaration = decompiledData.getJetDeclarationByClsElement(clsMember); - - if (decompiledDeclaration == null) { - return null; - } - - JetDeclaration sourceElement = decompiledDeclaration.accept(new SourceForDecompiledExtractingVisitor(), null); - return sourceElement != null ? sourceElement : decompiledDeclaration; - } - - private static class SourceForDecompiledExtractingVisitor extends JetVisitor { - @Override - public JetDeclaration visitNamedFunction(JetNamedFunction function, Void data) { - return JetSourceNavigationHelper.getSourceFunction(function); - } - - @Override - public JetDeclaration visitProperty(JetProperty property, Void data) { - return JetSourceNavigationHelper.getSourceProperty(property); - } - - @Override - public JetDeclaration visitObjectDeclaration(JetObjectDeclaration declaration, Void data) { - return JetSourceNavigationHelper.getSourceClassOrObject(declaration); - } - - @Override - public JetDeclaration visitClass(JetClass klass, Void data) { - return JetSourceNavigationHelper.getSourceClassOrObject(klass); - } - } -} diff --git a/idea/src/org/jetbrains/jet/plugin/libraries/JetSourceNavigationHelper.java b/idea/src/org/jetbrains/jet/plugin/libraries/JetSourceNavigationHelper.java index 0ebe5130a5d..4a85b43d1af 100644 --- a/idea/src/org/jetbrains/jet/plugin/libraries/JetSourceNavigationHelper.java +++ b/idea/src/org/jetbrains/jet/plugin/libraries/JetSourceNavigationHelper.java @@ -420,4 +420,32 @@ public class JetSourceNavigationHelper { return original; } + + @NotNull + public static JetDeclaration replaceBySourceDeclarationIfPresent(@NotNull JetDeclaration original) { + JetDeclaration sourceElement = original.accept(new SourceForDecompiledExtractingVisitor(), null); + return sourceElement != null ? sourceElement : original; + } + + private static class SourceForDecompiledExtractingVisitor extends JetVisitor { + @Override + public JetDeclaration visitNamedFunction(JetNamedFunction function, Void data) { + return getSourceFunction(function); + } + + @Override + public JetDeclaration visitProperty(JetProperty property, Void data) { + return getSourceProperty(property); + } + + @Override + public JetDeclaration visitObjectDeclaration(JetObjectDeclaration declaration, Void data) { + return getSourceClassOrObject(declaration); + } + + @Override + public JetDeclaration visitClass(JetClass klass, Void data) { + return getSourceClassOrObject(klass); + } + } } diff --git a/idea/src/org/jetbrains/jet/plugin/references/JetPsiReference.java b/idea/src/org/jetbrains/jet/plugin/references/JetPsiReference.java index a999808a5ee..459e975f7a8 100644 --- a/idea/src/org/jetbrains/jet/plugin/references/JetPsiReference.java +++ b/idea/src/org/jetbrains/jet/plugin/references/JetPsiReference.java @@ -25,10 +25,12 @@ import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; +import org.jetbrains.jet.lang.psi.JetDeclaration; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.JetReferenceExpression; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContextUtils; +import org.jetbrains.jet.plugin.libraries.DecompiledNavigationUtils; import org.jetbrains.jet.lang.resolve.java.JetClsMethod; import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache; @@ -113,6 +115,14 @@ public abstract class JetPsiReference implements PsiPolyVariantReference { if (psiElements.size() > 1) { return null; } + DeclarationDescriptor referencedDescriptor = context.get(BindingContext.REFERENCE_TARGET, myExpression); + if (referencedDescriptor != null) { + JetDeclaration declarationInDecompiledFile = + DecompiledNavigationUtils.findDeclarationForReference(myExpression.getProject(), referencedDescriptor); + if (declarationInDecompiledFile != null) { + return declarationInDecompiledFile; + } + } Collection stdlibSymbols = resolveStandardLibrarySymbol(context); if (stdlibSymbols.size() == 1) { return stdlibSymbols.iterator().next();