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

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


The following commit(s) were added to refs/heads/GROOVY_3_0_X by this push:
     new 6ddf1e242e GROOVY-11579: skip bridge method in final method override 
checking
6ddf1e242e is described below

commit 6ddf1e242e2214bba82a1c3aef0a54018df7b820
Author: Eric Milles <[email protected]>
AuthorDate: Sun Mar 9 12:34:39 2025 -0500

    GROOVY-11579: skip bridge method in final method override checking
    
    3_0_X backport
---
 .../groovy/classgen/ClassCompletionVerifier.java   | 39 +++++++++---------
 src/test/groovy/OverrideTest.groovy                | 46 ++++++++++++++++------
 2 files changed, 54 insertions(+), 31 deletions(-)

diff --git 
a/src/main/java/org/codehaus/groovy/classgen/ClassCompletionVerifier.java 
b/src/main/java/org/codehaus/groovy/classgen/ClassCompletionVerifier.java
index dff9da3a94..53407fe105 100644
--- a/src/main/java/org/codehaus/groovy/classgen/ClassCompletionVerifier.java
+++ b/src/main/java/org/codehaus/groovy/classgen/ClassCompletionVerifier.java
@@ -73,6 +73,7 @@ import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
 import static org.objectweb.asm.Opcodes.ACC_STATIC;
 import static org.objectweb.asm.Opcodes.ACC_STRICT;
 import static org.objectweb.asm.Opcodes.ACC_SYNCHRONIZED;
+import static org.objectweb.asm.Opcodes.ACC_SYNTHETIC;
 import static org.objectweb.asm.Opcodes.ACC_TRANSIENT;
 import static org.objectweb.asm.Opcodes.ACC_VOLATILE;
 /**
@@ -368,38 +369,39 @@ public class ClassCompletionVerifier extends 
ClassCodeVisitorSupport {
 
     private void checkMethodsForOverridingFinal(ClassNode cn) {
         for (MethodNode method : cn.getMethods()) {
+            if ((method.getModifiers() & ACC_SYNTHETIC) != 0) continue; // 
GROOVY-11579: bridge method
+
+            ClassNode sc = cn.getSuperClass();
             Parameter[] params = method.getParameters();
-            for (MethodNode superMethod : 
cn.getSuperClass().getMethods(method.getName())) {
-                Parameter[] superParams = superMethod.getParameters();
-                if (!hasEqualParameterTypes(params, superParams)) continue;
-                if (!superMethod.isFinal()) break;
-                addInvalidUseOfFinalError(method, params, 
superMethod.getDeclaringClass());
-                return;
+            for (MethodNode superMethod : sc.getMethods(method.getName())) {
+                if (superMethod.isFinal()
+                        && hasEqualParameterTypes(params, 
superMethod.getParameters())) {
+                    StringBuilder sb = new StringBuilder();
+                    sb.append("You are not allowed to override the final 
method ");
+                    sb.append(method.getName());
+                    appendParamsDescription(params, sb);
+                    sb.append(" from ");
+                    sb.append(getDescription(sc));
+                    sb.append(".");
+
+                    addError(sb.toString(), method.getLineNumber() > 0 ? 
method : cn);
+                }
             }
         }
     }
 
-    private void addInvalidUseOfFinalError(MethodNode method, Parameter[] 
parameters, ClassNode superCN) {
-        StringBuilder msg = new StringBuilder();
-        msg.append("You are not allowed to override the final method 
").append(method.getName());
-        appendParamsDescription(parameters, msg);
-        msg.append(" from ").append(getDescription(superCN));
-        msg.append(".");
-        addError(msg.toString(), method);
-    }
-
     private void appendParamsDescription(Parameter[] parameters, StringBuilder 
msg) {
-        msg.append("(");
+        msg.append('(');
         boolean needsComma = false;
         for (Parameter parameter : parameters) {
             if (needsComma) {
-                msg.append(",");
+                msg.append(',');
             } else {
                 needsComma = true;
             }
             msg.append(parameter.getType());
         }
-        msg.append(")");
+        msg.append(')');
     }
 
     private void addWeakerAccessError(ClassNode cn, MethodNode method, 
Parameter[] parameters, MethodNode superMethod) {
@@ -414,6 +416,7 @@ public class ClassCompletionVerifier extends 
ClassCodeVisitorSupport {
         msg.append(superMethod.getDeclaringClass().getName());
         msg.append("; attempting to assign weaker access privileges; was ");
         msg.append(superMethod.isPublic() ? "public" : 
(superMethod.isProtected() ? "protected" : "package-private"));
+
         addError(msg.toString(), method);
     }
 
diff --git a/src/test/groovy/OverrideTest.groovy 
b/src/test/groovy/OverrideTest.groovy
index c29618a8d9..ed7ccb0a08 100644
--- a/src/test/groovy/OverrideTest.groovy
+++ b/src/test/groovy/OverrideTest.groovy
@@ -140,7 +140,8 @@ final class OverrideTest {
         assert err.message.contains("Method 'methodTakesObject' from class 
'HasMethodWithBadArgType' does not override method from its superclass or 
interfaces but is annotated with @Override.")
     }
 
-    @Test // GROOVY-6654
+    // GROOVY-6654
+    @Test
     void testCovariantParameterType1() {
         assertScript '''
             class C<T> {
@@ -156,7 +157,8 @@ final class OverrideTest {
         '''
     }
 
-    @Test // GROOVY-10675
+    // GROOVY-10675
+    @Test
     void testCovariantParameterType2() {
         assertScript '''
             @FunctionalInterface
@@ -174,48 +176,66 @@ final class OverrideTest {
         '''
     }
 
-    @Test // GROOVY-7849
+    // GROOVY-7849
+    @Test
     void testCovariantArrayReturnType1() {
         assertScript '''
-            interface Base {}
-
-            interface Derived extends Base {}
-
+            interface A {
+            }
+            interface B extends A {
+            }
             interface I {
-                Base[] foo()
+                A[] foo()
             }
-
             class C implements I {
-                Derived[] foo() { null }
+                B[] foo() { null }
             }
+
             new C().foo()
         '''
     }
 
-    @Test // GROOVY-7185
+    // GROOVY-7185
+    @Test
     void testCovariantArrayReturnType2() {
         assertScript '''
             interface A<T> {
                 T[] process();
             }
-
             class B implements A<String> {
                 @Override
                 public String[] process() {
                     ['foo']
                 }
             }
-
             class C extends B {
                 @Override
                 String[] process() {
                     super.process()
                 }
             }
+
             assert new C().process()[0] == 'foo'
         '''
     }
 
+    // GROOVY-11579
+    @Test
+    void testCovariantBridgeReturnType() {
+        assertScript '''
+            interface I<T> {
+                T m()
+            }
+            abstract class A {
+                final String m() { 'A' }
+            }
+            class C extends A implements I<String> {
+            }
+
+            assert new C().m() == 'A'
+        '''
+    }
+
     @Test
     void testOverrideOnMethodWithDefaultParameters() {
         assertScript '''

Reply via email to