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 2023/05/04 19:49:46 UTC

[groovy] branch GROOVY_3_0_X updated: GROOVY-11044: SC: retain implicit-this of property transformed to setter

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 dc988d25f9 GROOVY-11044: SC: retain implicit-this of property transformed to setter
dc988d25f9 is described below

commit dc988d25f909940556379c613c1124848c3521a9
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Thu May 4 13:00:56 2023 -0500

    GROOVY-11044: SC: retain implicit-this of property transformed to setter
    
    3_0_X backport
---
 .../transformers/BinaryExpressionTransformer.java  |   2 +-
 src/test/groovy/beans/BindableTransformTest.groovy | 360 ++++++++++-----------
 2 files changed, 176 insertions(+), 186 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/transform/sc/transformers/BinaryExpressionTransformer.java b/src/main/java/org/codehaus/groovy/transform/sc/transformers/BinaryExpressionTransformer.java
index 04994f7a5d..a0915e5b37 100644
--- a/src/main/java/org/codehaus/groovy/transform/sc/transformers/BinaryExpressionTransformer.java
+++ b/src/main/java/org/codehaus/groovy/transform/sc/transformers/BinaryExpressionTransformer.java
@@ -110,7 +110,7 @@ public class BinaryExpressionTransformer {
                             pe.getObjectExpression(), // "a"
                             directMCT, // "setX"
                             right, // "val"
-                            false,
+                            pe.isImplicitThis(),
                             pe.isSafe(),
                             pe.getProperty(), // "x"
                             bin // "a.x = val"
diff --git a/src/test/groovy/beans/BindableTransformTest.groovy b/src/test/groovy/beans/BindableTransformTest.groovy
index 11f822817f..7ef51221a3 100644
--- a/src/test/groovy/beans/BindableTransformTest.groovy
+++ b/src/test/groovy/beans/BindableTransformTest.groovy
@@ -18,19 +18,24 @@
  */
 package groovy.beans
 
-import groovy.test.GroovyShellTestCase
 import org.codehaus.groovy.control.CompilationFailedException
+import org.junit.Test
 
-import java.beans.PropertyChangeListener
-
+import static groovy.test.GroovyAssert.assertScript
+import static groovy.test.GroovyAssert.shouldFail
 import static java.lang.reflect.Modifier.isPublic
 
-class BindableTransformTest extends GroovyShellTestCase {
+final class BindableTransformTest {
 
-    void testSimpleBindableProperty() {
-        assertScript """
-            import groovy.beans.Bindable
+    private static final imports = '''\
+        import java.beans.*
+        import groovy.beans.*
+        import groovy.transform.*
+    '''
 
+    @Test
+    void testSimpleBindableProperty() {
+        assertScript imports + '''
             class BindableTestBean1 {
                 @Bindable String name
             }
@@ -41,13 +46,12 @@ class BindableTransformTest extends GroovyShellTestCase {
             sb.propertyChange = {changed = true}
             sb.name = "foo"
             assert changed
-        """
+        '''
     }
 
+    @Test
     void testMultipleBindableProperty() {
-        assertScript """
-            import groovy.beans.Bindable
-
+        assertScript imports + '''
             class BindableTestBean2 {
                 @Bindable String name
                 @Bindable String value
@@ -59,17 +63,19 @@ class BindableTransformTest extends GroovyShellTestCase {
             sb.name = "baz"
             sb.value = "biff"
             assert changed == 2
-        """
+        '''
     }
 
+    @Test
     void testMutatingSetter() {
-        assertScript """
+        assertScript imports + '''
             class BindableTestBean3 {
-                @groovy.beans.Bindable String name
+                @Bindable String name
                 void setName(String newName) {
                      this.@name = "x\$newName"
                 }
             }
+
             sb = new BindableTestBean3(name:"foo")
             changed = 0
             sb.propertyChange = {evt ->
@@ -78,109 +84,87 @@ class BindableTransformTest extends GroovyShellTestCase {
             }
             sb.name = "baz"
             assert changed == 1
-        """
+        '''
     }
 
+    @Test
     void testWithSettersAndGetters() {
-        for (int i = 0; i < 16; i++) {
+        for (i in 0..<16) {
             boolean bindClass = i & 1
             boolean field = i & 2
             boolean setter = i & 4
             boolean getter = i & 8
             int expectedCount = (bindClass && !field) ? 2 : 1
             String script = """
-                    import groovy.beans.Bindable
-
-                    ${bindClass ? '@Bindable ' : ''}class BindableTestSettersAndGetters$i {
-
-                        @Bindable String alwaysBound
-                        ${field ? 'protected ' : ''} String name
+                ${bindClass ? '@Bindable ' : ''}class BindableTestSettersAndGetters$i {
+                    @Bindable String alwaysBound
+                    ${field ? 'protected ' : ''} String name
+                    ${setter ? '' : '//'}void setName(String newName) { this.@name = "x\$newName" }
+                    ${getter ? '' : '//'}String getName() { return this.@name }
+                }
 
-                        ${setter ? '' : '//'}void setName(String newName) { this.@name = "x\$newName" }
-                        ${getter ? '' : '//'}String getName() { return this.@name }
-                    }
-                    sb = new BindableTestSettersAndGetters$i(name:"foo", alwaysBound:"bar")
-                    changed = 0
-                    sb.propertyChange = {evt ->
-                        changed++
-                    }
-                    sb.alwaysBound = "baz"
-                    sb.name = "bif"
-                    sb.name = "bif"
-                    assert changed == $expectedCount
-                """
-            try {
-                GroovyShell shell = new GroovyShell()
-                shell.evaluate(script);
-            } catch (Throwable t) {
-                System.out.println("Failed Script: $script")
-                throw t
-            }
+                sb = new BindableTestSettersAndGetters$i(name:"foo", alwaysBound:"bar")
+                changed = 0
+                sb.propertyChange = {evt ->
+                    changed++
+                }
+                sb.alwaysBound = "baz"
+                sb.name = "bif"
+                sb.name = "bif"
+                assert changed == $expectedCount
+            """
+            assertScript(imports + script)
         }
     }
 
+    @Test
     void testOnField() {
-        GroovyShell shell = new GroovyShell()
-        shouldFail(CompilationFailedException) {
-            shell.evaluate("""
-                class BindableTestBean4 {
-                    public @groovy.beans.Bindable String name
-                }
-            """)
-        }
+        shouldFail CompilationFailedException, imports + '''
+            class BindableTestBean4 {
+                public @Bindable String name
+            }
+        '''
     }
 
+    @Test
     void testOnStaticField() {
-        GroovyShell shell = new GroovyShell()
-        shouldFail(CompilationFailedException) {
-            shell.evaluate("""
-                class BindableTestBean5 {
-                     @groovy.beans.Bindable static String name
-                }
-            """)
-        }
+        shouldFail CompilationFailedException, imports +'''
+            class BindableTestBean5 {
+                 @Bindable static String name
+            }
+        '''
     }
 
+    @Test
     void testClassMarkers() {
-        for (int i = 0; i < 7; i++) {
+        for (i in 0..<7) {
             boolean bindField = i & 1
             boolean bindClass = i & 2
             boolean staticField = i & 4
             int bindCount = bindClass ? (staticField ? 2 : 3) : (bindField ? 1 : 0);
 
             String script = """
-                    import groovy.beans.Bindable
-
-                    ${bindClass ? '@Bindable ' : ''}class ClassMarkerBindable$i {
-                        String neither
-
-                        ${bindField ? '@Bindable ' : ''}String bind
-
-                        ${staticField ? 'static ' : ''}String staticString
-                    }
+                ${bindClass ? '@Bindable ' : ''}class ClassMarkerBindable$i {
+                    String neither
+                    ${bindField ? '@Bindable ' : ''}String bind
+                    ${staticField ? 'static ' : ''}String staticString
+                }
 
-                    cb = new ClassMarkerBindable$i(neither:'a', bind:'b', staticString:'c')
-                    bindCount = 0
-                    ${bindClass | bindField ? 'cb.propertyChange = { bindCount++ }' : ''}
-                    cb.neither = 'd'
-                    cb.bind = 'e'
-                    cb.staticString = 'f'
-                    assert bindCount == $bindCount
-                """
-            try {
-                GroovyShell shell = new GroovyShell()
-                shell.evaluate(script);
-            } catch (Throwable t) {
-                System.out.println("Failed Script: $script")
-                throw t
-            }
+                cb = new ClassMarkerBindable$i(neither:'a', bind:'b', staticString:'c')
+                bindCount = 0
+                ${bindClass | bindField ? 'cb.propertyChange = { bindCount++ }' : ''}
+                cb.neither = 'd'
+                cb.bind = 'e'
+                cb.staticString = 'f'
+                assert bindCount == $bindCount
+            """
+            assertScript(imports + script)
         }
     }
 
+    @Test
     void testPrimitiveTypes() {
-        assertScript """
-            import groovy.beans.Bindable
-
+        assertScript imports + '''
             class BindableTestBean7 {
                 @Bindable String testField
                 @Bindable boolean testBoolean
@@ -205,46 +189,35 @@ class BindableTransformTest extends GroovyShellTestCase {
             sb.testFloat = 1
             sb.testDouble = 1
             assert changed == 8
-        """
+        '''
     }
 
+    @Test
     void testBadInheritance() {
-        shouldFail(CompilationFailedException) {
-            GroovyShell shell = new GroovyShell()
-            shell.evaluate("""
-                import groovy.beans.Bindable
-
-                class BindableTestBean8  {
-                    @Bindable String testField
-                    void addPropertyChangeListener(java.beans.PropertyChangeListener l) {}
-                }
-                new BindableTestBean8()
-            """)
-        }
-        shouldFail(CompilationFailedException) {
-            GroovyShell shell = new GroovyShell()
-            shell.evaluate("""
-                import groovy.beans.Bindable
+        shouldFail CompilationFailedException, imports + '''
+            class BindableTestBean8  {
+                @Bindable String testField
+                void addPropertyChangeListener(PropertyChangeListener l) {}
+            }
 
-                class BindableTestBean9  {
-                    void addPropertyChangeListener(java.beans.PropertyChangeListener l) {}
-                }
+            new BindableTestBean8()
+        '''
 
-                class BindableTestBean10 extends BindableTestBean9 {
-                    @Bindable String testField
-                }
+        shouldFail CompilationFailedException, imports + '''
+            class BindableTestBean9  {
+                void addPropertyChangeListener(PropertyChangeListener l) {}
+            }
+            class BindableTestBean10 extends BindableTestBean9 {
+                @Bindable String testField
+            }
 
-                new BindableTestBean10()
-            """)
-        }
+            new BindableTestBean10()
+        '''
     }
 
+    @Test
     void testBindableParent() {
-        assertScript """
-            import groovy.beans.Bindable
-            import java.beans.PropertyChangeEvent
-            import java.beans.PropertyChangeListener
-
+        assertScript imports + '''
             @Bindable
             class BindableTestBeanChild extends BindableTestBeanParent {
                 String prop2
@@ -252,90 +225,72 @@ class BindableTransformTest extends GroovyShellTestCase {
                     super()
                 }
             }
-
             @Bindable
             class BindableTestBeanParent implements PropertyChangeListener {
                 String prop1
                 BindableTestBeanParent() {
                     addPropertyChangeListener(this)
                 }
-
-                void propertyChange(PropertyChangeEvent event) {}
+                void propertyChange(PropertyChangeEvent event) {
+                }
             }
 
             new BindableTestBeanChild()
-        """
+        '''
     }
 
+    @Test
     void testFinalProperty() {
-        shouldFail(CompilationFailedException) {
-            GroovyShell shell = new GroovyShell()
-            shell.evaluate("""
-                import groovy.beans.Bindable
-
-                class BindableTestBean11  {
-                  @Bindable final String testField
-                }
-                1+1
-            """)
-        }
+        shouldFail CompilationFailedException, imports + '''
+            class BindableTestBean11  {
+              @Bindable final String testField
+            }
+            1+1
+        '''
     }
 
+    @Test
     void testOnClassFinalProperty() {
-        shouldFail(ReadOnlyPropertyException) {
-            GroovyShell shell = new GroovyShell()
-            shell.evaluate("""
-                import groovy.beans.Bindable
-
-                @Bindable class BindableTestBean12  {
-                  String testField
-                  final String anotherTestField = 'Fixed'
-                }
+        shouldFail ReadOnlyPropertyException, imports + '''
+            @Bindable class BindableTestBean12  {
+              String testField
+              final String anotherTestField = 'Fixed'
+            }
 
-                sb = new BindableTestBean12()
-                int changed = 0
-                sb.propertyChange = {changed++}
-                sb.testField = 'newValue'
-                assert changed == 1
+            sb = new BindableTestBean12()
+            int changed = 0
+            sb.propertyChange = {changed++}
+            sb.testField = 'newValue'
+            assert changed == 1
 
-                sb.anotherTestField = 'Changed'
-            """)
-        }
+            sb.anotherTestField = 'Changed'
+        '''
     }
 
+    @Test
     void testFinalClass() {
-        shouldFail(ReadOnlyPropertyException) {
-            GroovyShell shell = new GroovyShell()
-            shell.evaluate("""
-                import groovy.beans.Bindable
-
-                @Bindable final class BindableTestBean12  {
-                  String testField
-                  final String anotherTestField = 'Fixed'
-                }
-
-                sb = new BindableTestBean12()
-                int changed = 0
-                sb.propertyChange = {changed++}
-                sb.testField = 'newValue'
-                assert changed == 1
+        shouldFail ReadOnlyPropertyException, imports + '''
+            @Bindable final class BindableTestBean12  {
+              String testField
+              final String anotherTestField = 'Fixed'
+            }
 
-                sb.anotherTestField = 'Changed'
-            """)
-        }
+            sb = new BindableTestBean12()
+            int changed = 0
+            sb.propertyChange = {changed++}
+            sb.testField = 'newValue'
+            assert changed == 1
+            sb.anotherTestField = 'Changed'
+        '''
     }
 
+    @Test
     void testGetPropertyChangeListeners() {
-        assertScript """
-            import groovy.beans.Bindable
-            import java.beans.PropertyChangeListener
-            import java.beans.PropertyChangeEvent
-
+        assertScript imports + '''
             class BindableTestBean14 {
                 @Bindable String foo
                 @Bindable String bar
             }
-
             class FooListener implements PropertyChangeListener {
                void propertyChange( PropertyChangeEvent e ) { }
             }
@@ -347,42 +302,77 @@ class BindableTransformTest extends GroovyShellTestCase {
             assert !sb.getPropertyChangeListeners("bar")
             assert sb.getPropertyChangeListeners("foo") == [listener]
             assert sb.propertyChangeListeners.size() == 1
-        """
+        '''
     }
 
+    @Test
     void testPropertyChangeMethodsNotSynthetic() {
-        def clazz = new GroovyClassLoader().parseClass('class MyBean { @groovy.beans.Bindable String dummy }', 'dummyName')
-        def method = clazz.getMethod('addPropertyChangeListener', PropertyChangeListener)
+        def myBean = new GroovyClassLoader().parseClass('class MyBean { @groovy.beans.Bindable String dummy }', 'dummyName')
+        def method = myBean.getMethod('addPropertyChangeListener', java.beans.PropertyChangeListener)
         assert isPublic(method.modifiers)
         assert !method.isSynthetic()
     }
 
+    @Test
     void testPropertyChangeMethodWithCompileStatic() {
-        assertScript """
-            import groovy.beans.Bindable
-            import groovy.transform.CompileStatic
-
+        assertScript imports + '''
             @CompileStatic
             class MyBean {
               @Bindable String test = "a test"
             }
+
             assert new MyBean()
-        """
+        '''
     }
 
-    void testBindableGeneratedMethodsAreAnnotatedWithGenerated_GROOVY9053() {
-        def person = evaluate('''
+    // GROOVY-11044
+    @Test
+    void testPropertyChangeMethodWithCompileStatic2() {
+        assertScript imports + '''
+            class Bar {
+                @Bindable
+                String baz
+                String other
+            }
+            class Foo {
+                Bar bar
+                @Bindable
+                String another
+                @CompileStatic
+                void postConstruct() {
+                    bar = new Bar()
+                    bar.with {
+                        addPropertyChangeListener('baz') { event ->
+                            other = 'value' // ClassCastException: Foo cannot be cast to Bar
+                            print 'changed'
+                        }
+                    }
+                    print 'ready;'
+                }
+            }
+
+            Foo foo = new Foo()
+            foo.postConstruct()
+            foo.getBar().setBaz('xxx')
+        '''
+    }
+
+    // GROOVY-9053
+    @Test
+    void testBindableGeneratedMethodsAreAnnotatedWithGenerated() {
+        def person = new GroovyShell().evaluate(imports + '''
             class Person {
-                @groovy.beans.Bindable
+                @Bindable
                 String firstName
 
                 void setFirstName(String fn) {
                     this.firstName = fn.toUpperCase()
                 }
 
-                @groovy.beans.Bindable
+                @Bindable
                 def zipCode
              }
+
              new Person()
         ''')