diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyMethodResult.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyMethodResult.java index 198d0886be22..b0c291562ac7 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyMethodResult.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyMethodResult.java @@ -15,6 +15,7 @@ */ package org.jetbrains.plugins.groovy.lang.psi.impl; +import com.intellij.openapi.util.NotNullLazyValue; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiSubstitutor; @@ -24,20 +25,25 @@ import org.jetbrains.plugins.groovy.lang.psi.api.SpreadState; public class GroovyMethodResult extends GroovyResolveResultImpl { + private final NotNullLazyValue mySubstitutorInferer; + public GroovyMethodResult(@NotNull PsiMethod method, @Nullable PsiElement resolveContext, @Nullable SpreadState spreadState, @NotNull PsiSubstitutor substitutor, boolean isAccessible, boolean staticsOK) { super(method, resolveContext, spreadState, substitutor, isAccessible, staticsOK, true, true); + mySubstitutorInferer = NotNullLazyValue.createConstantValue(substitutor); } - public GroovyMethodResult(@NotNull PsiMethod method, + public GroovyMethodResult(@NotNull PsiMethod element, @Nullable PsiElement resolveContext, @Nullable SpreadState spreadState, - @NotNull PsiSubstitutor substitutor, + @NotNull PsiSubstitutor partialSubstitutor, + @NotNull NotNullLazyValue substitutorInferer, boolean isAccessible, boolean staticsOK, boolean isApplicable) { - super(method, resolveContext, spreadState, substitutor, isAccessible, staticsOK, false, isApplicable); + super(element, resolveContext, spreadState, partialSubstitutor, isAccessible, staticsOK, false, isApplicable); + mySubstitutorInferer = substitutorInferer; } @NotNull @@ -45,4 +51,15 @@ public class GroovyMethodResult extends GroovyResolveResultImpl { public PsiMethod getElement() { return (PsiMethod)super.getElement(); } + + @NotNull + @Override + public PsiSubstitutor getSubstitutor() { + return mySubstitutorInferer.getValue(); + } + + @NotNull + public PsiSubstitutor getSubstitutor(boolean infer) { + return infer ? mySubstitutorInferer.getValue() : super.getSubstitutor(); + } } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java index cea6b499d9ce..4613c283d26f 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java @@ -18,7 +18,10 @@ package org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions; import com.intellij.lang.ASTNode; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.*; +import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.RecursionManager; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.impl.source.resolve.ResolveCache; @@ -42,7 +45,6 @@ import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor; import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; -import org.jetbrains.plugins.groovy.lang.psi.api.SpreadState; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrApplicationStatement; @@ -265,8 +267,8 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl shapeResults = resolveByShape(allVariants, upToArgument); - if (!genericsMatter && !allVariants && shapeResults.first) { - assertAllAreValid(shapeResults.second); - return shapeResults.second; - } + final MethodResolverProcessor methodProcessor = new MethodResolverProcessor( + name, this, false, + PsiImplUtil.getQualifierType(this), + PsiUtil.getArgumentTypes(this, false, upToArgument, !genericsMatter), + getTypeArguments(), + allVariants, + !genericsMatter + ); + processMethods(resolveRunner, methodProcessor); + final GroovyResolveResult[] methodCandidates = hasMemberPointer() ? collapseReflectedMethods(methodProcessor.getCandidates()) + : methodProcessor.getCandidates(); + assertAllAreValid(methodCandidates); - MethodResolverProcessor methodResolver = null; - if (genericsMatter) { - methodResolver = createMethodProcessor(allVariants, name, false, upToArgument); - - for (GroovyResolveResult result : shapeResults.second) { - final ResolveState state = ResolveState.initial(). - put(PsiSubstitutor.KEY, result.getSubstitutor()). - put(ClassHint.RESOLVE_CONTEXT, result.getCurrentFileResolveContext()). - put(SpreadState.SPREAD_STATE, result.getSpreadState()); - PsiElement element = result.getElement(); - assert element != null; - methodResolver.execute(element, state); - } - - if (!allVariants && methodResolver.hasApplicableCandidates()) { - return methodResolver.getCandidates(); - } + if (!allVariants && methodProcessor.hasApplicableCandidates()) { + return methodCandidates; } //search for fields inside its class @@ -339,7 +333,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl allCandidates = new ArrayList(); ContainerUtil.addAll(allCandidates, propertyCandidates); - ContainerUtil.addAll(allCandidates, genericsMatter ? methodResolver.getCandidates() : shapeResults.second); + ContainerUtil.addAll(allCandidates, methodCandidates); filterOutBindings(allCandidates); @@ -379,39 +373,6 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl resolveByShape(boolean allVariants, @Nullable GrExpression upToArgument) { - if (allVariants) { - return doResolveByShape(true, upToArgument); - } - - LOG.assertTrue(upToArgument == null); - - return TypeInferenceHelper.getCurrentContext().getCachedValue(this, new NullableComputable>() { - @Override - public Pair compute() { - return doResolveByShape(false, null); - } - }); - } - - @NotNull - private Pair doResolveByShape(boolean allVariants, @Nullable GrExpression upToArgument) { - final String name = getReferenceName(); - LOG.assertTrue(name != null); - - final MethodResolverProcessor shapeProcessor = createMethodProcessor(allVariants, name, true, upToArgument); - processMethods(shapeProcessor); - GroovyResolveResult[] candidates = shapeProcessor.getCandidates(); - assertAllAreValid(candidates); - - if (hasMemberPointer()) { - candidates = collapseReflectedMethods(candidates); - } - - return Pair.create(shapeProcessor.hasApplicableCandidates(), candidates); - } - @NotNull private static GroovyResolveResult[] collapseReflectedMethods(GroovyResolveResult[] candidates) { Set visited = ContainerUtil.newHashSet(); @@ -437,21 +398,6 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl candidates) { - GroovyResolveResult[] array = candidates.toArray(new GroovyResolveResult[candidates.size()]); - if (array.length == 1) return array; + if (candidates.size() == 0) return GroovyResolveResult.EMPTY_ARRAY; + if (candidates.size() == 1) return candidates.toArray(new GroovyResolveResult[candidates.size()]); - List result = new ArrayList(); - result.add(array[0]); + final List result = new ArrayList(); + + final Iterator allIterator = candidates.iterator(); + result.add(allIterator.next()); Outer: - for (int i = 1; i < array.length; i++) { - PsiElement currentElement = array[i].getElement(); - if (currentElement instanceof PsiMethod) { - PsiMethod currentMethod = (PsiMethod)currentElement; - for (Iterator iterator = result.iterator(); iterator.hasNext();) { - final GroovyResolveResult otherResolveResult = iterator.next(); - PsiElement element = otherResolveResult.getElement(); - if (element instanceof PsiMethod) { - PsiMethod method = (PsiMethod)element; - if (dominated(currentMethod, array[i].getSubstitutor(), method, otherResolveResult.getSubstitutor())) { - continue Outer; - } - else if (dominated(method, otherResolveResult.getSubstitutor(), currentMethod, array[i].getSubstitutor())) { - iterator.remove(); - } - } + while (allIterator.hasNext()) { + final GroovyResolveResult currentResult = allIterator.next(); + + final PsiMethod currentMethod; + final PsiSubstitutor currentSubstitutor; + if (currentResult instanceof GroovyMethodResult) { + final GroovyMethodResult currentMethodResult = (GroovyMethodResult)currentResult; + currentMethod = currentMethodResult.getElement(); + currentSubstitutor = currentMethodResult.getSubstitutor(false); + } + else if (currentResult.getElement() instanceof PsiMethod) { + currentMethod = (PsiMethod)currentResult.getElement(); + currentSubstitutor = currentResult.getSubstitutor(); + } + else { + result.add(currentResult); + continue; + } + + Inner: + for (Iterator resultIterator = result.iterator(); resultIterator.hasNext(); ) { + final GroovyResolveResult otherResult = resultIterator.next(); + + final PsiMethod otherMethod; + final PsiSubstitutor otherSubstitutor; + if (otherResult instanceof GroovyMethodResult) { + final GroovyMethodResult otherMethodResult = (GroovyMethodResult)otherResult; + otherMethod = otherMethodResult.getElement(); + otherSubstitutor = otherMethodResult.getSubstitutor(false); + } + else if (otherResult.getElement() instanceof PsiMethod) { + otherMethod = (PsiMethod)otherResult.getElement(); + otherSubstitutor = otherResult.getSubstitutor(); + } + else { + continue Inner; + } + + if (dominated(currentMethod, currentSubstitutor, otherMethod, otherSubstitutor)) { + // if current method is dominated by other method + // then do not add current method to result and skip rest other methods + continue Outer; + } + else if (dominated(otherMethod, otherSubstitutor, currentMethod, currentSubstitutor)) { + // if other method is dominated by current method + // then remove other from result + resultIterator.remove(); } } - result.add(array[i]); + result.add(currentResult); } return result.toArray(new GroovyResolveResult[result.size()]); diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/MethodResolverProcessor.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/MethodResolverProcessor.java index 5fdf39ac376e..60a6db54a443 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/MethodResolverProcessor.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/MethodResolverProcessor.java @@ -16,6 +16,7 @@ package org.jetbrains.plugins.groovy.lang.resolve.processors; +import com.intellij.openapi.util.NotNullLazyValue; import com.intellij.psi.*; import com.intellij.psi.scope.JavaScopeProcessorEvent; import com.intellij.psi.util.InheritanceUtil; @@ -82,10 +83,15 @@ public class MethodResolverProcessor extends ResolverProcessor substitutorInferer + = myByShape ? NotNullLazyValue.createConstantValue(partialSubstitutor) : new NotNullLazyValue() { + @NotNull + @Override + protected PsiSubstitutor compute() { + return mySubstitutorComputer.obtainSubstitutor(partialSubstitutor, method, resolveContext); + } + }; boolean isAccessible = isAccessible(method); boolean isStaticsOK = isStaticsOK(method, resolveContext, false); - boolean isApplicable = PsiUtil.isApplicable(myArgumentTypes, method, substitutor, myPlace, myByShape); + boolean isApplicable = PsiUtil.isApplicable(myArgumentTypes, method, null, myPlace, true); boolean isValidResult = isStaticsOK && isAccessible && isApplicable; GroovyMethodResult candidate = new GroovyMethodResult( - method, resolveContext, spreadState, substitutor, isAccessible, isStaticsOK, isValidResult + method, resolveContext, spreadState, partialSubstitutor, substitutorInferer, isAccessible, isStaticsOK, isValidResult ); if (!myAllVariants && isValidResult) { @@ -132,12 +145,10 @@ public class MethodResolverProcessor extends ResolverProcessor