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}" + */ + } }