Skip to content

Commit 6ddf1e2

Browse files
committed
GROOVY-11579: skip bridge method in final method override checking
3_0_X backport
1 parent 77ac1c8 commit 6ddf1e2

File tree

2 files changed

+54
-31
lines changed

2 files changed

+54
-31
lines changed

src/main/java/org/codehaus/groovy/classgen/ClassCompletionVerifier.java

+21-18
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
import static org.objectweb.asm.Opcodes.ACC_STATIC;
7474
import static org.objectweb.asm.Opcodes.ACC_STRICT;
7575
import static org.objectweb.asm.Opcodes.ACC_SYNCHRONIZED;
76+
import static org.objectweb.asm.Opcodes.ACC_SYNTHETIC;
7677
import static org.objectweb.asm.Opcodes.ACC_TRANSIENT;
7778
import static org.objectweb.asm.Opcodes.ACC_VOLATILE;
7879
/**
@@ -368,38 +369,39 @@ private static boolean isConstructor(MethodNode method) {
368369

369370
private void checkMethodsForOverridingFinal(ClassNode cn) {
370371
for (MethodNode method : cn.getMethods()) {
372+
if ((method.getModifiers() & ACC_SYNTHETIC) != 0) continue; // GROOVY-11579: bridge method
373+
374+
ClassNode sc = cn.getSuperClass();
371375
Parameter[] params = method.getParameters();
372-
for (MethodNode superMethod : cn.getSuperClass().getMethods(method.getName())) {
373-
Parameter[] superParams = superMethod.getParameters();
374-
if (!hasEqualParameterTypes(params, superParams)) continue;
375-
if (!superMethod.isFinal()) break;
376-
addInvalidUseOfFinalError(method, params, superMethod.getDeclaringClass());
377-
return;
376+
for (MethodNode superMethod : sc.getMethods(method.getName())) {
377+
if (superMethod.isFinal()
378+
&& hasEqualParameterTypes(params, superMethod.getParameters())) {
379+
StringBuilder sb = new StringBuilder();
380+
sb.append("You are not allowed to override the final method ");
381+
sb.append(method.getName());
382+
appendParamsDescription(params, sb);
383+
sb.append(" from ");
384+
sb.append(getDescription(sc));
385+
sb.append(".");
386+
387+
addError(sb.toString(), method.getLineNumber() > 0 ? method : cn);
388+
}
378389
}
379390
}
380391
}
381392

382-
private void addInvalidUseOfFinalError(MethodNode method, Parameter[] parameters, ClassNode superCN) {
383-
StringBuilder msg = new StringBuilder();
384-
msg.append("You are not allowed to override the final method ").append(method.getName());
385-
appendParamsDescription(parameters, msg);
386-
msg.append(" from ").append(getDescription(superCN));
387-
msg.append(".");
388-
addError(msg.toString(), method);
389-
}
390-
391393
private void appendParamsDescription(Parameter[] parameters, StringBuilder msg) {
392-
msg.append("(");
394+
msg.append('(');
393395
boolean needsComma = false;
394396
for (Parameter parameter : parameters) {
395397
if (needsComma) {
396-
msg.append(",");
398+
msg.append(',');
397399
} else {
398400
needsComma = true;
399401
}
400402
msg.append(parameter.getType());
401403
}
402-
msg.append(")");
404+
msg.append(')');
403405
}
404406

405407
private void addWeakerAccessError(ClassNode cn, MethodNode method, Parameter[] parameters, MethodNode superMethod) {
@@ -414,6 +416,7 @@ private void addWeakerAccessError(ClassNode cn, MethodNode method, Parameter[] p
414416
msg.append(superMethod.getDeclaringClass().getName());
415417
msg.append("; attempting to assign weaker access privileges; was ");
416418
msg.append(superMethod.isPublic() ? "public" : (superMethod.isProtected() ? "protected" : "package-private"));
419+
417420
addError(msg.toString(), method);
418421
}
419422

src/test/groovy/OverrideTest.groovy

+33-13
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,8 @@ final class OverrideTest {
140140
assert err.message.contains("Method 'methodTakesObject' from class 'HasMethodWithBadArgType' does not override method from its superclass or interfaces but is annotated with @Override.")
141141
}
142142

143-
@Test // GROOVY-6654
143+
// GROOVY-6654
144+
@Test
144145
void testCovariantParameterType1() {
145146
assertScript '''
146147
class C<T> {
@@ -156,7 +157,8 @@ final class OverrideTest {
156157
'''
157158
}
158159

159-
@Test // GROOVY-10675
160+
// GROOVY-10675
161+
@Test
160162
void testCovariantParameterType2() {
161163
assertScript '''
162164
@FunctionalInterface
@@ -174,48 +176,66 @@ final class OverrideTest {
174176
'''
175177
}
176178

177-
@Test // GROOVY-7849
179+
// GROOVY-7849
180+
@Test
178181
void testCovariantArrayReturnType1() {
179182
assertScript '''
180-
interface Base {}
181-
182-
interface Derived extends Base {}
183-
183+
interface A {
184+
}
185+
interface B extends A {
186+
}
184187
interface I {
185-
Base[] foo()
188+
A[] foo()
186189
}
187-
188190
class C implements I {
189-
Derived[] foo() { null }
191+
B[] foo() { null }
190192
}
193+
191194
new C().foo()
192195
'''
193196
}
194197

195-
@Test // GROOVY-7185
198+
// GROOVY-7185
199+
@Test
196200
void testCovariantArrayReturnType2() {
197201
assertScript '''
198202
interface A<T> {
199203
T[] process();
200204
}
201-
202205
class B implements A<String> {
203206
@Override
204207
public String[] process() {
205208
['foo']
206209
}
207210
}
208-
209211
class C extends B {
210212
@Override
211213
String[] process() {
212214
super.process()
213215
}
214216
}
217+
215218
assert new C().process()[0] == 'foo'
216219
'''
217220
}
218221

222+
// GROOVY-11579
223+
@Test
224+
void testCovariantBridgeReturnType() {
225+
assertScript '''
226+
interface I<T> {
227+
T m()
228+
}
229+
abstract class A {
230+
final String m() { 'A' }
231+
}
232+
class C extends A implements I<String> {
233+
}
234+
235+
assert new C().m() == 'A'
236+
'''
237+
}
238+
219239
@Test
220240
void testOverrideOnMethodWithDefaultParameters() {
221241
assertScript '''

0 commit comments

Comments
 (0)