You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2021/03/19 20:05:51 UTC

[groovy] branch master updated: GROOVY-7686: AIC: place local variable references above super ctor call

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 2f1ff3c  GROOVY-7686: AIC: place local variable references above super ctor call
2f1ff3c is described below

commit 2f1ff3cc14ed82270fb941e6bf7a8803e93632a9
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Wed Mar 17 09:00:00 2021 -0500

    GROOVY-7686: AIC: place local variable references above super ctor call
---
 .../org/codehaus/groovy/classgen/Verifier.java     | 42 ++++++++++++++++++----
 src/test/gls/innerClass/InnerClassTest.groovy      | 24 +++++++++++++
 2 files changed, 59 insertions(+), 7 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/classgen/Verifier.java b/src/main/java/org/codehaus/groovy/classgen/Verifier.java
index 8d571bd..4db0de2 100644
--- a/src/main/java/org/codehaus/groovy/classgen/Verifier.java
+++ b/src/main/java/org/codehaus/groovy/classgen/Verifier.java
@@ -1044,14 +1044,16 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
             }
         }
 
-        statements.addAll(node.getObjectInitializerStatements());
-
         BlockStatement block = getCodeAsBlock(constructorNode);
         List<Statement> blockStatements = block.getStatements();
         if (!blockStatements.isEmpty()) {
             if (specialCtorCall != null) {
                 blockStatements.remove(0);
                 statements.add(0, firstStatement);
+                // GROOVY-7686: place local variable references above super ctor call
+                if (node instanceof InnerClassNode && ((InnerClassNode) node).isAnonymous()) {
+                    extractVariableReferenceInitializers(statements).forEach(s -> statements.add(0, s));
+                }
             }
             if (node instanceof InnerClassNode) {
                 // GROOVY-4471: place this$0 init above other field init and super ctor call;
@@ -1061,7 +1063,10 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
                     statements.add(0, initThis$0);
                 }
             }
+            statements.addAll(node.getObjectInitializerStatements());
             statements.addAll(blockStatements);
+        } else {
+            statements.addAll(node.getObjectInitializerStatements());
         }
 
         BlockStatement newBlock = new BlockStatement(statements, block.getVariableScope());
@@ -1108,23 +1113,23 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
                 List<Statement> stmts = ((BlockStatement) stmt).getStatements();
                 for (Statement bstmt : stmts) {
                     if (bstmt instanceof ExpressionStatement) {
-                        if (extractImplicitThis$0StmtIfInnerClassFromExpression(stmts, bstmt)) return bstmt;
+                        if (extractImplicitThis$0StmtFromExpression(stmts, bstmt)) return bstmt;
                     }
                 }
             } else if (stmt instanceof ExpressionStatement) {
-                if (extractImplicitThis$0StmtIfInnerClassFromExpression(statements, stmt)) return stmt;
+                if (extractImplicitThis$0StmtFromExpression(statements, stmt)) return stmt;
             }
         }
         return null;
     }
 
-    private static boolean extractImplicitThis$0StmtIfInnerClassFromExpression(final List<Statement> stmts, final Statement bstmt) {
-        Expression expr = ((ExpressionStatement) bstmt).getExpression();
+    private static boolean extractImplicitThis$0StmtFromExpression(final List<Statement> stmts, final Statement exprStmt) {
+        Expression expr = ((ExpressionStatement) exprStmt).getExpression();
         if (expr instanceof BinaryExpression) {
             Expression lExpr = ((BinaryExpression) expr).getLeftExpression();
             if (lExpr instanceof FieldExpression) {
                 if ("this$0".equals(((FieldExpression) lExpr).getFieldName())) {
-                    stmts.remove(bstmt); // remove from here and let the caller reposition it
+                    stmts.remove(exprStmt); // remove from here and let the caller reposition it
                     return true;
                 }
             }
@@ -1132,6 +1137,29 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
         return false;
     }
 
+    private static List<Statement> extractVariableReferenceInitializers(final List<Statement> statements) {
+        List<Statement> localVariableReferences = new ArrayList<>();
+        for (ListIterator<Statement> it = statements.listIterator(1); it.hasNext();) {
+            // the first statement is the super constructor call  ^
+
+            Statement stmt = it.next();
+            if (stmt instanceof ExpressionStatement
+                    && ((ExpressionStatement) stmt).getExpression() instanceof BinaryExpression) {
+                BinaryExpression expr = (BinaryExpression) ((ExpressionStatement) stmt).getExpression();
+
+                if (expr.getOperation().getType() == Types.ASSIGN
+                        && expr.getLeftExpression() instanceof FieldExpression
+                        && expr.getLeftExpression().getType().equals(ClassHelper.REFERENCE_TYPE)
+                        && (((FieldExpression) expr.getLeftExpression()).getField().getModifiers() & Opcodes.ACC_SYNTHETIC) != 0
+                        /* also could check if the right expression is a variable expression that references ctor parameter */) {
+                    localVariableReferences.add(stmt);
+                    it.remove();
+                }
+            }
+        }
+        return localVariableReferences;
+    }
+
     // TODO: add generics to collections
     protected void addFieldInitialization(final List list, final List staticList, final FieldNode fieldNode, final boolean isEnumClassNode, final List initStmtsAfterEnumValuesInit, final Set explicitStaticPropsInEnum) {
         Expression expression = fieldNode.getInitialExpression();
diff --git a/src/test/gls/innerClass/InnerClassTest.groovy b/src/test/gls/innerClass/InnerClassTest.groovy
index ceae77c..2a5fd57 100644
--- a/src/test/gls/innerClass/InnerClassTest.groovy
+++ b/src/test/gls/innerClass/InnerClassTest.groovy
@@ -1177,6 +1177,30 @@ final class InnerClassTest {
         '''
     }
 
+    @Test // GROOVY-7686
+    void testReferencedVariableInAIC3() {
+        assertScript '''
+            abstract class A {
+                A() {
+                    m()
+                }
+                abstract void m();
+            }
+            void test() {
+                def v = false
+                def a = new A() {
+                    // run by super ctor
+                    @Override void m() {
+                        assert v != null
+                    }
+                }
+                v = true
+                a.m()
+            }
+            test()
+        '''
+    }
+
     @Test // GROOVY-5754
     void testResolveInnerOfSuperType() {
         assertScript '''