You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2023/02/23 00:25:23 UTC
[groovy] branch master updated: GROOVY-10935: throw missing exception from inner class
This is an automated email from the ASF dual-hosted git repository.
emilles pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/master by this push:
new 95103625d0 GROOVY-10935: throw missing exception from inner class
95103625d0 is described below
commit 95103625d0162b3018513e2664dd51cefa3eeaaa
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Wed Feb 22 18:24:29 2023 -0600
GROOVY-10935: throw missing exception from inner class
---
.../classgen/InnerClassCompletionVisitor.java | 45 +++++++++++++++++-----
src/test/gls/innerClass/InnerClassTest.groovy | 39 ++++++++++++-------
src/test/groovy/bugs/Groovy8678.groovy | 8 ++--
3 files changed, 65 insertions(+), 27 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/classgen/InnerClassCompletionVisitor.java b/src/main/java/org/codehaus/groovy/classgen/InnerClassCompletionVisitor.java
index 7b01bfeab4..37ea270490 100644
--- a/src/main/java/org/codehaus/groovy/classgen/InnerClassCompletionVisitor.java
+++ b/src/main/java/org/codehaus/groovy/classgen/InnerClassCompletionVisitor.java
@@ -18,6 +18,8 @@
*/
package org.codehaus.groovy.classgen;
+import groovy.lang.MissingMethodException;
+import groovy.lang.MissingPropertyException;
import groovy.transform.CompileStatic;
import groovy.transform.stc.POJO;
import org.codehaus.groovy.ast.ClassHelper;
@@ -32,6 +34,7 @@ import org.codehaus.groovy.ast.expr.Expression;
import org.codehaus.groovy.ast.expr.TupleExpression;
import org.codehaus.groovy.ast.expr.VariableExpression;
import org.codehaus.groovy.ast.stmt.BlockStatement;
+import org.codehaus.groovy.ast.stmt.TryCatchStatement;
import org.codehaus.groovy.classgen.asm.BytecodeHelper;
import org.codehaus.groovy.control.CompilationUnit;
import org.codehaus.groovy.control.SourceUnit;
@@ -48,15 +51,22 @@ import static org.codehaus.groovy.ast.ClassHelper.CLOSURE_TYPE;
import static org.codehaus.groovy.ast.ClassHelper.OBJECT_TYPE;
import static org.codehaus.groovy.ast.ClassHelper.STRING_TYPE;
import static org.codehaus.groovy.ast.ClassHelper.VOID_TYPE;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.args;
import static org.codehaus.groovy.ast.tools.GeneralUtils.block;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.callX;
import static org.codehaus.groovy.ast.tools.GeneralUtils.castX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.catchS;
import static org.codehaus.groovy.ast.tools.GeneralUtils.classX;
import static org.codehaus.groovy.ast.tools.GeneralUtils.ctorSuperX;
import static org.codehaus.groovy.ast.tools.GeneralUtils.ctorThisX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.ctorX;
import static org.codehaus.groovy.ast.tools.GeneralUtils.nullX;
import static org.codehaus.groovy.ast.tools.GeneralUtils.param;
import static org.codehaus.groovy.ast.tools.GeneralUtils.params;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.propX;
import static org.codehaus.groovy.ast.tools.GeneralUtils.stmt;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.throwS;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.tryCatchS;
import static org.codehaus.groovy.ast.tools.GeneralUtils.varX;
import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
import static org.objectweb.asm.Opcodes.ACC_STATIC;
@@ -212,7 +222,7 @@ public class InnerClassCompletionVisitor extends InnerClassVisitorHelper {
final String outerClassInternalName = getInternalName(outerClass, isStatic);
final String outerClassDescriptor = getTypeDescriptor(outerClass, isStatic);
- addSyntheticMethod(node,
+ addMissingHandler(node,
"methodMissing",
ACC_PUBLIC,
OBJECT_TYPE,
@@ -237,7 +247,7 @@ public class InnerClassCompletionVisitor extends InnerClassVisitorHelper {
}
);
- addSyntheticMethod(node,
+ addMissingHandler(node,
"$static_methodMissing",
ACC_PUBLIC | ACC_STATIC,
OBJECT_TYPE,
@@ -247,7 +257,7 @@ public class InnerClassCompletionVisitor extends InnerClassVisitorHelper {
}
);
- addSyntheticMethod(node,
+ addMissingHandler(node,
"propertyMissing",
ACC_PUBLIC,
VOID_TYPE,
@@ -272,7 +282,7 @@ public class InnerClassCompletionVisitor extends InnerClassVisitorHelper {
}
);
- addSyntheticMethod(node,
+ addMissingHandler(node,
"$static_propertyMissing",
ACC_PUBLIC | ACC_STATIC,
VOID_TYPE,
@@ -282,7 +292,7 @@ public class InnerClassCompletionVisitor extends InnerClassVisitorHelper {
}
);
- addSyntheticMethod(node,
+ addMissingHandler(node,
"propertyMissing",
ACC_PUBLIC,
OBJECT_TYPE,
@@ -306,7 +316,7 @@ public class InnerClassCompletionVisitor extends InnerClassVisitorHelper {
}
);
- addSyntheticMethod(node,
+ addMissingHandler(node,
"$static_propertyMissing",
ACC_PUBLIC | ACC_STATIC,
OBJECT_TYPE,
@@ -317,12 +327,29 @@ public class InnerClassCompletionVisitor extends InnerClassVisitorHelper {
);
}
- private void addSyntheticMethod(final InnerClassNode innerClass, final String methodName, final int modifiers,
+ private void addMissingHandler(final InnerClassNode innerClass, final String methodName, final int modifiers,
final ClassNode returnType, final Parameter[] parameters, final BiConsumer<BlockStatement, Parameter[]> consumer) {
MethodNode method = innerClass.getDeclaredMethod(methodName, parameters);
if (method == null) {
- BlockStatement methodBody = block();
- consumer.accept(methodBody, parameters);
+ Parameter catchParam = param(OBJECT_TYPE, "notFound"); // dummy type
+ ClassNode exceptionT;
+ Expression newException;
+ Expression selfType = varX("this");
+ if ((modifiers & ACC_STATIC) == 0) selfType = callX(selfType, "getClass");
+ if (methodName.endsWith("methodMissing")) {
+ exceptionT = ClassHelper.make(MissingMethodException.class);
+ newException = ctorX(exceptionT, args(propX(varX(catchParam),"method"), selfType, propX(varX(catchParam),"arguments")));
+ } else {
+ exceptionT = ClassHelper.make(MissingPropertyException.class);
+ newException = ctorX(exceptionT, args(propX(varX(catchParam), "property"), selfType, propX(varX(catchParam), "cause")));
+ }
+
+ catchParam.setType(exceptionT);
+ catchParam.setOriginType(exceptionT);
+ BlockStatement handleMissing = block();
+ consumer.accept(handleMissing, parameters);
+ TryCatchStatement methodBody = tryCatchS(handleMissing);
+ methodBody.addCatch(catchS(catchParam, throwS(newException)));
innerClass.addSyntheticMethod(methodName, modifiers, returnType, parameters, ClassNode.EMPTY_ARRAY, methodBody);
// if there is a user-defined method, add compiler error and continue
diff --git a/src/test/gls/innerClass/InnerClassTest.groovy b/src/test/gls/innerClass/InnerClassTest.groovy
index f21681560e..102f148469 100644
--- a/src/test/gls/innerClass/InnerClassTest.groovy
+++ b/src/test/gls/innerClass/InnerClassTest.groovy
@@ -1937,8 +1937,8 @@ final class InnerClassTest {
@Test // GROOVY-8274
void testMissingMethodHandling() {
assertScript '''
- class A {
- class B {
+ class Outer {
+ class Inner {
def methodMissing(String name, args) {
return name
}
@@ -1946,12 +1946,12 @@ final class InnerClassTest {
def test(Closure c) {
c.resolveStrategy = Closure.DELEGATE_ONLY
- c.delegate = new B()
+ c.delegate = new Inner()
c.call()
}
}
- def x = new A().test { ->
+ def x = new Outer().test { ->
hello() // missing
}
assert x == 'hello'
@@ -1964,21 +1964,32 @@ final class InnerClassTest {
class Outer {
private static List items = []
void add() { items.add('Outer') }
- static class Nested {
- void add() { items.add('Nested') }
- static class NestedNested {
- void add() { items.add('NestedNested') }
- void set() { items = ['Overridden'] }
+ static class Inner {
+ void add() { items.add('Inner') }
+ static class InnerInner {
+ void add() { items.add('InnerInner') }
+ void set() { items = ['Overwritten'] }
}
}
}
new Outer().add()
- new Outer.Nested().add()
- new Outer.Nested.NestedNested().add()
- assert Outer.items == ["Outer", "Nested", "NestedNested"]
- new Outer.Nested.NestedNested().set()
- assert Outer.items == ["Overridden"]
+ new Outer.Inner().add()
+ new Outer.Inner.InnerInner().add()
+ assert Outer.items == ['Outer', 'Inner', 'InnerInner']
+ new Outer.Inner.InnerInner().set()
+ assert Outer.items == ['Overwritten']
+ '''
+ }
+
+ @Test // GROOVY-10935
+ void testNestedPropertyHandling2() {
+ def err = shouldFail '''
+ class Outer {
+ static class Inner {}
+ }
+ new Outer.Inner().missing
'''
+ assert err =~ /No such property: missing for class: Outer.Inner/
}
@Test // GROOVY-7312
diff --git a/src/test/groovy/bugs/Groovy8678.groovy b/src/test/groovy/bugs/Groovy8678.groovy
index 4657789959..014e2a0f0e 100644
--- a/src/test/groovy/bugs/Groovy8678.groovy
+++ b/src/test/groovy/bugs/Groovy8678.groovy
@@ -81,16 +81,16 @@ final class Groovy8678 {
def x = new WithMethods()
def throwable = shouldFail () -> x.'42'
assert throwable.class == MissingPropertyException.class
- assert throwable.message == 'No such property: 42 for class: groovy.bugs.Groovy8678'
+ assert throwable.message.startsWith('No such property: 42 for class: groovy.bugs.Groovy8678$WithMethods')
throwable = shouldFail () -> x.'42d'
assert throwable.class == MissingPropertyException.class
- assert throwable.message == 'No such property: 42d for class: groovy.bugs.Groovy8678'
+ assert throwable.message.startsWith('No such property: 42d for class: groovy.bugs.Groovy8678$WithMethods')
throwable = shouldFail () -> x.'84'()
assert throwable.class == MissingMethodException.class
- assert throwable.message.startsWith('No signature of method: groovy.bugs.Groovy8678.84() is applicable for argument types: () values: []')
+ assert throwable.message.startsWith('No signature of method: groovy.bugs.Groovy8678$WithMethods.84() is applicable for argument types: () values: []')
throwable = shouldFail () -> x.'84f'()
assert throwable.class == MissingMethodException.class
- assert throwable.message.startsWith('No signature of method: groovy.bugs.Groovy8678.84f() is applicable for argument types: () values: []')
+ assert throwable.message.startsWith('No signature of method: groovy.bugs.Groovy8678$WithMethods.84f() is applicable for argument types: () values: []')
}
@Test