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 2022/01/31 18:00:22 UTC

[groovy] 03/05: GROOVY-7686: AIC: place local variable references above super ctor call

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

emilles pushed a commit to branch GROOVY_2_5_X
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit 8f4baead5215c96b6cd08d4c218a11e6d9f0c849
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
    
    Conflicts:
    	src/main/java/org/codehaus/groovy/classgen/Verifier.java
    	src/test/gls/innerClass/InnerClassTest.groovy
---
 .../org/codehaus/groovy/classgen/Verifier.java     | 36 +++++++++++++++++++--
 src/test/gls/innerClass/InnerClassTest.groovy      | 37 ++++++++++++++++++++++
 2 files changed, 71 insertions(+), 2 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/classgen/Verifier.java b/src/main/java/org/codehaus/groovy/classgen/Verifier.java
index 4a7e627..14e6e19 100644
--- a/src/main/java/org/codehaus/groovy/classgen/Verifier.java
+++ b/src/main/java/org/codehaus/groovy/classgen/Verifier.java
@@ -81,6 +81,7 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
+import java.util.ListIterator;
 import java.util.Map;
 import java.util.Set;
 
@@ -1050,8 +1051,6 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
             }
         }
 
-        statements.addAll(node.getObjectInitializerStatements());
-
         Statement code = constructorNode.getCode();
         BlockStatement block = new BlockStatement();
         List<Statement> otherStatements = block.getStatements();
@@ -1066,6 +1065,12 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
                 // it is super(..) since this(..) is already covered
                 otherStatements.remove(0);
                 statements.add(0, firstStatement);
+                // GROOVY-7686: place local variable references above super ctor call
+                if (node instanceof InnerClassNode && ((InnerClassNode) node).isAnonymous()) {
+                    for (Statement stmt : extractVariableReferenceInitializers(statements)) {
+                        statements.add(0, stmt);
+                    }
+                }
             }
             Statement stmtThis$0 = getImplicitThis$0StmtIfInnerClass(otherStatements);
             if (stmtThis$0 != null) {
@@ -1073,8 +1078,12 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
                 // that uses this$0, it needs to bubble up before the super call itself (GROOVY-4471)
                 statements.add(0, stmtThis$0);
             }
+            statements.addAll(node.getObjectInitializerStatements());
             statements.addAll(otherStatements);
+        } else {
+            statements.addAll(node.getObjectInitializerStatements());
         }
+
         BlockStatement newBlock = new BlockStatement(statements, block.getVariableScope());
         newBlock.setSourcePosition(block);
         constructorNode.setCode(newBlock);
@@ -1142,6 +1151,29 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
         return null;
     }
 
+    private static List<Statement> extractVariableReferenceInitializers(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;
+    }
+
     protected void addFieldInitialization(List list, List staticList, FieldNode fieldNode,
                                           boolean isEnumClassNode, List initStmtsAfterEnumValuesInit, Set explicitStaticPropsInEnum) {
         Expression expression = fieldNode.getInitialExpression();
diff --git a/src/test/gls/innerClass/InnerClassTest.groovy b/src/test/gls/innerClass/InnerClassTest.groovy
index 3a3a73c..73e7fb7 100644
--- a/src/test/gls/innerClass/InnerClassTest.groovy
+++ b/src/test/gls/innerClass/InnerClassTest.groovy
@@ -1001,6 +1001,43 @@ 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 '''
+            interface I { class C { } }
+
+            class Outer implements I {
+                static class Inner extends C {}
+            }
+
+            print I.C
+        '''
+    }
+
     @Test // GROOVY-5989
     void testReferenceToOuterClassNestedInterface() {
         assertScript '''