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 '''