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 2021/03/20 15:51:23 UTC
[groovy] 01/01: GROOVY-5728: anon. inner can use private
constructor when super is outer
This is an automated email from the ASF dual-hosted git repository.
emilles pushed a commit to branch GROOVY-5728
in repository https://gitbox.apache.org/repos/asf/groovy.git
commit 61895c2a020ce30ea702aa329ee8e18a9324b4af
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Sat Mar 20 10:51:07 2021 -0500
GROOVY-5728: anon. inner can use private constructor when super is outer
---
.../classgen/InnerClassCompletionVisitor.java | 31 ++++++++++++++++++++--
.../stc/AnonymousInnerClassSTCTest.groovy | 17 ++++++++++++
2 files changed, 46 insertions(+), 2 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/classgen/InnerClassCompletionVisitor.java b/src/main/java/org/codehaus/groovy/classgen/InnerClassCompletionVisitor.java
index 2b88d8f..3c0fddc 100644
--- a/src/main/java/org/codehaus/groovy/classgen/InnerClassCompletionVisitor.java
+++ b/src/main/java/org/codehaus/groovy/classgen/InnerClassCompletionVisitor.java
@@ -45,8 +45,11 @@ 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.block;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.castX;
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.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.stmt;
@@ -81,7 +84,7 @@ public class InnerClassCompletionVisitor extends InnerClassVisitorHelper {
}
@Override
- public void visitClass(ClassNode node) {
+ public void visitClass(final ClassNode node) {
classNode = node;
thisField = null;
InnerClassNode innerClass = null;
@@ -102,9 +105,33 @@ public class InnerClassCompletionVisitor extends InnerClassVisitorHelper {
}
@Override
- public void visitConstructor(ConstructorNode node) {
+ public void visitConstructor(final ConstructorNode node) {
addThisReference(node);
super.visitConstructor(node);
+ // an anonymous inner class may use a private constructor (via a bridge) if its super class is also an outer class
+ if (((InnerClassNode) classNode).isAnonymous() && classNode.getOuterClasses().contains(classNode.getSuperClass())) {
+ ConstructorNode superCtor = classNode.getSuperClass().getDeclaredConstructor(node.getParameters());
+ if (superCtor != null && superCtor.isPrivate()) {
+ ClassNode superClass = classNode.getUnresolvedSuperClass();
+ makeBridgeConstructor(superClass, node.getParameters()); // GROOVY-5728
+ ConstructorCallExpression superCtorCall = getFirstIfSpecialConstructorCall(node.getCode());
+ ((TupleExpression) superCtorCall.getArguments()).addExpression(castX(superClass, nullX()));
+ }
+ }
+ }
+
+ private static void makeBridgeConstructor(final ClassNode c, final Parameter[] p) {
+ Parameter[] newP = new Parameter[p.length + 1];
+ for (int i = 0; i < p.length; i += 1) {
+ newP[i] = new Parameter(p[i].getType(), "p" + i);
+ }
+ newP[p.length] = new Parameter(c, "$anonymous");
+
+ if (c.getDeclaredConstructor(newP) == null) {
+ TupleExpression args = new TupleExpression();
+ for (int i = 0; i < p.length; i += 1) args.addExpression(varX(newP[i]));
+ addGeneratedConstructor(c, ACC_SYNTHETIC, newP, ClassNode.EMPTY_ARRAY, stmt(ctorThisX(args)));
+ }
}
private static String getTypeDescriptor(ClassNode node, boolean isStatic) {
diff --git a/src/test/groovy/transform/stc/AnonymousInnerClassSTCTest.groovy b/src/test/groovy/transform/stc/AnonymousInnerClassSTCTest.groovy
index 1fb7aac..822a712 100644
--- a/src/test/groovy/transform/stc/AnonymousInnerClassSTCTest.groovy
+++ b/src/test/groovy/transform/stc/AnonymousInnerClassSTCTest.groovy
@@ -207,4 +207,21 @@ class AnonymousInnerClassSTCTest extends StaticTypeCheckingTestCase {
}
'''
}
+
+ // GROOVY-5728
+ void testPrivateConstructorAndPublicStaticFactory() {
+ assertScript '''
+ abstract class A {
+ private A() { }
+ abstract answer()
+ static A create() {
+ return new A() { // IllegalAccessError when A$1 calls private constructor
+ def answer() { 42 }
+ }
+ }
+ }
+
+ assert A.create().answer() == 42
+ '''
+ }
}