From 6e19b98997453c9318286c7cf397aca940af17e7 Mon Sep 17 00:00:00 2001 From: Evgeny Gerashchenko Date: Mon, 18 Nov 2013 21:19:34 +0400 Subject: [PATCH] Unified resolve and multiResolve for references. --- .../jet/lang/resolve/BindingContextUtils.java | 11 --- .../references/JetArrayAccessReference.java | 48 ++++----- .../JetInvokeFunctionReference.java | 33 +++---- .../plugin/references/JetPsiReference.java | 97 +++++++++---------- .../BuiltInsReferenceResolverTest.java | 2 +- 5 files changed, 77 insertions(+), 114 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContextUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContextUtils.java index 75db515663b..d56cb3d2ac7 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContextUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContextUtils.java @@ -83,17 +83,6 @@ public class BindingContextUtils { return null; } - @NotNull - public static List 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; diff --git a/idea/src/org/jetbrains/jet/plugin/references/JetArrayAccessReference.java b/idea/src/org/jetbrains/jet/plugin/references/JetArrayAccessReference.java index 4fad0b332de..f7a389b356f 100644 --- a/idea/src/org/jetbrains/jet/plugin/references/JetArrayAccessReference.java +++ b/idea/src/org/jetbrains/jet/plugin/references/JetArrayAccessReference.java @@ -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 getFunction = bindingContext.get(INDEXED_LVALUE_GET, expression); - ResolvedCall setFunction = bindingContext.get(INDEXED_LVALUE_SET, expression); - if (getFunction != null && setFunction != null) { - return null; // Call doMultiResolve - } - return super.doResolve(); - } + protected Collection getTargetDescriptors(@NotNull BindingContext context) { + List result = Lists.newArrayList(); - @Override - protected ResolveResult[] doMultiResolve() { - BindingContext bindingContext = AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile) getElement().getContainingFile()) - .getBindingContext(); - ResolvedCall getFunction = bindingContext.get(INDEXED_LVALUE_GET, expression); - ResolvedCall setFunction = bindingContext.get(INDEXED_LVALUE_SET, expression); - if (getFunction == null || setFunction == null) { - return new ResolveResult[0]; + ResolvedCall 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 setFunction = context.get(INDEXED_LVALUE_SET, expression); + if (setFunction != null) { + result.add(setFunction.getResultingDescriptor()); + } + + return result; } @Override diff --git a/idea/src/org/jetbrains/jet/plugin/references/JetInvokeFunctionReference.java b/idea/src/org/jetbrains/jet/plugin/references/JetInvokeFunctionReference.java index 7d96f953006..46515f6f698 100644 --- a/idea/src/org/jetbrains/jet/plugin/references/JetInvokeFunctionReference.java +++ b/idea/src/org/jetbrains/jet/plugin/references/JetInvokeFunctionReference.java @@ -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 getTargetDescriptors(@NotNull BindingContext context) { JetExpression calleeExpression = ((JetCallExpression) myExpression).getCalleeExpression(); - BindingContext bindingContext = AnalyzerFacadeWithCache.getContextForElement(myExpression); + ResolvedCall resolvedCall = context.get(RESOLVED_CALL, calleeExpression); - ResolvedCall 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 getRanges() { JetCallExpression callExpression = (JetCallExpression) myExpression; diff --git a/idea/src/org/jetbrains/jet/plugin/references/JetPsiReference.java b/idea/src/org/jetbrains/jet/plugin/references/JetPsiReference.java index c34a3ecada3..56986fb46d6 100644 --- a/idea/src/org/jetbrains/jet/plugin/references/JetPsiReference.java +++ b/idea/src/org/jetbrains/jet/plugin/references/JetPsiReference.java @@ -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 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 resolveToPsiElements() { BindingContext context = AnalyzerFacadeWithCache.getContextForElement(myExpression); - List 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 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 declarationDescriptors = bindingContext.get(AMBIGUOUS_REFERENCE_TARGET, myExpression); - if (declarationDescriptors == null) { - List psiElements = BindingContextUtils.resolveToDeclarationPsiElements(bindingContext, myExpression); - if (psiElements.size() > 1) { - return PsiElementResolveResult.createResults(psiElements); + @NotNull + private Collection resolveToPsiElements(@NotNull BindingContext context) { + Collection targetDescriptors = getTargetDescriptors(context); + + if (targetDescriptors != null) { + assert !(targetDescriptors.isEmpty()) : "targetDescriptors is not null, but empty, for " + myExpression.getText(); + Set result = Sets.newHashSet(); + for (DeclarationDescriptor target : targetDescriptors) { + result.addAll(BindingContextUtils.descriptorToDeclarations(context, target)); + result.addAll(findDeclarationsForDescriptorWithoutTrace(myExpression.getProject(), target)); } - Collection labelTargets = bindingContext.get(AMBIGUOUS_LABEL_TARGET, myExpression); - if (labelTargets != null && !labelTargets.isEmpty()) { - return PsiElementResolveResult.createResults(labelTargets); - } - Collection standardLibraryElements = resolveStandardLibrarySymbol(bindingContext); - if (standardLibraryElements.size() > 1) { - return PsiElementResolveResult.createResults(standardLibraryElements); - } - return ResolveResult.EMPTY_ARRAY; + return result; } - List results = new ArrayList(declarationDescriptors.size()); - for (DeclarationDescriptor descriptor : declarationDescriptors) { - List elements = BindingContextUtils.descriptorToDeclarations(bindingContext, descriptor); - for (PsiElement element : elements) { - results.add(new PsiElementResolveResult(element, true)); - } + Collection labelTargets = getLabelTargets(context); + if (labelTargets != null) { + return labelTargets; } - return results.toArray(new ResolveResult[results.size()]); + + return Collections.emptySet(); } - private Collection resolveStandardLibrarySymbol(@NotNull BindingContext bindingContext) { - return myExpression.getProject().getComponent(BuiltInsReferenceResolver.class) - .resolveBuiltInSymbol(bindingContext, myExpression); + @Nullable + protected Collection 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 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); } } diff --git a/idea/tests/org/jetbrains/jet/plugin/references/BuiltInsReferenceResolverTest.java b/idea/tests/org/jetbrains/jet/plugin/references/BuiltInsReferenceResolverTest.java index 09fc66b1b52..3ccca1ff9c0 100644 --- a/idea/tests/org/jetbrains/jet/plugin/references/BuiltInsReferenceResolverTest.java +++ b/idea/tests/org/jetbrains/jet/plugin/references/BuiltInsReferenceResolverTest.java @@ -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 comments = PsiTreeUtil.getChildrenOfTypeAsList(getFile(), PsiComment.class); String[] expectedTarget = comments.get(comments.size() - 1).getText().substring(2).split(":");