You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2022/05/24 18:45:21 UTC

[groovy] branch GROOVY_3_0_X updated: GROOVY-10143: super trait field access

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

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


The following commit(s) were added to refs/heads/GROOVY_3_0_X by this push:
     new d29589d143 GROOVY-10143: super trait field access
d29589d143 is described below

commit d29589d1435ce77d1bbb6de6b454cf866b03741d
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Tue May 24 13:33:24 2022 -0500

    GROOVY-10143: super trait field access
    
    3_0_X backport
---
 .../transform/trait/TraitReceiverTransformer.java  | 19 +++--
 .../traitx/TraitASTTransformationTest.groovy       | 92 ++++++++++++++++++++++
 2 files changed, 101 insertions(+), 10 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/transform/trait/TraitReceiverTransformer.java b/src/main/java/org/codehaus/groovy/transform/trait/TraitReceiverTransformer.java
index 879b7a992f..2277acbee2 100644
--- a/src/main/java/org/codehaus/groovy/transform/trait/TraitReceiverTransformer.java
+++ b/src/main/java/org/codehaus/groovy/transform/trait/TraitReceiverTransformer.java
@@ -43,6 +43,7 @@ import org.codehaus.groovy.ast.expr.VariableExpression;
 import org.codehaus.groovy.control.SourceUnit;
 import org.codehaus.groovy.syntax.SyntaxException;
 import org.codehaus.groovy.syntax.Token;
+import org.codehaus.groovy.syntax.Types;
 
 import java.lang.reflect.Modifier;
 import java.util.Collection;
@@ -100,8 +101,7 @@ class TraitReceiverTransformer extends ClassCodeExpressionTransformer {
             return transformBinaryExpression((BinaryExpression) exp, weavedType);
         } else if (exp instanceof StaticMethodCallExpression) {
             StaticMethodCallExpression call = (StaticMethodCallExpression) exp;
-            ClassNode ownerType = call.getOwnerType();
-            if (traitClass.equals(ownerType)) {
+            if (call.getOwnerType().equals(traitClass)) {
                 MethodCallExpression mce = callX(
                         varX(weaved),
                         call.getMethod(),
@@ -187,9 +187,8 @@ class TraitReceiverTransformer extends ClassCodeExpressionTransformer {
         Expression leftExpression = exp.getLeftExpression();
         Expression rightExpression = exp.getRightExpression();
         Token operation = exp.getOperation();
-        if (operation.getText().equals("=")) {
+        if (operation.getType() == Types.ASSIGN) {
             String leftFieldName = null;
-            // it's an assignment
             if (leftExpression instanceof VariableExpression && ((VariableExpression) leftExpression).getAccessedVariable() instanceof FieldNode) {
                 leftFieldName = ((VariableExpression) leftExpression).getAccessedVariable().getName();
             } else if (leftExpression instanceof FieldExpression) {
@@ -197,14 +196,13 @@ class TraitReceiverTransformer extends ClassCodeExpressionTransformer {
             } else if (leftExpression instanceof PropertyExpression
                     && (((PropertyExpression) leftExpression).isImplicitThis() || "this".equals(((PropertyExpression) leftExpression).getObjectExpression().getText()))) {
                 leftFieldName = ((PropertyExpression) leftExpression).getPropertyAsString();
-                FieldNode fn = tryGetFieldNode(weavedType, leftFieldName);
-                if (fieldHelper == null || fn == null && !fieldHelper.hasPossibleMethod(Traits.helperSetterName(new FieldNode(leftFieldName, 0, ClassHelper.OBJECT_TYPE, weavedType, null)), rightExpression)) {
-                    return binX(propX(varX(weaved), leftFieldName), operation, transform(rightExpression));
-                }
             }
             if (leftFieldName != null) {
-                FieldNode fn = weavedType.getDeclaredField(leftFieldName);
                 FieldNode staticField = tryGetFieldNode(weavedType, leftFieldName);
+                if (fieldHelper == null || staticField == null && !fieldHelper.hasPossibleMethod(Traits.helperSetterName(new FieldNode(leftFieldName, 0, ClassHelper.OBJECT_TYPE, weavedType, null)), rightExpression)) {
+                    return binX(propX(varX(weaved), leftFieldName), operation, transform(rightExpression)); // GROOVY-7342, GROOVY-7456, GROOVY-9739, GROOVY-10143, et al.
+                }
+                FieldNode fn = weavedType.getDeclaredField(leftFieldName);
                 if (fn == null) {
                     fn = new FieldNode(leftFieldName, 0, ClassHelper.OBJECT_TYPE, weavedType, null);
                 }
@@ -217,7 +215,7 @@ class TraitReceiverTransformer extends ClassCodeExpressionTransformer {
                 MethodCallExpression mce = callX(
                         receiver,
                         method,
-                        args(super.transform(rightExpression))
+                        super.transform(rightExpression)
                 );
                 mce.setImplicitThis(false);
                 mce.setSourcePosition(leftExpression instanceof PropertyExpression ? ((PropertyExpression) leftExpression).getProperty() : leftExpression);
@@ -225,6 +223,7 @@ class TraitReceiverTransformer extends ClassCodeExpressionTransformer {
                 return mce;
             }
         }
+
         Expression leftTransform = transform(leftExpression);
         Expression rightTransform = transform(rightExpression);
         Expression ret = exp instanceof DeclarationExpression ?
diff --git a/src/test/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy b/src/test/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
index be886add9c..df8589a62a 100644
--- a/src/test/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
+++ b/src/test/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
@@ -22,6 +22,8 @@ import groovy.transform.SelfType
 import org.codehaus.groovy.ast.ClassHelper
 import org.codehaus.groovy.ast.expr.ClassExpression
 import org.codehaus.groovy.ast.expr.ListExpression
+import org.codehaus.groovy.control.CompilationUnit
+import org.codehaus.groovy.control.CompilerConfiguration
 import org.junit.Test
 
 import static groovy.test.GroovyAssert.assertScript
@@ -3352,6 +3354,96 @@ final class TraitASTTransformationTest {
         '''
     }
 
+    @Test // GROOVY-10143
+    void testTraitAccessToInheritedProperty() {
+        def sourceDir = File.createTempDir()
+        def config = new CompilerConfiguration(
+            targetDirectory: File.createTempDir(),
+            jointCompilationOptions: [memStub: true]
+        )
+        try {
+            def a = new File(sourceDir, 'A.groovy')
+            a.write '''
+                abstract class A {
+                }
+            '''
+            def b = new File(sourceDir, 'B.groovy')
+            b.write '''
+                @groovy.transform.SelfType(A)
+                trait B {
+                    abstract boolean booleanMethod1()
+                    abstract boolean booleanMethod2()
+                    abstract boolean booleanMethod3()
+                    Object getManager() {
+                        if (this.managerObject == null) {
+                            this.managerObject = new C(this as B)
+                        }
+                        this.managerObject
+                    }
+                    C managerObject
+                }
+            '''
+            def c = new File(sourceDir, 'C.groovy')
+            c.write '''
+                class C {
+                    final B base
+                    C(B base) {
+                        this.base = base
+                    }
+                }
+            '''
+            def d = new File(sourceDir, 'D.groovy')
+            d.write '''
+                @groovy.transform.SelfType([A])
+                trait D extends B {
+                    boolean booleanMethod1() {
+                        true
+                    }
+                    boolean booleanMethod2() {
+                        true
+                    }
+                    boolean booleanMethod3() {
+                        true
+                    }
+                    @Override
+                    Object getManager() {
+                        if (managerObject == null) {
+                            managerObject = new E(this as B)
+                        }
+                        managerObject
+                    }
+                }
+            '''
+            def e = new File(sourceDir, 'E.groovy')
+            e.write '''
+                @groovy.transform.InheritConstructors
+                class E extends C {
+                    String getStringValue() {
+                        'string value'
+                    }
+                }
+            '''
+            def f = new File(sourceDir, 'Main.groovy')
+            f.write '''
+                class X extends A implements D {
+                }
+                def x = new X()
+                assert x.manager.base === x
+                assert x.manager.stringValue == 'string value'
+            '''
+
+            def loader = new GroovyClassLoader(this.class.classLoader)
+            def cu = new CompilationUnit(config, null, loader)
+            cu.addSources(a, b, c, d, e, f)
+            cu.compile()
+
+            loader.addClasspath(config.targetDirectory.absolutePath)
+            loader.loadClass('Main').main()
+        } finally {
+            [sourceDir, config.targetDirectory]*.deleteDir()
+        }
+    }
+
     @Test // GROOVY-9386
     void testTraitPropertyInitializedByTap() {
         assertScript '''