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

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

commit ede7100033612c48c7d41d73918b318377bfef20
Author: Eric Milles <[email protected]>
AuthorDate: Tue Sep 16 10:12:56 2025 -0500

    new property access method when super's is private or package-private
---
 .../org/codehaus/groovy/classgen/Verifier.java     | 24 +++++++------
 src/test/groovy/groovy/PropertyTest.groovy         | 42 ++++++++++++++++++----
 2 files changed, 49 insertions(+), 17 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/classgen/Verifier.java 
b/src/main/java/org/codehaus/groovy/classgen/Verifier.java
index a7b08f0310..beac6f0125 100644
--- a/src/main/java/org/codehaus/groovy/classgen/Verifier.java
+++ b/src/main/java/org/codehaus/groovy/classgen/Verifier.java
@@ -114,6 +114,7 @@ import static 
org.codehaus.groovy.ast.tools.GeneralUtils.ctorX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.declS;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.fieldX;
 import static 
org.codehaus.groovy.ast.tools.GeneralUtils.getInterfacesAndSuperInterfaces;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.inSamePackage;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.localVarX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.param;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.params;
@@ -809,16 +810,6 @@ public class Verifier implements GroovyClassVisitor, 
Opcodes {
     public void visitField(final FieldNode node) {
     }
 
-    private boolean methodNeedsReplacement(final MethodNode m) {
-        // no method found, we need to replace
-        if (m == null) return true;
-        // method is in current class, nothing to be done
-        if (m.getDeclaringClass() == getClassNode()) return false;
-        // do not overwrite final
-        if (isFinal(m.getModifiers())) return false;
-        return true;
-    }
-
     @Override
     public void visitProperty(final PropertyNode node) {
         String name = node.getName();
@@ -868,6 +859,19 @@ public class Verifier implements GroovyClassVisitor, 
Opcodes {
         }
     }
 
+    private boolean methodNeedsReplacement(final MethodNode mn) {
+        if (mn != null) {
+            ClassNode declaringClass = mn.getDeclaringClass();
+            // nothing to be done for method of current class
+            if (declaringClass == classNode) return false;
+            // cannot overwrite a non-private final method
+            if (mn.isFinal() && !mn.isPrivate() && (!mn.isPackageScope() || 
inSamePackage(declaringClass, classNode))) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     private void visitGetter(final PropertyNode node, final FieldNode field, 
final Statement getterBlock, final int getterModifiers, final String 
getterName) {
         MethodNode getter = new MethodNode(getterName, getterModifiers, 
node.getType(), Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, getterBlock);
         getter.setSynthetic(true);
diff --git a/src/test/groovy/groovy/PropertyTest.groovy 
b/src/test/groovy/groovy/PropertyTest.groovy
index 30f6653370..88c3493600 100644
--- a/src/test/groovy/groovy/PropertyTest.groovy
+++ b/src/test/groovy/groovy/PropertyTest.groovy
@@ -325,15 +325,42 @@ final class PropertyTest {
         '''
     }
 
+    @Test
+    void testPropertyOverridesGetterAndSetter2() {
+        assertScript '''
+            abstract class A {
+                private final String getFoo() { 'A' }
+            }
+            class C extends A {
+                final String foo = 'C'
+            }
+
+            assert new C().getFoo() == 'C'
+            assert C.getMethod('getFoo').declaringClass.name == 'C'
+        '''
+
+        assertScript '''
+            abstract class A {
+                private final void setFoo(String foo) { }
+            }
+            class C extends A {
+                String foo
+            }
+
+            assert new C(foo: 'C').getFoo() == 'C'
+            assert C.getMethod('setFoo', String).declaringClass.name == 'C'
+        '''
+    }
+
     @Test
     void testPropertyWithOverrideGetterAndSetter() {
         assertScript '''
-            abstract class Base {
+            abstract class A {
                 abstract String getName()
                 abstract void setName(String name)
             }
-            class A extends Base {
-                private String name = 'AA'
+            class C extends A {
+                private String name = 'C'
 
                 @Override
                 String getName() {
@@ -344,10 +371,11 @@ final class PropertyTest {
                     this.name = name
                 }
             }
-            Base a = new A()
-            assert 'AA' == a.name
-            a.name = 'BB'
-            assert 'BB' == a.name
+
+            A a = new C()
+            assert a.name == 'C'
+            a.name = 'X'
+            assert a.name == 'X'
         '''
     }
 

Reply via email to