This is an automated email from the ASF dual-hosted git repository.

emilles pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git


The following commit(s) were added to refs/heads/master by this push:
     new 49e1d6487e GROOVY-3069, GROOVY-11677: call expr variable or parameter 
precedence
49e1d6487e is described below

commit 49e1d6487e18a7165b92f670590761877594baaa
Author: Eric Milles <eric.mil...@thomsonreuters.com>
AuthorDate: Fri Jul 18 09:55:16 2025 -0500

    GROOVY-3069, GROOVY-11677: call expr variable or parameter precedence
---
 .../groovy/classgen/VariableScopeVisitor.java      | 31 +++++-----
 .../{Groovy3069Bug.groovy => Groovy3069.groovy}    | 70 +++++++++++++++-------
 2 files changed, 63 insertions(+), 38 deletions(-)

diff --git 
a/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java 
b/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java
index e4001ee0c5..e615e6909b 100644
--- a/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java
+++ b/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java
@@ -18,7 +18,6 @@
  */
 package org.codehaus.groovy.classgen;
 
-import org.codehaus.groovy.GroovyBugError;
 import org.codehaus.groovy.ast.ASTNode;
 import org.codehaus.groovy.ast.AnnotationNode;
 import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
@@ -716,27 +715,25 @@ public class VariableScopeVisitor extends 
ClassCodeVisitorSupport {
 
     @Override
     public void visitMethodCallExpression(final MethodCallExpression 
expression) {
-        if (expression.isImplicitThis() && expression.getMethod() instanceof 
ConstantExpression) {
-            ConstantExpression methodNameConstant = (ConstantExpression) 
expression.getMethod();
-            String methodName = methodNameConstant.getText();
-
-            if (methodName == null) {
-                throw new GroovyBugError("method name is null");
-            }
-
+        String methodName = expression.getMethodAsString();
+        if (methodName != null && expression.isImplicitThis()) {
+            // GROOVY-3069, GROOVY-11677: variable or parameter call
             Variable variable = findVariableDeclaration(methodName);
-            if (variable != null && !(variable instanceof DynamicVariable)) {
-                checkVariableContextAccess(variable, expression);
-            }
-
+            // if "name" resolves to a variable, replace "name(...)" with 
"name.call(...)"
             if (variable instanceof VariableExpression || variable instanceof 
Parameter) {
-                VariableExpression object = new VariableExpression(variable);
-                object.setSourcePosition(methodNameConstant);
+                Expression object = new VariableExpression(variable);
+                object.setSourcePosition(expression.getMethod());
                 expression.setObjectExpression(object);
-                ConstantExpression method = new ConstantExpression("call");
-                method.setSourcePosition(methodNameConstant); // important for 
GROOVY-4344
                 expression.setImplicitThis(false);
+
+                Expression method = new ConstantExpression("call");
+                // GROOVY-4344: ensure result of "call" for assert
+                method.setSourcePosition(expression.getMethod());
                 expression.setMethod(method);
+
+                checkVariableContextAccess(variable, expression);
+                expression.getArguments().visit(this);
+                return;
             }
         } else if (expression.getGenericsTypes() != null) {
             visitTypeVariables(expression.getGenericsTypes());
diff --git a/src/test/groovy/bugs/Groovy3069Bug.groovy 
b/src/test/groovy/bugs/Groovy3069.groovy
similarity index 56%
rename from src/test/groovy/bugs/Groovy3069Bug.groovy
rename to src/test/groovy/bugs/Groovy3069.groovy
index b72bd02f18..886f757a23 100644
--- a/src/test/groovy/bugs/Groovy3069Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3069.groovy
@@ -18,47 +18,75 @@
  */
 package bugs
 
-import groovy.test.GroovyTestCase
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.params.ParameterizedTest
+import org.junit.jupiter.params.provider.ValueSource
 
-class Groovy3069Bug extends GroovyTestCase {
-    final String CLOSURE_STR = '[Closure]'
-    final String CLASS_METHOD_STR = '[ClassMethod]'
+import static groovy.test.GroovyAssert.shouldFail
 
-    def void testClosureParamPrecedenceWithTypeSpecified() {
-        def cl = { CLOSURE_STR }
-        checkPrecendenceWithTypeSpecified(cl)
-    }
+final class Groovy3069 {
 
-    def void testClosureParamPrecedenceWithTypeNotSpecified() {
-        def cl = { CLOSURE_STR }
-        checkPrecendenceWithTypeNotSpecified(cl)
-    }
+    private static final String CLOSURE_STR = '[Closure]'
+    private static final String CLASS_METHOD_STR = '[ClassMethod]'
 
-    def void testClosureLocalVarPrecedenceExplicitClosureType() {
-        Closure method = { CLOSURE_STR }
+    String method() {
+        CLASS_METHOD_STR
+    }
 
+    String checkPrecendenceWithTypeSpecified(Closure method) {
         assert method() == CLOSURE_STR
         assert this.method() == CLASS_METHOD_STR
     }
 
-    def void testClosureLocalVarPrecedenceImplicitClosureType() {
-        def method = { CLOSURE_STR }
-
+    String checkPrecendenceWithTypeNotSpecified(method) {
         assert method() == CLOSURE_STR
         assert this.method() == CLASS_METHOD_STR
     }
 
-    String method() {
-        return CLASS_METHOD_STR
+    //
+
+    @Test
+    void testClosureParamPrecedenceWithTypeSpecified() {
+        def cl = { CLOSURE_STR }
+        checkPrecendenceWithTypeSpecified(cl)
     }
 
-    String checkPrecendenceWithTypeSpecified(Closure method) {
+    @Test
+    void testClosureParamPrecedenceWithTypeNotSpecified() {
+        def cl = { CLOSURE_STR }
+        checkPrecendenceWithTypeNotSpecified(cl)
+    }
+
+    @Test
+    void testClosureLocalVarPrecedenceExplicitClosureType() {
+        Closure method = { CLOSURE_STR }
         assert method() == CLOSURE_STR
         assert this.method() == CLASS_METHOD_STR
     }
 
-    String checkPrecendenceWithTypeNotSpecified(method) {
+    @Test
+    void testClosureLocalVarPrecedenceImplicitClosureType() {
+        def method = { CLOSURE_STR }
         assert method() == CLOSURE_STR
         assert this.method() == CLASS_METHOD_STR
     }
+
+    // GROOVY-11677
+    @ParameterizedTest
+    @ValueSource(strings=['CompileDynamic','TypeChecked','CompileStatic'])
+    void testNonCallableVariable(String mode) {
+        shouldFail """
+            class C {
+                @groovy.transform.$mode
+                void test(List<String> names = ['fizz','buzz']) {
+                    print(names  [0])
+                    print(names()[0]) // error: not callable
+                }
+                List<String> names() {
+                    ['foo','bar']
+                }
+            }
+            new C().test()
+        """
+    }
 }

Reply via email to