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

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


The following commit(s) were added to refs/heads/GROOVY_4_0_X by this push:
     new e8a8f50b15 GROOVY-11223: STC: create setter access error
e8a8f50b15 is described below

commit e8a8f50b1593907ff7aeaa2a1844dcd498459594
Author: Eric Milles <eric.mil...@thomsonreuters.com>
AuthorDate: Tue May 7 15:47:33 2024 -0500

    GROOVY-11223: STC: create setter access error
---
 build.gradle                                       |  8 +++-
 .../transform/stc/StaticTypeCheckingVisitor.java   | 17 +++++++-
 .../stc/FieldsAndPropertiesSTCTest.groovy          | 45 +++++++++++++++++++---
 .../sc/FieldsAndPropertiesStaticCompileTest.groovy | 25 +++++++++++-
 4 files changed, 85 insertions(+), 10 deletions(-)

diff --git a/build.gradle b/build.gradle
index 925ea8c9c0..c5fe6a7356 100644
--- a/build.gradle
+++ b/build.gradle
@@ -198,7 +198,7 @@ def testExtensionModuleJar = 
tasks.register("testExtensionModuleJar", Jar) {
     archiveBaseName = 'module-test'
     archiveVersion = '1.4'
     from compileTestExtensionModule
-    from extModuleFixtureDir.dir("src/main/resources")
+    from extModuleFixtureDir.dir('src/main/resources')
     // emulate Maven repo format for output
     destinationDirectory = extModuleRepoDir.map { 
it.dir("jars/module-test/module-test/${archiveVersion.get()}") }
 }
@@ -211,6 +211,10 @@ tasks.named('test') {
     dependsOn testExtensionModuleJar
 }
 
+clean.doFirst {
+    delete "${rootDir}/buildSrc"
+}
+
 if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_16)) {
     logger.lifecycle '''
 ************************************* WARNING 
***********************************************
@@ -251,7 +255,7 @@ sonarqube {
 
 def UNSTABLE = 
/^([\d.-]+(alpha|beta|rc|m)[\d.-]+(groovy[\d.-]+)?|20030203.000550|20031129.200437|200404\d\d|2004-03-19)$/
 // ignore non-stable releases
-tasks.named("dependencyUpdates")?.configure {
+tasks.named('dependencyUpdates')?.configure {
     gradleReleaseChannel = 'current'
     rejectVersionIf {
         !(it.currentVersion.toLowerCase() ==~ UNSTABLE) && 
it.candidate.version.toLowerCase() ==~ UNSTABLE
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 25be6f9e4c..60b17da09c 100644
--- 
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ 
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -1083,8 +1083,21 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
             }
             return false;
         } else {
-            ClassNode firstSetterType = 
setterType.apply(setterInfo.setters.get(0));
-            addAssignmentError(firstSetterType, getType(valueExpression), 
expression);
+            List<MethodNode> visibleSetters = 
filterMethodsByVisibility(setterInfo.setters, 
typeCheckingContext.getEnclosingClassNode());
+            if (visibleSetters.isEmpty()) {
+                String message; // GROOVY-11223
+                if (setterInfo.setters.size() == 1) {
+                    message = String.format("Cannot access method: %2$s of 
class: %1$s",
+                        
prettyPrintTypeName(setterInfo.setters.get(0).getDeclaringClass()),
+                        toMethodParametersString(setterInfo.name, 
extractTypesFromParameters(setterInfo.setters.get(0).getParameters())));
+                } else {
+                    message = "Cannot access methods: " + 
prettyPrintMethodList(setterInfo.setters);
+                }
+                addStaticTypeError(message, leftExpression);
+            } else {
+                ClassNode[] tergetTypes = 
visibleSetters.stream().map(setterType).toArray(ClassNode[]::new);
+                addAssignmentError(tergetTypes.length == 1 ? tergetTypes[0] : 
new UnionTypeClassNode(tergetTypes), getType(valueExpression), expression);
+            }
             return true;
         }
     }
diff --git a/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy 
b/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
index 56fd2e5193..4b140a5eff 100644
--- a/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
+++ b/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
@@ -238,6 +238,7 @@ class FieldsAndPropertiesSTCTest extends 
StaticTypeCheckingTestCase {
                     this.x
                 }
             }
+            new D().test()
         ''',
         'No such property: x for class: D'
     }
@@ -705,13 +706,21 @@ class FieldsAndPropertiesSTCTest extends 
StaticTypeCheckingTestCase {
                 def foo = 1
             }
             def map = new C()
-            map.put('foo', 42)
-            assert map.foo == 42
+            map.put('foo', 11)
+            assert map.foo == 11
+            assert map['foo'] == 11
         '''
         assertScript """
             def map = new ${MapType.name}()
-            map.put('foo', 42)
-            assert map.foo == 42
+            map.put('foo', 11)
+            assert map.foo == 11
+            assert map['foo'] == 11
+            map.put('bar', 22)
+            assert map.bar == 22
+            assert map['bar'] == 22
+            map.put('baz', 33)
+            assert map.baz == 33
+            assert map['baz'] == 33
         """
     }
 
@@ -809,6 +818,28 @@ class FieldsAndPropertiesSTCTest extends 
StaticTypeCheckingTestCase {
         '''
     }
 
+    // GROOVY-11223
+    void testMapPropertyAccess10() {
+        assertScript """
+            def map = new ${MapType.name}()
+            map.foo = 11 // public setter
+            assert map.foo == null
+            assert map.getFoo() == 11
+        """
+        assertScript """
+            def map = new ${MapType.name}()
+            map.bar = 22 // protected setter
+            assert map.bar == null
+            assert map.@bar == 2
+        """
+        assertScript """
+            def map = new ${MapType.name}()
+            map.baz = 33 // package-private setter
+            assert map.baz == null
+            assert map.@baz == 3
+        """
+    }
+
     void testTypeCheckerDoesNotThinkPropertyIsReadOnly() {
         assertScript '''
             // a base class defining a read-only property
@@ -1644,8 +1675,12 @@ class FieldsAndPropertiesSTCTest extends 
StaticTypeCheckingTestCase {
         String boo = "I don't fancy fields in interfaces"
     }
 
-    static class MapType extends HashMap<String,Object> {
+    static class MapType extends HashMap<String,Number> {
         def foo = 1
+        protected bar = 2
+        @PackageScope baz = 3
+        protected void setBar(bar) {}
+        @PackageScope void setBaz(baz) {}
     }
 
     static class BaseClass {
diff --git 
a/src/test/org/codehaus/groovy/classgen/asm/sc/FieldsAndPropertiesStaticCompileTest.groovy
 
b/src/test/org/codehaus/groovy/classgen/asm/sc/FieldsAndPropertiesStaticCompileTest.groovy
index 749d788942..14831a4594 100644
--- 
a/src/test/org/codehaus/groovy/classgen/asm/sc/FieldsAndPropertiesStaticCompileTest.groovy
+++ 
b/src/test/org/codehaus/groovy/classgen/asm/sc/FieldsAndPropertiesStaticCompileTest.groovy
@@ -40,7 +40,7 @@ final class FieldsAndPropertiesStaticCompileTest extends 
FieldsAndPropertiesSTCT
     }
 
     // GROOVY-5579
-    void testUseSetterAndNotSetProperty() {
+    void testUseSetterNotSetProperty() {
         assertScript '''
             Date d = new Date()
             d.time = 1
@@ -858,4 +858,27 @@ final class FieldsAndPropertiesStaticCompileTest extends 
FieldsAndPropertiesSTCT
             new D().test()
         '''
     }
+
+    // GROOVY-11223
+    @Override
+    void testMapPropertyAccess10() {
+        assertScript """
+            def map = new ${MapType.name}()
+            map.foo = 11 // public setter
+            assert map.foo == null
+            assert map.getFoo() == 11
+        """
+        shouldFailWithMessages """
+            def map = new ${MapType.name}()
+            map.bar = 22 // protected setter
+        """,
+        "Method setBar is protected in ${MapType.name}"
+        /*
+        shouldFailWithMessages """
+            def map = new ${MapType.name}()
+            map.baz = 33 // package-private setter
+        """,
+        "Method setBaz is package-private in ${MapType.name}"
+        */
+    }
 }

Reply via email to