Skip to content

Commit 6a018e0

Browse files
committed
GROOVY-8050
1 parent 0873c66 commit 6a018e0

4 files changed

Lines changed: 138 additions & 45 deletions

File tree

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

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2141,21 +2141,76 @@ public void testCompileStatic7996e() {
21412141
}
21422142

21432143
@Test
2144-
public void testCompileStatic8051() {
2144+
public void testCompileStatic8050() {
2145+
//@formatter:off
2146+
String[] sources = {
2147+
"Main.groovy",
2148+
"@groovy.transform.CompileStatic\n" +
2149+
"class Outer {\n" +
2150+
" class Inner {\n" +
2151+
" }\n" +
2152+
" def foo = 1\n" +
2153+
"}\n" +
2154+
"@groovy.transform.CompileStatic\n" +
2155+
"void test(Outer.Inner inner) {\n" +
2156+
" print inner.getFoo()\n" +
2157+
"}\n" +
2158+
"test(new Outer.Inner(new Outer()))\n",
2159+
};
2160+
//@formatter:on
2161+
2162+
runNegativeTest(sources,
2163+
"----------\n" +
2164+
"1. ERROR in Main.groovy (at line 9)\n" +
2165+
"\tprint inner.getFoo()\n" +
2166+
"\t ^^^^^^^^^^^^^^\n" +
2167+
"Groovy:[Static type checking] - Cannot find matching method Outer$Inner#getFoo(). Please check if the declared type is correct and if the method exists.\n" +
2168+
"----------\n");
2169+
}
2170+
2171+
@Test
2172+
public void testCompileStatic8050a() {
21452173
//@formatter:off
21462174
String[] sources = {
21472175
"Main.groovy",
21482176
"@groovy.transform.CompileStatic\n" +
21492177
"class Outer {\n" +
2178+
" class Inner {\n" +
2179+
" }\n" +
21502180
" def foo = 1\n" +
2151-
" Inner createInner() { new Inner() }\n" +
2181+
"}\n" +
2182+
"@groovy.transform.CompileStatic\n" +
2183+
"void test(Outer.Inner inner) {\n" +
2184+
" print inner.foo\n" +
2185+
"}\n" +
2186+
"test(new Outer.Inner(new Outer()))\n",
2187+
};
2188+
//@formatter:on
2189+
2190+
runNegativeTest(sources,
2191+
"----------\n" +
2192+
"1. ERROR in Main.groovy (at line 9)\n" +
2193+
"\tprint inner.foo\n" +
2194+
"\t ^^^^^^^^^\n" +
2195+
"Groovy:[Static type checking] - No such property: foo for class: Outer$Inner\n" +
2196+
"----------\n");
2197+
}
2198+
2199+
@Test
2200+
public void testCompileStatic8051() {
2201+
//@formatter:off
2202+
String[] sources = {
2203+
"Main.groovy",
2204+
"@groovy.transform.CompileStatic\n" +
2205+
"class Outer {\n" +
21522206
" class Inner {\n" +
21532207
" Closure createClosure() {\n" +
21542208
" return { foo }\n" +
21552209
" }\n" +
21562210
" }\n" +
2211+
" def foo = 1\n" +
21572212
"}\n" +
2158-
"def i = new Outer().createInner()\n" +
2213+
"def i = new Outer.Inner(new Outer())\n" +
21592214
"def c = i.createClosure()\n" +
21602215
"print c()\n",
21612216
};

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

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5712,12 +5712,11 @@ protected List<MethodNode> findMethod(ClassNode receiver, final String name, fin
57125712
}
57135713
} else {
57145714
methods = findMethodsWithGenerated(receiver, name);
5715-
/* GRECLIPSE edit -- GROOVY-9890
5715+
/* GRECLIPSE edit -- GROOVY-8050, GROOVY-9890
57165716
if (receiver.isInterface()) {
57175717
collectAllInterfaceMethodsByName(receiver, name, methods);
57185718
methods.addAll(OBJECT_TYPE.getMethods(name));
57195719
}
5720-
*/
57215720
// TODO: investigate the trait exclusion a bit further, needed otherwise
57225721
// CallMethodOfTraitInsideClosureAndClosureParamTypeInference fails saying
57235722
// not static method can't be called from a static context
@@ -5729,6 +5728,15 @@ protected List<MethodNode> findMethod(ClassNode receiver, final String name, fin
57295728
methods.addAll(findMethodsWithGenerated(parent, name));
57305729
}
57315730
}
5731+
*/
5732+
if (!receiver.isStaticClass() && receiver.getOuterClass() != null
5733+
&& !receiver.getName().endsWith("$Trait$Helper") // GROOVY-7242
5734+
&& typeCheckingContext.getEnclosingClassNodes().contains(receiver)) {
5735+
ClassNode outer = receiver.getOuterClass();
5736+
do { methods.addAll(findMethodsWithGenerated(outer, name));
5737+
} while (!outer.isStaticClass() && (outer = outer.getOuterClass()) != null);
5738+
}
5739+
// GRECLIPSE end
57325740
if (methods.isEmpty()) {
57335741
addArrayMethods(methods, receiver, name, args);
57345742
}
@@ -5739,8 +5747,8 @@ protected List<MethodNode> findMethod(ClassNode receiver, final String name, fin
57395747
pname = extractPropertyNameFromMethodName("is", name);
57405748
}
57415749
if (pname != null) {
5742-
// we don't use property exists there because findMethod is called on super clases recursively
57435750
PropertyNode property = null;
5751+
/* GRECLIPSE edit -- GROOVY-8050
57445752
ClassNode curNode = receiver;
57455753
while (property == null && curNode != null) {
57465754
property = curNode.getProperty(pname);
@@ -5755,6 +5763,20 @@ protected List<MethodNode> findMethod(ClassNode receiver, final String name, fin
57555763
}
57565764
curNode = curNode.getSuperClass();
57575765
}
5766+
*/
5767+
outer_upper: // can't use existsProperty because it calls findMethod
5768+
for (ClassNode cn = receiver; cn != null; cn = cn.getSuperClass()) {
5769+
property = cn.getProperty(pname);
5770+
if (property != null) break outer_upper;
5771+
if (!cn.isStaticClass() && cn.getOuterClass() != null
5772+
&& typeCheckingContext.getEnclosingClassNodes().contains(cn)) {
5773+
ClassNode outer = cn.getOuterClass();
5774+
do { property = outer.getProperty(pname);
5775+
if (property != null) break outer_upper;
5776+
} while (!outer.isStaticClass() && (outer = outer.getOuterClass()) != null);
5777+
}
5778+
}
5779+
// GRECLIPSE end
57585780
if (property != null) {
57595781
int mods = Opcodes.ACC_PUBLIC | (property.isStatic() ? Opcodes.ACC_STATIC : 0);
57605782
MethodNode node = new MethodNode(name, mods, property.getType(), Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, GENERATED_EMPTY_STATEMENT);

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

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5445,6 +5445,7 @@ protected List<MethodNode> findMethod(ClassNode receiver, final String name, fin
54455445
methods.add(callMethod);
54465446
}
54475447
}
5448+
/* GRECLIPSE edit -- GROOVY-8050
54485449
// TODO: investigate the trait exclusion a bit further, needed otherwise
54495450
// CallMethodOfTraitInsideClosureAndClosureParamTypeInference fails saying
54505451
// not static method can't be called from a static context
@@ -5456,6 +5457,15 @@ protected List<MethodNode> findMethod(ClassNode receiver, final String name, fin
54565457
methods.addAll(findMethodsWithGenerated(parent, name));
54575458
}
54585459
}
5460+
*/
5461+
if (!receiver.isStaticClass() && receiver.getOuterClass() != null
5462+
&& !receiver.getName().endsWith("$Trait$Helper") // GROOVY-7242
5463+
&& typeCheckingContext.getEnclosingClassNodes().contains(receiver)) {
5464+
ClassNode outer = receiver.getOuterClass();
5465+
do { methods.addAll(findMethodsWithGenerated(outer, name));
5466+
} while (!outer.isStaticClass() && (outer = outer.getOuterClass()) != null);
5467+
}
5468+
// GRECLIPSE end
54595469
if (methods.isEmpty()) {
54605470
addArrayMethods(methods, receiver, name, args);
54615471
}
@@ -5466,8 +5476,8 @@ protected List<MethodNode> findMethod(ClassNode receiver, final String name, fin
54665476
pname = extractPropertyNameFromMethodName("is", name);
54675477
}
54685478
if (pname != null) {
5469-
// we don't use property exists there because findMethod is called on super clases recursively
54705479
PropertyNode property = null;
5480+
/* GRECLIPSE edit -- GROOVY-8050
54715481
ClassNode curNode = receiver;
54725482
while (property == null && curNode != null) {
54735483
property = curNode.getProperty(pname);
@@ -5482,6 +5492,20 @@ protected List<MethodNode> findMethod(ClassNode receiver, final String name, fin
54825492
}
54835493
curNode = curNode.getSuperClass();
54845494
}
5495+
*/
5496+
outer_upper: // can't use existsProperty because it calls findMethod
5497+
for (ClassNode cn = receiver; cn != null; cn = cn.getSuperClass()) {
5498+
property = cn.getProperty(pname);
5499+
if (property != null) break outer_upper;
5500+
if (!cn.isStaticClass() && cn.getOuterClass() != null
5501+
&& typeCheckingContext.getEnclosingClassNodes().contains(cn)) {
5502+
ClassNode outer = cn.getOuterClass();
5503+
do { property = outer.getProperty(pname);
5504+
if (property != null) break outer_upper;
5505+
} while (!outer.isStaticClass() && (outer = outer.getOuterClass()) != null);
5506+
}
5507+
}
5508+
// GRECLIPSE end
54855509
if (property != null) {
54865510
int mods = Opcodes.ACC_PUBLIC | (property.isStatic() ? Opcodes.ACC_STATIC : 0);
54875511
MethodNode node = new MethodNode(name, mods, property.getType(), Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, GENERATED_EMPTY_STATEMENT);

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

Lines changed: 30 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -4770,13 +4770,14 @@ private static List<MethodNode> addGeneratedMethods(final ClassNode receiver, fi
47704770

47714771
protected List<MethodNode> findMethod(ClassNode receiver, final String name, final ClassNode... args) {
47724772
if (isPrimitiveType(receiver)) receiver = getWrapper(receiver);
4773+
47734774
List<MethodNode> methods;
4774-
if (!receiver.isInterface() && "<init>".equals(name)) {
4775+
if ("<init>".equals(name) && !receiver.isInterface()) {
47754776
methods = addGeneratedMethods(receiver, new ArrayList<>(receiver.getDeclaredConstructors()));
47764777
if (methods.isEmpty()) {
47774778
MethodNode node = new ConstructorNode(Opcodes.ACC_PUBLIC, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, GENERATED_EMPTY_STATEMENT);
47784779
node.setDeclaringClass(receiver);
4779-
methods = Collections.singletonList(node);
4780+
methods.add(node);
47804781
if (receiver.isArray()) {
47814782
// No need to check the arguments against an array constructor: it just needs to exist. The array is
47824783
// created through coercion or by specifying its dimension(s), anyway, and would not match an
@@ -4786,25 +4787,21 @@ protected List<MethodNode> findMethod(ClassNode receiver, final String name, fin
47864787
}
47874788
} else {
47884789
methods = findMethodsWithGenerated(receiver, name);
4789-
if (receiver.isInterface()) {
4790-
if ("call".equals(name) && isFunctionalInterface(receiver)) {
4791-
MethodNode sam = findSAM(receiver);
4790+
if ("call".equals(name) && receiver.isInterface()) {
4791+
MethodNode sam = findSAM(receiver);
4792+
if (sam != null) {
47924793
MethodNode callMethod = new MethodNode("call", sam.getModifiers(), sam.getReturnType(), sam.getParameters(), sam.getExceptions(), sam.getCode());
47934794
callMethod.setDeclaringClass(sam.getDeclaringClass());
47944795
callMethod.setSourcePosition(sam);
47954796
methods.add(callMethod);
47964797
}
47974798
}
4798-
// TODO: investigate the trait exclusion a bit further, needed otherwise
4799-
// CallMethodOfTraitInsideClosureAndClosureParamTypeInference fails saying
4800-
// not static method can't be called from a static context
4801-
if (typeCheckingContext.getEnclosingClosure() == null || (receiver.getOuterClass() != null && !receiver.getName().endsWith("$Trait$Helper"))) {
4802-
// not in a closure or within an inner class
4803-
ClassNode parent = receiver;
4804-
while (parent.getOuterClass() != null && !parent.isStaticClass()) {
4805-
parent = parent.getOuterClass();
4806-
methods.addAll(findMethodsWithGenerated(parent, name));
4807-
}
4799+
if (!receiver.isStaticClass() && receiver.getOuterClass() != null
4800+
&& !receiver.getName().endsWith("$Trait$Helper") // GROOVY-7242
4801+
&& typeCheckingContext.getEnclosingClassNodes().contains(receiver)) {
4802+
ClassNode outer = receiver.getOuterClass();
4803+
do { methods.addAll(findMethodsWithGenerated(outer, name));
4804+
} while (!outer.isStaticClass() && (outer = outer.getOuterClass()) != null);
48084805
}
48094806
if (methods.isEmpty()) {
48104807
addArrayMethods(methods, receiver, name, args);
@@ -4817,33 +4814,28 @@ protected List<MethodNode> findMethod(ClassNode receiver, final String name, fin
48174814
}
48184815
PropertyNode property = null;
48194816
if (pname != null) {
4820-
// we don't use property exists there because findMethod is called on super clases recursively
4821-
ClassNode curNode = receiver;
4822-
while (property == null && curNode != null) {
4823-
property = curNode.getProperty(pname);
4824-
ClassNode svCur = curNode;
4825-
while (property == null && svCur.getOuterClass() != null && !svCur.isStaticClass()) {
4826-
svCur = svCur.getOuterClass();
4827-
property = svCur.getProperty(pname);
4828-
if (property != null) {
4829-
receiver = svCur;
4830-
break;
4831-
}
4817+
outer_upper: // can't use existsProperty because it calls findMethod
4818+
for (ClassNode cn = receiver; cn != null; cn = cn.getSuperClass()) {
4819+
property = cn.getProperty(pname);
4820+
if (property != null) break outer_upper;
4821+
if (!cn.isStaticClass() && cn.getOuterClass() != null
4822+
&& typeCheckingContext.getEnclosingClassNodes().contains(cn)) {
4823+
ClassNode outer = cn.getOuterClass();
4824+
do {
4825+
property = outer.getProperty(pname);
4826+
if (property != null) break outer_upper;
4827+
} while (!outer.isStaticClass() && (outer = outer.getOuterClass()) != null);
48324828
}
4833-
curNode = curNode.getSuperClass();
48344829
}
4835-
} else {
4836-
// look for a property with the getterName set since it may not match above
4837-
ClassNode curNode = receiver;
4838-
while (property == null && curNode != null && !curNode.isStaticClass()) {
4839-
for (PropertyNode p : curNode.getProperties()) {
4840-
if (name.equals(p.getGetterName())) {
4841-
property = p;
4842-
receiver = curNode;
4843-
break;
4830+
} else { // look for property via getGetterName() for non-canonical case
4831+
out:
4832+
for (ClassNode cn = receiver; cn != null; cn = cn.getSuperClass()) {
4833+
for (PropertyNode pn : cn.getProperties()) {
4834+
if (name.equals(pn.getGetterName())) {
4835+
property = pn;
4836+
break out;
48444837
}
48454838
}
4846-
curNode = curNode.getSuperClass();
48474839
}
48484840
}
48494841
if (property != null) {

0 commit comments

Comments
 (0)