Use new JetDecompiledData to navigate to declarations in decompiled files
This commit is contained in:
@@ -271,8 +271,6 @@
|
|||||||
<fileBasedIndex implementation="org.jetbrains.jet.plugin.vfilefinder.KotlinClassFileIndex"/>
|
<fileBasedIndex implementation="org.jetbrains.jet.plugin.vfilefinder.KotlinClassFileIndex"/>
|
||||||
|
|
||||||
<contentBasedClassFileProcessor implementation="org.jetbrains.jet.plugin.libraries.JetContentBasedFileSubstitutor"/>
|
<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.versions.KotlinLibrariesNotificationProvider"/>
|
||||||
<editorNotificationProvider implementation="org.jetbrains.jet.plugin.quickfix.AbsentJdkAnnotationsNotifications"/>
|
<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;
|
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.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
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.JetFile;
|
||||||
import org.jetbrains.jet.lang.psi.JetReferenceExpression;
|
import org.jetbrains.jet.lang.psi.JetReferenceExpression;
|
||||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||||
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
|
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.lang.resolve.java.JetClsMethod;
|
||||||
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache;
|
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache;
|
||||||
|
|
||||||
@@ -113,6 +115,14 @@ public abstract class JetPsiReference implements PsiPolyVariantReference {
|
|||||||
if (psiElements.size() > 1) {
|
if (psiElements.size() > 1) {
|
||||||
return null;
|
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);
|
Collection<PsiElement> stdlibSymbols = resolveStandardLibrarySymbol(context);
|
||||||
if (stdlibSymbols.size() == 1) {
|
if (stdlibSymbols.size() == 1) {
|
||||||
return stdlibSymbols.iterator().next();
|
return stdlibSymbols.iterator().next();
|
||||||
|
|||||||
Reference in New Issue
Block a user