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

sunlan 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 b50739745c GROOVY-11568: try 
`invokeMethod(Class,Object,Object[],boolean,boolean)`
b50739745c is described below

commit b50739745c19b7ab556cb2b5da94a73a74377076
Author: Eric Milles <[email protected]>
AuthorDate: Sun Feb 16 20:25:26 2025 -0600

    GROOVY-11568: try `invokeMethod(Class,Object,Object[],boolean,boolean)`
---
 src/main/java/groovy/lang/MetaClassImpl.java       | 33 +++++++----
 .../groovy/runtime/metaclass/ClosureMetaClass.java |  2 +-
 .../v8/IndyGuardsFiltersAndSignatures.java         | 66 ++++++++++-----------
 .../org/codehaus/groovy/vmplugin/v8/Selector.java  | 26 +++++++--
 src/spec/test/builder/NodeBuilderTest.groovy       |  7 ++-
 src/test/groovy/bugs/Groovy11568.groovy            | 67 ++++++++++++++++++++++
 src/test/groovy/lang/MixinTest.groovy              |  3 +-
 .../groovy/groovy/xml/MarkupBuilderTest.groovy     | 32 +++++------
 8 files changed, 165 insertions(+), 71 deletions(-)

diff --git a/src/main/java/groovy/lang/MetaClassImpl.java 
b/src/main/java/groovy/lang/MetaClassImpl.java
index 6908e3b6f2..495639eac8 100644
--- a/src/main/java/groovy/lang/MetaClassImpl.java
+++ b/src/main/java/groovy/lang/MetaClassImpl.java
@@ -324,9 +324,7 @@ public class MetaClassImpl implements MetaClass, 
MutableMetaClass {
     }
 
     /**
-     * Returns the class this object this is the metaclass of.
-     *
-     * @return The class contained by this metaclass
+     * Returns the class this metaclass represents.
      */
     @Override
     public Class getTheClass() {
@@ -334,14 +332,19 @@ public class MetaClassImpl implements MetaClass, 
MutableMetaClass {
     }
 
     /**
-     * Return whether the class represented by this metaclass instance is an 
instance of the GroovyObject class
-     *
-     * @return true if this is a groovy class, false otherwise.
+     * Indicates if the represented class is an instance of the {@link 
GroovyObject} class.
      */
     public boolean isGroovyObject() {
         return isGroovyObject;
     }
 
+    /**
+     * Indicates if the represented class comes from a Groovy closure or 
lambda expression.
+     */
+    private boolean isGroovyFunctor() {
+        return GeneratedClosure.class.isAssignableFrom(theClass);
+    }
+
     private void fillMethodIndex() {
         mainClassMethodHeader = metaMethodIndex.getHeader(theClass);
 
@@ -671,7 +674,10 @@ public class MetaClassImpl implements MetaClass, 
MutableMetaClass {
     private Object getMethods(final Class<?> sender, final String name, final 
boolean isCallToSuper) {
         Object answer;
 
-        final MetaMethodIndex.Cache entry = metaMethodIndex.getMethods(sender, 
name);
+        var entry = metaMethodIndex.getMethods( sender , name);
+        if (entry == null && !isGroovyFunctor()) {
+            entry = metaMethodIndex.getMethods(theClass, name);
+        }
         if (entry == null) {
             answer = FastArray.EMPTY_LIST;
         } else if (isCallToSuper) {
@@ -1086,7 +1092,7 @@ public class MetaClassImpl implements MetaClass, 
MutableMetaClass {
             throw new NullPointerException("Cannot invoke method: " + 
methodName + " on null object");
         }
 
-        final Object[] arguments = originalArguments == null ? EMPTY_ARGUMENTS 
: originalArguments;
+        final Object[] arguments = 
Optional.ofNullable(originalArguments).orElse(EMPTY_ARGUMENTS);
 
         MetaMethod method = getMetaMethod(sender, object, methodName, 
isCallToSuper, arguments);
 
@@ -1237,9 +1243,9 @@ public class MetaClassImpl implements MetaClass, 
MutableMetaClass {
             method = getMethodWithCaching(sender, methodName, arguments, 
isCallToSuper);
         }
         MetaClassHelper.unwrap(arguments);
-
-        if (method == null)
+        if (method == null) {
             method = tryListParamMetaMethod(sender, methodName, isCallToSuper, 
arguments);
+        }
         return method;
     }
 
@@ -1330,6 +1336,9 @@ public class MetaClassImpl implements MetaClass, 
MutableMetaClass {
                       : (isCallToSuper && e.methodsForSuper == null)) { // 
allow "super.name()" to find DGM if class declares method "name"
             e = metaMethodIndex.getMethods(sender.getSuperclass(), methodName);
         }
+        if (e == null && !isGroovyFunctor()) { // GROOVY-4322, GROOVY-11568
+            e = metaMethodIndex.getMethods(theClass, methodName);
+        }
         if (e == null) {
             return null;
         } else if (isCallToSuper) {
@@ -2932,7 +2941,7 @@ public class MetaClassImpl implements MetaClass, 
MutableMetaClass {
      */
     @Override
     public ClassNode getClassNode() {
-        if (classNode == null && 
GroovyObject.class.isAssignableFrom(theClass)) {
+        if (classNode == null && isGroovyObject()) {
             // let's try load it from the classpath
             String groovyFile = theClass.getName();
             int idx = groovyFile.indexOf('$');
@@ -3465,7 +3474,7 @@ public class MetaClassImpl implements MetaClass, 
MutableMetaClass {
         if (!GroovyCategorySupport.hasCategoryInCurrentThread() && !(this 
instanceof AdaptingMetaClass)) {
             Class[] params = MetaClassHelper.convertToTypeArray(args);
             CallSite tempSite = site;
-            if (site.getName().equals(CALL_METHOD) && 
GeneratedClosure.class.isAssignableFrom(theClass)) {
+            if (site.getName().equals(CALL_METHOD) && isGroovyFunctor()) {
                 // here, we want to point to a method named "doCall" instead 
of "call"
                 // but we don't want to replace the original call site name, 
otherwise
                 // we lose the fact that the original method name was "call" 
so instead
diff --git 
a/src/main/java/org/codehaus/groovy/runtime/metaclass/ClosureMetaClass.java 
b/src/main/java/org/codehaus/groovy/runtime/metaclass/ClosureMetaClass.java
index 2d7332d332..479c6b20e9 100644
--- a/src/main/java/org/codehaus/groovy/runtime/metaclass/ClosureMetaClass.java
+++ b/src/main/java/org/codehaus/groovy/runtime/metaclass/ClosureMetaClass.java
@@ -365,7 +365,7 @@ public final class ClosureMetaClass extends MetaClassImpl {
         }
         Class thisType = sender;
         while (GeneratedClosure.class.isAssignableFrom(thisType)) thisType = 
thisType.getEnclosingClass();
-        if (thisType != sender && thisType != object.getClass() && 
thisType.isInstance(object)) { // GROOVY-2433, GROOVY-11128
+        if (thisType != object.getClass() && thisType.isInstance(object)) { // 
GROOVY-2433, GROOVY-11128
             try {
                 return ((GroovyObject) 
object).getMetaClass().invokeMethod(thisType, object, methodName, arguments, 
false, true);
             } catch (GroovyRuntimeException gre) {
diff --git 
a/src/main/java/org/codehaus/groovy/vmplugin/v8/IndyGuardsFiltersAndSignatures.java
 
b/src/main/java/org/codehaus/groovy/vmplugin/v8/IndyGuardsFiltersAndSignatures.java
index db2d6307bc..a992f38c21 100644
--- 
a/src/main/java/org/codehaus/groovy/vmplugin/v8/IndyGuardsFiltersAndSignatures.java
+++ 
b/src/main/java/org/codehaus/groovy/vmplugin/v8/IndyGuardsFiltersAndSignatures.java
@@ -56,15 +56,14 @@ public class IndyGuardsFiltersAndSignatures {
 
     private static final MethodType
             OBJECT_FILTER = MethodType.methodType(Object.class, Object.class),
-            OBJECT_GUARD = MethodType.methodType(boolean.class, Object.class),
-            INVOKER = MethodType.methodType(Object.class, Object.class, 
String.class, Object[].class);
+            OBJECT_GUARD = MethodType.methodType(boolean.class, Object.class);
 
     protected static final MethodHandle
             SAME_CLASS, SAME_CLASSES, SAME_MC, IS_NULL, NON_NULL,
             UNWRAP_METHOD, UNWRAP_EXCEPTION,
             HAS_CATEGORY_IN_CURRENT_THREAD_GUARD,
-            META_METHOD_INVOKER, GROOVY_OBJECT_INVOKER, 
GROOVY_OBJECT_GET_PROPERTY,
-            META_CLASS_INVOKE_STATIC_METHOD,
+            GROOVY_OBJECT_INVOKER, 
GROOVY_OBJECT_GET_PROPERTY,META_METHOD_INVOKER,
+            META_CLASS_INVOKE_METHOD, META_CLASS_INVOKE_STATIC_METHOD,
             BEAN_CONSTRUCTOR_PROPERTY_SETTER,
             META_PROPERTY_GETTER,
             SLOW_META_CLASS_FIND,
@@ -78,35 +77,36 @@ public class IndyGuardsFiltersAndSignatures {
 
     static {
         try {
-            SAME_CLASS = 
LOOKUP.findStatic(IndyGuardsFiltersAndSignatures.class, "sameClass", 
MethodType.methodType(boolean.class, Class.class, Object.class));
-            SAME_CLASSES = 
LOOKUP.findStatic(IndyGuardsFiltersAndSignatures.class, "sameClasses", 
MethodType.methodType(boolean.class, Class[].class, Object[].class));
-            SAME_MC = LOOKUP.findStatic(IndyGuardsFiltersAndSignatures.class, 
"isSameMetaClass", MethodType.methodType(boolean.class, MetaClass.class, 
Object.class));
-            IS_NULL = LOOKUP.findStatic(IndyGuardsFiltersAndSignatures.class, 
"isNull", OBJECT_GUARD);
-            NON_NULL = LOOKUP.findStatic(Objects.class, "nonNull", 
MethodType.methodType(boolean.class, Object.class));
-            UNWRAP_METHOD = 
LOOKUP.findStatic(IndyGuardsFiltersAndSignatures.class, "unwrap", 
OBJECT_FILTER);
-            UNWRAP_EXCEPTION = 
LOOKUP.findStatic(IndyGuardsFiltersAndSignatures.class, "unwrap", 
MethodType.methodType(Object.class, GroovyRuntimeException.class));
-            HAS_CATEGORY_IN_CURRENT_THREAD_GUARD = 
LOOKUP.findStatic(GroovyCategorySupport.class, "hasCategoryInCurrentThread", 
MethodType.methodType(boolean.class));
-            META_METHOD_INVOKER = LOOKUP.findVirtual(MetaMethod.class, 
"doMethodInvoke", MethodType.methodType(Object.class, Object.class, 
Object[].class));
-            GROOVY_OBJECT_INVOKER = 
LOOKUP.findStatic(IndyGuardsFiltersAndSignatures.class, 
"invokeGroovyObjectInvoker", INVOKER.insertParameterTypes(0, 
MissingMethodException.class));
-            GROOVY_OBJECT_GET_PROPERTY = 
LOOKUP.findVirtual(GroovyObject.class, "getProperty", 
MethodType.methodType(Object.class, String.class));
-            META_CLASS_INVOKE_STATIC_METHOD = 
LOOKUP.findVirtual(MetaObjectProtocol.class, "invokeStaticMethod", INVOKER);
-            BEAN_CONSTRUCTOR_PROPERTY_SETTER = 
LOOKUP.findStatic(IndyGuardsFiltersAndSignatures.class, "setBeanProperties", 
MethodType.methodType(Object.class, MetaClass.class, Object.class, Map.class));
-            META_PROPERTY_GETTER = LOOKUP.findVirtual(MetaProperty.class, 
"getProperty", OBJECT_FILTER);
-            SLOW_META_CLASS_FIND = LOOKUP.findStatic(InvokerHelper.class, 
"getMetaClass", MethodType.methodType(MetaClass.class, Object.class));
-            MOP_GET = LOOKUP.findVirtual(MetaObjectProtocol.class, 
"getProperty", MethodType.methodType(Object.class, Object.class, String.class));
-            MOP_INVOKE_CONSTRUCTOR = 
LOOKUP.findVirtual(MetaObjectProtocol.class, "invokeConstructor", 
MethodType.methodType(Object.class, Object[].class));
-            MOP_INVOKE_METHOD = LOOKUP.findVirtual(MetaObjectProtocol.class, 
"invokeMethod", INVOKER);
-            INTERCEPTABLE_INVOKER = LOOKUP.findVirtual(GroovyObject.class, 
"invokeMethod", MethodType.methodType(Object.class, String.class, 
Object.class));
-
-            BOOLEAN_IDENTITY = MethodHandles.identity(Boolean.class);
-            CLASS_FOR_NAME = LOOKUP.findStatic(Class.class, "forName", 
MethodType.methodType(Class.class, String.class, boolean.class, 
ClassLoader.class));
-            DTT_CAST_TO_TYPE = 
LOOKUP.findStatic(DefaultTypeTransformation.class, "castToType", 
MethodType.methodType(Object.class, Object.class, Class.class));
-            SAM_CONVERSION = LOOKUP.findStatic(CachedSAMClass.class, 
"coerceToSAM", MethodType.methodType(Object.class, Closure.class, Method.class, 
Class.class));
-            HASHSET_CONSTRUCTOR = LOOKUP.findConstructor(HashSet.class, 
MethodType.methodType(void.class, Collection.class));
-            ARRAYLIST_CONSTRUCTOR = LOOKUP.findConstructor(ArrayList.class, 
MethodType.methodType(void.class, Collection.class));
-            GROOVY_CAST_EXCEPTION = 
LOOKUP.findConstructor(GroovyCastException.class, 
MethodType.methodType(void.class, Object.class, Class.class));
-
-            EQUALS = LOOKUP.findVirtual(Object.class, "equals", OBJECT_GUARD);
+            SAME_CLASS                           = LOOKUP.findStatic 
(IndyGuardsFiltersAndSignatures.class, "sameClass", 
MethodType.methodType(boolean.class, Class.class, Object.class));
+            SAME_CLASSES                         = LOOKUP.findStatic 
(IndyGuardsFiltersAndSignatures.class, "sameClasses", 
MethodType.methodType(boolean.class, Class[].class, Object[].class));
+            SAME_MC                              = LOOKUP.findStatic 
(IndyGuardsFiltersAndSignatures.class, "isSameMetaClass", 
MethodType.methodType(boolean.class, MetaClass.class, Object.class));
+            IS_NULL                              = LOOKUP.findStatic 
(IndyGuardsFiltersAndSignatures.class, "isNull", OBJECT_GUARD);
+            NON_NULL                             = LOOKUP.findStatic 
(Objects.class, "nonNull", MethodType.methodType(boolean.class, Object.class));
+            UNWRAP_METHOD                        = LOOKUP.findStatic 
(IndyGuardsFiltersAndSignatures.class, "unwrap", OBJECT_FILTER);
+            UNWRAP_EXCEPTION                     = LOOKUP.findStatic 
(IndyGuardsFiltersAndSignatures.class, "unwrap", 
MethodType.methodType(Object.class, GroovyRuntimeException.class));
+            HAS_CATEGORY_IN_CURRENT_THREAD_GUARD = LOOKUP.findStatic 
(GroovyCategorySupport.class, "hasCategoryInCurrentThread", 
MethodType.methodType(boolean.class));
+            GROOVY_OBJECT_INVOKER                = LOOKUP.findStatic 
(IndyGuardsFiltersAndSignatures.class, "invokeGroovyObjectInvoker", 
MethodType.methodType(Object.class, MissingMethodException.class, Object.class, 
String.class, Object[].class));
+            GROOVY_OBJECT_GET_PROPERTY           = 
LOOKUP.findVirtual(GroovyObject.class, "getProperty", 
MethodType.methodType(Object.class, String.class));
+            META_METHOD_INVOKER                  = 
LOOKUP.findVirtual(MetaMethod.class, "doMethodInvoke", 
MethodType.methodType(Object.class, Object.class, Object[].class));
+            META_CLASS_INVOKE_METHOD             = 
LOOKUP.findVirtual(MetaClass.class, "invokeMethod", 
MethodType.methodType(Object.class, Class.class, Object.class, String.class, 
Object[].class, boolean.class, boolean.class));
+            META_CLASS_INVOKE_STATIC_METHOD      = 
LOOKUP.findVirtual(MetaObjectProtocol.class, "invokeStaticMethod", 
MethodType.methodType(Object.class, Object.class, String.class, 
Object[].class));
+            BEAN_CONSTRUCTOR_PROPERTY_SETTER     = LOOKUP.findStatic 
(IndyGuardsFiltersAndSignatures.class, "setBeanProperties", 
MethodType.methodType(Object.class, MetaClass.class, Object.class, Map.class));
+            META_PROPERTY_GETTER                 = 
LOOKUP.findVirtual(MetaProperty.class, "getProperty", OBJECT_FILTER);
+            SLOW_META_CLASS_FIND                 = LOOKUP.findStatic 
(InvokerHelper.class, "getMetaClass", MethodType.methodType(MetaClass.class, 
Object.class));
+            MOP_GET                              = 
LOOKUP.findVirtual(MetaObjectProtocol.class, "getProperty", 
MethodType.methodType(Object.class, Object.class, String.class));
+            MOP_INVOKE_CONSTRUCTOR               = 
LOOKUP.findVirtual(MetaObjectProtocol.class, "invokeConstructor", 
MethodType.methodType(Object.class, Object[].class));
+            MOP_INVOKE_METHOD                    = 
LOOKUP.findVirtual(MetaObjectProtocol.class, "invokeMethod", 
MethodType.methodType(Object.class, Object.class, String.class, 
Object[].class));
+            INTERCEPTABLE_INVOKER                = 
LOOKUP.findVirtual(GroovyObject.class, "invokeMethod", 
MethodType.methodType(Object.class, String.class, Object.class));
+
+            BOOLEAN_IDENTITY                     = 
MethodHandles.identity(Boolean.class);
+            CLASS_FOR_NAME                       = 
LOOKUP.findStatic(Class.class, "forName", MethodType.methodType(Class.class, 
String.class, boolean.class, ClassLoader.class));
+            DTT_CAST_TO_TYPE                     = 
LOOKUP.findStatic(DefaultTypeTransformation.class, "castToType", 
MethodType.methodType(Object.class, Object.class, Class.class));
+            SAM_CONVERSION                       = 
LOOKUP.findStatic(CachedSAMClass.class, "coerceToSAM", 
MethodType.methodType(Object.class, Closure.class, Method.class, Class.class));
+            HASHSET_CONSTRUCTOR                  = 
LOOKUP.findConstructor(HashSet.class, MethodType.methodType(void.class, 
Collection.class));
+            ARRAYLIST_CONSTRUCTOR                = 
LOOKUP.findConstructor(ArrayList.class, MethodType.methodType(void.class, 
Collection.class));
+            GROOVY_CAST_EXCEPTION                = 
LOOKUP.findConstructor(GroovyCastException.class, 
MethodType.methodType(void.class, Object.class, Class.class));
+
+            EQUALS                               = 
LOOKUP.findVirtual(Object.class, "equals", OBJECT_GUARD);
         } catch (Exception e) {
             throw new GroovyBugError(e);
         }
diff --git a/src/main/java/org/codehaus/groovy/vmplugin/v8/Selector.java 
b/src/main/java/org/codehaus/groovy/vmplugin/v8/Selector.java
index b9da452a7e..be586fdff0 100644
--- a/src/main/java/org/codehaus/groovy/vmplugin/v8/Selector.java
+++ b/src/main/java/org/codehaus/groovy/vmplugin/v8/Selector.java
@@ -79,6 +79,7 @@ import static 
org.codehaus.groovy.vmplugin.v8.IndyGuardsFiltersAndSignatures.HAS
 import static 
org.codehaus.groovy.vmplugin.v8.IndyGuardsFiltersAndSignatures.HAS_CATEGORY_IN_CURRENT_THREAD_GUARD;
 import static 
org.codehaus.groovy.vmplugin.v8.IndyGuardsFiltersAndSignatures.INTERCEPTABLE_INVOKER;
 import static 
org.codehaus.groovy.vmplugin.v8.IndyGuardsFiltersAndSignatures.IS_NULL;
+import static 
org.codehaus.groovy.vmplugin.v8.IndyGuardsFiltersAndSignatures.META_CLASS_INVOKE_METHOD;
 import static 
org.codehaus.groovy.vmplugin.v8.IndyGuardsFiltersAndSignatures.META_CLASS_INVOKE_STATIC_METHOD;
 import static 
org.codehaus.groovy.vmplugin.v8.IndyGuardsFiltersAndSignatures.META_METHOD_INVOKER;
 import static 
org.codehaus.groovy.vmplugin.v8.IndyGuardsFiltersAndSignatures.META_PROPERTY_GETTER;
@@ -727,6 +728,13 @@ public abstract class Selector {
             return targetType;
         }
 
+        private Method metaClassMethod(String name, Class<?>... signature) {
+            try { return mc.getClass().getMethod(name, signature);
+            } catch (ReflectiveOperationException e) {
+                throw new GroovyBugError(e);
+            }
+        }
+
         /**
          * Creates a MethodHandle, which will use the metaclass path.
          * This method is called only if no handle has been created before. 
This
@@ -741,9 +749,19 @@ public abstract class Selector {
                 handle = META_CLASS_INVOKE_STATIC_METHOD.bindTo(mc);
                 if (LOG_ENABLED) LOG.info("use invokeStaticMethod with bound 
meta class");
             } else {
-                handle = MOP_INVOKE_METHOD.bindTo(mc);
-                if (LOG_ENABLED) LOG.info("use invokeMethod with bound meta 
class");
-
+                if (standardMetaClass
+                    || metaClassMethod("invokeMethod", Object.class, 
String.class, Object[].class).getDeclaringClass().isAssignableFrom(
+                       metaClassMethod("invokeMethod", Class.class, 
Object.class, String.class, Object[].class, boolean.class, 
boolean.class).getDeclaringClass())
+                ) {
+                    // GROOVY-11568: use 
MetaClass#invokeMethod(Class,Object,Object[],boolean,boolean)
+                    handle = META_CLASS_INVOKE_METHOD;
+                    handle = handle.bindTo(mc).bindTo(sender);
+                    handle = MethodHandles.insertArguments(handle, 3, 
Boolean.FALSE, Boolean.FALSE);
+                    if (LOG_ENABLED) LOG.info("use invokeMethod with bound 
meta class and sender class");
+                } else {
+                    handle = MOP_INVOKE_METHOD.bindTo(mc);
+                    if (LOG_ENABLED) LOG.info("use invokeMethod with bound 
meta class");
+                }
                 if (receiver instanceof GroovyObject) {
                     // if the metaclass call fails we may still want to fall 
back to call
                     // GroovyObject#invokeMethod if the receiver is a 
GroovyObject
@@ -1011,7 +1029,7 @@ public abstract class Selector {
         }
 
         /**
-         * Sets a handle to call {@link 
GroovyInterceptable#invokeMethod(String, Object)}
+         * Sets a handle to call {@link 
GroovyObject#invokeMethod(String,Object)}
          */
         public boolean setInterceptor() {
             if (!(args[0] instanceof GroovyInterceptable)) return false;
diff --git a/src/spec/test/builder/NodeBuilderTest.groovy 
b/src/spec/test/builder/NodeBuilderTest.groovy
index 9871e1e393..82034d0d89 100644
--- a/src/spec/test/builder/NodeBuilderTest.groovy
+++ b/src/spec/test/builder/NodeBuilderTest.groovy
@@ -18,10 +18,11 @@
  */
 package builder
 
-import groovy.test.GroovyTestCase
+import org.junit.jupiter.api.Test
 
-class NodeBuilderTest extends GroovyTestCase {
+final class NodeBuilderTest {
 
+    @Test
     void testNodeBuilder() {
         // tag::node_builder_example[]
         def nodeBuilder = new NodeBuilder()
@@ -41,6 +42,7 @@ class NodeBuilderTest extends GroovyTestCase {
     }
 
     // GROOVY-7044
+    @Test
     void testNodeCloning() {
         def node = new NodeBuilder().a {
             b()
@@ -53,6 +55,7 @@ class NodeBuilderTest extends GroovyTestCase {
     }
 
     // GROOVY-7044
+    @Test
     void testNodeCloningWithAttributes() {
         def node = new NodeBuilder().a(foo: 'bar') {
             b()
diff --git a/src/test/groovy/bugs/Groovy11568.groovy 
b/src/test/groovy/bugs/Groovy11568.groovy
new file mode 100644
index 0000000000..a9b9405c5e
--- /dev/null
+++ b/src/test/groovy/bugs/Groovy11568.groovy
@@ -0,0 +1,67 @@
+/*
+ *  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.jupiter.api.Test
+
+import static groovy.test.GroovyAssert.assertScript
+
+final class Groovy11568 {
+    @Test
+    void testPrivateMethodWithCustomMetaClass() {
+        assertScript '''
+            class CMC extends MetaClassImpl {
+                CMC(Class theClass) {
+                    super(theClass)
+                }
+                @Override
+                Object invokeMethod(Object object, String methodName, Object 
arguments) {
+                    super.invokeMethod(object, methodName, arguments)
+                }
+                @Override
+                Object invokeMethod(Object object, String methodName, Object[] 
originalArguments) {
+                    super.invokeMethod(object, methodName, originalArguments)
+                }
+                @Override
+                Object invokeMethod(Class sender, Object object, String 
methodName, Object[] arguments, boolean isCallToSuper, boolean fromInsideClass) 
{
+                    super.invokeMethod(sender, object, methodName, arguments, 
isCallToSuper, fromInsideClass)
+                }
+            }
+
+            class C {
+                def publicMethod() {
+                    privateMethod()
+                }
+                private privateMethod() {
+                    'C#privateMethod()'
+                }
+            }
+
+            class D extends C {
+            }
+
+            def cmc = new CMC(D.class)
+            cmc.initialize()
+            def obj = new D()
+            obj.setMetaClass(cmc)
+            def str = obj.publicMethod()
+            assert str == 'C#privateMethod()'
+        '''
+    }
+}
diff --git a/src/test/groovy/lang/MixinTest.groovy 
b/src/test/groovy/lang/MixinTest.groovy
index 8d27dc51d9..3694da2252 100644
--- a/src/test/groovy/lang/MixinTest.groovy
+++ b/src/test/groovy/lang/MixinTest.groovy
@@ -306,9 +306,8 @@ class MixinTest extends GroovyTestCase {
         u << 2
 
         assertEquals 6, u.size()
-        assertEquals 6, ((List) u).size()
         assertEquals 6, ((Collection) u).size()
-        assertEquals 2, u.mixedIn[Set].size()
+        assertEquals 6, ((List) u).size()
         assertEquals 2, ((Set) u).size()
     }
 
diff --git 
a/subprojects/groovy-xml/src/test/groovy/groovy/xml/MarkupBuilderTest.groovy 
b/subprojects/groovy-xml/src/test/groovy/groovy/xml/MarkupBuilderTest.groovy
index 916ba581ab..b943bc5457 100644
--- a/subprojects/groovy-xml/src/test/groovy/groovy/xml/MarkupBuilderTest.groovy
+++ b/subprojects/groovy-xml/src/test/groovy/groovy/xml/MarkupBuilderTest.groovy
@@ -23,7 +23,7 @@ package groovy.xml
  * to MarkupBuilder. Functionality in common with StreamingMarkupBuilder
  * is tested in the BuilderTestSupport parent class.
  */
-class MarkupBuilderTest extends BuilderTestSupport {
+final class MarkupBuilderTest extends BuilderTestSupport {
     private StringWriter writer
     private MarkupBuilder xml
 
@@ -238,18 +238,19 @@ class MarkupBuilderTest extends BuilderTestSupport {
         assertExpectedXmlDefault "<element />"
     }
 
+    // GROOVY-4322
     void testDelegateOnlyToSkipInternalClosureMethods() {
         def items = {
-          pizza(price: 8.5)
-          curry(price: 8)
+          pizza (price: 8.5)
+          curry (price: 8  )
           burger(price: 7.5)
         }
         items.resolveStrategy = Closure.DELEGATE_ONLY
         xml.menu(items)
         assertExpectedXmlDefault '''
             <menu>
-              <pizza price='8.5' />
-              <curry price='8' />
+              <pizza  price='8.5' />
+              <curry  price='8'   />
               <burger price='7.5' />
             </menu>
         '''
@@ -278,29 +279,22 @@ class MarkupBuilderTest extends BuilderTestSupport {
     }
 
     void testEscapingOfAttributes() {
-        def writer = new StringWriter()
-        def builder = new groovy.xml.MarkupBuilder(writer)
-        builder.a(href: "http://www.example.com?foo=1&bar=2";)
+        xml.a(href: 'http://www.example.com?foo=1&bar=2')
         assert 
writer.toString().contains('http://www.example.com?foo=1&amp;bar=2')
     }
 
     void testNoEscapingOfAttributes() {
-        def writer = new StringWriter()
-        def builder = new groovy.xml.MarkupBuilder(writer)
-        builder.escapeAttributes = false
-        builder.a(href: "http://www.example.com?foo=1&bar=2";)
+        xml.escapeAttributes = false
+        xml.a(href: 'http://www.example.com?foo=1&bar=2')
         assert writer.toString().contains('http://www.example.com?foo=1&bar=2')
     }
 
-    private myMethod(x) {
-      x.value='call to outside'
-      return x
-    }
-
+    @Override
     protected assertExpectedXml(Closure markup, String expectedXml) {
         assertExpectedXml markup, null, expectedXml
     }
 
+    @Override
     protected assertExpectedXml(Closure markup, Closure configureBuilder, 
String expectedXml) {
         def writer = new StringWriter()
         def builder = new MarkupBuilder(writer)
@@ -310,4 +304,8 @@ class MarkupBuilderTest extends BuilderTestSupport {
         checkXml(expectedXml, writer)
     }
 
+    private myMethod(x) {
+        x.value = 'call to outside'
+        x
+    }
 }

Reply via email to