Skip to content

Commit 9299d69

Browse files
committed
GROOVY-11627: SC: disable mixed public and private overloads checking
1 parent e29ced4 commit 9299d69

4 files changed

Lines changed: 70 additions & 41 deletions

File tree

src/main/java/groovy/lang/MetaClassImpl.java

Lines changed: 31 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -446,50 +446,48 @@ protected LinkedList<CachedClass> getSuperClasses() {
446446
}
447447

448448
private void removeMultimethodsOverloadedWithPrivateMethods() {
449-
MethodIndexAction mia = new MethodIndexAction() {
449+
var mia = new MethodIndexAction() {
450450
@Override
451451
public boolean skipClass(final Class<?> clazz) {
452452
return clazz == theClass;
453453
}
454454

455455
@Override
456-
public void methodNameAction(final Class<?> clazz, final MetaMethodIndex.Cache e) {
457-
if (e.methods == null)
458-
return;
459-
460-
boolean hasPrivate = false;
461-
if (e.methods instanceof FastArray) {
462-
FastArray methods = (FastArray) e.methods;
463-
final int len = methods.size();
464-
final Object[] data = methods.getArray();
465-
for (int i = 0; i != len; ++i) {
456+
public void methodNameAction(final Class<?> clazz, final MetaMethodIndex.Cache entry) {
457+
if (hasPrivateInMethods(clazz, entry)) { // GROOVY-5193, etc.
458+
// We have private methods for that name, so remove the
459+
// multimethods. That is the same as in our index for
460+
// super, so just copy the list from there. It is not
461+
// possible to use a pointer here because the methods
462+
// in the index for super are replaced later by MOP
463+
// methods like super$5$foo
464+
Object o = entry.methodsForSuper;
465+
if (o instanceof FastArray) {
466+
entry.methods = ((FastArray) o).copy();
467+
} else {
468+
entry.methods = o;
469+
}
470+
}
471+
}
472+
473+
private boolean hasPrivateInMethods(final Class<?> clazz, final MetaMethodIndex.Cache entry) {
474+
if (entry.methods instanceof FastArray) {
475+
FastArray methods = (FastArray) entry.methods;
476+
int size = methods.size();
477+
var data = methods.getArray();
478+
for (int i = 0; i != size; ++i) {
466479
MetaMethod method = (MetaMethod) data[i];
467-
if (method.isPrivate() && clazz == method.getDeclaringClass().getTheClass()) {
468-
hasPrivate = true;
469-
break;
480+
if (method.isPrivate() && method.getDeclaringClass().getTheClass() == clazz) {
481+
return true;
470482
}
471483
}
472-
} else {
473-
MetaMethod method = (MetaMethod) e.methods;
474-
if (method.isPrivate() && clazz == method.getDeclaringClass().getTheClass()) {
475-
hasPrivate = true;
484+
} else if (entry.methods instanceof MetaMethod) {
485+
MetaMethod method = (MetaMethod) entry.methods;
486+
if (method.isPrivate() && method.getDeclaringClass().getTheClass() == clazz) {
487+
return true;
476488
}
477489
}
478-
479-
if (!hasPrivate) return;
480-
481-
// We have private methods for that name, so remove the
482-
// multimethods. That is the same as in our index for
483-
// super, so just copy the list from there. It is not
484-
// possible to use a pointer here, because the methods
485-
// in the index for super are replaced later by MOP
486-
// methods like super$5$foo
487-
final Object o = e.methodsForSuper;
488-
if (o instanceof FastArray) {
489-
e.methods = ((FastArray) o).copy();
490-
} else {
491-
e.methods = o;
492-
}
490+
return false;
493491
}
494492
};
495493
mia.iterate();

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
import static org.codehaus.groovy.ast.tools.GenericsUtils.buildWildcardType;
7575
import static org.codehaus.groovy.ast.tools.GenericsUtils.correctToGenericsSpecRecurse;
7676
import static org.codehaus.groovy.ast.tools.GenericsUtils.createGenericsSpec;
77+
import static org.codehaus.groovy.transform.sc.StaticCompilationVisitor.isStaticallyCompiled;
7778
import static org.objectweb.asm.Opcodes.ACC_FINAL;
7879
import static org.objectweb.asm.Opcodes.ACC_PRIVATE;
7980
import static org.objectweb.asm.Opcodes.ACC_STATIC;
@@ -538,8 +539,8 @@ public void visitMethod(final MethodNode node) {
538539
checkOverloadingPrivateAndPublic(node);
539540
}
540541
checkMethodForIncorrectModifiers(node);
541-
checkGenericsUsage(node, node.getParameters());
542542
checkGenericsUsage(node, node.getReturnType());
543+
checkGenericsUsage(node, node.getParameters());
543544
for (Parameter param : node.getParameters()) {
544545
if (ClassHelper.isPrimitiveVoid(param.getType())) {
545546
addError("The " + getDescription(param) + " in " + getDescription(node) + " has invalid type void", param);
@@ -588,6 +589,7 @@ private void checkMethodForWeakerAccessPrivileges(final MethodNode mn, final Cla
588589
}
589590

590591
private void checkOverloadingPrivateAndPublic(final MethodNode node) {
592+
if (isStaticallyCompiled(currentClass)) return; // GROOVY-11627
591593
boolean mixed = false;
592594
if (node.isPublic()) {
593595
for (MethodNode mn : currentClass.getDeclaredMethods(node.getName())) {

src/test/groovy/bugs/Groovy5193.groovy

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ package bugs
2121
import org.codehaus.groovy.control.MultipleCompilationErrorsException
2222
import org.junit.jupiter.api.Test
2323

24+
import static groovy.test.GroovyAssert.assertScript
2425
import static groovy.test.GroovyAssert.shouldFail
2526

2627
final class Groovy5193 {
@@ -54,4 +55,29 @@ final class Groovy5193 {
5455
'''
5556
assert err.message.contains('Mixing private and public/protected methods of the same name causes multimethods to be disabled')
5657
}
58+
59+
@Test
60+
void testMixingMethodsWithPrivatePublicAccessInSameClass3() {
61+
assertScript '''
62+
class A {
63+
def f(x) { g(x) }
64+
def g(x) {"object case"}
65+
}
66+
class B extends A {
67+
private g(String x) {"string case"}
68+
}
69+
70+
def a = new A()
71+
assert a.f(null) == "object case"
72+
assert a.g(null) == "object case"
73+
assert a.f("xx") == "object case"
74+
assert a.g("xx") == "object case"
75+
76+
def b = new B()
77+
assert b.f(null) == "object case"
78+
assert b.g(null) == "object case"
79+
assert b.f("xx") == "object case"
80+
assert b.g("xx") == "string case"
81+
'''
82+
}
5783
}

src/test/groovy/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1810,21 +1810,24 @@ final class TraitASTTransformationTest {
18101810
"""
18111811
}
18121812

1813-
// GROOVY-5193
1813+
// GROOVY-5193, GROOVY-11627
18141814
@Test
18151815
void testMixPrivatePublicMethodsOfSameName() {
1816-
def err = shouldFail shell, '''
1816+
assertScript shell, '''
1817+
@CompileStatic
18171818
trait T {
1818-
private String secret(String s) { s.toUpperCase() }
1819-
String secret() { 'public' }
1820-
String foo() { secret('secret') }
1819+
private String f(String s) { s.toUpperCase() }
1820+
public String f(Object o) { 'default value' }
1821+
public String f( ) { 'unknown value' }
1822+
def m() {
1823+
f('secret')
1824+
}
18211825
}
18221826
class C implements T {
18231827
}
18241828
1825-
assert new C().foo() == 'SECRET'
1829+
assert new C().m() == 'SECRET'
18261830
'''
1827-
assert err =~ 'Mixing private and public/protected methods of the same name causes multimethods to be disabled'
18281831
}
18291832

18301833
@Test

0 commit comments

Comments
 (0)