Added no-resolve optimization for class functions and properties.

This commit is contained in:
Evgeny Gerashchenko
2012-12-29 20:02:46 +04:00
parent b3b885b8f9
commit a7b703798a
@@ -50,6 +50,7 @@ import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.types.JetType; 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.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;
@@ -100,15 +101,26 @@ public class JetSourceNavigationHelper {
@Nullable @Nullable
public static JetClassOrObject getSourceClassOrObject(@NotNull JetClassOrObject decompiledClassOrObject) { public static JetClassOrObject getSourceClassOrObject(@NotNull JetClassOrObject decompiledClassOrObject) {
Pair<BindingContext, ClassDescriptor> bindingContextAndClassDescriptor = getBindingContextAndClassDescriptor( if (decompiledClassOrObject instanceof JetObjectDeclaration && decompiledClassOrObject.getParent() instanceof JetClassObject) {
decompiledClassOrObject); // class object case
if (bindingContextAndClassDescriptor == null) return null;
PsiElement declaration = BindingContextUtils.classDescriptorToDeclaration( JetClass decompiledClass = PsiTreeUtil.getParentOfType(decompiledClassOrObject, JetClass.class);
bindingContextAndClassDescriptor.first, bindingContextAndClassDescriptor.second); assert decompiledClass != null;
if (declaration == null) {
throw new IllegalStateException("class not found by " + bindingContextAndClassDescriptor.second); JetClass sourceClass = (JetClass) getSourceForNamedClassOrObject(decompiledClass);
if (sourceClass == null) {
return null;
}
if (sourceClass.hasModifier(JetTokens.ENUM_KEYWORD)) {
return sourceClass;
}
JetClassObject classObject = sourceClass.getClassObject();
assert classObject != null;
return classObject.getObjectDeclaration();
} }
return (JetClassOrObject) declaration; return getSourceForNamedClassOrObject(decompiledClassOrObject);
} }
@NotNull @NotNull
@@ -267,6 +279,27 @@ public class JetSourceNavigationHelper {
return candidates.isEmpty() ? null : candidates.iterator().next(); return candidates.isEmpty() ? null : candidates.iterator().next();
} }
@Nullable
private static JetNamedDeclaration findSpecialProperty(@NotNull Name memberName, @NotNull JetClass containingClass) {
// property constructor parameters
List<JetParameter> constructorParameters = containingClass.getPrimaryConstructorParameters();
for (JetParameter constructorParameter : constructorParameters) {
if (memberName.equals(constructorParameter.getNameAsName()) && constructorParameter.getValOrVarNode() != null) {
return constructorParameter;
}
}
// enum entries
if (containingClass.hasModifier(JetTokens.ENUM_KEYWORD)) {
for (JetEnumEntry enumEntry : ContainerUtil.findAll(containingClass.getDeclarations(), JetEnumEntry.class)) {
if (memberName.equals(enumEntry.getNameAsName())) {
return enumEntry;
}
}
}
return null;
}
@Nullable @Nullable
private static <Decl extends JetNamedDeclaration, Descr extends CallableDescriptor> JetNamedDeclaration private static <Decl extends JetNamedDeclaration, Descr extends CallableDescriptor> JetNamedDeclaration
getSourcePropertyOrFunction( getSourcePropertyOrFunction(
@@ -277,22 +310,43 @@ public class JetSourceNavigationHelper {
assert memberNameAsString != null; assert memberNameAsString != null;
Name memberName = Name.identifier(memberNameAsString); Name memberName = Name.identifier(memberNameAsString);
if (decompiledDeclaration.getParent() instanceof JetFile) { PsiElement decompiledContainer = decompiledDeclaration.getParent();
Collection<Decl> candidates = getInitialCandidates(decompiledDeclaration, navigationStrategy);
candidates = filterByReceiverPresenceAndParametersCount(decompiledDeclaration, navigationStrategy, candidates); Collection<Decl> candidates;
if (decompiledContainer instanceof JetFile) {
candidates = getInitialCandidates(decompiledDeclaration, navigationStrategy);
}
else if (decompiledContainer instanceof JetClassBody) {
JetClassOrObject decompiledClassOrObject = (JetClassOrObject) decompiledContainer.getParent();
JetClassOrObject sourceClassOrObject = getSourceClassOrObject(decompiledClassOrObject);
candidates = sourceClassOrObject == null
? Collections.<Decl>emptyList()
: getInitialCandidates(sourceClassOrObject, memberName, navigationStrategy.getDeclarationClass());
if (candidates.isEmpty()) {
if (decompiledDeclaration instanceof JetProperty && sourceClassOrObject instanceof JetClass) {
return findSpecialProperty(memberName, (JetClass) sourceClassOrObject);
}
}
}
else {
throw new IllegalStateException("Unexpected container of decompiled declaration: "
+ decompiledContainer.getClass().getSimpleName());
}
candidates = filterByReceiverPresenceAndParametersCount(decompiledDeclaration, navigationStrategy, candidates);
if (candidates.size() <= 1) {
return getUnambiguousCandidate(candidates);
}
if (!haveRenamesInImports(getContainingFiles(candidates))) {
candidates = filterByReceiverAndParameterTypes(decompiledDeclaration, navigationStrategy, candidates);
if (candidates.size() <= 1) { if (candidates.size() <= 1) {
return getUnambiguousCandidate(candidates); return getUnambiguousCandidate(candidates);
} }
if (!haveRenamesInImports(getContainingFiles(candidates))) {
candidates = filterByReceiverAndParameterTypes(decompiledDeclaration, navigationStrategy, candidates);
if (candidates.size() <= 1) {
return getUnambiguousCandidate(candidates);
}
}
} }
Pair<BindingContext, JetScope> contextAndMemberScope = getBindingContextAndMemberScopeForLibrarySources(decompiledDeclaration); Pair<BindingContext, JetScope> contextAndMemberScope = getBindingContextAndMemberScopeForLibrarySources(decompiledDeclaration);
@@ -313,6 +367,23 @@ public class JetSourceNavigationHelper {
return null; return null;
} }
@Nullable
private static JetClassOrObject getSourceForNamedClassOrObject(@NotNull JetClassOrObject decompiledClassOrObject) {
FqName classFqName = JetPsiUtil.getFQName((JetNamedDeclaration) decompiledClassOrObject);
assert classFqName != null;
GlobalSearchScope librarySourcesScope = createLibrarySourcesScope((JetNamedDeclaration) decompiledClassOrObject);
if (librarySourcesScope == GlobalSearchScope.EMPTY_SCOPE) { // .getProject() == null for EMPTY_SCOPE, and this breaks code
return null;
}
Collection<JetClassOrObject> classes = JetFullClassNameIndex.getInstance()
.get(classFqName.getFqName(), decompiledClassOrObject.getProject(), librarySourcesScope);
if (classes.isEmpty()) {
return null;
}
return classes.iterator().next(); // if there are more than one class with this FQ, find first of them
}
@NotNull @NotNull
private static <Decl extends JetNamedDeclaration, Descr extends CallableDescriptor> Collection<Decl> getInitialCandidates( private static <Decl extends JetNamedDeclaration, Descr extends CallableDescriptor> Collection<Decl> getInitialCandidates(
@NotNull Decl decompiledDeclaration, @NotNull Decl decompiledDeclaration,
@@ -329,6 +400,21 @@ public class JetSourceNavigationHelper {
return index.get(memberFqName.getFqName(), decompiledDeclaration.getProject(), librarySourcesScope); return index.get(memberFqName.getFqName(), decompiledDeclaration.getProject(), librarySourcesScope);
} }
@NotNull
private static <Decl extends JetNamedDeclaration> List<Decl> getInitialCandidates(
@NotNull JetClassOrObject sourceClassOrObject,
@NotNull final Name name,
@NotNull Class<Decl> declarationClass
) {
List<Decl> allByClass = ContainerUtil.findAll(sourceClassOrObject.getDeclarations(), declarationClass);
return ContainerUtil.filter(allByClass, new Condition<Decl>() {
@Override
public boolean value(Decl declaration) {
return name.equals(declaration.getNameAsSafeName());
}
});
}
@NotNull @NotNull
private static <Decl extends JetNamedDeclaration, Descr extends CallableDescriptor> List<Decl> filterByReceiverPresenceAndParametersCount( private static <Decl extends JetNamedDeclaration, Descr extends CallableDescriptor> List<Decl> filterByReceiverPresenceAndParametersCount(
final @NotNull Decl decompiledDeclaration, final @NotNull Decl decompiledDeclaration,
@@ -396,6 +482,9 @@ public class JetSourceNavigationHelper {
} }
private interface NavigationStrategy<Decl extends JetNamedDeclaration, Descr extends CallableDescriptor> { private interface NavigationStrategy<Decl extends JetNamedDeclaration, Descr extends CallableDescriptor> {
@NotNull
Class<Decl> getDeclarationClass();
boolean declarationsMatchByParameterCount(@NotNull Decl a, @NotNull Decl b); boolean declarationsMatchByParameterCount(@NotNull Decl a, @NotNull Decl b);
boolean declarationsMatchByParameterTypes(@NotNull Decl a, @NotNull Decl b); boolean declarationsMatchByParameterTypes(@NotNull Decl a, @NotNull Decl b);
@@ -411,6 +500,12 @@ public class JetSourceNavigationHelper {
} }
private static class FunctionNavigationStrategy implements NavigationStrategy<JetNamedFunction, FunctionDescriptor> { private static class FunctionNavigationStrategy implements NavigationStrategy<JetNamedFunction, FunctionDescriptor> {
@NotNull
@Override
public Class<JetNamedFunction> getDeclarationClass() {
return JetNamedFunction.class;
}
@Override @Override
public boolean declarationsMatchByParameterCount(@NotNull JetNamedFunction a, @NotNull JetNamedFunction b) { public boolean declarationsMatchByParameterCount(@NotNull JetNamedFunction a, @NotNull JetNamedFunction b) {
return a.getValueParameters().size() == b.getValueParameters().size(); return a.getValueParameters().size() == b.getValueParameters().size();
@@ -488,6 +583,12 @@ public class JetSourceNavigationHelper {
} }
private static class PropertyNavigationStrategy implements NavigationStrategy<JetProperty, VariableDescriptor> { private static class PropertyNavigationStrategy implements NavigationStrategy<JetProperty, VariableDescriptor> {
@NotNull
@Override
public Class<JetProperty> getDeclarationClass() {
return JetProperty.class;
}
@Override @Override
public boolean declarationsMatchByParameterCount(@NotNull JetProperty a, @NotNull JetProperty b) { public boolean declarationsMatchByParameterCount(@NotNull JetProperty a, @NotNull JetProperty b) {
return true; return true;