Unified resolve and multiResolve for references.

This commit is contained in:
Evgeny Gerashchenko
2013-11-18 21:19:34 +04:00
parent f36743e8b8
commit 6e19b98997
5 changed files with 77 additions and 114 deletions
@@ -83,17 +83,6 @@ public class BindingContextUtils {
return null;
}
@NotNull
public static List<PsiElement> resolveToDeclarationPsiElements(@NotNull BindingContext bindingContext, @Nullable JetReferenceExpression referenceExpression) {
DeclarationDescriptor declarationDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, referenceExpression);
if (declarationDescriptor == null) {
return Lists.newArrayList(bindingContext.get(BindingContext.LABEL_TARGET, referenceExpression));
}
return descriptorToDeclarations(bindingContext, declarationDescriptor);
}
@Nullable
public static VariableDescriptor extractVariableDescriptorIfAny(@NotNull BindingContext bindingContext, @Nullable JetElement element, boolean onlyReference) {
DeclarationDescriptor descriptor = null;
@@ -16,28 +16,30 @@
package org.jetbrains.jet.plugin.references;
import com.beust.jcommander.internal.Lists;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.psi.MultiRangeReference;
import com.intellij.psi.PsiReference;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.psi.JetArrayAccessExpression;
import org.jetbrains.jet.lang.psi.JetContainerNode;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import static org.jetbrains.jet.lang.resolve.BindingContext.INDEXED_LVALUE_GET;
import static org.jetbrains.jet.lang.resolve.BindingContext.INDEXED_LVALUE_SET;
class JetArrayAccessReference extends JetPsiReference implements MultiRangeReference {
private JetArrayAccessExpression expression;
private final JetArrayAccessExpression expression;
public static PsiReference[] create(JetArrayAccessExpression expression) {
JetContainerNode indicesNode = expression.getIndicesNode();
@@ -54,32 +56,22 @@ class JetArrayAccessReference extends JetPsiReference implements MultiRangeRefer
return getElement().getTextRange().shiftRight(-getElement().getTextOffset());
}
@Nullable
@Override
protected PsiElement doResolve() {
BindingContext bindingContext = AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile) getElement().getContainingFile())
.getBindingContext();
ResolvedCall<FunctionDescriptor> getFunction = bindingContext.get(INDEXED_LVALUE_GET, expression);
ResolvedCall<FunctionDescriptor> setFunction = bindingContext.get(INDEXED_LVALUE_SET, expression);
if (getFunction != null && setFunction != null) {
return null; // Call doMultiResolve
}
return super.doResolve();
}
protected Collection<? extends DeclarationDescriptor> getTargetDescriptors(@NotNull BindingContext context) {
List<DeclarationDescriptor> result = Lists.newArrayList();
@Override
protected ResolveResult[] doMultiResolve() {
BindingContext bindingContext = AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile) getElement().getContainingFile())
.getBindingContext();
ResolvedCall<FunctionDescriptor> getFunction = bindingContext.get(INDEXED_LVALUE_GET, expression);
ResolvedCall<FunctionDescriptor> setFunction = bindingContext.get(INDEXED_LVALUE_SET, expression);
if (getFunction == null || setFunction == null) {
return new ResolveResult[0];
ResolvedCall<FunctionDescriptor> getFunction = context.get(INDEXED_LVALUE_GET, expression);
if (getFunction != null) {
result.add(getFunction.getResultingDescriptor());
}
PsiElement getFunctionElement = BindingContextUtils.callableDescriptorToDeclaration(bindingContext, getFunction.getResultingDescriptor());
assert getFunctionElement != null;
PsiElement setFunctionElement = BindingContextUtils.callableDescriptorToDeclaration(bindingContext, setFunction.getResultingDescriptor());
assert setFunctionElement != null;
return new ResolveResult[] {new PsiElementResolveResult(getFunctionElement, true), new PsiElementResolveResult(setFunctionElement, true)};
ResolvedCall<FunctionDescriptor> setFunction = context.get(INDEXED_LVALUE_SET, expression);
if (setFunction != null) {
result.add(setFunction.getResultingDescriptor());
}
return result;
}
@Override
@@ -18,19 +18,21 @@ package org.jetbrains.jet.plugin.references;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.psi.MultiRangeReference;
import com.intellij.psi.PsiReference;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import static org.jetbrains.jet.lang.resolve.BindingContext.RESOLVED_CALL;
@@ -50,31 +52,18 @@ class JetInvokeFunctionReference extends JetPsiReference implements MultiRangeRe
return getElement().getTextRange().shiftRight(-getElement().getTextOffset());
}
@Nullable
@Override
protected PsiElement doResolve() {
protected Collection<? extends DeclarationDescriptor> getTargetDescriptors(@NotNull BindingContext context) {
JetExpression calleeExpression = ((JetCallExpression) myExpression).getCalleeExpression();
BindingContext bindingContext = AnalyzerFacadeWithCache.getContextForElement(myExpression);
ResolvedCall<? extends CallableDescriptor> resolvedCall = context.get(RESOLVED_CALL, calleeExpression);
ResolvedCall<? extends CallableDescriptor> invokeFunction = bindingContext.get(RESOLVED_CALL, calleeExpression);
if (invokeFunction != null && invokeFunction instanceof VariableAsFunctionResolvedCall) {
FunctionDescriptor resultingDescriptor = ((VariableAsFunctionResolvedCall) invokeFunction).getResultingDescriptor();
return BindingContextUtils.callableDescriptorToDeclaration(bindingContext, resultingDescriptor);
if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
return Collections.singleton(((VariableAsFunctionResolvedCall) resolvedCall).getResultingDescriptor());
}
return null;
}
@Override
protected ResolveResult[] doMultiResolve() {
// TODO If there are more than one invoke(), add all function ("ambiguity"). See JetPsiReference
PsiElement element = doResolve();
if (element == null) {
return ResolveResult.EMPTY_ARRAY;
}
return new ResolveResult[] {new PsiElementResolveResult(element, true)};
}
@Override
public List<TextRange> getRanges() {
JetCallExpression callExpression = (JetCallExpression) myExpression;
@@ -16,6 +16,7 @@
package org.jetbrains.jet.plugin.references;
import com.beust.jcommander.internal.Sets;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementResolveResult;
@@ -25,19 +26,16 @@ 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.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.lang.resolve.java.jetAsJava.KotlinLightMethod;
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Collections;
import java.util.Set;
import static org.jetbrains.jet.lang.resolve.BindingContext.AMBIGUOUS_LABEL_TARGET;
import static org.jetbrains.jet.lang.resolve.BindingContext.AMBIGUOUS_REFERENCE_TARGET;
import static org.jetbrains.jet.plugin.codeInsight.DescriptorToDeclarationUtil.findDeclarationsForDescriptorWithoutTrace;
public abstract class JetPsiReference implements PsiPolyVariantReference {
@@ -60,12 +58,16 @@ public abstract class JetPsiReference implements PsiPolyVariantReference {
@NotNull
@Override
public ResolveResult[] multiResolve(boolean incompleteCode) {
return doMultiResolve();
return PsiElementResolveResult.createResults(resolveToPsiElements());
}
@Override
public PsiElement resolve() {
return doResolve();
Collection<? extends PsiElement> psiElements = resolveToPsiElements();
if (psiElements.size() == 1) {
return psiElements.iterator().next();
}
return null;
}
@NotNull
@@ -103,59 +105,50 @@ public abstract class JetPsiReference implements PsiPolyVariantReference {
return false;
}
@Nullable
protected PsiElement doResolve() {
@NotNull
private Collection<? extends PsiElement> resolveToPsiElements() {
BindingContext context = AnalyzerFacadeWithCache.getContextForElement(myExpression);
List<PsiElement> psiElements = BindingContextUtils.resolveToDeclarationPsiElements(context, myExpression);
if (psiElements.size() == 1) {
return psiElements.iterator().next();
}
if (psiElements.size() > 1) {
return null;
}
DeclarationDescriptor referencedDescriptor = context.get(BindingContext.REFERENCE_TARGET, myExpression);
if (referencedDescriptor == null) {
return null;
}
Collection<PsiElement> elements = findDeclarationsForDescriptorWithoutTrace(myExpression.getProject(), referencedDescriptor);
if (elements.size() == 1) {
return elements.iterator().next();
}
return null;
return resolveToPsiElements(context);
}
protected ResolveResult[] doMultiResolve() {
JetFile file = (JetFile) getElement().getContainingFile();
BindingContext bindingContext = AnalyzerFacadeWithCache.analyzeFileWithCache(file).getBindingContext();
Collection<? extends DeclarationDescriptor> declarationDescriptors = bindingContext.get(AMBIGUOUS_REFERENCE_TARGET, myExpression);
if (declarationDescriptors == null) {
List<PsiElement> psiElements = BindingContextUtils.resolveToDeclarationPsiElements(bindingContext, myExpression);
if (psiElements.size() > 1) {
return PsiElementResolveResult.createResults(psiElements);
@NotNull
private Collection<? extends PsiElement> resolveToPsiElements(@NotNull BindingContext context) {
Collection<? extends DeclarationDescriptor> targetDescriptors = getTargetDescriptors(context);
if (targetDescriptors != null) {
assert !(targetDescriptors.isEmpty()) : "targetDescriptors is not null, but empty, for " + myExpression.getText();
Set<PsiElement> result = Sets.newHashSet();
for (DeclarationDescriptor target : targetDescriptors) {
result.addAll(BindingContextUtils.descriptorToDeclarations(context, target));
result.addAll(findDeclarationsForDescriptorWithoutTrace(myExpression.getProject(), target));
}
Collection<? extends PsiElement> labelTargets = bindingContext.get(AMBIGUOUS_LABEL_TARGET, myExpression);
if (labelTargets != null && !labelTargets.isEmpty()) {
return PsiElementResolveResult.createResults(labelTargets);
}
Collection<PsiElement> standardLibraryElements = resolveStandardLibrarySymbol(bindingContext);
if (standardLibraryElements.size() > 1) {
return PsiElementResolveResult.createResults(standardLibraryElements);
}
return ResolveResult.EMPTY_ARRAY;
return result;
}
List<ResolveResult> results = new ArrayList<ResolveResult>(declarationDescriptors.size());
for (DeclarationDescriptor descriptor : declarationDescriptors) {
List<PsiElement> elements = BindingContextUtils.descriptorToDeclarations(bindingContext, descriptor);
for (PsiElement element : elements) {
results.add(new PsiElementResolveResult(element, true));
}
Collection<? extends PsiElement> labelTargets = getLabelTargets(context);
if (labelTargets != null) {
return labelTargets;
}
return results.toArray(new ResolveResult[results.size()]);
return Collections.emptySet();
}
private Collection<PsiElement> resolveStandardLibrarySymbol(@NotNull BindingContext bindingContext) {
return myExpression.getProject().getComponent(BuiltInsReferenceResolver.class)
.resolveBuiltInSymbol(bindingContext, myExpression);
@Nullable
protected Collection<? extends DeclarationDescriptor> getTargetDescriptors(@NotNull BindingContext context) {
DeclarationDescriptor targetDescriptor = context.get(BindingContext.REFERENCE_TARGET, myExpression);
if (targetDescriptor != null) {
return Collections.singleton(targetDescriptor);
}
return context.get(BindingContext.AMBIGUOUS_REFERENCE_TARGET, myExpression);
}
@Nullable
private Collection<? extends PsiElement> getLabelTargets(@NotNull BindingContext context) {
PsiElement labelTarget = context.get(BindingContext.LABEL_TARGET, myExpression);
if (labelTarget != null) {
return Collections.singleton(labelTarget);
}
return context.get(BindingContext.AMBIGUOUS_LABEL_TARGET, myExpression);
}
}
@@ -114,7 +114,7 @@ public class BuiltInsReferenceResolverTest extends ResolveTestCase {
JetPsiReference reference = (JetPsiReference) configureByFile(getTestName(true) + ".kt");
PsiElement resolved = reference.resolve();
assertNotNull(resolved);
assertEmpty(reference.multiResolve(false));
assertEquals(1, reference.multiResolve(false).length);
List<PsiComment> comments = PsiTreeUtil.getChildrenOfTypeAsList(getFile(), PsiComment.class);
String[] expectedTarget = comments.get(comments.size() - 1).getText().substring(2).split(":");