This is an automated email from the ASF dual-hosted git repository. emilles pushed a commit to branch GROOVY_5_0_X in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/GROOVY_5_0_X by this push: new 99ddcf17be GROOVY-11675: split property may declare final modifier for accessors 99ddcf17be is described below commit 99ddcf17bed599ecb13b7ddec6227a330e3a53d5 Author: Eric Milles <eric.mil...@thomsonreuters.com> AuthorDate: Wed Sep 17 08:44:56 2025 -0500 GROOVY-11675: split property may declare final modifier for accessors --- .../groovy/ast/tools/PropertyNodeUtils.java | 15 ++++-- src/test/groovy/groovy/PropertyTest.groovy | 55 +++++++++++++++++++++- 2 files changed, 64 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/codehaus/groovy/ast/tools/PropertyNodeUtils.java b/src/main/java/org/codehaus/groovy/ast/tools/PropertyNodeUtils.java index 1f282023d8..a0abc685a6 100644 --- a/src/main/java/org/codehaus/groovy/ast/tools/PropertyNodeUtils.java +++ b/src/main/java/org/codehaus/groovy/ast/tools/PropertyNodeUtils.java @@ -23,6 +23,7 @@ import org.codehaus.groovy.ast.PropertyNode; import java.lang.reflect.Modifier; public class PropertyNodeUtils { + /** * Fields within the AST that have no explicit visibility are deemed to be properties * and represented by a PropertyNode. The Groovy compiler creates accessor methods and @@ -33,11 +34,17 @@ public class PropertyNodeUtils { * methods (such as {@code volatile} and {@code transient}) but other modifiers are carried over, * for example {@code static}. * - * @param propNode the original property node + * @since 2.4.8 + * @param node the original property node * @return the modifiers which make sense for an accessor method */ - public static int adjustPropertyModifiersForMethod(PropertyNode propNode) { - // GROOVY-3726: clear some modifiers so that they do not get applied to methods - return propNode.getModifiers() & ~(Modifier.FINAL | Modifier.TRANSIENT | Modifier.VOLATILE); + public static int adjustPropertyModifiersForMethod(final PropertyNode node) { + // GROOVY-3726, GROOVY-7969: clear modifiers that do not apply to methods + int mods = node.getModifiers() & ~(Modifier.TRANSIENT|Modifier.VOLATILE); + // GROOVY-11675: split property case may declare final modifier + if (node.getField() == null || node.getField().isSynthetic()) { + mods &= ~Modifier.FINAL; + } + return mods; } } diff --git a/src/test/groovy/groovy/PropertyTest.groovy b/src/test/groovy/groovy/PropertyTest.groovy index 2a9db0a400..761fcde041 100644 --- a/src/test/groovy/groovy/PropertyTest.groovy +++ b/src/test/groovy/groovy/PropertyTest.groovy @@ -132,6 +132,57 @@ final class PropertyTest { assert foo.body == "James" } + // GROOVY-11675 + @Test + void testSplitProperty() { + assertScript '''import java.lang.reflect.* + class C { + @Deprecated private final Integer one + final Integer one + + protected synchronized Integer two + synchronized Integer two + + public Integer three + @Deprecated Integer three + } + + Member m = C.getDeclaredField('one') + assert m.isAnnotationPresent(Deprecated) + assert m.modifiers == Modifier.PRIVATE + Modifier.FINAL + + m = C.getDeclaredMethod('getOne') + assert !m.isAnnotationPresent(Deprecated) + assert m.modifiers == Modifier.PUBLIC + Modifier.FINAL + + groovy.test.GroovyAssert.shouldFail(NoSuchMethodException) { + m = C.getDeclaredMethod('setOne', Integer) + } + + m = C.getDeclaredField('two') + assert m.modifiers == Modifier.PROTECTED + // field cannot carry modifier SYNCHRONIZED + + m = C.getDeclaredMethod('getTwo') + assert m.modifiers == Modifier.PUBLIC + Modifier.SYNCHRONIZED + + m = C.getDeclaredMethod('setTwo', Integer) + assert m.modifiers == Modifier.PUBLIC + Modifier.SYNCHRONIZED + + m = C.getDeclaredField('three') + assert m.modifiers == Modifier.PUBLIC + assert !m.isAnnotationPresent(Deprecated) + + m = C.getDeclaredMethod('getThree') + assert m.modifiers == Modifier.PUBLIC + assert m.isAnnotationPresent(Deprecated) + + m = C.getDeclaredMethod('setThree', Integer) + assert m.modifiers == Modifier.PUBLIC + assert m.isAnnotationPresent(Deprecated) + ''' + } + @Test void testFinalProperty() { assertScript ''' @@ -821,7 +872,7 @@ final class PropertyTest { static class Child extends Base { protected String field = 'foo' + super.field - def getField() { field } + def getField() { field } void setSuperField(value) { super.field = value } @@ -829,7 +880,7 @@ final class PropertyTest { def thing = 'bar thing' - def superthing() { + def superthing() { 'bar1' + super.thing }