diff --git a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java index ba62be14cb0..ce8dfec9ea1 100644 --- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java +++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java @@ -145,6 +145,7 @@ import java.util.stream.Collectors; import java.util.stream.IntStream; +import static org.apache.groovy.ast.tools.ClassNodeUtils.getField; import static org.apache.groovy.ast.tools.MethodNodeUtils.withDefaultArgumentMethods; import static org.apache.groovy.util.BeanUtils.capitalize; import static org.apache.groovy.util.BeanUtils.decapitalize; @@ -3650,14 +3651,18 @@ public void visitMethodCallExpression(final MethodCallExpression call) { case "doCall": if (!isThisObjectExpression) { isCallOnClosure = receiver.equals(CLOSURE_TYPE); - break; } default: if (isThisObjectExpression) { - ClassNode enclosingType = typeCheckingContext.getEnclosingClassNode(); - fieldNode = enclosingType.getDeclaredField(name); - if (fieldNode != null && getType(fieldNode).equals(CLOSURE_TYPE) - && !enclosingType.hasPossibleMethod(name, callArguments)) { + // GROOVY-5705, GROOVY-11366: "this.x(...)" could refer to field + if (!typeCheckingContext.isInStaticContext) { + fieldNode = getField(receiver, name); + } else { + fieldNode = getField(receiver, name, FieldNode::isStatic); + } + if (fieldNode != null + && getType(fieldNode).equals(CLOSURE_TYPE) + && !receiver.hasPossibleMethod(name, callArguments)) { isCallOnClosure = true; } } diff --git a/src/test/groovy/transform/stc/ClosuresSTCTest.groovy b/src/test/groovy/transform/stc/ClosuresSTCTest.groovy index 8bceb4cfd23..ddc80666015 100644 --- a/src/test/groovy/transform/stc/ClosuresSTCTest.groovy +++ b/src/test/groovy/transform/stc/ClosuresSTCTest.groovy @@ -188,6 +188,47 @@ class ClosuresSTCTest extends StaticTypeCheckingTestCase { ''' } + // GROOVY-5705 + void testCallClosure19() { + assertScript ''' + class Foo { + Closure c = { it } + def test() { + c("123") + } + } + + String result = new Foo().test() + assert result == '123' + ''' + shouldFailWithMessages ''' + class Foo { + Closure c = { -> } + static test() { + c() + } + } + ''', + 'Cannot find matching method java.lang.Class#c() or static method Foo#c()' + } + + // GROOVY-11366 + void testCallClosure20() { + assertScript ''' + class Bar { + Closure c = { it } + } + class Foo extends Bar { + def test() { + c("123") + } + } + + String result = new Foo().test() + assert result == '123' + ''' + } + void testClosureReturnTypeInference1() { assertScript ''' def c = { int a, int b -> return a + b } @@ -693,20 +734,6 @@ class ClosuresSTCTest extends StaticTypeCheckingTestCase { ''' } - // GROOVY-5705 - void testNPEWhenCallingClosureFromAField() { - assertScript ''' - class Test { - Closure c = { it } - void test() { - c("123") - } - } - - new Test().test() - ''' - } - // GROOVY-6219, GROOVY-10277 void testClosureReturnDoesNotMatchTarget() { shouldFailWithMessages '''