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:22 UTC

[groovy] branch GROOVY-5728 created (now 61895c2)

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

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


      at 61895c2  GROOVY-5728: anon. inner can use private constructor when super is outer

This branch includes the following new commits:

     new 61895c2  GROOVY-5728: anon. inner can use private constructor when super is outer

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


[groovy] 01/01: GROOVY-5728: anon. inner can use private constructor when super is outer

Posted by em...@apache.org.
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
+        '''
+    }
 }