Skip to content

Commit e9b3d70

Browse files
committed
single-pass resolution
GROOVY-4386, GROOVY-5961, GROOVY-6977, GROOVY-9642 ~GROOVY-4287, GROOVY-8947~
1 parent f3e2092 commit e9b3d70

File tree

8 files changed

+206
-96
lines changed

8 files changed

+206
-96
lines changed

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

+29-7
Original file line numberDiff line numberDiff line change
@@ -788,19 +788,41 @@ public void testStaticProperty3() {
788788
public void testStaticProperty4() {
789789
//@formatter:off
790790
String[] sources = {
791-
"Super.groovy",
792-
"class Super {\n" +
793-
" def static getSql() { 'sql' }\n" +
791+
"Script.groovy",
792+
"abstract class A {\n" +
793+
" static getB() { 'bee' }\n" +
794794
"}\n" +
795-
"class Sub extends Super {\n" +
796-
" def static m() {\n" +
797-
" sql.charAt(0)\n" +
795+
"class C extends A {\n" +
796+
" static m() {\n" +
797+
" print b.charAt(0)\n" +
798+
" }\n" +
799+
"}\n" +
800+
"new C().m()\n",
801+
};
802+
//@formatter:on
803+
804+
runConformTest(sources, "b");
805+
}
806+
807+
@Test
808+
public void testStaticProperty4a() {
809+
//@formatter:off
810+
String[] sources = {
811+
"C.groovy",
812+
"class C extends A {\n" +
813+
" static main(args) {\n" +
814+
" print b.charAt(0)\n" +
798815
" }\n" +
799816
"}\n",
817+
818+
"A.groovy",
819+
"abstract class A {\n" +
820+
" static getB() { 'bee' }\n" +
821+
"}\n",
800822
};
801823
//@formatter:on
802824

803-
runNegativeTest(sources, "");
825+
runConformTest(sources, "b");
804826
}
805827

806828
@Test // GRECLIPSE-364

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

+88-4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package org.eclipse.jdt.groovy.core.tests.basic;
1717

18+
import org.junit.Ignore;
1819
import org.junit.Test;
1920

2021
public final class InnerClassTests extends GroovyCompilerTestSuite {
@@ -213,7 +214,7 @@ public void testInnerClass2() {
213214
}
214215

215216
@Test
216-
public void testInnerClass2a() {
217+
public void testInnerClass3() {
217218
//@formatter:off
218219
String[] sources = {
219220
"Outer.groovy",
@@ -234,7 +235,7 @@ public void testInnerClass2a() {
234235
}
235236

236237
@Test
237-
public void testInnerClass3() {
238+
public void testInnerClass4() {
238239
//@formatter:off
239240
String[] sources = {
240241
"WithInnerClass.groovy",
@@ -253,8 +254,28 @@ public void testInnerClass3() {
253254
runNegativeTest(sources, "");
254255
}
255256

257+
@Test // GROOVY-4287
258+
public void testInnerClass5() {
259+
//@formatter:off
260+
String[] sources = {
261+
"Script.groovy",
262+
"import static p.Outer.Inner\n" +
263+
"new Inner()\n",
264+
265+
"p/Outer.groovy",
266+
"package p\n" +
267+
"class Outer {\n" +
268+
" static class Inner {\n" +
269+
" }\n" +
270+
"}\n",
271+
};
272+
//@formatter:on
273+
274+
runConformTest(sources);
275+
}
276+
256277
@Test // https://github.com/groovy/groovy-eclipse/issues/708
257-
public void testInnerClass4() {
278+
public void testInnerClass6() {
258279
//@formatter:off
259280
String[] sources = {
260281
"Script.groovy",
@@ -281,7 +302,51 @@ public void testInnerClass4() {
281302
}
282303

283304
@Test
284-
public void testInnerClass5() {
305+
public void testInnerClass7() {
306+
//@formatter:off
307+
String[] sources = {
308+
"Script.groovy",
309+
"class Outer {\n" +
310+
" @groovy.transform.TupleConstructor(defaults=false)\n" +
311+
" class Inner {\n" +
312+
" int p\n" +
313+
" }\n" +
314+
" static m(int n) {\n" +
315+
" new Inner(new Outer(), n)\n" +
316+
" }\n" +
317+
"}\n" +
318+
"print Outer.m(4).p\n" +
319+
"print new Outer.Inner(new Outer(), 2).p\n",
320+
};
321+
//@formatter:on
322+
323+
runConformTest(sources, "42");
324+
}
325+
326+
@Ignore @Test // GROOVY-8947
327+
public void testInnerClass8() {
328+
//@formatter:off
329+
String[] sources = {
330+
"Script.groovy",
331+
"class Outer {\n" +
332+
" @groovy.transform.TupleConstructor(defaults=false)\n" +
333+
" class Inner {\n" +
334+
" int p\n" +
335+
" }\n" +
336+
" static m(int n) {\n" +
337+
" new Outer().(new Inner(n))\n" + // TODO: no parens
338+
" }\n" +
339+
"}\n" +
340+
"print Outer.m(4).p\n" +
341+
"print new Outer().(new Outer.Inner(2)).p\n", // TODO: no parens, no qualifier
342+
};
343+
//@formatter:on
344+
345+
runConformTest(sources, "42");
346+
}
347+
348+
@Test
349+
public void testInnerClass9() {
285350
//@formatter:off
286351
String[] sources = {
287352
"Script.groovy",
@@ -1595,6 +1660,25 @@ public void testAnonymousInnerClass32() {
15951660
runConformTest(sources);
15961661
}
15971662

1663+
@Test // GROOVY-6977
1664+
public void testAnonymousInnerClass33() {
1665+
//@formatter:off
1666+
String[] sources = {
1667+
"Script.groovy",
1668+
"class C {\n" +
1669+
" def <T> List<T> foo() {\n" +
1670+
" new ArrayList<T>() {}\n" +
1671+
" }\n" +
1672+
"}\n" +
1673+
"def longList = new C().<Long>foo()\n" +
1674+
"assert longList != null\n" +
1675+
"assert longList.empty\n",
1676+
};
1677+
//@formatter:on
1678+
1679+
runConformTest(sources);
1680+
}
1681+
15981682
@Test
15991683
public void testMixedModeInnerProperties_GRE597() {
16001684
//@formatter:off

base/org.codehaus.groovy25/src/org/codehaus/groovy/control/CompilationUnit.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636
import org.codehaus.groovy.classgen.GeneratorContext;
3737
import org.codehaus.groovy.classgen.InnerClassCompletionVisitor;
3838
import org.codehaus.groovy.classgen.InnerClassVisitor;
39-
import org.codehaus.groovy.classgen.VariableScopeVisitor;
4039
import org.codehaus.groovy.classgen.Verifier;
4140
import org.codehaus.groovy.control.customizers.CompilationCustomizer;
4241
import org.codehaus.groovy.control.io.InputStreamReaderSource;
@@ -582,12 +581,12 @@ public void compile(int throughPhase) throws CompilationFailedException {
582581
throughPhase = Math.min(throughPhase, Phases.ALL);
583582

584583
while (throughPhase >= phase && phase <= Phases.ALL) {
585-
584+
/* GRECLIPSE edit -- GROOVY-4386, et al.
586585
if (phase == Phases.SEMANTIC_ANALYSIS) {
587586
doPhaseOperation(resolve);
588587
if (dequeued()) continue;
589588
}
590-
589+
*/
591590
processPhaseOperations(phase);
592591
// Grab processing may have brought in new AST transforms into various phases, process them as well
593592
processNewPhaseOperations(phase);
@@ -689,9 +688,10 @@ protected boolean dequeued() throws CompilationFailedException {
689688
public void call(SourceUnit source) throws CompilationFailedException {
690689
List<ClassNode> classes = source.ast.getClasses();
691690
for (ClassNode node : classes) {
691+
/* GRECLIPSE edit -- GROOVY-4386, et al.
692692
VariableScopeVisitor scopeVisitor = new VariableScopeVisitor(source);
693693
scopeVisitor.visitClass(node);
694-
694+
*/
695695
resolveVisitor.setClassNodeResolver(classNodeResolver);
696696
resolveVisitor.startResolving(node, source);
697697
}

base/org.codehaus.groovy25/src/org/codehaus/groovy/control/ResolveVisitor.java

+22-1
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
import org.codehaus.groovy.ast.stmt.CatchStatement;
6262
import org.codehaus.groovy.ast.stmt.ForStatement;
6363
import org.codehaus.groovy.ast.stmt.Statement;
64+
import org.codehaus.groovy.classgen.VariableScopeVisitor;
6465
import org.codehaus.groovy.control.ClassNodeResolver.LookupResult;
6566
import org.codehaus.groovy.syntax.Types;
6667
import org.codehaus.groovy.transform.trait.Traits;
@@ -70,6 +71,7 @@
7071
import java.util.Collections;
7172
import java.util.HashMap;
7273
import java.util.HashSet;
74+
import java.util.Iterator;
7375
import java.util.LinkedHashMap;
7476
import java.util.LinkedList;
7577
import java.util.List;
@@ -1330,10 +1332,15 @@ protected Expression transformClosureExpression(ClosureExpression ce) {
13301332
}
13311333

13321334
protected Expression transformConstructorCallExpression(ConstructorCallExpression cce) {
1335+
/* GRECLIPSE edit -- GROOVY-4386, et al.
13331336
ClassNode type = cce.getType();
13341337
if (cce.isUsingAnonymousInnerClass()) { // GROOVY-9642
13351338
resolveOrFail(type.getUnresolvedSuperClass(false), type);
13361339
} else {
1340+
*/
1341+
if (!cce.isUsingAnonymousInnerClass()) {
1342+
ClassNode type = cce.getType();
1343+
// GRECLIPSE end
13371344
resolveOrFail(type, cce);
13381345
if (type.isAbstract()) {
13391346
addError("You cannot create an instance from the abstract " + getDescription(type) + ".", cce);
@@ -1506,14 +1513,15 @@ public void visitClass(ClassNode node) {
15061513
if (Modifier.isStatic(node.getModifiers())) {
15071514
genericParameterNames = new HashMap<GenericsTypeName, GenericsType>();
15081515
}
1509-
1516+
/* GRECLIPSE edit -- GROOVY-4386, et al.
15101517
InnerClassNode innerClassNode = (InnerClassNode) node;
15111518
if (innerClassNode.isAnonymous()) {
15121519
MethodNode enclosingMethod = innerClassNode.getEnclosingMethod();
15131520
if (null != enclosingMethod) {
15141521
resolveGenericsHeader(enclosingMethod.getGenericsTypes());
15151522
}
15161523
}
1524+
*/
15171525
} else {
15181526
genericParameterNames = new HashMap<GenericsTypeName, GenericsType>();
15191527
}
@@ -1609,6 +1617,19 @@ public void visitClass(ClassNode node) {
16091617
}
16101618
}
16111619
}
1620+
// VariableScopeVisitor visits anon. inner class body inline, so resolve now
1621+
for (Iterator<InnerClassNode> it = node.getInnerClasses(); it.hasNext(); ) {
1622+
InnerClassNode cn = it.next();
1623+
if (cn.isAnonymous()) {
1624+
MethodNode enclosingMethod = cn.getEnclosingMethod();
1625+
if (enclosingMethod != null) {
1626+
resolveGenericsHeader(enclosingMethod.getGenericsTypes()); // GROOVY-6977
1627+
}
1628+
resolveOrFail(cn.getUnresolvedSuperClass(false), cn); // GROOVY-9642
1629+
}
1630+
}
1631+
// initialize scopes/variables now that imports and super types are resolved
1632+
new VariableScopeVisitor(source).visitClass(node);
16121633
// GRECLIPSE end
16131634
super.visitClass(node);
16141635

base/org.codehaus.groovy30/src/org/codehaus/groovy/control/CompilationUnit.java

+9-13
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@
3939
import org.codehaus.groovy.classgen.GeneratorContext;
4040
import org.codehaus.groovy.classgen.InnerClassCompletionVisitor;
4141
import org.codehaus.groovy.classgen.InnerClassVisitor;
42-
import org.codehaus.groovy.classgen.VariableScopeVisitor;
4342
import org.codehaus.groovy.classgen.Verifier;
4443
import org.codehaus.groovy.control.customizers.CompilationCustomizer;
4544
import org.codehaus.groovy.control.io.InputStreamReaderSource;
@@ -629,25 +628,21 @@ public void compile(int throughPhase) throws CompilationFailedException {
629628
throughPhase = Math.min(throughPhase, Phases.ALL);
630629

631630
while (throughPhase >= phase && phase <= Phases.ALL) {
632-
// GRECLIPSE add
633-
if (phase == Phases.CONVERSION) {
634-
if (sources.size() > 1 && Boolean.TRUE.equals(configuration.getOptimizationOptions().get(CompilerConfiguration.PARALLEL_PARSE))) {
635-
sources.values().parallelStream().forEach(SourceUnit::buildAST);
636-
} else {
637-
sources.values().forEach(SourceUnit::buildAST);
638-
}
639-
} else
640-
// GRECLIPSE end
631+
/* GRECLIPSE edit -- GROOVY-4386, et al.
641632
if (phase == Phases.SEMANTIC_ANALYSIS) {
642633
resolve.doPhaseOperation(this);
643634
if (dequeued()) continue;
644635
}
645-
/* GRECLIPSE edit
646636
if (phase == Phases.CONVERSION) {
647637
buildASTs();
648638
}
649639
*/
650-
640+
if (phase == Phases.CONVERSION) {
641+
for (SourceUnit source : sources.values()) {
642+
source.buildAST();
643+
}
644+
}
645+
// GRECLIPSE end
651646
processPhaseOperations(phase);
652647
// Grab processing may have brought in new AST transforms into various phases, process them as well
653648
processNewPhaseOperations(phase);
@@ -749,9 +744,10 @@ protected boolean dequeued() throws CompilationFailedException {
749744
*/
750745
private final ISourceUnitOperation resolve = (final SourceUnit source) -> {
751746
for (ClassNode classNode : source.getAST().getClasses()) {
747+
/* GRECLIPSE edit -- GROOVY-4386, et al.
752748
GroovyClassVisitor visitor = new VariableScopeVisitor(source);
753749
visitor.visitClass(classNode);
754-
750+
*/
755751
resolveVisitor.setClassNodeResolver(classNodeResolver);
756752
resolveVisitor.startResolving(classNode, source);
757753
}

0 commit comments

Comments
 (0)