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 baacf4e001 GROOVY-11579: skip bridge method in final method override
checking
baacf4e001 is described below
commit baacf4e001b6403bf153b114ea7cf7714883bac2
Author: Eric Milles <[email protected]>
AuthorDate: Sun Mar 9 12:34:39 2025 -0500
GROOVY-11579: skip bridge method in final method override checking
4_0_X backport
---
.../groovy/classgen/ClassCompletionVerifier.java | 33 +++++++++-------
src/test/groovy/OverrideTest.groovy | 46 ++++++++++++++++------
2 files changed, 51 insertions(+), 28 deletions(-)
diff --git
a/src/main/java/org/codehaus/groovy/classgen/ClassCompletionVerifier.java
b/src/main/java/org/codehaus/groovy/classgen/ClassCompletionVerifier.java
index 8ff9c1ef00..0240ebbbc1 100644
--- a/src/main/java/org/codehaus/groovy/classgen/ClassCompletionVerifier.java
+++ b/src/main/java/org/codehaus/groovy/classgen/ClassCompletionVerifier.java
@@ -74,6 +74,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;
@@ -432,26 +433,27 @@ public class ClassCompletionVerifier extends
ClassCodeVisitorSupport {
private void checkMethodsForOverridingFinal(final 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 (!ParameterUtils.parametersEqual(params, superParams))
continue;
- if (!superMethod.isFinal()) break;
- addInvalidUseOfFinalError(method, params,
superMethod.getDeclaringClass());
- return;
+ for (MethodNode superMethod : sc.getMethods(method.getName())) {
+ if (superMethod.isFinal()
+ && ParameterUtils.parametersEqual(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(final MethodNode method, final
Parameter[] parameters, final 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(final Parameter[] parameters, final
StringBuilder msg) {
msg.append('(');
boolean needsComma = false;
@@ -478,6 +480,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 2280822ba3..a7699d7002 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 '''