Replaced eager resolve with lazy when navigating to library sources.
This commit is contained in:
@@ -16,48 +16,43 @@
|
||||
|
||||
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.Sets;
|
||||
import com.intellij.openapi.project.DumbService;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.OrderEntry;
|
||||
import com.intellij.openapi.roots.OrderRootType;
|
||||
import com.intellij.openapi.roots.ProjectFileIndex;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.impl.cache.CacheManager;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.search.GlobalSearchScopes;
|
||||
import com.intellij.psi.search.UsageSearchContext;
|
||||
import com.intellij.psi.stubs.StringStubIndexExtension;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
import org.jetbrains.jet.lang.DefaultModuleConfiguration;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.AnalyzerScriptParameter;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
|
||||
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacadeForJVM;
|
||||
import org.jetbrains.jet.lang.resolve.lazy.FileBasedDeclarationProviderFactory;
|
||||
import org.jetbrains.jet.lang.resolve.lazy.ResolveSession;
|
||||
import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||
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.lexer.JetTokens;
|
||||
import org.jetbrains.jet.plugin.stubindex.JetFullClassNameIndex;
|
||||
import org.jetbrains.jet.plugin.stubindex.JetTopLevelFunctionsFqnNameIndex;
|
||||
import org.jetbrains.jet.plugin.stubindex.JetTopLevelPropertiesFqnNameIndex;
|
||||
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 {
|
||||
private static boolean forceResolve = false;
|
||||
@@ -65,43 +60,6 @@ public class 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
|
||||
public static JetClassOrObject getSourceClassOrObject(@NotNull JetClassOrObject decompiledClassOrObject) {
|
||||
if (decompiledClassOrObject instanceof JetObjectDeclaration && decompiledClassOrObject.getParent() instanceof JetClassObject) {
|
||||
@@ -158,74 +116,6 @@ public class JetSourceNavigationHelper {
|
||||
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) {
|
||||
for (JetFile file : files) {
|
||||
for (JetImportDirective importDirective : file.getImportDirectives()) {
|
||||
@@ -354,18 +244,27 @@ public class JetSourceNavigationHelper {
|
||||
}
|
||||
}
|
||||
|
||||
Pair<BindingContext, JetScope> contextAndMemberScope = getBindingContextAndMemberScopeForLibrarySources(decompiledDeclaration);
|
||||
if (contextAndMemberScope == null) return null;
|
||||
BindingContext bindingContext = contextAndMemberScope.first;
|
||||
JetScope memberScope = contextAndMemberScope.second;
|
||||
Project project = decompiledDeclaration.getProject();
|
||||
FileBasedDeclarationProviderFactory providerFactory = new FileBasedDeclarationProviderFactory(getContainingFiles(candidates),
|
||||
new Predicate<FqName>() {
|
||||
@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);
|
||||
DeclarationDescriptor expectedContainer = memberScope.getContainingDeclaration();
|
||||
for (Descr candidate : navigationStrategy.getCandidateDescriptors(contextAndMemberScope.second, memberName)) {
|
||||
if (candidate.getContainingDeclaration() == expectedContainer
|
||||
&& receiversMatch(receiverType, candidate.getReceiverParameter())
|
||||
&& navigationStrategy.declarationAndDescriptorMatch(decompiledDeclaration, candidate)) {
|
||||
return (JetNamedDeclaration) BindingContextUtils.descriptorToDeclaration(bindingContext, candidate);
|
||||
for (Decl candidate : candidates) {
|
||||
//noinspection unchecked
|
||||
Descr candidateDescriptor = (Descr) resolveSession.resolveToDescriptor(candidate);
|
||||
if (receiversMatch(receiverType, candidateDescriptor.getReceiverParameter())
|
||||
&& navigationStrategy.declarationAndDescriptorMatch(decompiledDeclaration, candidateDescriptor)) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -501,8 +400,6 @@ public class JetSourceNavigationHelper {
|
||||
|
||||
boolean declarationAndDescriptorMatch(@NotNull Decl declaration, @NotNull Descr descriptor);
|
||||
|
||||
@NotNull Collection<Descr> getCandidateDescriptors(@NotNull JetScope scope, @NotNull Name name);
|
||||
|
||||
@Nullable JetTypeReference getReceiverType(@NotNull Decl declaration);
|
||||
|
||||
@NotNull
|
||||
@@ -573,12 +470,6 @@ public class JetSourceNavigationHelper {
|
||||
return true;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<FunctionDescriptor> getCandidateDescriptors(@NotNull JetScope scope, @NotNull Name name) {
|
||||
return scope.getFunctions(name);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public JetTypeReference getReceiverType(@NotNull JetNamedFunction declaration) {
|
||||
@@ -614,12 +505,6 @@ public class JetSourceNavigationHelper {
|
||||
return true;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<VariableDescriptor> getCandidateDescriptors(@NotNull JetScope scope, @NotNull Name name) {
|
||||
return scope.getProperties(name);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public JetTypeReference getReceiverType(@NotNull JetProperty declaration) {
|
||||
|
||||
Reference in New Issue
Block a user