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);
     }
 }

Reply via email to