This is an automated email from the ASF dual-hosted git repository.

emilles pushed a commit to branch GROOVY_4_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit bd451f6ec108db14b0b46dae4c58e318cf19baa3
Author: Eric Milles <[email protected]>
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

Reply via email to