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 c9ea8e9026 GROOVY-11675: split property may declare final modifier for
accessors
c9ea8e9026 is described below
commit c9ea8e902699982dc66c17a489065f0495821822
Author: Eric Milles <[email protected]>
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 | 101 +++++++++++++++------
2 files changed, 85 insertions(+), 31 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 fdbd437b56..6d7564965c 100644
--- a/src/test/groovy/groovy/PropertyTest.groovy
+++ b/src/test/groovy/groovy/PropertyTest.groovy
@@ -117,38 +117,85 @@ class PropertyTest extends GroovyTestCase {
assert foo.body == "James"
}
+ // GROOVY-11675
+ 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)
+ '''
+ }
+
void testFinalProperty() {
- def shell = new GroovyShell();
- assertScript """
- class A {
- final foo = 1
- }
- A.class.declaredMethods.each {
- assert it.name!="setFoo"
+ assertScript '''
+ class C {
+ final foo = 1
+ }
+ C.declaredMethods.each {
+ assert it.name != "setFoo"
+ }
- }
- assert new A().foo==1
- """
- shouldFail {
- shell.execute """
- class A {
- final foo = 1
- }
- new A().foo = 2
- """
- }
+ assert new C().foo == 1
+ '''
+
+ shouldFail '''
+ class C {
+ final foo = 1
+ }
+
+ new C().foo = 2
+ '''
}
void testFinalField() {
- def shell = new GroovyShell();
- shouldFail {
- shell.execute """
- class A {
- public final foo = 1
- }
- new A().foo = 2
- """
- }
+ shouldFail '''
+ class C {
+ public final foo = 1
+ }
+
+ new C().foo = 2
+ '''
}
void testFinalPropertyWithInheritance() {