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 2020/07/01 22:26:41 UTC

[groovy] 01/01: GROOVY-4945, GROOVY-9615: call invokeMissingMethod on MetaClass of super

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

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

commit b77583473187a5ccb8f3384ae523681449ec06c8
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Wed Jul 1 17:26:18 2020 -0500

    GROOVY-4945, GROOVY-9615: call invokeMissingMethod on MetaClass of super
---
 src/main/java/groovy/lang/MetaClassImpl.java | 59 +++++++++++++-------------
 src/test/groovy/bugs/Groovy9615.groovy       | 63 ++++++++++++++++++++++++++++
 2 files changed, 94 insertions(+), 28 deletions(-)

diff --git a/src/main/java/groovy/lang/MetaClassImpl.java b/src/main/java/groovy/lang/MetaClassImpl.java
index 5dda2f5..ed63b58 100644
--- a/src/main/java/groovy/lang/MetaClassImpl.java
+++ b/src/main/java/groovy/lang/MetaClassImpl.java
@@ -906,39 +906,42 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
     }
 
     private Object invokeMissingMethod(Object instance, String methodName, Object[] arguments, RuntimeException original, boolean isCallToSuper) {
-        if (!isCallToSuper) {
-            Class instanceKlazz = instance.getClass();
-            if (theClass != instanceKlazz && theClass.isAssignableFrom(instanceKlazz))
-                instanceKlazz = theClass;
+        if (isCallToSuper) {
+            MetaClass metaClass = InvokerHelper.getMetaClass(theClass.getSuperclass());
+            return metaClass.invokeMissingMethod(instance, methodName, arguments);
+        }
 
-            Class[] argClasses = MetaClassHelper.castArgumentsToClassArray(arguments);
+        Class instanceKlazz = instance.getClass();
+        if (theClass != instanceKlazz && theClass.isAssignableFrom(instanceKlazz))
+            instanceKlazz = theClass;
 
-            MetaMethod method = findMixinMethod(methodName, argClasses);
-            if (method != null) {
-                onMixinMethodFound(method);
-                return method.invoke(instance, arguments);
-            }
+        Class[] argClasses = MetaClassHelper.castArgumentsToClassArray(arguments);
 
-            method = findMethodInClassHierarchy(instanceKlazz, methodName, argClasses, this);
-            if (method != null) {
-                onSuperMethodFoundInHierarchy(method);
-                return method.invoke(instance, arguments);
-            }
+        MetaMethod method = findMixinMethod(methodName, argClasses);
+        if (method != null) {
+            onMixinMethodFound(method);
+            return method.invoke(instance, arguments);
+        }
 
-            // still not method here, so see if there is an invokeMethod method up the hierarchy
-            final Class[] invokeMethodArgs = {String.class, Object[].class};
-            method = findMethodInClassHierarchy(instanceKlazz, INVOKE_METHOD_METHOD, invokeMethodArgs, this);
-            if (method instanceof ClosureMetaMethod) {
-                onInvokeMethodFoundInHierarchy(method);
-                return method.invoke(instance, invokeMethodArgs);
-            }
+        method = findMethodInClassHierarchy(instanceKlazz, methodName, argClasses, this);
+        if (method != null) {
+            onSuperMethodFoundInHierarchy(method);
+            return method.invoke(instance, arguments);
+        }
 
-            // last resort look in the category
-            if (method == null && GroovyCategorySupport.hasCategoryInCurrentThread()) {
-                method = getCategoryMethodMissing(instanceKlazz);
-                if (method != null) {
-                    return method.invoke(instance, new Object[]{methodName, arguments});
-                }
+        // still not method here, so see if there is an invokeMethod method up the hierarchy
+        final Class[] invokeMethodArgs = {String.class, Object[].class};
+        method = findMethodInClassHierarchy(instanceKlazz, INVOKE_METHOD_METHOD, invokeMethodArgs, this);
+        if (method instanceof ClosureMetaMethod) {
+            onInvokeMethodFoundInHierarchy(method);
+            return method.invoke(instance, invokeMethodArgs);
+        }
+
+        // last resort look in the category
+        if (method == null && GroovyCategorySupport.hasCategoryInCurrentThread()) {
+            method = getCategoryMethodMissing(instanceKlazz);
+            if (method != null) {
+                return method.invoke(instance, new Object[]{methodName, arguments});
             }
         }
 
diff --git a/src/test/groovy/bugs/Groovy9615.groovy b/src/test/groovy/bugs/Groovy9615.groovy
new file mode 100644
index 0000000..fd8e6ab
--- /dev/null
+++ b/src/test/groovy/bugs/Groovy9615.groovy
@@ -0,0 +1,63 @@
+/*
+ *  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 groovy.bugs
+
+import org.junit.Test
+
+import static groovy.test.GroovyAssert.shouldFail
+
+final class Groovy9615 {
+
+    @Test // GROOVY-4945
+    void testCallSuperMethod1() {
+        def err = shouldFail MissingMethodException, '''
+            class C {
+                void test() {
+                    super.whatever()
+                }
+                void whatever() {
+                    assert false : 'should not have been called!'
+                }
+            }
+            new C().test()
+        '''
+
+        assert err =~ /No signature of method: java\.lang\.Object\.whatever\(\) is applicable for argument types: \(\) values: \[\]
+Possible solutions: every\(\)$/
+    }
+
+    @Test // GROOVY-9615
+    void testCallSuperMethod2() {
+        def err = shouldFail MissingMethodException, '''
+            class Outer {
+                class Inner {
+                    void test() {
+                        super.whatever()
+                    }
+                }
+                void whatever() {
+                    assert false : 'should not have been called!'
+                }
+            }
+            new Outer.Inner(new Outer()).test()
+        '''
+
+        assert err =~ /No signature of method: java\.lang\.Object\.whatever\(\) is applicable for argument types: \(\) values: \[\]/
+    }
+}