From e8de1be521a59a13048e28562d63d1f50dfa403d Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Mon, 25 Apr 2016 21:08:29 +0300 Subject: [PATCH] [groovy] resolve `call()` in @DelegatesTo processing --- .../statements/blocks/GrDelegatesToUtil.java | 36 +++++++++++-- .../resolve/ResolveWithDelegatesToTest.groovy | 51 +++++++++++++++++++ 2 files changed, 83 insertions(+), 4 deletions(-) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrDelegatesToUtil.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrDelegatesToUtil.java index 82dac2def4ff..6ba4716a04d5 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrDelegatesToUtil.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrDelegatesToUtil.java @@ -17,9 +17,7 @@ package org.jetbrains.plugins.groovy.lang.psi.impl.statements.blocks; import com.intellij.openapi.util.Key; import com.intellij.psi.*; -import com.intellij.psi.util.InheritanceUtil; -import com.intellij.psi.util.PsiUtil; -import com.intellij.psi.util.TypeConversionUtil; +import com.intellij.psi.util.*; import com.intellij.util.ArrayUtil; import groovy.lang.Closure; import org.jetbrains.annotations.NotNull; @@ -37,10 +35,14 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrRefere import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral; import org.jetbrains.plugins.groovy.lang.psi.impl.GrAnnotationUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.GrClosureType; +import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.signatures.GrClosureSignatureUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; import org.jetbrains.plugins.groovy.lang.psi.util.GdkMethodUtil; import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames; +import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; + +import static org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil.getArgumentTypes; /** * @author Max Medvedev @@ -55,7 +57,7 @@ public class GrDelegatesToUtil { GrCall call = getContainingCall(closableBlock); if (call == null) return null; - GroovyResolveResult result = call.advancedResolve(); + GroovyResolveResult result = resolveActualCall(call); if (GdkMethodUtil.isWithOrIdentity(result.getElement())) { final GrExpression qualifier = inferCallQualifier((GrMethodCall)call); @@ -270,6 +272,32 @@ public class GrDelegatesToUtil { return null; } + @NotNull + static GroovyResolveResult resolveActualCall(@NotNull GrCall call) { + if (call instanceof GrMethodCall) { + return CachedValuesManager.getCachedValue(call, () -> CachedValueProvider.Result.create( + doResolveActualCall((GrMethodCall)call), PsiModificationTracker.MODIFICATION_COUNT + )); + } + else { + return call.advancedResolve(); + } + } + + @NotNull + private static GroovyResolveResult doResolveActualCall(@NotNull GrMethodCall call) { + GroovyResolveResult result = call.advancedResolve(); + if (result.getElement() instanceof PsiMethod && !result.isInvokedOnProperty()) { + return result; + } + GrExpression expression = call.getInvokedExpression(); + PsiType type = expression.getType(); + if (type == null) return result; + + GroovyResolveResult[] calls = ResolveUtil.getMethodCandidates(type, "call", expression, getArgumentTypes(expression, false)); + return PsiImplUtil.extractUniqueResult(calls); + } + public static class DelegatesToInfo { final PsiType myClassToDelegate; final int myStrategy; diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveWithDelegatesToTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveWithDelegatesToTest.groovy index 2c0dd0906a78..dd7871c185d3 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveWithDelegatesToTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveWithDelegatesToTest.groovy @@ -347,6 +347,7 @@ test() ''', 'LinkedHashMap' } + void testShouldChooseMethodFromOwnerInJava() { myFixture.configureByText("Abc.java", '''\ import groovy.lang.Closure; @@ -737,4 +738,54 @@ doX { final containingClass = resolved.containingClass.name assertEquals(resolvedClass, containingClass) } + + void 'test delegate within implicit call()'() { + assertScript '''\ +class A { + def call(@DelegatesTo(Boo) Closure c) {} +} + +class Boo { + def foo() {} +} + +def a = new A() +a { + foo() +} +''', 'Boo' + } + + void 'test delegate within index property'() { + assertScript '''\ +class A { + def getAt(@DelegatesTo(Boo) Closure c) {} +} + +class Boo { + def foo() {} +} + +def a = new A() +a[{ + foo() +}] +''', 'Boo' + } + + void 'test delegate within constructor argument'() { + assertScript '''\ +class A { + A(@DelegatesTo(Boo) Closure c) {} +} + +class Boo { + def foo() {} +} + +new A({ + foo() +}) +''', 'Boo' + } }