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"/>
|
||||
|
||||
<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();
|
||||
|
||||
Reference in New Issue
Block a user