Skip to content

Commit d77c93a

Browse files
committedFeb 22, 2024·
GROOVY-11323: check interfaces for possible public method
3_0_X backport
1 parent a4b0104 commit d77c93a

File tree

2 files changed

+40
-11
lines changed

2 files changed

+40
-11
lines changed
 

‎src/main/java/org/codehaus/groovy/ast/ClassNode.java

+20-11
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.codehaus.groovy.ast.stmt.Statement;
3030
import org.codehaus.groovy.ast.tools.ParameterUtils;
3131
import org.codehaus.groovy.control.CompilePhase;
32+
import org.codehaus.groovy.runtime.DefaultGroovyMethods;
3233
import org.codehaus.groovy.transform.ASTTransformation;
3334
import org.codehaus.groovy.transform.GroovyASTTransformation;
3435
import org.codehaus.groovy.vmplugin.VMPluginFactory;
@@ -47,6 +48,7 @@
4748
import java.util.Map;
4849
import java.util.Optional;
4950
import java.util.Set;
51+
import java.util.stream.IntStream;
5052

5153
import static java.util.Arrays.stream;
5254
import static java.util.stream.Collectors.toList;
@@ -1276,21 +1278,16 @@ public boolean hasPossibleMethod(final String name, final Expression arguments)
12761278
}
12771279

12781280
public MethodNode tryFindPossibleMethod(final String name, final Expression arguments) {
1279-
if (!(arguments instanceof TupleExpression)) {
1280-
return null;
1281-
}
1282-
1283-
// TODO: this won't strictly be true when using list expansion in argument calls
1284-
TupleExpression args = (TupleExpression) arguments;
1285-
int nArgs = args.getExpressions().size();
1281+
List<Expression> args = arguments instanceof TupleExpression ? ((TupleExpression) arguments).getExpressions() : Collections.singletonList(arguments);
1282+
int nArgs = args.size(); // TODO: this isn't strictly accurate when using spread argument expansion
12861283
MethodNode method = null;
12871284

12881285
for (ClassNode cn = this; cn != null; cn = cn.getSuperClass()) {
12891286
for (MethodNode mn : cn.getDeclaredMethods(name)) {
12901287
if (hasCompatibleNumberOfArgs(mn, nArgs)) {
12911288
boolean match = true;
12921289
for (int i = 0; i < nArgs; i += 1) {
1293-
if (!hasCompatibleType(args, mn, i)) {
1290+
if (!hasCompatibleType(args.get(i), mn, i)) {
12941291
match = false;
12951292
break;
12961293
}
@@ -1314,6 +1311,18 @@ public MethodNode tryFindPossibleMethod(final String name, final Expression argu
13141311
}
13151312
}
13161313

1314+
faces: if (method == null && DefaultGroovyMethods.asBoolean(getInterfaces())) { // GROOVY-11323
1315+
for (ClassNode cn : getAllInterfaces()) {
1316+
for (MethodNode mn : cn.getDeclaredMethods(name)) {
1317+
if (mn.isPublic() && !mn.isStatic() && hasCompatibleNumberOfArgs(mn, nArgs) && (nArgs == 0
1318+
|| IntStream.range(0,nArgs).allMatch(i -> hasCompatibleType(args.get(i),mn,i)))) {
1319+
method = mn;
1320+
break faces;
1321+
}
1322+
}
1323+
}
1324+
}
1325+
13171326
return method;
13181327
}
13191328

@@ -1323,10 +1332,10 @@ private static boolean hasExactMatchingCompatibleType(final MethodNode match, fi
13231332
|| (i >= lastParamIndex && isPotentialVarArg(maybe, lastParamIndex) && match.getParameters()[i].getType().equals(maybe.getParameters()[lastParamIndex].getType().getComponentType()));
13241333
}
13251334

1326-
private static boolean hasCompatibleType(final TupleExpression args, final MethodNode method, final int i) {
1335+
private static boolean hasCompatibleType(final Expression arg, final MethodNode method, final int i) {
13271336
int lastParamIndex = method.getParameters().length - 1;
1328-
return (i <= lastParamIndex && args.getExpression(i).getType().isDerivedFrom(method.getParameters()[i].getType()))
1329-
|| (i >= lastParamIndex && isPotentialVarArg(method, lastParamIndex) && args.getExpression(i).getType().isDerivedFrom(method.getParameters()[lastParamIndex].getType().getComponentType()));
1337+
return (i <= lastParamIndex && arg.getType().isDerivedFrom(method.getParameters()[i].getType()))
1338+
|| (i >= lastParamIndex && isPotentialVarArg(method, lastParamIndex) && arg.getType().isDerivedFrom(method.getParameters()[lastParamIndex].getType().getComponentType()));
13301339
}
13311340

13321341
private static boolean hasCompatibleNumberOfArgs(final MethodNode method, final int nArgs) {

‎src/test/groovy/StaticImportTest.groovy

+20
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,26 @@ final class StaticImportTest extends groovy.test.GroovyTestCase {
139139
'''
140140
}
141141

142+
// GROOVY-11323
143+
void testStaticImportAndInterfaceDefaultMethod() {
144+
assertScript '''import static Bar.*
145+
interface Foo {
146+
default m() { 'Foo' }
147+
}
148+
class Bar {
149+
static m() { 'Bar' }
150+
}
151+
152+
class Baz implements Foo {
153+
void test() {
154+
assert m() == 'Foo'
155+
}
156+
}
157+
158+
new Baz().test()
159+
'''
160+
}
161+
142162
void testStaticImportProperty() {
143163
for (imports in ['import static Foo.getX; import static Foo.setX', 'import static Foo.*']) {
144164
assertScript """$imports

0 commit comments

Comments
 (0)
Please sign in to comment.