This is an automated email from the ASF dual-hosted git repository.
emilles 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 7d1054c28f refactor `InnerClassVisitor` -- separate out AIC
constructor generation
7d1054c28f is described below
commit 7d1054c28febf853c66ed379fa85e741138e07c9
Author: Eric Milles <[email protected]>
AuthorDate: Sun Mar 22 10:26:04 2026 -0500
refactor `InnerClassVisitor` -- separate out AIC constructor generation
---
.../groovy/classgen/InnerClassVisitor.java | 269 +++++++++++----------
1 file changed, 137 insertions(+), 132 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitor.java
b/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitor.java
index afd0ba7ac7..ff00bf9f15 100644
--- a/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitor.java
+++ b/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitor.java
@@ -36,7 +36,6 @@ import org.codehaus.groovy.ast.expr.Expression;
import org.codehaus.groovy.ast.expr.TupleExpression;
import org.codehaus.groovy.ast.expr.VariableExpression;
import org.codehaus.groovy.ast.stmt.BlockStatement;
-import org.codehaus.groovy.ast.stmt.ExpressionStatement;
import org.codehaus.groovy.control.CompilationUnit;
import org.codehaus.groovy.control.SourceUnit;
@@ -48,7 +47,7 @@ import java.util.List;
import static org.codehaus.groovy.ast.tools.GeneralUtils.attrX;
import static org.codehaus.groovy.ast.tools.GeneralUtils.callX;
import static org.codehaus.groovy.ast.tools.GeneralUtils.constX;
-import static org.codehaus.groovy.ast.tools.GeneralUtils.varX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.ctorSuperS;
import static org.codehaus.groovy.transform.trait.Traits.isTrait;
import static org.objectweb.asm.Opcodes.ACC_FINAL;
import static org.objectweb.asm.Opcodes.ACC_MANDATED;
@@ -73,6 +72,8 @@ public class InnerClassVisitor extends
InnerClassVisitorHelper {
return sourceUnit;
}
+
//--------------------------------------------------------------------------
+
@Override
public void visitClass(ClassNode node) {
classNode = node;
@@ -96,11 +97,27 @@ public class InnerClassVisitor extends
InnerClassVisitorHelper {
}
@Override
- public void visitClosureExpression(ClosureExpression expression) {
- boolean inClosureOld = inClosure;
+ public void visitField(FieldNode node) {
+ currentField = node;
+ super.visitField(node);
+ currentField = null;
+ }
+
+ @Override
+ public void visitProperty(PropertyNode node) {
+ final FieldNode field = node.getField();
+ final Expression init = field.getInitialExpression();
+ field.setInitialValueExpression(null);
+ super.visitProperty(node);
+ field.setInitialValueExpression(init);
+ }
+
+ @Override
+ public void visitClosureExpression(ClosureExpression closure) {
+ boolean inClosurePrevious = inClosure;
inClosure = true;
- super.visitClosureExpression(expression);
- inClosure = inClosureOld;
+ super.visitClosureExpression(closure);
+ inClosure = inClosurePrevious;
}
@Override
@@ -126,144 +143,38 @@ public class InnerClassVisitor extends
InnerClassVisitorHelper {
}
@Override
- public void visitField(FieldNode node) {
- currentField = node;
- super.visitField(node);
- currentField = null;
- }
-
- @Override
- public void visitProperty(PropertyNode node) {
- final FieldNode field = node.getField();
- final Expression init = field.getInitialExpression();
- field.setInitialValueExpression(null);
- super.visitProperty(node);
- field.setInitialValueExpression(init);
- }
-
- @Override
- public void visitConstructorCallExpression(ConstructorCallExpression call)
{
+ public void visitConstructorCallExpression(final ConstructorCallExpression
call) {
super.visitConstructorCallExpression(call);
if (!call.isUsingAnonymousInnerClass()) {
passThisReference(call);
return;
}
- InnerClassNode innerClass = (InnerClassNode) call.getType();
+ ClassNode innerClass = call.getType();
ClassNode outerClass = innerClass.getOuterClass();
ClassNode upperClass = innerClass.getUnresolvedSuperClass(false);
if (upperClass.getOuterClass() != null && !upperClass.isInterface()
&& !(upperClass.isStaticClass() || (upperClass.getModifiers()
& ACC_STATIC) != 0)) {
insertThis0ToSuperCall(call, innerClass);
}
- if (!innerClass.getDeclaredConstructors().isEmpty()) return;
- if ((innerClass.getModifiers() & ACC_STATIC) != 0) return;
-
- VariableScope scope = innerClass.getVariableScope();
- if (scope == null) return;
- boolean isStatic = !inClosure && isStatic(innerClass, scope, call);
-
- // expressions = constructor call arguments
- List<Expression> expressions = ((TupleExpression)
call.getArguments()).getExpressions();
- // block = init code for the constructor we produce
- BlockStatement block = new BlockStatement();
- // parameters = parameters of the constructor
- int additionalParamCount = (isStatic ? 0 : 1) +
scope.getReferencedLocalVariablesCount();
- List<Parameter> parameters = new ArrayList<>(expressions.size() +
additionalParamCount);
- // superCallArguments = arguments for the super call == the
constructor call arguments
- List<Expression> superCallArguments = new
ArrayList<>(expressions.size());
-
- // first we add a super() call for all expressions given in the
constructor call expression
- for (int i = 0, n = expressions.size(); i < n; i += 1) {
- // add one parameter for each expression in the constructor call
- Parameter param = new Parameter(ClassHelper.OBJECT_TYPE, "p" +
additionalParamCount + i);
- parameters.add(param);
- // add the corresponding argument to the super constructor call
- superCallArguments.add(new VariableExpression(param));
- }
-
- // add the super call
- ConstructorCallExpression cce = new ConstructorCallExpression(
- ClassNode.SUPER,
- new TupleExpression(superCallArguments)
- );
- block.addStatement(new ExpressionStatement(cce));
-
- int pCount = 0;
- if (!isStatic) {
- // need to pass "this" to access unknown methods/properties
- ClassNode enclosingType = (inClosure ? ClassHelper.CLOSURE_TYPE :
outerClass).getPlainNodeReference();
- expressions.add(pCount, new VariableExpression("this",
enclosingType));
- Parameter thisParameter = new Parameter(enclosingType, "p" +
pCount);
- thisParameter.setModifiers(ACC_FINAL | ACC_MANDATED);
- parameters.add(pCount++, thisParameter);
-
- // "this" reference is saved in a field named "this$0"
- FieldNode thisField = innerClass.addField("this$0", ACC_FINAL |
ACC_SYNTHETIC, enclosingType, null);
- addFieldInit(thisParameter, thisField, block);
- }
-
- // for each shared variable, add a Reference field
- for (Iterator<Variable> it =
scope.getReferencedLocalVariablesIterator(); it.hasNext();) {
- Variable var = it.next();
-
- VariableExpression ve = new VariableExpression(var);
- ve.setClosureSharedVariable(true);
- ve.setUseReferenceDirectly(true);
- expressions.add(pCount, ve);
-
- ClassNode referenceType =
ClassHelper.REFERENCE_TYPE.getPlainNodeReference();
- Parameter p = new Parameter(referenceType, "p" + pCount);
- p.setOriginType(var.getOriginType());
- parameters.add(pCount++, p);
+ if ((innerClass.getModifiers() & ACC_STATIC) != 0) return;
+ if (!innerClass.getDeclaredConstructors().isEmpty()) return;
- VariableExpression initial = new VariableExpression(p);
- initial.setSynthetic(true);
- initial.setUseReferenceDirectly(true);
- FieldNode pField = innerClass.addFieldFirst(ve.getName(),
ACC_PUBLIC | ACC_SYNTHETIC, referenceType, initial);
- pField.setHolder(true);
- pField.setOriginType(ClassHelper.getWrapper(var.getOriginType()));
+ VariableScope scope = ((InnerClassNode) innerClass).getVariableScope();
+ if (scope != null) {
+ List<Expression> arguments = ((TupleExpression)
call.getArguments()).getExpressions();
+ boolean isStatic = !inClosure && isStatic(innerClass, scope, call);
+ addConstructor(innerClass, outerClass, scope, arguments, isStatic);
}
-
- innerClass.addConstructor(ACC_SYNTHETIC,
parameters.toArray(Parameter.EMPTY_ARRAY), ClassNode.EMPTY_ARRAY, block);
}
- private boolean isStatic(final ClassNode innerClass, final VariableScope
scope, final ConstructorCallExpression call) {
- boolean isStatic = innerClass.isStaticClass();
- if (!isStatic) {
- if (currentMethod != null) {
- if (currentMethod instanceof ConstructorNode ctor) {
- boolean[] precedesSuperOrThisCall = new boolean[1];
- GroovyCodeVisitor visitor = new CodeVisitorSupport() {
- @Override
- public void
visitConstructorCallExpression(ConstructorCallExpression cce) {
- if (cce == call) {
- precedesSuperOrThisCall[0] = true;
- } else {
- super.visitConstructorCallExpression(cce);
- }
- }
- };
- if (ctor.firstStatementIsSpecialConstructorCall())
currentMethod.getFirstStatement().visit(visitor);
-
Arrays.stream(ctor.getParameters()).filter(Parameter::hasInitialExpression).forEach(p
-> p.getInitialExpression().visit(visitor));
-
- isStatic = precedesSuperOrThisCall[0];
- } else {
- isStatic = currentMethod.isStatic();
- }
- } else if (currentField != null) {
- isStatic = currentField.isStatic();
- }
- }
- // GROOVY-8433: Category transform implies static method
- isStatic = isStatic ||
innerClass.getOuterClass().getAnnotations().stream()
- .anyMatch(a ->
"groovy.lang.Category".equals(a.getClassNode().getName()));
- return isStatic;
- }
+
//--------------------------------------------------------------------------
- // this is the counterpart of addThisReference(). To non-static inner
classes, outer this should be
- // passed as the first argument implicitly.
+ /**
+ * This is the counterpart of <code>addThisReference</code>. For
non-static
+ * inner classes, outer this should be passed as the implicit first
argument.
+ */
private void passThisReference(final ConstructorCallExpression call) {
ClassNode cn = call.getType().redirect();
if (!shouldHandleImplicitThisForInnerClass(cn)) return;
@@ -297,20 +208,20 @@ public class InnerClassVisitor extends
InnerClassVisitorHelper {
}
}
- private void insertThis0ToSuperCall(final ConstructorCallExpression call,
final ClassNode cn) {
+ private void insertThis0ToSuperCall(final ConstructorCallExpression call,
final ClassNode innerClass) {
// calculate outer class which we need for this$0
ClassNode parent = classNode;
int level = 0;
- for (; parent != null && parent != cn.getOuterClass(); parent =
parent.getOuterClass()) {
+ for (; parent != null && parent != innerClass.getOuterClass(); parent
= parent.getOuterClass()) {
level++;
}
- // if constructor call is not in outer class, don't pass 'this'
implicitly. Return.
+ // if constructor call is not in outer class, do not pass 'this'
implicitly
if (parent == null) return;
Expression args = call.getArguments();
- if (args instanceof TupleExpression) {
- Expression this0 = varX("this"); // bypass closure
+ if (args instanceof TupleExpression tuple) {
+ Expression this0 = new VariableExpression("this"); // bypass
closure
for (int i = 0; i != level; ++i) {
this0 = attrX(this0, constX("this$0"));
// GROOVY-8104: an anonymous inner class may still have
closure nesting
@@ -318,8 +229,102 @@ public class InnerClassVisitor extends
InnerClassVisitorHelper {
this0 = callX(this0, "getThisObject");
}
}
+ tuple.getExpressions().add(0, this0);
+ }
+ }
+
+ private boolean isStatic(final ClassNode innerClass, final VariableScope
scope, final ConstructorCallExpression call) {
+ boolean isStatic = innerClass.isStaticClass();
+ if (!isStatic) {
+ if (currentMethod != null) {
+ if (currentMethod instanceof ConstructorNode ctor) {
+ boolean[] precedesSuperOrThisCall = new boolean[1];
+ GroovyCodeVisitor visitor = new CodeVisitorSupport() {
+ @Override
+ public void
visitConstructorCallExpression(ConstructorCallExpression cce) {
+ if (cce == call) {
+ precedesSuperOrThisCall[0] = true;
+ } else {
+ super.visitConstructorCallExpression(cce);
+ }
+ }
+ };
+ if (ctor.firstStatementIsSpecialConstructorCall())
currentMethod.getFirstStatement().visit(visitor);
+
Arrays.stream(ctor.getParameters()).filter(Parameter::hasInitialExpression).forEach(p
-> p.getInitialExpression().visit(visitor));
- ((TupleExpression) args).getExpressions().add(0, this0);
+ isStatic = precedesSuperOrThisCall[0];
+ } else {
+ isStatic = currentMethod.isStatic();
+ }
+ } else if (currentField != null) {
+ isStatic = currentField.isStatic();
+ }
}
+ // GROOVY-8433: Category transform implies static method
+ isStatic = isStatic ||
innerClass.getOuterClass().getAnnotations().stream()
+ .anyMatch(a ->
"groovy.lang.Category".equals(a.getClassNode().getName()));
+ return isStatic;
+ }
+
+ private void addConstructor(final ClassNode innerClass, final ClassNode
outerClass, final VariableScope scope, final List<Expression> arguments, final
boolean isStatic) {
+ // block: init code for the constructor
+ BlockStatement block = new BlockStatement();
+ // parameters: parameters of the constructor
+ int additionalParamCount = (isStatic ? 0 : 1) +
scope.getReferencedLocalVariablesCount();
+ List<Parameter> parameters = new ArrayList<>(arguments.size() +
additionalParamCount);
+ // superCallArguments: arguments for the super constructor call
+ List<Expression> superCallArguments = new
ArrayList<>(arguments.size());
+
+ // first we add a super() call for all expressions given in the
constructor call expression
+ for (int i = 0, n = arguments.size(); i < n; i += 1) {
+ // add one parameter for each expression in the constructor call
+ Parameter p = new Parameter(ClassHelper.OBJECT_TYPE, "p" +
additionalParamCount + i);
+ parameters.add(p);
+ // add the corresponding argument to the super constructor call
+ superCallArguments.add(new VariableExpression(p));
+ }
+
+ // add the super call
+ block.addStatement(ctorSuperS(new
TupleExpression(superCallArguments)));
+
+ int pCount = 0;
+ if (!isStatic) {
+ // need to pass "this" to access unknown methods/properties
+ ClassNode enclosingType = (inClosure ? ClassHelper.CLOSURE_TYPE :
outerClass).getPlainNodeReference();
+ arguments.add(pCount, new VariableExpression("this",
enclosingType));
+ Parameter thisParameter = new Parameter(enclosingType, "p" +
pCount);
+ thisParameter.setModifiers(ACC_FINAL | ACC_MANDATED);
+ parameters.add(pCount++, thisParameter);
+
+ // "this" reference is saved in a field named "this$0"
+ FieldNode thisField = innerClass.addField("this$0", ACC_FINAL |
ACC_SYNTHETIC, enclosingType, null);
+ addFieldInit(thisParameter, thisField, block);
+ }
+
+ // for each shared variable, add a Reference field
+ for (Iterator<Variable> it =
scope.getReferencedLocalVariablesIterator(); it.hasNext(); ) {
+ Variable v = it.next();
+
+ VariableExpression ve = new VariableExpression(v);
+ ve.setClosureSharedVariable(true);
+ ve.setUseReferenceDirectly(true);
+ arguments.add(pCount, ve);
+
+ ClassNode referenceType =
ClassHelper.REFERENCE_TYPE.getPlainNodeReference();
+ Parameter p = new Parameter(referenceType, "p" + pCount);
+ p.setOriginType(v.getOriginType());
+ parameters.add(pCount++, p);
+
+ VariableExpression initial = new VariableExpression(p);
+ initial.setSynthetic(true);
+ initial.setUseReferenceDirectly(true);
+
+ FieldNode pField = innerClass.addFieldFirst(ve.getName(),
ACC_PUBLIC | ACC_SYNTHETIC, referenceType, initial);
+ pField.setHolder(true);
+ pField.setOriginType(ClassHelper.getWrapper(v.getOriginType()));
+ }
+
+ // TODO: JLS 15.9.5.1 : checked exceptions of super constructor should
be declared by constructor
+ innerClass.addConstructor(0, parameters.toArray(Parameter[]::new),
ClassNode.EMPTY_ARRAY, block);
}
}