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() {