You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2019/08/02 14:23:16 UTC

[groovy] branch master updated: GROOVY-8002: propagate source position to method in chain assignment

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

sunlan 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 9c55d50  GROOVY-8002: propagate source position to method in chain assignment
9c55d50 is described below

commit 9c55d50c886b249c6da9f470562bfe7dd208b01c
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Sat Jul 20 13:20:11 2019 -0500

    GROOVY-8002: propagate source position to method in chain assignment
---
 .../groovy/ast/expr/MethodCallExpression.java      | 21 +++++++
 .../asm/sc/StaticPropertyAccessHelper.java         |  2 +
 src/test/groovy/bugs/Groovy8002.groovy             | 65 ++++++++++++++++++++++
 3 files changed, 88 insertions(+)

diff --git a/src/main/java/org/codehaus/groovy/ast/expr/MethodCallExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/MethodCallExpression.java
index a15cb2f..f0250a8 100644
--- a/src/main/java/org/codehaus/groovy/ast/expr/MethodCallExpression.java
+++ b/src/main/java/org/codehaus/groovy/ast/expr/MethodCallExpression.java
@@ -209,4 +209,25 @@ public class MethodCallExpression extends Expression implements MethodCall {
     public MethodNode getMethodTarget() {
         return target;
     }
+
+    @Override
+    public void setSourcePosition(ASTNode node) {
+        super.setSourcePosition(node);
+        // GROOVY-8002: propagate position to (possibly new) method expression
+        if (node instanceof MethodCall) {
+            if (node instanceof MethodCallExpression) {
+                method.setSourcePosition(((MethodCallExpression) node).getMethod());
+            } else if (node.getLineNumber() > 0) {
+                method.setLineNumber(node.getLineNumber());
+                method.setColumnNumber(node.getColumnNumber());
+                method.setLastLineNumber(node.getLineNumber());
+                method.setLastColumnNumber(node.getColumnNumber() + getMethodAsString().length());
+            }
+            if (arguments != null) {
+                arguments.setSourcePosition(((MethodCall) node).getArguments());
+            }
+        } else if (node instanceof PropertyExpression) {
+            method.setSourcePosition(((PropertyExpression) node).getProperty());
+        }
+    }
 }
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticPropertyAccessHelper.java b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticPropertyAccessHelper.java
index b36801b..67f75f6 100644
--- a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticPropertyAccessHelper.java
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticPropertyAccessHelper.java
@@ -35,6 +35,7 @@ import java.util.Arrays;
  * @since 2.4.0
  */
 public abstract class StaticPropertyAccessHelper {
+
     public static Expression transformToSetterCall(
             Expression receiver,
             MethodNode setterMethod,
@@ -114,6 +115,7 @@ public abstract class StaticPropertyAccessHelper {
         public Expression transformExpression(final ExpressionTransformer transformer) {
             PoppingMethodCallExpression trn = new PoppingMethodCallExpression(receiver.transformExpression(transformer), setter, (TemporaryVariableExpression) tmp.transformExpression(transformer));
             trn.copyNodeMetaData(this);
+            trn.setSourcePosition(this);
             trn.setImplicitThis(isImplicitThis());
             trn.setSafe(isSafe());
             trn.setSpreadSafe(isSpreadSafe());
diff --git a/src/test/groovy/bugs/Groovy8002.groovy b/src/test/groovy/bugs/Groovy8002.groovy
new file mode 100644
index 0000000..2f628bc
--- /dev/null
+++ b/src/test/groovy/bugs/Groovy8002.groovy
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * 	http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package groovy.bugs
+
+import groovy.transform.CompileStatic
+import org.junit.Test
+
+import static groovy.test.GroovyAssert.assertScript
+
+@CompileStatic
+final class Groovy8002 {
+
+    @Test
+    void testSourcePositionOfMethodInChainAssignmentCS() {
+        assertScript '''
+            import groovy.transform.*
+            import static org.codehaus.groovy.control.CompilePhase.*
+
+            class B {
+                private String z
+                void setZero(String zero) { z = zero }
+            }
+
+            @CompileStatic
+            class C {
+                String x
+                B b = new B()
+                @ASTTest(phase=CLASS_GENERATION, value={
+                    def expr = node.code.statements[-1].expression.rightExpression.@call
+                    assert expr.class.simpleName == 'PoppingMethodCallExpression'
+                    assert expr.lineNumber > 0 && expr.columnNumber > 0
+
+                    def zero = expr.method // "zero" in "x = b.zero = 'X'"
+                    assert zero.lineNumber > 0
+                    assert zero.columnNumber > 0
+                    assert zero.lastLineNumber == zero.lineNumber
+                    assert zero.lastColumnNumber == zero.columnNumber + 4
+                })
+                C() {
+                    x = b.zero = 'X'
+                }
+            }
+
+            def c = new C()
+            assert c.x == 'X'
+            assert c.b.@z == 'X'
+        '''
+    }
+}