Use new JetDecompiledData to navigate to declarations in decompiled files

This commit is contained in:
Pavel V. Talanov
2013-08-05 20:08:56 +04:00
parent 385c15d0e2
commit 78818e7a31
6 changed files with 162 additions and 123 deletions
-2
View File
@@ -271,8 +271,6 @@
<fileBasedIndex implementation="org.jetbrains.jet.plugin.vfilefinder.KotlinClassFileIndex"/>
<contentBasedClassFileProcessor implementation="org.jetbrains.jet.plugin.libraries.JetContentBasedFileSubstitutor"/>
<psi.clsCustomNavigationPolicy implementation="org.jetbrains.jet.plugin.libraries.JetClsNavigationPolicy"/>
<psi.clsDecompiledFileProvider implementation="org.jetbrains.jet.plugin.libraries.JetClsFileDecompiledPsiFileProvider"/>
<editorNotificationProvider implementation="org.jetbrains.jet.plugin.versions.KotlinLibrariesNotificationProvider"/>
<editorNotificationProvider implementation="org.jetbrains.jet.plugin.quickfix.AbsentJdkAnnotationsNotifications"/>
@@ -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() {
}
}
@@ -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;
}
}
@@ -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<JetDeclaration, Void> {
@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);
}
}
}
@@ -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<JetDeclaration, Void> {
@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);
}
}
}
@@ -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<PsiElement> stdlibSymbols = resolveStandardLibrarySymbol(context);
if (stdlibSymbols.size() == 1) {
return stdlibSymbols.iterator().next();