This is an automated email from the ASF dual-hosted git repository.
emilles pushed a commit to branch GROOVY_5_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/GROOVY_5_0_X by this push:
new 3015f5e5cc GROOVY-11854: enclosing method is `run()` for anon. inner
in a script
3015f5e5cc is described below
commit 3015f5e5cc7b2e27ed581ccfa7a88b23ba03c83c
Author: Eric Milles <[email protected]>
AuthorDate: Wed Feb 4 11:15:30 2026 -0600
GROOVY-11854: enclosing method is `run()` for anon. inner in a script
---
.../java/org/codehaus/groovy/ast/ModuleNode.java | 12 +
.../groovy/classgen/AsmClassGenerator.java | 8 +-
src/test/groovy/bugs/Groovy10840.groovy | 39 ++
src/test/groovy/bugs/Groovy7785.groovy | 5 -
src/test/groovy/bugs/Groovy7938Bug.groovy | 70 ----
.../groovy/gls/innerClass/InnerClassTest.groovy | 450 +++++++++++++++------
src/test/groovy/groovy/ClosureTest.groovy | 69 +---
src/test/groovy/groovy/PropertyTest.groovy | 18 -
8 files changed, 392 insertions(+), 279 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/ast/ModuleNode.java
b/src/main/java/org/codehaus/groovy/ast/ModuleNode.java
index 8c7edf3bf2..576d1dabc9 100644
--- a/src/main/java/org/codehaus/groovy/ast/ModuleNode.java
+++ b/src/main/java/org/codehaus/groovy/ast/ModuleNode.java
@@ -19,6 +19,7 @@
package org.codehaus.groovy.ast;
import org.apache.groovy.ast.tools.ClassNodeUtils;
+import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
import org.codehaus.groovy.ast.expr.DeclarationExpression;
import org.codehaus.groovy.ast.expr.Expression;
import org.codehaus.groovy.ast.expr.ListExpression;
@@ -454,6 +455,17 @@ public class ModuleNode extends ASTNode {
methodNode.addAnnotations(existingMain.getAnnotations());
}
ClassNodeUtils.addGeneratedMethod(classNode, methodNode, true);
+
+ new CodeVisitorSupport() {
+ @Override
+ public void visitConstructorCallExpression(final
ConstructorCallExpression cce) {
+ if (cce.isUsingAnonymousInnerClass()) { // GROOVY-11854
+ cce.getType().setEnclosingMethod(methodNode);
+ }
+ super.visitConstructorCallExpression(cce);
+ }
+ }
+ .visit(statementBlock);
} else {
fields.forEach(classNode::addField);
classNode.addAnnotations(existingRun.getAnnotations());
diff --git a/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
b/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
index 8f2b726614..a724628667 100644
--- a/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
+++ b/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
@@ -345,7 +345,7 @@ public class AsmClassGenerator extends ClassGenerator {
MethodNode enclosingMethod = classNode.getEnclosingMethod();
if (enclosingMethod != null) {
classVisitor.visitOuterClass(
-
BytecodeHelper.getClassInternalName(classNode.getOuterClass()),
+
BytecodeHelper.getClassInternalName(enclosingMethod.getDeclaringClass()),
enclosingMethod.getName(),
BytecodeHelper.getMethodDescriptor(enclosingMethod));
}
}
@@ -441,9 +441,6 @@ public class AsmClassGenerator extends ClassGenerator {
}
private void makeInnerClassEntry(final ClassNode innerClass) {
- ClassNode outerClass = innerClass.getOuterClass();
- maybeInnerClassEntry(outerClass); // GROOVY-9842
-
String innerClassName = innerClass.getName();
String innerClassInternalName =
BytecodeHelper.getClassInternalName(innerClassName);
{
@@ -452,7 +449,8 @@ public class AsmClassGenerator extends ClassGenerator {
}
String outerClassInternalName;
if (innerClass.getEnclosingMethod() == null) {
- outerClassInternalName =
BytecodeHelper.getClassInternalName(outerClass.getName());
+ maybeInnerClassEntry(innerClass.getOuterClass()); // GROOVY-9842
+ outerClassInternalName =
BytecodeHelper.getClassInternalName(innerClass.getOuterClass().getName());
} else {
outerClassInternalName = null; // local inner classes don't
specify the outer class name
if (innerClass instanceof InnerClassNode && ((InnerClassNode)
innerClass).isAnonymous()) innerClassName = null;
diff --git a/src/test/groovy/bugs/Groovy10840.groovy
b/src/test/groovy/bugs/Groovy10840.groovy
new file mode 100644
index 0000000000..d7079200b4
--- /dev/null
+++ b/src/test/groovy/bugs/Groovy10840.groovy
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package bugs
+
+import org.junit.jupiter.api.Test
+
+import static groovy.test.GroovyAssert.assertScript
+
+final class Groovy10840 {
+
+ @Test
+ void testSpecialConstructorCallWithArray() {
+ assertScript '''
+ class BAIS extends ByteArrayInputStream {
+ BAIS(String input) {
+ super(input.bytes)
+ }
+ }
+
+ assert new BAIS('input').available() >= 5
+ '''
+ }
+}
diff --git a/src/test/groovy/bugs/Groovy7785.groovy
b/src/test/groovy/bugs/Groovy7785.groovy
index ea9d60d59c..1f98995820 100644
--- a/src/test/groovy/bugs/Groovy7785.groovy
+++ b/src/test/groovy/bugs/Groovy7785.groovy
@@ -18,14 +18,9 @@
*/
package bugs
-import org.junit.jupiter.api.Test
-import org.junit.jupiter.api.condition.DisabledIfEnvironmentVariable
-
import static groovy.test.GroovyAssert.assertScript
-@DisabledIfEnvironmentVariable(named = "CI", matches = ".*") // runs locally
but fails in CI, more investigation needed
final class Groovy7785 {
- @Test
void testManyChainedMethodCalls() {
assertScript '''
def r = new
StringBuilder().append("a").append("a").append("a").append("a").append("a").append("a").append("a").append("a").append("a").append("a").append("a").append("a").append("a").append("a").append("a").append("a").append("a").append("a").append("a").append("a").append("a").append("a").append("a").append("a").append("a").append("a").append("a").append("a").append("a").append("a").append("a").append("a").append("a").append("a").append("a").append("a").append("a").append("
[...]
diff --git a/src/test/groovy/bugs/Groovy7938Bug.groovy
b/src/test/groovy/bugs/Groovy7938Bug.groovy
deleted file mode 100644
index a7476f4f60..0000000000
--- a/src/test/groovy/bugs/Groovy7938Bug.groovy
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package bugs
-
-import groovy.test.GroovyTestCase
-
-class Groovy7938Bug extends GroovyTestCase {
- void testClassUsageInInterfaceDef() {
- assertScript """
- class Outer {
- static Integer fooCount = 0
- Integer barCount = 0
- static void incFoo() { fooCount++ }
- void incBar() { barCount++ }
- static class Nested {
- static void nestedIncFoo() { incFoo() }
- static class NestedNested {
- static void nestedNestedIncFoo() { incFoo() }
- }
- }
- Inner innerFactory() { new Inner() }
- class Inner {
- InnerInner innerInnerFactory() { new InnerInner() }
- void innerIncFoo() { incFoo() }
- static void staticInnerIncFoo() { incFoo() }
- class InnerInner {
- void innerInnerIncFoo() { incFoo() }
- static void staticInnerInnerIncFoo() { incFoo() }
- }
- }
- }
- Outer.incFoo()
- Outer.Nested.nestedIncFoo()
- Outer.Nested.NestedNested.nestedNestedIncFoo()
- assert Outer.fooCount == 3
- new Outer().with {
- incBar()
- incFoo()
- innerFactory().with {
- incBar()
- innerIncFoo()
- staticInnerIncFoo()
- innerInnerFactory().with {
- incBar()
- innerInnerIncFoo()
- staticInnerInnerIncFoo()
- }
- }
- assert barCount == 3
- assert fooCount == 8
- }
- """
- }
-}
diff --git a/src/test/groovy/gls/innerClass/InnerClassTest.groovy
b/src/test/groovy/gls/innerClass/InnerClassTest.groovy
index 3006f7798b..d0d546c4cd 100644
--- a/src/test/groovy/gls/innerClass/InnerClassTest.groovy
+++ b/src/test/groovy/gls/innerClass/InnerClassTest.groovy
@@ -50,10 +50,10 @@ final class InnerClassTest {
assertScript '''import Foo as Bar
class Foo {}
- def regular = new Bar()
- def anonymous = new Bar() {}
- assert regular.class.name == 'Foo'
- assert anonymous.class.superclass.name == 'Foo'
+ def obj = new Bar()
+ def aic = new Bar() {}
+ assert obj.class.name == 'Foo'
+ assert aic.class.superclass.name == 'Foo'
'''
assertScript '''import static Baz.Foo as Bar
@@ -61,24 +61,43 @@ final class InnerClassTest {
static class Foo {}
}
- def regular = new Bar()
- def anonymous = new Bar() {}
- assert regular.class.name == 'Baz$Foo'
- assert anonymous.class.superclass.name == 'Baz$Foo'
+ def obj = new Bar()
+ def aic = new Bar() {}
+ assert obj.class.name == 'Baz$Foo'
+ assert aic.class.superclass.name == 'Baz$Foo'
'''
}
- // GROOVY-10840
+ // GROOVY-11846
@Test
- void testArrayAIC() {
+ void testInnerAIC() {
assertScript '''
- class BAIS extends ByteArrayInputStream {
- BAIS(String input) {
- super(input.bytes)
+ class C {
+ def m() {
+ return { ->
+ new Object() {
+ }
+ }
}
}
- assert new BAIS('input').available() >= 5
+ def obj = new C().m() ()
+ def aic = obj.getClass()
+ assert aic.getName() == 'C$1'
+ assert aic.getEnclosingClass().getName() == 'C' // C$_m_closure1?
+ assert aic.getEnclosingMethod().getName() == 'm' // doCall?
+ '''
+ }
+
+ // GROOVY-11854
+ @Test
+ void testScriptAIC() {
+ assertScript '''
+ def obj = new Object(){}
+ def aic = obj.getClass()
+ assert aic.getName().endsWith('$1')
+ assert aic.getEnclosingClass().getName().startsWith('TestScript')
+ assert aic.getEnclosingMethod()?.getName() == 'run'
'''
}
@@ -141,6 +160,35 @@ final class InnerClassTest {
'''
}
+ @Test
+ void testAccessLocalVariableInAIC() {
+ assertScript '''
+ final String objName = 'My name is Guillaume'
+
+ assert new Object() {
+ String toString() { objName }
+ }.toString() == objName
+ '''
+ }
+
+ // GROOVY-5041
+ @Test
+ void testAccessLocalVariableInAIC2() {
+ assertScript '''
+ abstract class A {
+ abstract call()
+ }
+
+ def x = 1
+ def a = new A() {
+ def call() { x }
+ }
+ assert a.call() == 1
+ x = 2
+ assert a.call() == 2
+ '''
+ }
+
// GROOVY-8448
@Test
void testAccessLocalVariableVsGetterInAIC() {
@@ -186,17 +234,6 @@ final class InnerClassTest {
'''
}
- @Test
- void testAccessFinalLocalVariableFromMethodInAIC() {
- assertScript '''
- final String objName = "My name is Guillaume"
-
- assert new Object() {
- String toString() { objName }
- }.toString() == objName
- '''
- }
-
// GROOVY-9825
@Test
void testAccessSuperInterfaceConstantWithInnerClass() {
@@ -234,14 +271,14 @@ final class InnerClassTest {
}
class Two extends One {
- Two() {
- super(new Object() { // AIC before special ctor call completes
- int hashCode() {
- hash() // should be able to call static method safely
- }
- })
- }
- static int hash() { 42 }
+ Two() {
+ super(new Object() { // AIC before special ctor call
completes
+ int hashCode() {
+ hash() // should be able to call static method
safely
+ }
+ })
+ }
+ static int hash() { 42 }
}
def obj = new Two()
@@ -388,8 +425,10 @@ final class InnerClassTest {
void testStaticInnerClass2() {
assertScript '''
class A {
- static class B {}
+ static class B {
+ }
}
+
assert A.declaredClasses.length == 1
assert A.declaredClasses[0] == A.B
'''
@@ -401,11 +440,12 @@ final class InnerClassTest {
class A {
static class B {
String p
+ String getQ() { WHY }
}
B m() {
return [p:'x'] // calls
ScriptBytecodeAdapter.castToType([p:'x'], A$B.class)
}
- static final String q = 'y'
+ private static final String WHY = 'y'
}
o = new A().m()
@@ -422,6 +462,7 @@ final class InnerClassTest {
final String foo = 'foo'
}
}
+
def b = new A.B(new A())
assert b.foo == 'foo'
'''
@@ -465,6 +506,7 @@ final class InnerClassTest {
class A {
class B {}
}
+
def x = new A.B() // requires reference to A
'''
}
@@ -573,14 +615,14 @@ final class InnerClassTest {
@Test
void testUsageOfOuterField() {
assertScript '''
- interface Run {
+ interface A {
def run()
}
- class Foo {
+ class C {
private x = 1
def foo() {
- def runner = new Run() {
+ def runner = new A() {
def run() { return x }
}
runner.run()
@@ -588,24 +630,25 @@ final class InnerClassTest {
void x(y) { x = y }
}
- def foo = new Foo()
- assert foo.foo() == 1
- foo.x(2)
- assert foo.foo() == 2
+
+ def c = new C()
+ assert c.foo() == 1
+ c.x(2)
+ assert c.foo() == 2
'''
}
@Test
void testUsageOfOuterField2() {
assertScript '''
- interface Run {
+ interface A {
def run()
}
- class Foo {
+ class C {
private static x = 1
static foo() {
- def runner = new Run() {
+ def runner = new A() {
def run() { return x }
}
runner.run()
@@ -613,39 +656,16 @@ final class InnerClassTest {
static x(y) { x = y }
}
- assert Foo.foo() == 1
- Foo.x(2)
- assert Foo.foo() == 2
- '''
- }
- @Test
- void testUsageOfOuterField3() {
- assertScript '''
- interface X {
- def m()
- }
-
- class A {
- def pm = "pm"
-
- def bar(x) {x().m()}
- def foo() {
- bar { ->
- return new X() {
- def m() { pm }
- }
- }
- }
- }
- def a = new A()
- assert "pm" == a.foo()
+ assert C.foo() == 1
+ C.x(2)
+ assert C.foo() == 2
'''
}
// GROOVY-6141
@Test
- void testUsageOfOuterField4() {
+ void testUsageOfOuterField3() {
assertScript '''
class A {
def x = 1
@@ -676,7 +696,7 @@ final class InnerClassTest {
// GROOVY-9189
@Test
- void testUsageOfOuterField5() {
+ void testUsageOfOuterField4() {
assertScript '''
interface Run {
def run()
@@ -692,6 +712,7 @@ final class InnerClassTest {
static x(y) { x = y }
}
+
assert Foo.foo() == 1
Foo.x(2)
assert Foo.foo() == 2
@@ -700,7 +721,7 @@ final class InnerClassTest {
// GROOVY-9168
@Test
- void testUsageOfOuterField6() {
+ void testUsageOfOuterField5() {
assertScript '''
class A {
// AIC in this position can use static
properties:
@@ -719,7 +740,7 @@ final class InnerClassTest {
// GROOVY-9501
@Test
- void testUsageOfOuterField7() {
+ void testUsageOfOuterField6() {
assertScript '''
class Main extends Outer {
static main(args) {
@@ -755,7 +776,7 @@ final class InnerClassTest {
}
@Test // inner class is static instead of final
- void testUsageOfOuterField8() {
+ void testUsageOfOuterField7() {
assertScript '''
class Main extends Outer {
static main(args) {
@@ -792,7 +813,7 @@ final class InnerClassTest {
// GROOVY-9569
@Test
- void testUsageOfOuterField9() {
+ void testUsageOfOuterField8() {
assertScript '''
class Main extends Outer {
static main(args) {
@@ -829,7 +850,7 @@ final class InnerClassTest {
}
@Test
- void testUsageOfOuterField10() {
+ void testUsageOfOuterField9() {
assertScript '''
class Outer {
static final String OUTER_CONSTANT = 'Constant Value'
@@ -853,7 +874,7 @@ final class InnerClassTest {
// GROOVY-5259
@Test
- void testUsageOfOuterField11() {
+ void testUsageOfOuterField10() {
assertScript '''
class Base {
Base(String string) {
@@ -885,7 +906,7 @@ final class InnerClassTest {
}
@Test
- void testUsageOfOuterField12() {
+ void testUsageOfOuterField11() {
def err = shouldFail '''
class C {
int count
@@ -906,18 +927,35 @@ final class InnerClassTest {
// GROOVY-8050
@Test
- void testUsageOfOuterField13() {
+ void testUsageOfOuterField12() {
assertScript '''
class Outer {
class Inner {
}
def p = 1
}
+
def i = new Outer.Inner(new Outer())
assert i.p == 1
'''
}
+ @NotYetImplemented @Test
+ void testUsageOfOuterField13() {
+ assertScript '''
+ class Outer {
+ interface Inner {
+ default i() {
+ 'i' + o
+ }
+ }
+ private static o = 'o'
+ }
+
+ assert (new Outer.Inner() {}).i() == 'io'
+ '''
+ }
+
@Test
void testUsageOfOuterSuperField() {
assertScript '''
@@ -1026,28 +1064,27 @@ final class InnerClassTest {
@Test
void testUsageOfOuterFieldOverridden() {
assertScript '''
- interface Run {
+ interface A {
def run()
}
- class Foo {
- private x = 1
-
- def foo() {
- def runner = new Run() {
+ class B {
+ def test() {
+ def runner = new A() {
def run() { return x } // <-- dynamic variable
}
runner.run()
}
-
+ private x = 1
void setX(val) { x = val }
}
- class Bar extends Foo {
- def x = 'string' // hides 'foo.@x' and overrides
'foo.setX(val)'
+ class C extends B {
+ def x = 'string' // hides 'B.@x' and overrides 'B.setX(val)'
}
- def bar = new Bar()
- assert bar.foo() == 'string'
- bar.x = 'new string'
- assert bar.foo() == 'new string'
+
+ def c = new C()
+ assert c.test() == 'string'
+ c.x = 'new string'
+ assert c.test() == 'new string'
'''
}
@@ -1067,6 +1104,7 @@ final class InnerClassTest {
runner.run()
}
}
+
def foo = new Foo()
assert foo.foo() == 1
'''
@@ -1088,6 +1126,7 @@ final class InnerClassTest {
runner.run()
}
}
+
def foo = new Foo()
assert foo.foo() == 1
'''
@@ -1108,6 +1147,7 @@ final class InnerClassTest {
runner.run()
}
}
+
def foo = new Foo()
assert foo.foo() == 1
'''
@@ -1129,6 +1169,7 @@ final class InnerClassTest {
runner.run()
}
}
+
def foo = new Foo()
assert foo.foo() == 1
'''
@@ -1226,6 +1267,75 @@ final class InnerClassTest {
'''
}
+ // GROOVY-7938
+ @Test
+ void testUsageOfOuterMethod9() {
+ assertScript '''
+ class Outer {
+ Integer barCount = 0
+ static Integer fooCount = 0
+ void incBar() { barCount++ }
+ static void incFoo() { fooCount++ }
+ Inner innerFactory() { new Inner() }
+
+ static class Nested {
+ static void nestedIncFoo() { incFoo() }
+ static class NestedNested {
+ static void nestedNestedIncFoo() { incFoo() }
+ }
+ }
+ class Inner {
+ void innerIncFoo() { incFoo() }
+ static void staticInnerIncFoo() { incFoo() }
+ InnerInner innerInnerFactory() { new InnerInner() }
+
+ class InnerInner {
+ void innerInnerIncFoo() { incFoo() }
+ static void staticInnerInnerIncFoo() { incFoo() }
+ }
+ }
+ }
+
+ Outer.incFoo()
+ Outer.Nested.nestedIncFoo()
+ Outer.Nested.NestedNested.nestedNestedIncFoo()
+ assert Outer.fooCount == 3
+
+ new Outer().with {
+ incBar()
+ incFoo()
+ innerFactory().with {
+ incBar()
+ innerIncFoo()
+ staticInnerIncFoo()
+ innerInnerFactory().with {
+ incBar()
+ innerInnerIncFoo()
+ staticInnerInnerIncFoo()
+ }
+ }
+ assert barCount == 3
+ assert fooCount == 8
+ }
+ '''
+ }
+
+ @NotYetImplemented @Test
+ void testUsageOfOuterMethod10() {
+ assertScript '''
+ class Outer {
+ interface Inner {
+ default i() {
+ 'i' + o()
+ }
+ }
+ private static o() { 'o' }
+ }
+
+ assert (new Outer.Inner() {}).i() == 'io'
+ '''
+ }
+
@Test
void testUsageOfOuterMethodOverridden() {
assertScript '''
@@ -1446,23 +1556,27 @@ final class InnerClassTest {
@Test
void testInnerClassDotThisUsage2() {
assertScript '''
- interface X {
+ interface A {
def m()
}
-
- class A {
+ class B {
def foo() {
- def c = {
- return new X(){def m(){
- A.this
- } }
+ def x = { ->
+ return new A() {
+ @Override
+ def m() {
+ B.this
+ }
+ }
}
- return c().m()
+ return x().m()
}
}
- class B extends A {}
- def b = new B()
- assert b.foo() instanceof B
+ class C extends B {
+ }
+
+ def c = new C()
+ assert c.foo() instanceof C
'''
}
@@ -1558,17 +1672,13 @@ final class InnerClassTest {
void testReferencedVariableInAIC3() {
assertScript '''
abstract class A {
- A() {
- m()
- }
- abstract void m();
+ abstract void m()
}
void test() {
def v = false
def a = new A() {
- // run by super ctor
@Override void m() {
- assert v != null
+ assert v == true
}
}
v = true
@@ -2117,6 +2227,7 @@ final class InnerClassTest {
inner.inner()
}
}
+
assert new Outer().test() == 1
'''
}
@@ -2138,17 +2249,18 @@ final class InnerClassTest {
}
}
}
+
new Outer().obj.toString()
'''
}
// GROOVY-8274
@Test
- void testMissingMethodHandling() {
+ void testMethodMissing1() {
assertScript '''
class Outer {
class Inner {
- def methodMissing(String name, args) {
+ def methodMissing(String name, Object args) {
return name
}
}
@@ -2167,6 +2279,64 @@ final class InnerClassTest {
'''
}
+ @Test
+ void testMethodMissing2() {
+ assertScript '''
+ class Outer {
+ class Inner {
+ def methodMissing(String name, Object args) {
+ return 42
+ }
+ def propertyMissing(String name) {
+ return 42
+ }
+ }
+ }
+
+ def i = new Outer.Inner(new Outer())
+ assert i.foo() == 42
+ assert i.foobar == 42
+ '''
+ }
+
+ @Test
+ void testMethodMissing3() {
+ def err = shouldFail '''
+ class Outer {
+ static class Inner {
+ def methodMissing(String name, Object args) {
+ return 42
+ }
+ def propertyMissing(String name) {
+ return 42
+ }
+ }
+ }
+ '''
+ assert err =~ /"methodMissing" implementations are not supported on
static inner classes as a synthetic version of "methodMissing" is added during
compilation for the purpose of outer class delegation./
+ assert err =~ /"propertyMissing" implementations are not supported on
static inner classes as a synthetic version of "propertyMissing" is added
during compilation for the purpose of outer class delegation./
+ }
+
+ @Test
+ void testMethodMissing4() {
+ def err = shouldFail '''
+ class Outer {
+ static class Inner {
+ def methodMissing(String name, Object args) {
+ return 42
+ }
+ def propertyMissing(String name) {
+ return 42
+ }
+ }
+ static class Other extends Inner {
+ }
+ }
+ '''
+ assert err =~ /"methodMissing" implementations are not supported on
static inner classes as a synthetic version of "methodMissing" is added during
compilation for the purpose of outer class delegation./
+ assert err =~ /"propertyMissing" implementations are not supported on
static inner classes as a synthetic version of "propertyMissing" is added
during compilation for the purpose of outer class delegation./
+ }
+
// GROOVY-6831
@Test
void testNestedPropertyHandling() {
@@ -2228,6 +2398,7 @@ final class InnerClassTest {
def err = shouldFail """
class Upper {
$returnType propertyMissing(String name, Object value) {
+ throw new MissingPropertyException(name, getClass())
}
}
class Outer {
@@ -2239,6 +2410,59 @@ final class InnerClassTest {
assert err =~ /No such property: missing for class: Outer.Inner/
}
+ // GROOVY-11823
+ @NotYetImplemented @Test
+ void testNestedPropertyHandling5() {
+ assertScript '''
+ class Upper {
+ Object propertyMissing(String name) {
+ if (name == 'fizz') return 'buzz'
+ throw new MissingPropertyException(name, getClass())
+ }
+ }
+ class Outer {
+ static class Inner extends Upper {
+ }
+ }
+ def inner = new Outer.Inner()
+ assert inner.fizz == 'buzz'
+ '''
+ }
+
+ // GROOVY-9618
+ @Test
+ void testNestedPropertyHandling6() {
+ assertScript '''
+ class Super {
+ public static X = 1
+ static getX() { 2 }
+ }
+ class Outer extends Super {
+ static class Inner {
+ def m() { X }
+ }
+ }
+
+ assert new Outer.Inner().m() == 2
+ '''
+
+ assertScript '''
+ class Outer {
+ public static X = 1
+ static getX() { 2 }
+ static class Inner {
+ }
+ }
+ class Other extends Outer.Inner {
+ def m() {
+ X // shouldn't read super outer this way
+ }
+ }
+
+ new Other().m()
+ '''
+ }
+
// GROOVY-7312
@Test
void testInnerClassOfInterfaceIsStatic() {
diff --git a/src/test/groovy/groovy/ClosureTest.groovy
b/src/test/groovy/groovy/ClosureTest.groovy
index 829645151d..52cfc60b35 100644
--- a/src/test/groovy/groovy/ClosureTest.groovy
+++ b/src/test/groovy/groovy/ClosureTest.groovy
@@ -18,8 +18,7 @@
*/
package groovy
-import org.codehaus.groovy.control.MultipleCompilationErrorsException
-import org.junit.Test
+import org.junit.jupiter.api.Test
import static groovy.test.GroovyAssert.assertScript
import static groovy.test.GroovyAssert.shouldFail
@@ -484,72 +483,6 @@ final class ClosureTest {
'''
}
- @Test
- void testStaticInnerClassOwnerWithPropertyMissingImplementation() {
- def err = shouldFail MultipleCompilationErrorsException, '''
- class ClosureTestA {
- static class ClosureTestB {
- def propertyMissing(String myName, Object myValue) {
- return myValue
- }
-
- def propertyMissing(String myName) {
- return 42
- }
-
- def methodMissing(String myName, Object myArgs) {
- return 42
- }
- }
- }
- '''
-
- assert err.message.contains('"methodMissing" implementations are not
supported on static inner classes as a synthetic version of "methodMissing" is
added during compilation for the purpose of outer class delegation.')
- assert err.message.contains('"propertyMissing" implementations are not
supported on static inner classes as a synthetic version of "propertyMissing"
is added during compilation for the purpose of outer class delegation.')
- }
-
- @Test
- void testInnerClassOwnerWithPropertyMissingImplementation() {
- assertScript '''
- class ClosureTestA {
- class ClosureTestB {
- def propertyMissing(String myName, Object myValue) {
- return myValue
- }
-
- def propertyMissing(String myName) {
- return 42
- }
-
- def methodMissing(String myName, Object myArgs) {
- return 42
- }
- }
- }
-
- def a = new ClosureTestA()
- def b = new ClosureTestA.ClosureTestB(a)
- '''
- }
-
- @Test
- void testStaticInnerClassHierarchyWithMethodMissing() {
- def err = shouldFail MultipleCompilationErrorsException, '''
- class ClosureTestA {
- static class ClosureTestB {
- def methodMissing(String myName, Object myArgs) {
- return 42
- }
- }
-
- static class ClosureTestB1 extends ClosureTestB {
- }
- }
- '''
-
- assert err.message.contains('"methodMissing" implementations are not
supported on static inner classes as a synthetic version of "methodMissing" is
added during compilation for the purpose of outer class delegation.')
- }
-
// GROOVY-10943
@Test
void testClosureUnderscorePlaceholder() {
diff --git a/src/test/groovy/groovy/PropertyTest.groovy
b/src/test/groovy/groovy/PropertyTest.groovy
index 761fcde041..2b2547912e 100644
--- a/src/test/groovy/groovy/PropertyTest.groovy
+++ b/src/test/groovy/groovy/PropertyTest.groovy
@@ -831,24 +831,6 @@ final class PropertyTest {
'''
}
- // GROOVY-9618
- @Test
- void testPropertyAndStaticUppercaseFieldPriority() {
- assertScript '''
- class A {
- public static X = 1
- static getX() { 2 }
- static class B { }
- }
- class C extends A.B {
- def test() {
- X
- }
- }
- assert new C().test() == 2
- '''
- }
-
//--------------------------------------------------------------------------
static class Base {