Skip to content

Commit 02b40ca

Browse files
committed
GROOVY-10106
1 parent 3080292 commit 02b40ca

File tree

14 files changed

+273
-63
lines changed

14 files changed

+273
-63
lines changed

base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/search/TraitInferencingTests.java

+22-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2009-2020 the original author or authors.
2+
* Copyright 2009-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -563,6 +563,27 @@ public void testPublicStaticMethod4() {
563563
assertDeclType(contents, "m", "T");
564564
}
565565

566+
@Test // GROOVY-10106
567+
public void testPublicStaticMethod5() {
568+
for (String mods : new String[] {"", "@groovy.transform.TypeChecked ", "@groovy.transform.CompileStatic "}) {
569+
//@formatter:off
570+
String contents =
571+
"class C {\n" +
572+
"}\n" +
573+
mods + "trait T {\n" +
574+
" static void m(C c) {\n" +
575+
" }\n" +
576+
" final C c = new C().tap {\n" +
577+
" m(it)\n" +
578+
" }\n" +
579+
"}\n";
580+
//@formatter:on
581+
582+
assertDeclType(contents, "m", "T");
583+
assertDeclType(contents, "tap", "org.codehaus.groovy.runtime.DefaultGroovyMethods");
584+
}
585+
}
586+
566587
@Test // https://issues.apache.org/jira/browse/GROOVY-8272
567588
public void testPublicStaticSuperMethod1() {
568589
//@formatter:off

base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/basic/TraitsTests.java

+58
Original file line numberDiff line numberDiff line change
@@ -2734,4 +2734,62 @@ public void testTraits9901() {
27342734

27352735
runConformTest(sources, "");
27362736
}
2737+
2738+
@Test
2739+
public void testTraits9938() {
2740+
//@formatter:off
2741+
String[] sources = {
2742+
"Main.groovy",
2743+
"@groovy.transform.CompileStatic\n" +
2744+
"class Main {\n" +
2745+
" interface I {\n" +
2746+
" void m(@DelegatesTo(value=D, strategy=Closure.DELEGATE_FIRST) Closure<?> c)\n" +
2747+
" }\n" +
2748+
" trait T {\n" +
2749+
" void m(@DelegatesTo(value=D, strategy=Closure.DELEGATE_FIRST) Closure<?> c) {\n" +
2750+
" new D().with(c)\n" +
2751+
" }\n" +
2752+
" }\n" +
2753+
" static class C implements T {\n" + // generates m(Closure) that delegates to T$TraitHelper#m(Closure)
2754+
" }\n" +
2755+
" static class D {\n" +
2756+
" void f() {\n" +
2757+
" print 'works'\n" +
2758+
" }\n" +
2759+
" }\n" +
2760+
" static main(args) {\n" +
2761+
" new C().m { f() }\n" +
2762+
" }\n" +
2763+
"}\n",
2764+
};
2765+
//@formatter:on
2766+
2767+
runConformTest(sources, "works");
2768+
}
2769+
2770+
@Test
2771+
public void testTraits10106() {
2772+
//@formatter:off
2773+
String[] sources = {
2774+
"Script.groovy",
2775+
"class C {\n" +
2776+
" String s\n" +
2777+
"}\n" +
2778+
"@groovy.transform.CompileStatic\n" +
2779+
"trait T {\n" +
2780+
" final C c = new C().tap {\n" +
2781+
" config(it)\n" +
2782+
" }\n" +
2783+
" static void config(C c) {\n" +
2784+
" c.s = 'works'\n" +
2785+
" }\n" +
2786+
"}\n" +
2787+
"class X implements T {\n" +
2788+
"}\n" +
2789+
"print new X().c.s\n",
2790+
};
2791+
//@formatter:on
2792+
2793+
runConformTest(sources, "works");
2794+
}
27372795
}

base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/StaticCompilationTests.java

-32
Original file line numberDiff line numberDiff line change
@@ -6041,38 +6041,6 @@ public void testCompileStatic9938a() {
60416041
runConformTest(sources, "works");
60426042
}
60436043

6044-
@Test
6045-
public void testCompileStatic9938b() {
6046-
//@formatter:off
6047-
String[] sources = {
6048-
"Main.groovy",
6049-
"@groovy.transform.CompileStatic\n" +
6050-
"class Main {\n" +
6051-
" interface I {\n" +
6052-
" void m(@DelegatesTo(value=D, strategy=Closure.DELEGATE_FIRST) Closure<?> c)\n" +
6053-
" }\n" +
6054-
" trait T {\n" +
6055-
" void m(@DelegatesTo(value=D, strategy=Closure.DELEGATE_FIRST) Closure<?> c) {\n" +
6056-
" new D().with(c)\n" +
6057-
" }\n" +
6058-
" }\n" +
6059-
" static class C implements T {\n" + // generates m(Closure) that delegates to T$TraitHelper#m(Closure)
6060-
" }\n" +
6061-
" static class D {\n" +
6062-
" void f() {\n" +
6063-
" print 'works'\n" +
6064-
" }\n" +
6065-
" }\n" +
6066-
" static main(args) {\n" +
6067-
" new C().m { f() }\n" +
6068-
" }\n" +
6069-
"}\n",
6070-
};
6071-
//@formatter:on
6072-
6073-
runConformTest(sources, "works");
6074-
}
6075-
60766044
@Test
60776045
public void testCompileStatic9955() {
60786046
//@formatter:off

base/org.codehaus.groovy25/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java

+4-1
Original file line numberDiff line numberDiff line change
@@ -4751,9 +4751,12 @@ public void visitTernaryExpression(final TernaryExpression expression) {
47514751
expression.getBooleanExpression().visit(this);
47524752
Expression trueExpression = expression.getTrueExpression();
47534753
Expression falseExpression = expression.getFalseExpression();
4754+
// GRECLIPSE add
4755+
ClassNode typeOfTrue = findCurrentInstanceOfClass(trueExpression, null);
4756+
// GRECLIPSE end
47544757
trueExpression.visit(this);
47554758
// GRECLIPSE add
4756-
ClassNode typeOfTrue = findCurrentInstanceOfClass(trueExpression, getType(trueExpression));
4759+
if (typeOfTrue == null) typeOfTrue = getType(trueExpression);
47574760
// GRECLIPSE end
47584761
// pop if-then-else temporary type info
47594762
typeCheckingContext.popTemporaryTypeInfo();

base/org.codehaus.groovy25/src/org/codehaus/groovy/transform/trait/TraitASTTransformation.java

+7-1
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,11 @@ private ClassNode createHelperClass(final ClassNode cNode) {
211211
);
212212
}
213213
}
214-
214+
// GRECLIPSE add -- GROOVY-10106
215+
for (FieldNode field : fields) {
216+
processField(field, initializer, staticInitializer, fieldHelper, helper, staticFieldHelper, cNode, fieldNames);
217+
}
218+
// GRECLIPSE end
215219
// add methods
216220
List<MethodNode> methods = new ArrayList<MethodNode>(cNode.getMethods());
217221
List<MethodNode> nonPublicAPIMethods = new LinkedList<MethodNode>();
@@ -251,9 +255,11 @@ private ClassNode createHelperClass(final ClassNode cNode) {
251255
// GRECLIPSE end
252256

253257
// add fields
258+
/* GRECLIPSE edit
254259
for (FieldNode field : fields) {
255260
processField(field, initializer, staticInitializer, fieldHelper, helper, staticFieldHelper, cNode, fieldNames);
256261
}
262+
*/
257263

258264
// copy statements from static and instance init blocks
259265
if (staticInitStatements != null) {

base/org.codehaus.groovy25/src/org/codehaus/groovy/transform/trait/TraitReceiverTransformer.java

+55-11
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,7 @@
3030
import org.codehaus.groovy.ast.Variable;
3131
import org.codehaus.groovy.ast.expr.ArgumentListExpression;
3232
import org.codehaus.groovy.ast.expr.BinaryExpression;
33-
import org.codehaus.groovy.ast.expr.BooleanExpression;
3433
import org.codehaus.groovy.ast.expr.CastExpression;
35-
import org.codehaus.groovy.ast.expr.ClassExpression;
3634
import org.codehaus.groovy.ast.expr.ClosureExpression;
3735
import org.codehaus.groovy.ast.expr.ConstantExpression;
3836
import org.codehaus.groovy.ast.expr.DeclarationExpression;
@@ -41,16 +39,19 @@
4139
import org.codehaus.groovy.ast.expr.MethodCallExpression;
4240
import org.codehaus.groovy.ast.expr.PropertyExpression;
4341
import org.codehaus.groovy.ast.expr.StaticMethodCallExpression;
44-
import org.codehaus.groovy.ast.expr.TernaryExpression;
4542
import org.codehaus.groovy.ast.expr.TupleExpression;
4643
import org.codehaus.groovy.ast.expr.VariableExpression;
4744
import org.codehaus.groovy.control.SourceUnit;
4845
import org.codehaus.groovy.syntax.SyntaxException;
4946
import org.codehaus.groovy.syntax.Token;
50-
import org.codehaus.groovy.syntax.Types;
5147

5248
import java.util.Collection;
53-
import java.util.List;
49+
50+
import static org.codehaus.groovy.ast.tools.GeneralUtils.callX;
51+
import static org.codehaus.groovy.ast.tools.GeneralUtils.classX;
52+
import static org.codehaus.groovy.ast.tools.GeneralUtils.isInstanceOfX;
53+
import static org.codehaus.groovy.ast.tools.GeneralUtils.ternaryX;
54+
import static org.codehaus.groovy.ast.tools.GeneralUtils.varX;
5455

5556
/**
5657
* This expression transformer is used internally by the {@link org.codehaus.groovy.transform.trait.TraitASTTransformation
@@ -155,7 +156,7 @@ public Expression transform(final Expression exp) {
155156
FieldNode fn = (accessedVariable instanceof FieldNode ? (FieldNode) accessedVariable : ((PropertyNode) accessedVariable).getField());
156157
boolean isStatic = java.lang.reflect.Modifier.isStatic(accessedVariable.getModifiers());
157158
Expression receiver = createFieldHelperReceiver();
158-
if (isStatic) receiver = createStaticReceiver(receiver);
159+
if (isStatic) receiver = asClass(receiver);
159160

160161
MethodCallExpression mce = new MethodCallExpression(
161162
receiver,
@@ -316,6 +317,7 @@ private static void markDynamicCall(final MethodCallExpression mce, final FieldN
316317
}
317318
}
318319

320+
/* GRECLIPSE edit
319321
private TernaryExpression createStaticReceiver(final Expression receiver) {
320322
return new TernaryExpression(
321323
new BooleanExpression(new BinaryExpression(
@@ -324,9 +326,10 @@ private TernaryExpression createStaticReceiver(final Expression receiver) {
324326
new ClassExpression(ClassHelper.CLASS_Type)
325327
)),
326328
receiver,
327-
new MethodCallExpression(createFieldHelperReceiver(), "getClass", ArgumentListExpression.EMPTY_ARGUMENTS)
329+
new MethodCallExpression(receiver, "getClass", ArgumentListExpression.EMPTY_ARGUMENTS)
328330
);
329331
}
332+
*/
330333

331334
private BinaryExpression createAssignmentToField(final Expression rightExpression,
332335
final Token operation, final String fieldName) {
@@ -390,6 +393,7 @@ private Expression transformSuperMethodCall(final MethodCallExpression call) {
390393
private Expression transformMethodCallOnThis(final MethodCallExpression call) {
391394
Expression method = call.getMethod();
392395
Expression arguments = call.getArguments();
396+
/* GRECLIPSE edit -- GROOVY-10106
393397
if (method instanceof ConstantExpression) {
394398
String methodName = method.getText();
395399
List<MethodNode> methods = traitClass.getMethods(methodName);
@@ -408,19 +412,40 @@ private Expression transformMethodCallOnThis(final MethodCallExpression call) {
408412
}
409413
410414
return transformMethodCallOnThisFallBack(call, method, arguments);
415+
*/
416+
if (method instanceof ConstantExpression) {
417+
String methodName = call.getMethodAsString();
418+
for (MethodNode methodNode : traitClass.getMethods(methodName)) {
419+
if (methodName.equals(methodNode.getName()) && (methodNode.isStatic() || methodNode.isPrivate())) {
420+
ArgumentListExpression newArgs = createArgumentList(methodNode.isStatic() ? asClass(call.getObjectExpression()) : weaved, arguments);
421+
MethodCallExpression newCall = callX(inClosure ? classX(traitHelperClass) : varX("this"), methodName, newArgs);
422+
newCall.setImplicitThis(true);
423+
newCall.setSafe(call.isSafe());
424+
newCall.setSourcePosition(call);
425+
newCall.setSpreadSafe(call.isSpreadSafe());
426+
return newCall;
427+
}
428+
}
429+
}
411430

431+
MethodCallExpression newCall = callX(inClosure ? call.getObjectExpression() : weaved, method, transform(arguments));
432+
newCall.setImplicitThis(inClosure ? call.isImplicitThis() : false);
433+
newCall.setSafe(call.isSafe());
434+
newCall.setSourcePosition(call);
435+
newCall.setSpreadSafe(call.isSpreadSafe());
436+
return newCall;
437+
// GRECLIPSE end
412438
}
413439

440+
/* GRECLIPSE edit
414441
private Expression transformMethodCallOnThisFallBack(final MethodCallExpression call,
415442
final Expression method, final Expression arguments) {
416443
MethodCallExpression transformed = new MethodCallExpression(
417444
weaved,
418445
method,
419446
transform(arguments)
420447
);
421-
/* GRECLIPSE edit
422448
transformed.setSourcePosition(call);
423-
*/
424449
transformed.setSafe(call.isSafe());
425450
transformed.setSpreadSafe(call.isSpreadSafe());
426451
transformed.setImplicitThis(false);
@@ -433,9 +458,7 @@ private Expression transformMethodCallOnThisInClosure(final MethodCallExpression
433458
call.getMethod(),
434459
transform(call.getArguments())
435460
);
436-
/* GRECLIPSE edit
437461
transformed.setSourcePosition(call);
438-
*/
439462
transformed.setSafe(call.isSafe());
440463
transformed.setSpreadSafe(call.isSpreadSafe());
441464
transformed.setImplicitThis(call.isImplicitThis());
@@ -471,11 +494,31 @@ private Expression transformPrivateMethodCallOnThisInClosure(final MethodCallExp
471494
transformed.setImplicitThis(true);
472495
return transformed;
473496
}
497+
*/
498+
private ArgumentListExpression createArgumentList(final Expression self, final Expression arguments) {
499+
ArgumentListExpression newArgs = new ArgumentListExpression();
500+
newArgs.addExpression(self);
501+
if (arguments instanceof TupleExpression) {
502+
for (Expression argument : (TupleExpression) arguments) {
503+
newArgs.addExpression(transform(argument));
504+
}
505+
} else {
506+
newArgs.addExpression(transform(arguments));
507+
}
508+
return newArgs;
509+
}
510+
511+
private static Expression asClass(final Expression e) {
512+
ClassNode rawClass = ClassHelper.CLASS_Type.getPlainNodeReference();
513+
return ternaryX(isInstanceOfX(e, rawClass), e, callX(e, "getClass"));
514+
}
515+
// GRECLIPSE end
474516

475517
private Expression createFieldHelperReceiver() {
476518
return ClassHelper.CLASS_Type.equals(weaved.getOriginType()) ? weaved : new CastExpression(fieldHelper, weaved);
477519
}
478520

521+
/* GRECLIPSE edit
479522
private ArgumentListExpression createArgumentList(final Expression origCallArgs) {
480523
ArgumentListExpression newArgs = new ArgumentListExpression();
481524
newArgs.addExpression(new VariableExpression(weaved));
@@ -489,4 +532,5 @@ private ArgumentListExpression createArgumentList(final Expression origCallArgs)
489532
}
490533
return newArgs;
491534
}
535+
*/
492536
}

base/org.codehaus.groovy30/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java

+6
Original file line numberDiff line numberDiff line change
@@ -4524,8 +4524,14 @@ public void visitTernaryExpression(final TernaryExpression expression) {
45244524
expression.getBooleanExpression().visit(this);
45254525
Expression trueExpression = expression.getTrueExpression();
45264526
Expression falseExpression = expression.getFalseExpression();
4527+
/* GRECLIPSE edit -- GROOVY-10106
45274528
trueExpression.visit(this);
45284529
ClassNode typeOfTrue = findCurrentInstanceOfClass(trueExpression, getType(trueExpression));
4530+
*/
4531+
ClassNode typeOfTrue = findCurrentInstanceOfClass(trueExpression, null);
4532+
trueExpression.visit(this);
4533+
if (typeOfTrue == null) typeOfTrue = getType(trueExpression);
4534+
// GRECLIPSE end
45294535
// pop if-then-else temporary type info
45304536
typeCheckingContext.popTemporaryTypeInfo();
45314537
falseExpression.visit(this);

base/org.codehaus.groovy30/src/org/codehaus/groovy/transform/trait/TraitASTTransformation.java

+7
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,11 @@ private ClassNode createHelperClass(final ClassNode cNode) {
221221
}
222222
}
223223

224+
// GRECLIPSE add -- GROOVY-10106
225+
for (FieldNode field : fields) {
226+
processField(field, initializer, staticInitializer, fieldHelper, helper, staticFieldHelper, cNode, fieldNames);
227+
}
228+
// GRECLIPSE end
224229
// add methods
225230
List<MethodNode> methods = new ArrayList<>(cNode.getMethods());
226231
List<MethodNode> nonPublicAPIMethods = new LinkedList<>();
@@ -260,9 +265,11 @@ private ClassNode createHelperClass(final ClassNode cNode) {
260265
// GRECLIPSE end
261266

262267
// add fields
268+
/* GRECLIPSE edit
263269
for (FieldNode field : fields) {
264270
processField(field, initializer, staticInitializer, fieldHelper, helper, staticFieldHelper, cNode, fieldNames);
265271
}
272+
*/
266273

267274
// copy statements from static and instance init blocks
268275
if (staticInitStatements != null) {

0 commit comments

Comments
 (0)