Replaced eager resolve with lazy when navigating to library sources.

This commit is contained in:
Evgeny Gerashchenko
2013-01-09 16:31:23 +04:00
parent b14ca4775c
commit 3760bdfee9
@@ -16,48 +16,43 @@
package org.jetbrains.jet.plugin.libraries; package org.jetbrains.jet.plugin.libraries;
import com.google.common.base.Predicates; import com.google.common.base.Predicate;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.OrderEntry; import com.intellij.openapi.roots.OrderEntry;
import com.intellij.openapi.roots.OrderRootType; import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFile;
import com.intellij.psi.impl.cache.CacheManager;
import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.GlobalSearchScopes; import com.intellij.psi.search.GlobalSearchScopes;
import com.intellij.psi.search.UsageSearchContext;
import com.intellij.psi.stubs.StringStubIndexExtension; import com.intellij.psi.stubs.StringStubIndexExtension;
import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly; import org.jetbrains.annotations.TestOnly;
import org.jetbrains.jet.lang.DefaultModuleConfiguration;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.AnalyzerScriptParameter; import org.jetbrains.jet.lang.resolve.lazy.FileBasedDeclarationProviderFactory;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.lazy.ResolveSession;
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacadeForJVM;
import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.plugin.stubindex.JetFullClassNameIndex; import org.jetbrains.jet.plugin.stubindex.JetFullClassNameIndex;
import org.jetbrains.jet.plugin.stubindex.JetTopLevelFunctionsFqnNameIndex; import org.jetbrains.jet.plugin.stubindex.JetTopLevelFunctionsFqnNameIndex;
import org.jetbrains.jet.plugin.stubindex.JetTopLevelPropertiesFqnNameIndex; import org.jetbrains.jet.plugin.stubindex.JetTopLevelPropertiesFqnNameIndex;
import org.jetbrains.jet.renderer.DescriptorRenderer; import org.jetbrains.jet.renderer.DescriptorRenderer;
import org.jetbrains.jet.util.slicedmap.ReadOnlySlice;
import java.util.*; import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
public class JetSourceNavigationHelper { public class JetSourceNavigationHelper {
private static boolean forceResolve = false; private static boolean forceResolve = false;
@@ -65,43 +60,6 @@ public class JetSourceNavigationHelper {
private JetSourceNavigationHelper() { private JetSourceNavigationHelper() {
} }
@Nullable
private static<D extends ClassOrNamespaceDescriptor> Pair<BindingContext, D>
getBindingContextAndClassOrNamespaceDescriptor(@NotNull ReadOnlySlice<FqName, D> slice,
@NotNull JetNamedDeclaration declaration,
@Nullable FqName fqName) {
if (fqName == null || DumbService.isDumb(declaration.getProject())) {
return null;
}
final Project project = declaration.getProject();
final List<JetFile> libraryFiles = findAllSourceFilesWhichContainIdentifier(declaration);
BindingContext bindingContext = AnalyzerFacadeForJVM.INSTANCE.analyzeFiles(
project,
libraryFiles,
Collections.<AnalyzerScriptParameter>emptyList(),
Predicates.<PsiFile>alwaysTrue()).getBindingContext();
D descriptor = bindingContext.get(slice, fqName);
if (descriptor != null) {
return new Pair<BindingContext, D>(bindingContext, descriptor);
}
return null;
}
@Nullable
private static Pair<BindingContext, ClassDescriptor> getBindingContextAndClassDescriptor(@NotNull JetClassOrObject decompiledClassOrObject) {
JetNamedDeclaration asNamed = (JetNamedDeclaration) decompiledClassOrObject;
return getBindingContextAndClassOrNamespaceDescriptor(
BindingContext.FQNAME_TO_CLASS_DESCRIPTOR, asNamed, JetPsiUtil.getFQName(asNamed));
}
@Nullable
private static Pair<BindingContext, NamespaceDescriptor> getBindingContextAndNamespaceDescriptor(
@NotNull JetNamedDeclaration declaration) {
JetFile file = (JetFile) declaration.getContainingFile();
return getBindingContextAndClassOrNamespaceDescriptor(
BindingContext.FQNAME_TO_NAMESPACE_DESCRIPTOR, declaration, JetPsiUtil.getFQName(file));
}
@Nullable @Nullable
public static JetClassOrObject getSourceClassOrObject(@NotNull JetClassOrObject decompiledClassOrObject) { public static JetClassOrObject getSourceClassOrObject(@NotNull JetClassOrObject decompiledClassOrObject) {
if (decompiledClassOrObject instanceof JetObjectDeclaration && decompiledClassOrObject.getParent() instanceof JetClassObject) { if (decompiledClassOrObject instanceof JetObjectDeclaration && decompiledClassOrObject.getParent() instanceof JetClassObject) {
@@ -158,74 +116,6 @@ public class JetSourceNavigationHelper {
return Lists.newArrayList(result); return Lists.newArrayList(result);
} }
@NotNull
private static List<JetFile> findAllSourceFilesWhichContainIdentifier(@NotNull JetNamedDeclaration jetDeclaration) {
VirtualFile libraryFile = jetDeclaration.getContainingFile().getVirtualFile();
String name = jetDeclaration.getName();
if (libraryFile == null || name == null) {
return Collections.emptyList();
}
Project project = jetDeclaration.getProject();
CacheManager cacheManager = CacheManager.SERVICE.getInstance(project);
PsiFile[] filesWithWord = cacheManager.getFilesWithWord(name,
UsageSearchContext.IN_CODE,
createLibrarySourcesScopeForFile(libraryFile, project),
true);
List<JetFile> jetFiles = new ArrayList<JetFile>();
for (PsiFile psiFile : filesWithWord) {
if (psiFile instanceof JetFile) {
jetFiles.add((JetFile) psiFile);
}
}
return jetFiles;
}
@Nullable
private static <Decl extends JetNamedDeclaration> Pair<BindingContext, JetScope> getBindingContextAndMemberScopeForLibrarySources(
@NotNull Decl decompiledDeclaration) {
PsiElement declarationContainer = decompiledDeclaration.getParent();
if (declarationContainer instanceof JetFile) {
Pair<BindingContext, NamespaceDescriptor> contextAndNamespace = getBindingContextAndNamespaceDescriptor(decompiledDeclaration);
if (contextAndNamespace == null) {
return null;
}
return Pair.create(contextAndNamespace.first, contextAndNamespace.second.getMemberScope());
}
if (declarationContainer instanceof JetClassBody) {
JetClassOrObject decompiledClassOrObject = (JetClassOrObject) declarationContainer.getParent();
assert decompiledClassOrObject != null;
if (decompiledClassOrObject instanceof JetObjectDeclaration && decompiledClassOrObject.getParent() instanceof JetClassObject) {
// class object case
JetClass klass = PsiTreeUtil.getParentOfType(decompiledClassOrObject, JetClass.class);
assert klass != null;
Pair<BindingContext, ClassDescriptor> contextAndClass = getBindingContextAndClassDescriptor(klass);
if (contextAndClass == null) {
return null;
}
JetType classObjectType = contextAndClass.second.getClassObjectType();
assert classObjectType != null;
return Pair.create(contextAndClass.first, classObjectType.getMemberScope());
}
else {
Pair<BindingContext, ClassDescriptor> contextAndClass = getBindingContextAndClassDescriptor(decompiledClassOrObject);
if (contextAndClass == null) {
return null;
}
return Pair.create(contextAndClass.first, contextAndClass.second.getDefaultType().getMemberScope());
}
}
throw new IllegalStateException("Unexpected container of decompiled declaration: "
+ declarationContainer.getClass().getSimpleName());
}
private static boolean haveRenamesInImports(@NotNull List<JetFile> files) { private static boolean haveRenamesInImports(@NotNull List<JetFile> files) {
for (JetFile file : files) { for (JetFile file : files) {
for (JetImportDirective importDirective : file.getImportDirectives()) { for (JetImportDirective importDirective : file.getImportDirectives()) {
@@ -354,18 +244,27 @@ public class JetSourceNavigationHelper {
} }
} }
Pair<BindingContext, JetScope> contextAndMemberScope = getBindingContextAndMemberScopeForLibrarySources(decompiledDeclaration); Project project = decompiledDeclaration.getProject();
if (contextAndMemberScope == null) return null; FileBasedDeclarationProviderFactory providerFactory = new FileBasedDeclarationProviderFactory(getContainingFiles(candidates),
BindingContext bindingContext = contextAndMemberScope.first; new Predicate<FqName>() {
JetScope memberScope = contextAndMemberScope.second; @Override
public boolean apply(@Nullable FqName fqName) {
return KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME.equals(fqName);
}
});
ResolveSession resolveSession = new ResolveSession(
project,
new ModuleDescriptor(Name.special("<library module>")),
DefaultModuleConfiguration.createStandardConfiguration(project),
providerFactory);
JetTypeReference receiverType = navigationStrategy.getReceiverType(decompiledDeclaration); JetTypeReference receiverType = navigationStrategy.getReceiverType(decompiledDeclaration);
DeclarationDescriptor expectedContainer = memberScope.getContainingDeclaration(); for (Decl candidate : candidates) {
for (Descr candidate : navigationStrategy.getCandidateDescriptors(contextAndMemberScope.second, memberName)) { //noinspection unchecked
if (candidate.getContainingDeclaration() == expectedContainer Descr candidateDescriptor = (Descr) resolveSession.resolveToDescriptor(candidate);
&& receiversMatch(receiverType, candidate.getReceiverParameter()) if (receiversMatch(receiverType, candidateDescriptor.getReceiverParameter())
&& navigationStrategy.declarationAndDescriptorMatch(decompiledDeclaration, candidate)) { && navigationStrategy.declarationAndDescriptorMatch(decompiledDeclaration, candidateDescriptor)) {
return (JetNamedDeclaration) BindingContextUtils.descriptorToDeclaration(bindingContext, candidate); return candidate;
} }
} }
@@ -501,8 +400,6 @@ public class JetSourceNavigationHelper {
boolean declarationAndDescriptorMatch(@NotNull Decl declaration, @NotNull Descr descriptor); boolean declarationAndDescriptorMatch(@NotNull Decl declaration, @NotNull Descr descriptor);
@NotNull Collection<Descr> getCandidateDescriptors(@NotNull JetScope scope, @NotNull Name name);
@Nullable JetTypeReference getReceiverType(@NotNull Decl declaration); @Nullable JetTypeReference getReceiverType(@NotNull Decl declaration);
@NotNull @NotNull
@@ -573,12 +470,6 @@ public class JetSourceNavigationHelper {
return true; return true;
} }
@NotNull
@Override
public Collection<FunctionDescriptor> getCandidateDescriptors(@NotNull JetScope scope, @NotNull Name name) {
return scope.getFunctions(name);
}
@Nullable @Nullable
@Override @Override
public JetTypeReference getReceiverType(@NotNull JetNamedFunction declaration) { public JetTypeReference getReceiverType(@NotNull JetNamedFunction declaration) {
@@ -614,12 +505,6 @@ public class JetSourceNavigationHelper {
return true; return true;
} }
@NotNull
@Override
public Collection<VariableDescriptor> getCandidateDescriptors(@NotNull JetScope scope, @NotNull Name name) {
return scope.getProperties(name);
}
@Nullable @Nullable
@Override @Override
public JetTypeReference getReceiverType(@NotNull JetProperty declaration) { public JetTypeReference getReceiverType(@NotNull JetProperty declaration) {