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/07/17 13:22:27 UTC

[groovy] branch master updated: GROOVY-2433, GROOVY-3073, GROOVY-9987: `this.privateMethod()` in closure

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 0738ed1049 GROOVY-2433, GROOVY-3073, GROOVY-9987: `this.privateMethod()` in closure
0738ed1049 is described below

commit 0738ed1049599db55b44dac64b4135f592262ca6
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Mon Jul 17 08:07:36 2023 -0500

    GROOVY-2433, GROOVY-3073, GROOVY-9987: `this.privateMethod()` in closure
---
 .../codehaus/groovy/vmplugin/v8/IndyInterface.java | 20 ++++---
 src/test/groovy/ClosureTest.groovy                 | 70 ++++++++++++++++++++++
 2 files changed, 82 insertions(+), 8 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/vmplugin/v8/IndyInterface.java b/src/main/java/org/codehaus/groovy/vmplugin/v8/IndyInterface.java
index 5f738118df..04a2d2d94a 100644
--- a/src/main/java/org/codehaus/groovy/vmplugin/v8/IndyInterface.java
+++ b/src/main/java/org/codehaus/groovy/vmplugin/v8/IndyInterface.java
@@ -22,13 +22,13 @@ import groovy.lang.GroovySystem;
 import org.apache.groovy.util.SystemUtil;
 import org.codehaus.groovy.GroovyBugError;
 import org.codehaus.groovy.reflection.ClassInfo;
+import org.codehaus.groovy.runtime.GeneratedClosure;
 import org.codehaus.groovy.runtime.NullObject;
 
 import java.lang.invoke.CallSite;
 import java.lang.invoke.ConstantCallSite;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
-import java.lang.invoke.MethodHandles.Lookup;
 import java.lang.invoke.MethodType;
 import java.lang.invoke.MutableCallSite;
 import java.lang.invoke.SwitchPoint;
@@ -204,7 +204,7 @@ public class IndyInterface {
      * @return the produced CallSite
      * @since Groovy 2.1.0
      */
-    public static CallSite bootstrap(Lookup caller, String callType, MethodType type, String name, int flags) {
+    public static CallSite bootstrap(MethodHandles.Lookup caller, String callType, MethodType type, String name, int flags) {
         CallType ct = CallType.fromCallSiteName(callType);
         if (null == ct) throw new GroovyBugError("Unknown call type: " + callType);
 
@@ -219,13 +219,17 @@ public class IndyInterface {
     /**
      * backing bootstrap method with all parameters
      */
-    private static CallSite realBootstrap(Lookup caller, String name, int callID, MethodType type, boolean safe, boolean thisCall, boolean spreadCall) {
-        // since indy does not give us the runtime types
-        // we produce first a dummy call site, which then changes the target to one when INDY_OPTIMIZE_THRESHOLD is reached,
-        // that does the method selection including the direct call to the
-        // real method.
+    private static CallSite realBootstrap(MethodHandles.Lookup caller, String name, int callID, MethodType type, boolean safe, boolean thisCall, boolean spreadCall) {
+        // first produce a dummy call site, since indy doesn't give the runtime types;
+        // the site then changes to the target when INDY_OPTIMIZE_THRESHOLD is reached
+        // that does the method selection including the direct call to the real method
         CacheableCallSite mc = new CacheableCallSite(type);
-        final Class<?> sender = caller.lookupClass();
+        Class<?> sender = caller.lookupClass();
+        if (thisCall) {
+            while (GeneratedClosure.class.isAssignableFrom(sender)) {
+                sender = sender.getEnclosingClass(); // GROOVY-2433
+            }
+        }
         MethodHandle mh = makeAdapter(mc, sender, name, callID, type, safe, thisCall, spreadCall);
         mc.setTarget(mh);
         mc.setDefaultTarget(mh);
diff --git a/src/test/groovy/ClosureTest.groovy b/src/test/groovy/ClosureTest.groovy
index 35b67b72bd..0fb52ee58f 100644
--- a/src/test/groovy/ClosureTest.groovy
+++ b/src/test/groovy/ClosureTest.groovy
@@ -538,6 +538,76 @@ final class ClosureTest {
         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-2433, GROOVY-3073, GROOVY-9987
+    @Test
+    void testClosureAccessToEnclosingClassPrivateMethod() {
+        assertScript '''
+            class C {
+                def getIds() {
+                    populateIds()
+                }
+                def populateIds = { ->
+                    this.sort([ 1, 5, 3, 4, 2 ])
+                }
+                private sort(list) {
+                    list.sort{ one, two -> one <=> two }
+                }
+            }
+
+            class D extends C {
+                void test() {
+                    assert ids == [1,2,3,4,5]
+                }
+            }
+
+            new D().test()
+        '''
+
+        assertScript '''
+            class C {
+                protected String protectedMethod() {
+                    def closure = { ->
+                        this.privateMethod()
+                    }
+                    closure()
+                }
+                private String privateMethod() {
+                    'hello world'
+                }
+            }
+
+            class D extends C {
+                void test() {
+                    def result = protectedMethod()
+                    assert result == 'hello world'
+                }
+            }
+
+            new D().test()
+        '''
+
+        assertScript '''
+            class C {
+                def publicMethod() {
+                    [1].each {
+                        this.privateStaticMethod()
+                    }
+                }
+                private static privateStaticMethod() {
+                    'hello world'
+                }
+            }
+
+            class D extends C {
+                void test() {
+                    publicMethod()
+                }
+            }
+
+            new D().test()
+        '''
+    }
+
     // GROOVY-3142
     @Test
     void testClosureAccessToEnclosingClassPrivateField() {