This is an automated email from the ASF dual-hosted git repository. asf-gitbox-commits pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/groovy.git
commit 30f0545366810220e5f84985728f5f036b8d6f83 Author: Daniel Sun <[email protected]> AuthorDate: Sun May 10 02:31:52 2026 +0900 Add missing javadoc --- .../groovy/classgen/AnnotationVisitor.java | 77 ++++++ .../groovy/classgen/AsmClassGenerator.java | 291 +++++++++++++++++++++ .../groovy/classgen/BytecodeExpression.java | 25 ++ .../groovy/classgen/BytecodeInstruction.java | 5 + .../codehaus/groovy/classgen/BytecodeSequence.java | 15 ++ .../groovy/classgen/ClassCompletionVerifier.java | 49 ++++ .../codehaus/groovy/classgen/ClassGenerator.java | 18 +- .../groovy/classgen/ClassGeneratorException.java | 11 + .../groovy/classgen/DummyClassGenerator.java | 43 +++ .../groovy/classgen/EnumCompletionVisitor.java | 12 + .../org/codehaus/groovy/classgen/EnumVisitor.java | 23 ++ .../codehaus/groovy/classgen/ExtendedVerifier.java | 41 +++ .../groovy/classgen/FinalVariableAnalyzer.java | 60 +++++ .../codehaus/groovy/classgen/GeneratorContext.java | 51 ++++ .../classgen/InnerClassCompletionVisitor.java | 20 ++ .../groovy/classgen/InnerClassVisitor.java | 36 +++ .../groovy/classgen/InnerClassVisitorHelper.java | 59 +++++ .../org/codehaus/groovy/classgen/ReturnAdder.java | 17 ++ .../groovy/classgen/VariableScopeVisitor.java | 95 +++++++ .../org/codehaus/groovy/classgen/Verifier.java | 168 ++++++++++++ .../groovy/classgen/VerifierCodeVisitor.java | 27 ++ 21 files changed, 1142 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/codehaus/groovy/classgen/AnnotationVisitor.java b/src/main/java/org/codehaus/groovy/classgen/AnnotationVisitor.java index 515edfd00e..f399213fdb 100644 --- a/src/main/java/org/codehaus/groovy/classgen/AnnotationVisitor.java +++ b/src/main/java/org/codehaus/groovy/classgen/AnnotationVisitor.java @@ -61,15 +61,33 @@ public class AnnotationVisitor { private AnnotationNode annotation; private ClassNode reportClass; + /** + * Creates a new annotation visitor. + * + * @param source the source unit being compiled + * @param errorCollector the error collector for reporting validation errors + */ public AnnotationVisitor(final SourceUnit source, final ErrorCollector errorCollector) { this.source = source; this.errorCollector = errorCollector; } + /** + * Sets the class to report errors against. + * + * @param node the class node for error reporting + */ public void setReportClass(final ClassNode node) { this.reportClass = node; } + /** + * Visits and validates an annotation node, checking that it conforms to annotation metadata + * and enhancing the AST to reflect real annotation semantics. + * + * @param node the annotation node to visit and validate + * @return the validated and potentially modified annotation node + */ public AnnotationNode visit(final AnnotationNode node) { this.annotation = node; setReportClass(node.getClassNode()); @@ -171,6 +189,13 @@ public class AnnotationVisitor { return type.implementsInterface(ClassHelper.Annotation_TYPE); } + /** + * Validates an annotation attribute value against its declared type. + * + * @param attrName the attribute name + * @param valueExpr the supplied value expression + * @param attrType the declared attribute type + */ protected void visitExpression(final String attrName, final Expression valueExpr, final ClassNode attrType) { if (attrType.isArray()) { ClassNode itemType = attrType.getComponentType(); @@ -212,6 +237,12 @@ public class AnnotationVisitor { } } + /** + * Verifies that an annotation member return type is valid under Java annotation rules. + * + * @param attrType the declared return type + * @param node the node to report against on error + */ public void checkReturnType(final ClassNode attrType, final ASTNode node) { if (attrType.isArray()) { checkReturnType(attrType.getComponentType(), node); @@ -248,12 +279,26 @@ public class AnnotationVisitor { return ret; } + /** + * Validates each element of an array-valued annotation attribute. + * + * @param attrName the attribute name + * @param listExpr the list expression representing the attribute value + * @param elementType the declared component type + */ protected void visitListExpression(final String attrName, final ListExpression listExpr, final ClassNode elementType) { for (Expression expression : listExpr.getExpressions()) { visitExpression(attrName, expression, elementType); } } + /** + * Validates an enum-valued annotation attribute. + * + * @param attrName the attribute name + * @param valueExpr the enum constant expression + * @param attrType the declared enum type + */ protected void visitEnumExpression(final String attrName, final PropertyExpression valueExpr, final ClassNode attrType) { ClassNode valueType = valueExpr.getObjectExpression().getType(); if (!valueType.isDerivedFrom(attrType)) { @@ -261,6 +306,13 @@ public class AnnotationVisitor { } } + /** + * Validates a constant-valued annotation attribute. + * + * @param attrName the attribute name + * @param valueExpr the constant expression + * @param attrType the declared attribute type + */ protected void visitConstantExpression(final String attrName, final ConstantExpression valueExpr, final ClassNode attrType) { ClassNode valueType = valueExpr.getType(); if (!ClassHelper.getWrapper(valueType).isDerivedFrom(ClassHelper.getWrapper(attrType))) { @@ -268,6 +320,13 @@ public class AnnotationVisitor { } } + /** + * Validates a nested annotation attribute. + * + * @param attrName the attribute name + * @param valueExpr the nested annotation expression + * @param attrType the declared annotation type + */ protected void visitAnnotationExpression(final String attrName, final AnnotationConstantExpression valueExpr, final ClassNode attrType) { AnnotationNode annotationNode = (AnnotationNode) valueExpr.getValue(); AnnotationVisitor visitor = new AnnotationVisitor(this.source, this.errorCollector); @@ -275,14 +334,32 @@ public class AnnotationVisitor { visitor.visit(annotationNode); } + /** + * Reports an error against the current annotation. + * + * @param msg the error message + */ protected void addError(final String msg) { addError(msg, this.annotation); } + /** + * Reports an error against the supplied AST node. + * + * @param msg the error message + * @param node the node to associate with the error + */ protected void addError(final String msg, final ASTNode node) { this.errorCollector.addErrorAndContinue(msg + " in @" + this.reportClass.getName() + '\n', node, this.source); } + /** + * Checks for circular references in nested annotations, which would cause infinite recursion. + * + * @param searchClass the annotation class being searched for in the dependency chain + * @param attrType the attribute type to check + * @param startExp the expression where the check started, for error reporting + */ public void checkCircularReference(final ClassNode searchClass, final ClassNode attrType, final Expression startExp) { if (!isValidAnnotationClass(attrType)) return; if (!(startExp instanceof AnnotationConstantExpression ace)) { diff --git a/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java b/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java index 4680db0ce3..5c8c22d514 100644 --- a/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java +++ b/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java @@ -237,14 +237,29 @@ import static org.objectweb.asm.TypeReference.newTypeReference; public class AsmClassGenerator extends ClassGenerator { // fields + /** + * Runtime helper used for dynamic field writes. + */ public static final MethodCallerMultiAdapter setField = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class, "setField", false, false); + /** + * Runtime helper used for dynamic field reads. + */ public static final MethodCallerMultiAdapter getField = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class, "getField", false, false); private static final MethodCallerMultiAdapter setFieldOnSuper = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class, "setFieldOnSuper", false, false); private static final MethodCallerMultiAdapter getFieldOnSuper = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class, "getFieldOnSuper", false, false); + /** + * Runtime helper used for dynamic field writes against {@code GroovyObject} receivers. + */ public static final MethodCallerMultiAdapter setGroovyObjectField = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class, "setGroovyObjectField", false, false); + /** + * Runtime helper used for dynamic field reads against {@code GroovyObject} receivers. + */ public static final MethodCallerMultiAdapter getGroovyObjectField = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class, "getGroovyObjectField", false, false); // properties + /** + * Runtime helper used for dynamic property writes. + */ public static final MethodCallerMultiAdapter setProperty = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class, "setProperty", false, false); private static final MethodCallerMultiAdapter getProperty = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class, "getProperty", false, false); private static final MethodCallerMultiAdapter setPropertyOnSuper = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class, "setPropertyOnSuper", false, false); @@ -271,9 +286,21 @@ public class AsmClassGenerator extends ClassGenerator { * Add marker in the bytecode to show source-bytecode relationship. */ public static final boolean ASM_DEBUG = false; + /** + * Enables emission of local-variable and source debug metadata. + */ public static final boolean CREATE_DEBUG_INFO = true; + /** + * Enables emission of line number tables. + */ public static final boolean CREATE_LINE_NUMBER_INFO = true; + /** + * Metadata key used to mark expressions whose value should be discarded. + */ public static final String ELIDE_EXPRESSION_VALUE = "_EXPR_VALUE_UNUSED"; + /** + * Metadata key used to request a minimum emitted bytecode level. + */ public static final String MINIMUM_BYTECODE_VERSION = "_MINIMUM_BYTECODE_VERSION"; private WriterController controller; @@ -284,6 +311,14 @@ public class AsmClassGenerator extends ClassGenerator { private ClassVisitor classVisitor; private final String sourceFile; + /** + * Creates a bytecode generator for a single class. + * + * @param source the source unit being compiled + * @param context shared generation state for the enclosing compile unit + * @param classVisitor the ASM visitor receiving the emitted class + * @param sourceFile the source file name recorded in the generated class + */ public AsmClassGenerator(final SourceUnit source, final GeneratorContext context, final ClassVisitor classVisitor, final String sourceFile) { this.source = source; this.context = context; @@ -291,11 +326,19 @@ public class AsmClassGenerator extends ClassGenerator { this.sourceFile = sourceFile; } + /** + * {@inheritDoc} + */ @Override public SourceUnit getSourceUnit() { return source; } + /** + * Returns the writer controller coordinating bytecode emission. + * + * @return the active writer controller + */ public WriterController getController() { return controller; } @@ -303,6 +346,9 @@ public class AsmClassGenerator extends ClassGenerator { // GroovyClassVisitor interface //-------------------------------------------------------------------------- + /** + * {@inheritDoc} + */ @Override public void visitClass(final ClassNode classNode) { referencedClasses.clear(); @@ -557,6 +603,9 @@ public class AsmClassGenerator extends ClassGenerator { return modifiers; } + /** + * {@inheritDoc} + */ @Override protected void visitConstructorOrMethod(final MethodNode node, final boolean isConstructor) { Parameter[] parameters = node.getParameters(); @@ -753,18 +802,27 @@ public class AsmClassGenerator extends ClassGenerator { visitAnnotationDefaultExpression(av,node.getReturnType(),exp); } + /** + * {@inheritDoc} + */ @Override public void visitConstructor(final ConstructorNode node) { controller.setConstructorNode(node); super.visitConstructor(node); } + /** + * {@inheritDoc} + */ @Override public void visitMethod(final MethodNode node) { controller.setMethodNode(node); super.visitMethod(node); } + /** + * {@inheritDoc} + */ @Override public void visitField(final FieldNode fieldNode) { onLineNumber(fieldNode, "visitField: " + fieldNode.getName()); @@ -798,6 +856,9 @@ public class AsmClassGenerator extends ClassGenerator { fv.visitEnd(); } + /** + * {@inheritDoc} + */ @Override public void visitProperty(final PropertyNode statement) { // the verifier created the field and the setter/getter methods, so here is @@ -812,86 +873,137 @@ public class AsmClassGenerator extends ClassGenerator { // Statements //-------------------------------------------------------------------------- + /** + * {@inheritDoc} + */ @Override protected void visitStatement(final Statement statement) { throw new GroovyBugError("visitStatement should not be visited here."); } + /** + * {@inheritDoc} + */ @Override public void visitBlockStatement(final BlockStatement statement) { controller.getStatementWriter().writeBlockStatement(statement); } + /** + * {@inheritDoc} + */ @Override public void visitForLoop(final ForStatement statement) { controller.getStatementWriter().writeForStatement(statement); } + /** + * {@inheritDoc} + */ @Override public void visitWhileLoop(final WhileStatement statement) { controller.getStatementWriter().writeWhileLoop(statement); } + /** + * {@inheritDoc} + */ @Override public void visitDoWhileLoop(final DoWhileStatement statement) { controller.getStatementWriter().writeDoWhileLoop(statement); } + /** + * {@inheritDoc} + */ @Override public void visitIfElse(final IfStatement statement) { controller.getStatementWriter().writeIfElse(statement); } + /** + * {@inheritDoc} + */ @Override public void visitAssertStatement(final AssertStatement statement) { controller.getStatementWriter().writeAssert(statement); } + /** + * {@inheritDoc} + */ @Override public void visitTryCatchFinally(final TryCatchStatement statement) { controller.getStatementWriter().writeTryCatchFinally(statement); } + /** + * {@inheritDoc} + */ @Override public void visitCatchStatement(final CatchStatement statement) { maybeInnerClassEntry(statement.getExceptionType()); statement.getCode().visit(this); } + /** + * {@inheritDoc} + */ @Override public void visitSwitch(final SwitchStatement statement) { controller.getStatementWriter().writeSwitch(statement); } + /** + * {@inheritDoc} + */ @Override public void visitCaseStatement(final CaseStatement statement) { } + /** + * {@inheritDoc} + */ @Override public void visitBreakStatement(final BreakStatement statement) { controller.getStatementWriter().writeBreak(statement); } + /** + * {@inheritDoc} + */ @Override public void visitContinueStatement(final ContinueStatement statement) { controller.getStatementWriter().writeContinue(statement); } + /** + * {@inheritDoc} + */ @Override public void visitSynchronizedStatement(final SynchronizedStatement statement) { controller.getStatementWriter().writeSynchronized(statement); } + /** + * {@inheritDoc} + */ @Override public void visitThrowStatement(final ThrowStatement statement) { controller.getStatementWriter().writeThrow(statement); } + /** + * {@inheritDoc} + */ @Override public void visitReturnStatement(final ReturnStatement statement) { controller.getStatementWriter().writeReturn(statement); } + /** + * {@inheritDoc} + */ @Override public void visitExpressionStatement(final ExpressionStatement statement) { controller.getStatementWriter().writeExpressionStatement(statement); @@ -900,6 +1012,9 @@ public class AsmClassGenerator extends ClassGenerator { // Expressions //-------------------------------------------------------------------------- + /** + * {@inheritDoc} + */ @Override public void visitTernaryExpression(final TernaryExpression expression) { onLineNumber(expression, "visitTernaryExpression"); @@ -907,12 +1022,18 @@ public class AsmClassGenerator extends ClassGenerator { doPostVisit(expression); // GROOVY-7473 } + /** + * {@inheritDoc} + */ @Override public void visitDeclarationExpression(final DeclarationExpression expression) { onLineNumber(expression, "visitDeclarationExpression: " + expression.getText()); controller.getBinaryExpressionHelper().evaluateEqual(expression, true); } + /** + * {@inheritDoc} + */ @Override public void visitBinaryExpression(final BinaryExpression expression) { onLineNumber(expression, "visitBinaryExpression: " + expression.getOperation().getText()); @@ -921,23 +1042,35 @@ public class AsmClassGenerator extends ClassGenerator { doPostVisit(expression); // GROOVY-5746 } + /** + * {@inheritDoc} + */ @Override public void visitPostfixExpression(final PostfixExpression expression) { controller.getBinaryExpressionHelper().evaluatePostfixMethod(expression); controller.getAssertionWriter().record(expression); } + /** + * {@inheritDoc} + */ @Override public void visitPrefixExpression(final PrefixExpression expression) { controller.getBinaryExpressionHelper().evaluatePrefixMethod(expression); controller.getAssertionWriter().record(expression); } + /** + * {@inheritDoc} + */ @Override public void visitClosureExpression(final ClosureExpression expression) { controller.getClosureWriter().writeClosure(expression); } + /** + * {@inheritDoc} + */ @Override public void visitLambdaExpression(final LambdaExpression expression) { controller.getLambdaWriter().writeLambda(expression); @@ -960,11 +1093,17 @@ public class AsmClassGenerator extends ClassGenerator { } } + /** + * {@inheritDoc} + */ @Override public void visitSpreadExpression(final SpreadExpression expression) { throw new GroovyBugError("SpreadExpression should not be visited here"); } + /** + * {@inheritDoc} + */ @Override public void visitSpreadMapExpression(final SpreadMapExpression expression) { // GROOVY-3421: SpreadMapExpression is key expression and contains value @@ -973,31 +1112,49 @@ public class AsmClassGenerator extends ClassGenerator { controller.getOperandStack().replace(ClassHelper.OBJECT_TYPE); } + /** + * {@inheritDoc} + */ @Override public void visitMethodPointerExpression(final MethodPointerExpression expression) { controller.getMethodPointerExpressionWriter().writeMethodPointerExpression(expression); } + /** + * {@inheritDoc} + */ @Override public void visitMethodReferenceExpression(final MethodReferenceExpression expression) { controller.getMethodReferenceExpressionWriter().writeMethodReferenceExpression(expression); } + /** + * {@inheritDoc} + */ @Override public void visitUnaryMinusExpression(final UnaryMinusExpression expression) { controller.getUnaryExpressionHelper().writeUnaryMinus(expression); } + /** + * {@inheritDoc} + */ @Override public void visitUnaryPlusExpression(final UnaryPlusExpression expression) { controller.getUnaryExpressionHelper().writeUnaryPlus(expression); } + /** + * {@inheritDoc} + */ @Override public void visitBitwiseNegationExpression(final BitwiseNegationExpression expression) { controller.getUnaryExpressionHelper().writeBitwiseNegate(expression); } + /** + * {@inheritDoc} + */ @Override public void visitCastExpression(final CastExpression castExpression) { Expression expression = castExpression.getExpression(); @@ -1079,11 +1236,17 @@ public class AsmClassGenerator extends ClassGenerator { controller.getOperandStack().replace(ClassHelper.OBJECT_TYPE); } + /** + * {@inheritDoc} + */ @Override public void visitNotExpression(final NotExpression expression) { controller.getUnaryExpressionHelper().writeNotExpression(expression); } + /** + * {@inheritDoc} + */ @Override public void visitBooleanExpression(final BooleanExpression expression) { OperandStack operandStack = controller.getOperandStack(); @@ -1093,6 +1256,9 @@ public class AsmClassGenerator extends ClassGenerator { operandStack.castToBool(mark, true); } + /** + * {@inheritDoc} + */ @Override public void visitMethodCallExpression(final MethodCallExpression call) { onLineNumber(call, "visitMethodCallExpression: \"" + call.getMethod() + "\":"); @@ -1100,6 +1266,9 @@ public class AsmClassGenerator extends ClassGenerator { controller.getAssertionWriter().record(call.getMethod()); } + /** + * {@inheritDoc} + */ @Override public void visitStaticMethodCallExpression(final StaticMethodCallExpression call) { onLineNumber(call, "visitStaticMethodCallExpression: \"" + call.getMethod() + "\":"); @@ -1108,6 +1277,9 @@ public class AsmClassGenerator extends ClassGenerator { maybeInnerClassEntry(call.getOwnerType()); } + /** + * {@inheritDoc} + */ @Override public void visitConstructorCallExpression(final ConstructorCallExpression call) { onLineNumber(call, "visitConstructorCallExpression: \"" + call.getType().getName() + "\":"); @@ -1155,6 +1327,14 @@ public class AsmClassGenerator extends ClassGenerator { return field != null && isMemberDirectlyAccessible(field.getModifiers(), field.getDeclaringClass(), accessingClass); } + /** + * Determines whether a member with the supplied modifiers is directly accessible to a class. + * + * @param modifiers the member modifiers + * @param declaringClass the class declaring the member + * @param accessingClass the class attempting access + * @return {@code true} if direct bytecode access is legal + */ public static boolean isMemberDirectlyAccessible(final int modifiers, final ClassNode declaringClass, final ClassNode accessingClass) { // a public member is accessible from anywhere if (Modifier.isPublic(modifiers)) return true; @@ -1175,6 +1355,15 @@ public class AsmClassGenerator extends ClassGenerator { return false; } + /** + * Resolves a field declared on the current class or an accessible superclass. + * + * @param accessingNode the class performing the access + * @param current the class whose hierarchy is being searched + * @param fieldName the field name to resolve + * @param skipCurrent whether to skip the current class and start with its superclass + * @return the resolved field, or {@code null} if none is directly accessible + */ public static FieldNode getDeclaredFieldOfCurrentClassOrAccessibleFieldOfSuper(final ClassNode accessingNode, final ClassNode current, final String fieldName, final boolean skipCurrent) { return getField(current, fieldName, fieldNode -> (!skipCurrent || !current.equals(fieldNode.getDeclaringClass())) && isFieldDirectlyAccessible(fieldNode, accessingNode) @@ -1272,6 +1461,9 @@ public class AsmClassGenerator extends ClassGenerator { return expression instanceof ClassExpression || controller.isStaticContext(); } + /** + * {@inheritDoc} + */ @Override public void visitPropertyExpression(final PropertyExpression expression) { Expression objectExpression = expression.getObjectExpression(); @@ -1333,6 +1525,9 @@ public class AsmClassGenerator extends ClassGenerator { } } + /** + * {@inheritDoc} + */ @Override public void visitAttributeExpression(final AttributeExpression expression) { Expression objectExpression = expression.getObjectExpression(); @@ -1369,6 +1564,9 @@ public class AsmClassGenerator extends ClassGenerator { } } + /** + * {@inheritDoc} + */ @Override public void visitFieldExpression(final FieldExpression expression) { if (expression.getField().isStatic()) { @@ -1386,6 +1584,11 @@ public class AsmClassGenerator extends ClassGenerator { } } + /** + * Loads a static field value onto the operand stack. + * + * @param expression the field expression to load + */ public void loadStaticField(final FieldExpression expression) { MethodVisitor mv = controller.getMethodVisitor(); FieldNode field = expression.getField(); @@ -1482,6 +1685,9 @@ public class AsmClassGenerator extends ClassGenerator { return BytecodeHelper.getClassInternalName(field.getOwner()); } + /** + * {@inheritDoc} + */ @Override public void visitVariableExpression(final VariableExpression expression) { CompileStack compileStack = controller.getCompileStack(); @@ -1523,6 +1729,9 @@ public class AsmClassGenerator extends ClassGenerator { } } + /** + * Creates helper class literal fields for interface bytecode generation. + */ protected void createInterfaceSyntheticStaticFields() { var icl = controller.getInterfaceClassLoadingClass(); // GROOVY-11982: also materialise the helper when there are call sites @@ -1539,6 +1748,9 @@ public class AsmClassGenerator extends ClassGenerator { } } + /** + * Creates synthetic class-literal helper fields and accessors on the current class. + */ protected void createSyntheticStaticFields() { if (referencedClasses.isEmpty()) { return; @@ -1602,6 +1814,9 @@ public class AsmClassGenerator extends ClassGenerator { mv.visitMaxs(0, 0); } + /** + * {@inheritDoc} + */ @Override public void visitClassExpression(final ClassExpression expression) { ClassNode type = expression.getType(); @@ -1636,6 +1851,9 @@ public class AsmClassGenerator extends ClassGenerator { operandStack.push(ClassHelper.CLASS_Type); } + /** + * {@inheritDoc} + */ @Override public void visitRangeExpression(final RangeExpression expression) { OperandStack operandStack = controller.getOperandStack(); @@ -1650,11 +1868,17 @@ public class AsmClassGenerator extends ClassGenerator { operandStack.replace(ClassHelper.RANGE_TYPE, 4); } + /** + * {@inheritDoc} + */ @Override public void visitMapEntryExpression(final MapEntryExpression expression) { throw new GroovyBugError("MapEntryExpression should not be visited here"); } + /** + * {@inheritDoc} + */ @Override public void visitMapExpression(final MapExpression expression) { MethodVisitor mv = controller.getMethodVisitor(); @@ -1686,6 +1910,9 @@ public class AsmClassGenerator extends ClassGenerator { operandStack.push(ClassHelper.MAP_TYPE); } + /** + * {@inheritDoc} + */ @Override public void visitArgumentlistExpression(final ArgumentListExpression ale) { if (containsSpreadExpression(ale)) { @@ -1695,6 +1922,9 @@ public class AsmClassGenerator extends ClassGenerator { } } + /** + * {@inheritDoc} + */ @Override public void visitTupleExpression(final TupleExpression expression) { visitTupleExpression(expression, false); @@ -1723,6 +1953,9 @@ public class AsmClassGenerator extends ClassGenerator { } } + /** + * {@inheritDoc} + */ @Override public void visitArrayExpression(final ArrayExpression expression) { MethodVisitor mv = controller.getMethodVisitor(); @@ -1855,6 +2088,9 @@ public class AsmClassGenerator extends ClassGenerator { operandStack.push(arrayType); } + /** + * {@inheritDoc} + */ @Override public void visitClosureListExpression(final ClosureListExpression expression) { MethodVisitor mv = controller.getMethodVisitor(); @@ -1996,12 +2232,18 @@ public class AsmClassGenerator extends ClassGenerator { controller.getOperandStack().pop(); } + /** + * {@inheritDoc} + */ @Override public void visitBytecodeExpression(final BytecodeExpression expression) { expression.visit(controller.getMethodVisitor()); controller.getOperandStack().push(expression.getType()); } + /** + * {@inheritDoc} + */ @Override public void visitBytecodeSequence(final BytecodeSequence bytecodeSequence) { MethodVisitor mv = controller.getMethodVisitor(); @@ -2025,6 +2267,9 @@ public class AsmClassGenerator extends ClassGenerator { operandStack.remove(mark - operandStack.getStackLength()); } + /** + * {@inheritDoc} + */ @Override public void visitListExpression(final ListExpression expression) { onLineNumber(expression, "ListExpression"); @@ -2090,6 +2335,9 @@ public class AsmClassGenerator extends ClassGenerator { operandStack.push(ClassHelper.LIST_TYPE); } + /** + * {@inheritDoc} + */ @Override public void visitGStringExpression(final GStringExpression expression) { MethodVisitor mv = controller.getMethodVisitor(); @@ -2129,6 +2377,9 @@ public class AsmClassGenerator extends ClassGenerator { operandStack.push(ClassHelper.GSTRING_TYPE); } + /** + * {@inheritDoc} + */ @Override public void visitAnnotations(final AnnotatedNode node) { // ignore it; annotation generation needs the current visitor @@ -2357,6 +2608,12 @@ public class AsmClassGenerator extends ClassGenerator { // Implementation methods //-------------------------------------------------------------------------- + /** + * Registers a generated inner class with the enclosing module. + * + * @param innerClass the inner class to register + * @return {@code true} if the inner class was queued for later emission + */ public boolean addInnerClass(final ClassNode innerClass) { ModuleNode mn = controller.getClassNode().getModule(); innerClass.setModule(mn); @@ -2364,6 +2621,12 @@ public class AsmClassGenerator extends ClassGenerator { return innerClasses.add(innerClass); } + /** + * Calculates the argument count represented by an argument expression. + * + * @param arguments the argument expression to inspect + * @return the represented argument count + */ public static int argumentSize(final Expression arguments) { if (arguments instanceof TupleExpression tupleExpression) { int size = tupleExpression.getExpressions().size(); @@ -2385,6 +2648,12 @@ public class AsmClassGenerator extends ClassGenerator { return true; } + /** + * Determines whether the supplied argument or collection expression contains a spread element. + * + * @param expression the expression to inspect + * @return {@code true} if any spread element is present + */ public static boolean containsSpreadExpression(final Expression expression) { List<Expression> expressions; if (expression instanceof TupleExpression) { @@ -2402,6 +2671,12 @@ public class AsmClassGenerator extends ClassGenerator { return false; } + /** + * Expands spread arguments into the runtime list representation expected by call sites. + * + * @param expressions the argument expressions to expand + * @param wrap whether certain arguments should be wrapped for constructor dispatch + */ public void despreadList(final List<Expression> expressions, final boolean wrap) { final int expressionCnt = expressions.size(); List<Expression> spreadIndexes = new ArrayList<>(expressionCnt); @@ -2471,6 +2746,11 @@ public class AsmClassGenerator extends ClassGenerator { } } + /** + * Wraps the top-of-stack value for reflective invocation helper paths. + * + * @param expression the expression whose runtime value should be wrapped + */ public void loadWrapper(final Expression expression) { MethodVisitor mv = controller.getMethodVisitor(); ClassNode goalClass = expression.getType(); @@ -2483,6 +2763,12 @@ public class AsmClassGenerator extends ClassGenerator { controller.getOperandStack().remove(1); } + /** + * Emits line number information for the supplied node when appropriate. + * + * @param node the current source node + * @param message a debug message retained for compatibility with existing callers + */ public void onLineNumber(final ASTNode node, final String message) { if (node != null && !(node instanceof BlockStatement)) { currentASTNode = node; @@ -2493,6 +2779,11 @@ public class AsmClassGenerator extends ClassGenerator { } } + /** + * Throws a parser exception associated with the current AST node. + * + * @param message the exception message + */ public void throwException(final String message) { throw new RuntimeParserException(message, currentASTNode); } diff --git a/src/main/java/org/codehaus/groovy/classgen/BytecodeExpression.java b/src/main/java/org/codehaus/groovy/classgen/BytecodeExpression.java index 805a83ac2a..4f7a0f9c76 100644 --- a/src/main/java/org/codehaus/groovy/classgen/BytecodeExpression.java +++ b/src/main/java/org/codehaus/groovy/classgen/BytecodeExpression.java @@ -29,6 +29,9 @@ import org.objectweb.asm.MethodVisitor; */ public abstract class BytecodeExpression extends Expression { + /** + * A no-operation bytecode expression that generates no instructions. + */ public static final BytecodeExpression NOP = new BytecodeExpression() { @Override public void visit(final MethodVisitor visitor) { @@ -36,25 +39,47 @@ public abstract class BytecodeExpression extends Expression { } }; + /** + * Creates a new bytecode expression. + */ public BytecodeExpression() { } + /** + * Creates a new bytecode expression with the specified type. + * + * @param type the type of the expression + */ public BytecodeExpression(final ClassNode type) { setType(type); } + /** + * {@inheritDoc} + */ @Override public String getText() { return "<bytecode sequence>"; } + /** + * Emits bytecode instructions using the provided method visitor. + * + * @param visitor the ASM method visitor to generate bytecode + */ public abstract void visit(MethodVisitor visitor); + /** + * {@inheritDoc} + */ @Override public void visit(final GroovyCodeVisitor visitor) { visitor.visitBytecodeExpression(this); } + /** + * {@inheritDoc} + */ @Override public Expression transformExpression(final ExpressionTransformer transformer) { return this; diff --git a/src/main/java/org/codehaus/groovy/classgen/BytecodeInstruction.java b/src/main/java/org/codehaus/groovy/classgen/BytecodeInstruction.java index 8729c80b70..6df1e62847 100644 --- a/src/main/java/org/codehaus/groovy/classgen/BytecodeInstruction.java +++ b/src/main/java/org/codehaus/groovy/classgen/BytecodeInstruction.java @@ -27,5 +27,10 @@ import org.objectweb.asm.MethodVisitor; */ // TODO: convert to @FunctionalInterface public abstract class BytecodeInstruction { + /** + * Emits bytecode instructions using the provided method visitor. + * + * @param mv the ASM method visitor to generate bytecode + */ public abstract void visit(MethodVisitor mv); } diff --git a/src/main/java/org/codehaus/groovy/classgen/BytecodeSequence.java b/src/main/java/org/codehaus/groovy/classgen/BytecodeSequence.java index 41f43a1a56..090140250c 100644 --- a/src/main/java/org/codehaus/groovy/classgen/BytecodeSequence.java +++ b/src/main/java/org/codehaus/groovy/classgen/BytecodeSequence.java @@ -33,14 +33,29 @@ import java.util.Objects; */ public class BytecodeSequence extends Statement { + /** + * Creates a bytecode sequence containing a single bytecode instruction. + * + * @param instruction the bytecode instruction to include + */ public BytecodeSequence(final BytecodeInstruction instruction) { this.instructions = Collections.singletonList(instruction); } + /** + * Creates a bytecode sequence containing multiple instructions or AST nodes. + * + * @param instructions the list of instructions or AST nodes + */ public BytecodeSequence(final List<?> instructions) { this.instructions = Objects.requireNonNull(instructions); } + /** + * Returns an immutable view of the instructions in this sequence. + * + * @return the list of instructions + */ public List<?> getInstructions() { return Collections.unmodifiableList(instructions); } diff --git a/src/main/java/org/codehaus/groovy/classgen/ClassCompletionVerifier.java b/src/main/java/org/codehaus/groovy/classgen/ClassCompletionVerifier.java index 98ac1861b8..92a56e5ca9 100644 --- a/src/main/java/org/codehaus/groovy/classgen/ClassCompletionVerifier.java +++ b/src/main/java/org/codehaus/groovy/classgen/ClassCompletionVerifier.java @@ -100,19 +100,35 @@ public class ClassCompletionVerifier extends ClassCodeVisitorSupport { private final SourceUnit source; private ClassNode currentClass; + /** + * Creates a new class completion verifier. + * + * @param source the source unit to verify + */ public ClassCompletionVerifier(final SourceUnit source) { this.source = source; } + /** + * {@inheritDoc} + */ @Override protected SourceUnit getSourceUnit() { return source; } + /** + * Returns the class node currently being verified. + * + * @return the current class node + */ public ClassNode getClassNode() { return currentClass; } + /** + * {@inheritDoc} + */ @Override public void visitClass(final ClassNode node) { ClassNode previousClass = currentClass; @@ -571,6 +587,9 @@ out: for (ClassNode sc : superTypes) { msg.append(')'); } + /** + * {@inheritDoc} + */ @Override public void visitMethod(final MethodNode node) { inConstructor = false; @@ -661,6 +680,9 @@ out: for (ClassNode sc : superTypes) { } } + /** + * {@inheritDoc} + */ @Override public void visitField(final FieldNode node) { if (currentClass.getDeclaredField(node.getName()) != node) { @@ -675,6 +697,9 @@ out: for (ClassNode sc : superTypes) { super.visitField(node); } + /** + * {@inheritDoc} + */ @Override public void visitProperty(final PropertyNode node) { if (currentClass.getProperty(node.getName()) != node) { @@ -713,6 +738,9 @@ out: for (ClassNode sc : superTypes) { } } + /** + * {@inheritDoc} + */ @Override public void visitBinaryExpression(final BinaryExpression expression) { if (expression.getOperation().getType() == Types.LEFT_SQUARE_BRACKET && @@ -767,6 +795,9 @@ out: for (ClassNode sc : superTypes) { } } + /** + * {@inheritDoc} + */ @Override public void visitConstructor(final ConstructorNode node) { inConstructor = true; inStaticConstructor = false; @@ -796,6 +827,9 @@ out: for (ClassNode sc : superTypes) { super.visitConstructor(node); } + /** + * {@inheritDoc} + */ @Override public void visitCatchStatement(final CatchStatement cs) { List<String> modifiers = new ArrayList<>(); @@ -819,6 +853,9 @@ out: for (ClassNode sc : superTypes) { super.visitCatchStatement(cs); } + /** + * {@inheritDoc} + */ @Override public void visitForLoop(final ForStatement fs) { if (fs.getValueVariable() != null) { @@ -842,6 +879,9 @@ out: for (ClassNode sc : superTypes) { } } + /** + * {@inheritDoc} + */ @Override public void visitMethodCallExpression(final MethodCallExpression mce) { super.visitMethodCallExpression(mce); @@ -860,6 +900,9 @@ out: for (ClassNode sc : superTypes) { addError("Invalid use of declaration inside method call.", exp); } + /** + * {@inheritDoc} + */ @Override public void visitDeclarationExpression(final DeclarationExpression expression) { super.visitDeclarationExpression(expression); @@ -889,12 +932,18 @@ out: for (ClassNode sc : superTypes) { } } + /** + * {@inheritDoc} + */ @Override public void visitConstantExpression(final ConstantExpression expression) { super.visitConstantExpression(expression); checkStringExceedingMaximumLength(expression); } + /** + * {@inheritDoc} + */ @Override public void visitGStringExpression(final GStringExpression expression) { super.visitGStringExpression(expression); diff --git a/src/main/java/org/codehaus/groovy/classgen/ClassGenerator.java b/src/main/java/org/codehaus/groovy/classgen/ClassGenerator.java index 417488f150..ecb1681861 100644 --- a/src/main/java/org/codehaus/groovy/classgen/ClassGenerator.java +++ b/src/main/java/org/codehaus/groovy/classgen/ClassGenerator.java @@ -28,18 +28,34 @@ import java.util.LinkedList; * Abstract base class for generator of Java class versions of Groovy AST classes */ public abstract class ClassGenerator extends ClassCodeVisitorSupport { - // inner classes created while generating bytecode + /** + * Inner classes queued while generating the current class. + */ protected LinkedList<ClassNode> innerClasses = new LinkedList<ClassNode>(); + /** + * Returns the list of inner classes that were created during bytecode generation. + * + * @return the list of inner classes + */ public LinkedList<ClassNode> getInnerClasses() { return innerClasses; } + /** + * {@inheritDoc} + */ @Override protected SourceUnit getSourceUnit() { return null; } + /** + * Visits a bytecode sequence during AST traversal. Subclasses should override + * this method to handle custom bytecode generation. + * + * @param bytecodeSequence the bytecode sequence to visit + */ public void visitBytecodeSequence(BytecodeSequence bytecodeSequence) { } } diff --git a/src/main/java/org/codehaus/groovy/classgen/ClassGeneratorException.java b/src/main/java/org/codehaus/groovy/classgen/ClassGeneratorException.java index 3bd0bfdaef..517829de85 100644 --- a/src/main/java/org/codehaus/groovy/classgen/ClassGeneratorException.java +++ b/src/main/java/org/codehaus/groovy/classgen/ClassGeneratorException.java @@ -27,10 +27,21 @@ public class ClassGeneratorException extends RuntimeException { @Serial private static final long serialVersionUID = 440899360174632769L; + /** + * Creates a new class generator exception with the specified message. + * + * @param message the detail message + */ public ClassGeneratorException(String message) { super(message); } + /** + * Creates a new class generator exception with the specified message and cause. + * + * @param message the detail message + * @param cause the underlying cause of this exception + */ public ClassGeneratorException(String message, Throwable cause) { super(message, cause); } diff --git a/src/main/java/org/codehaus/groovy/classgen/DummyClassGenerator.java b/src/main/java/org/codehaus/groovy/classgen/DummyClassGenerator.java index e4be6950f6..60453bb354 100644 --- a/src/main/java/org/codehaus/groovy/classgen/DummyClassGenerator.java +++ b/src/main/java/org/codehaus/groovy/classgen/DummyClassGenerator.java @@ -55,6 +55,14 @@ public class DummyClassGenerator extends ClassGenerator { private String internalBaseClassName; + /** + * Creates a new dummy class generator that produces class structures without implementation. + * + * @param context the generator context + * @param classVisitor the ASM class visitor to write to + * @param classLoader the class loader (currently unused) + * @param sourceFile the source file name (currently unused) + */ public DummyClassGenerator(final GeneratorContext context, final ClassVisitor classVisitor, final ClassLoader classLoader, final String sourceFile) { this.context = context; this.cv = classVisitor; @@ -63,6 +71,9 @@ public class DummyClassGenerator extends ClassGenerator { //-------------------------------------------------------------------------- // GroovyClassVisitor interface + /** + * {@inheritDoc} + */ @Override public void visitClass(final ClassNode classNode) { try { @@ -103,6 +114,9 @@ public class DummyClassGenerator extends ClassGenerator { } } + /** + * {@inheritDoc} + */ @Override public void visitConstructor(final ConstructorNode node) { visitParameters(node, node.getParameters()); @@ -117,6 +131,9 @@ public class DummyClassGenerator extends ClassGenerator { mv.visitMaxs(0, 0); } + /** + * {@inheritDoc} + */ @Override public void visitMethod(final MethodNode node) { visitParameters(node, node.getParameters()); @@ -133,6 +150,9 @@ public class DummyClassGenerator extends ClassGenerator { mv.visitMaxs(0, 0); } + /** + * {@inheritDoc} + */ @Override public void visitField(final FieldNode fieldNode) { cv.visitField( @@ -143,23 +163,46 @@ public class DummyClassGenerator extends ClassGenerator { null); } + /** + * {@inheritDoc} + */ @Override public void visitProperty(final PropertyNode statement) { } + /** + * {@inheritDoc} + */ @Override public void visitAnnotations(final AnnotatedNode node) { } + /** + * Visits the parameters declared by the supplied member node. + * + * @param node the owning constructor or method + * @param parameters the parameters to visit + */ protected void visitParameters(final ASTNode node, final Parameter[] parameters) { for (Parameter parameter : parameters) { visitParameter(node, parameter); } } + /** + * Visits a single parameter declared by the supplied member node. + * + * @param node the owning constructor or method + * @param parameter the parameter to visit + */ protected void visitParameter(final ASTNode node, final Parameter parameter) { } + /** + * Returns the compile unit associated with the class currently being emitted. + * + * @return the active compile unit + */ protected CompileUnit getCompileUnit() { CompileUnit answer = classNode.getCompileUnit(); if (answer == null) { diff --git a/src/main/java/org/codehaus/groovy/classgen/EnumCompletionVisitor.java b/src/main/java/org/codehaus/groovy/classgen/EnumCompletionVisitor.java index 1d0d9653ae..eb100bd9b7 100644 --- a/src/main/java/org/codehaus/groovy/classgen/EnumCompletionVisitor.java +++ b/src/main/java/org/codehaus/groovy/classgen/EnumCompletionVisitor.java @@ -55,15 +55,27 @@ public class EnumCompletionVisitor extends ClassCodeVisitorSupport { private final SourceUnit sourceUnit; + /** + * Creates a new enum completion visitor. + * + * @param cu the compilation unit (currently unused but kept for API compatibility) + * @param su the source unit for error reporting + */ public EnumCompletionVisitor(final CompilationUnit cu, final SourceUnit su) { sourceUnit = su; } + /** + * {@inheritDoc} + */ @Override protected SourceUnit getSourceUnit() { return sourceUnit; } + /** + * {@inheritDoc} + */ @Override public void visitClass(final ClassNode node) { if (node.isEnum() diff --git a/src/main/java/org/codehaus/groovy/classgen/EnumVisitor.java b/src/main/java/org/codehaus/groovy/classgen/EnumVisitor.java index d7d7d536f8..7eb22de349 100644 --- a/src/main/java/org/codehaus/groovy/classgen/EnumVisitor.java +++ b/src/main/java/org/codehaus/groovy/classgen/EnumVisitor.java @@ -84,19 +84,36 @@ import static org.objectweb.asm.Opcodes.ACC_PUBLIC; import static org.objectweb.asm.Opcodes.ACC_STATIC; import static org.objectweb.asm.Opcodes.ACC_SYNTHETIC; +/** + * Transforms enum classes by adding required methods and fields according to Java enum semantics. + * This visitor adds the synthetic {@code $VALUES} field, {@code values()} and {@code valueOf(String)} + * methods that are required for all enum types. + */ public class EnumVisitor extends ClassCodeVisitorSupport { private final SourceUnit sourceUnit; + /** + * Creates a new enum visitor. + * + * @param cu the compilation unit (currently unused but kept for API compatibility) + * @param su the source unit for error reporting + */ public EnumVisitor(final CompilationUnit cu, final SourceUnit su) { sourceUnit = su; } + /** + * {@inheritDoc} + */ @Override protected SourceUnit getSourceUnit() { return sourceUnit; } + /** + * {@inheritDoc} + */ @Override public void visitClass(final ClassNode node) { if (node.isEnum()) completeEnum(node); @@ -330,6 +347,12 @@ public class EnumVisitor extends ClassCodeVisitorSupport { ); } + /** + * Determines whether the enum node represents an anonymous enum constant body. + * + * @param enumClass the enum-related class node to test + * @return {@code true} if the node represents an anonymous inner enum class + */ static boolean isAnonymousInnerClass(final ClassNode enumClass) { return enumClass instanceof EnumConstantClassNode && ((EnumConstantClassNode) enumClass).getVariableScope() == null; diff --git a/src/main/java/org/codehaus/groovy/classgen/ExtendedVerifier.java b/src/main/java/org/codehaus/groovy/classgen/ExtendedVerifier.java index 56485ab555..d64edecca7 100644 --- a/src/main/java/org/codehaus/groovy/classgen/ExtendedVerifier.java +++ b/src/main/java/org/codehaus/groovy/classgen/ExtendedVerifier.java @@ -85,6 +85,9 @@ import static org.codehaus.groovy.ast.tools.ParameterUtils.parametersEqual; */ public class ExtendedVerifier extends ClassCodeVisitorSupport { + /** + * @deprecated This constant is no longer used and will be removed in a future version. + */ @Deprecated(forRemoval = true, since = "5.0.0") public static final String JVM_ERROR_MESSAGE = "Please make sure you are running on a JVM >= 1.5"; @@ -93,15 +96,26 @@ public class ExtendedVerifier extends ClassCodeVisitorSupport { private final Map<String, Boolean> repeatableCache = new HashMap<>(); private final Set<ModuleNode> visitedModules = new HashSet<>(); + /** + * Creates a new extended verifier. + * + * @param sourceUnit the source unit being verified + */ public ExtendedVerifier(final SourceUnit sourceUnit) { this.source = sourceUnit; } + /** + * {@inheritDoc} + */ @Override protected SourceUnit getSourceUnit() { return this.source; } + /** + * {@inheritDoc} + */ @Override public void visitClass(final ClassNode node) { AnnotationConstantsVisitor acv = new AnnotationConstantsVisitor(); @@ -135,6 +149,9 @@ public class ExtendedVerifier extends ClassCodeVisitorSupport { node.visitContents(this); } + /** + * {@inheritDoc} + */ @Override public void visitField(final FieldNode node) { visitAnnotations(node, FIELD_TARGET); @@ -148,10 +165,16 @@ public class ExtendedVerifier extends ClassCodeVisitorSupport { extractTypeUseAnnotations(node.getAnnotations(), node.getType(), FIELD_TARGET); } + /** + * {@inheritDoc} + */ @Override public void visitProperty(final PropertyNode node) { } + /** + * {@inheritDoc} + */ @Override public void visitDeclarationExpression(final DeclarationExpression expression) { visitAnnotations(expression, LOCAL_VARIABLE_TARGET); @@ -165,6 +188,9 @@ public class ExtendedVerifier extends ClassCodeVisitorSupport { expression.getRightExpression().visit(this); } + /** + * {@inheritDoc} + */ @Override public void visitConstructorCallExpression(final ConstructorCallExpression expression) { if (!expression.isSpecialCall()) { @@ -211,6 +237,9 @@ public class ExtendedVerifier extends ClassCodeVisitorSupport { } } + /** + * {@inheritDoc} + */ @Override public void visitConstructor(final ConstructorNode node) { visitAnnotations(node, CONSTRUCTOR_TARGET); @@ -221,6 +250,9 @@ public class ExtendedVerifier extends ClassCodeVisitorSupport { extractTypeUseAnnotations(node.getAnnotations(), node.getReturnType(), CONSTRUCTOR_TARGET); } + /** + * {@inheritDoc} + */ @Override public void visitMethod(final MethodNode node) { visitAnnotations(node, METHOD_TARGET); @@ -231,6 +263,9 @@ public class ExtendedVerifier extends ClassCodeVisitorSupport { } } + /** + * {@inheritDoc} + */ @Override protected void visitStatementAnnotations(final Statement statement) { for (AnnotationNode annotation : statement.getStatementAnnotations()) { @@ -313,6 +348,12 @@ public class ExtendedVerifier extends ClassCodeVisitorSupport { } } + /** + * Visits the annotations attached to the supplied node for the given target kind. + * + * @param node the annotated node to inspect + * @param target the annotation target mask being validated + */ protected void visitAnnotations(final AnnotatedNode node, final int target) { visitAnnotations(node, node.getAnnotations(), target); } diff --git a/src/main/java/org/codehaus/groovy/classgen/FinalVariableAnalyzer.java b/src/main/java/org/codehaus/groovy/classgen/FinalVariableAnalyzer.java index a5cd787a69..92861c947e 100644 --- a/src/main/java/org/codehaus/groovy/classgen/FinalVariableAnalyzer.java +++ b/src/main/java/org/codehaus/groovy/classgen/FinalVariableAnalyzer.java @@ -59,6 +59,12 @@ import java.util.List; import java.util.Map; import java.util.Set; +/** + * Analyzes variable assignments to determine if variables are effectively final, + * which is required for use in closures and lambda expressions. This visitor tracks + * variable states through control flow to detect reassignments that would prevent + * a variable from being considered effectively final. + */ public class FinalVariableAnalyzer extends ClassCodeVisitorSupport { private final SourceUnit sourceUnit; @@ -94,10 +100,21 @@ public class FinalVariableAnalyzer extends ClassCodeVisitorSupport { private final Deque<Map<Variable, VariableState>> assignmentTracker = new LinkedList<>(); + /** + * Creates a new final variable analyzer without a callback. + * + * @param sourceUnit the source unit being analyzed + */ public FinalVariableAnalyzer(final SourceUnit sourceUnit) { this(sourceUnit, null); } + /** + * Creates a new final variable analyzer with a callback for non-final variable detection. + * + * @param sourceUnit the source unit being analyzed + * @param callback the callback to invoke when a variable is found to not be final, may be null + */ public FinalVariableAnalyzer(final SourceUnit sourceUnit, final VariableNotFinalCallback callback) { this.callback = callback; this.sourceUnit = sourceUnit; @@ -128,17 +145,30 @@ public class FinalVariableAnalyzer extends ClassCodeVisitorSupport { return assignmentTracker.getLast(); } + /** + * {@inheritDoc} + */ @Override protected SourceUnit getSourceUnit() { return sourceUnit; } + /** + * Determines if a variable is effectively final, meaning it is not reassigned after initialization. + * Parameters without any state information are considered effectively final by default. + * + * @param v the variable to check + * @return true if the variable is effectively final, false otherwise + */ public boolean isEffectivelyFinal(Variable v) { VariableState state = getState().get(v); return (v instanceof Parameter && state == null) || (state != null && state.isFinal()); } + /** + * {@inheritDoc} + */ @Override public void visitBlockStatement(final BlockStatement block) { Set<Variable> old = declaredFinalVariables; @@ -147,6 +177,9 @@ public class FinalVariableAnalyzer extends ClassCodeVisitorSupport { declaredFinalVariables = old; } + /** + * {@inheritDoc} + */ @Override public void visitArgumentlistExpression(ArgumentListExpression ale) { boolean old = inArgumentList; @@ -155,6 +188,9 @@ public class FinalVariableAnalyzer extends ClassCodeVisitorSupport { inArgumentList = old; } + /** + * {@inheritDoc} + */ @Override public void visitBinaryExpression(final BinaryExpression expression) { boolean assignment = StaticTypeCheckingSupport.isAssignment(expression.getOperation().getType()); @@ -201,6 +237,9 @@ public class FinalVariableAnalyzer extends ClassCodeVisitorSupport { } } + /** + * {@inheritDoc} + */ @Override public void visitClosureExpression(final ClosureExpression expression) { boolean old = inAssignmentRHS; @@ -224,6 +263,9 @@ public class FinalVariableAnalyzer extends ClassCodeVisitorSupport { } } + /** + * {@inheritDoc} + */ @Override public void visitPrefixExpression(final PrefixExpression expression) { inAssignmentRHS = expression.getExpression() instanceof VariableExpression; @@ -232,6 +274,9 @@ public class FinalVariableAnalyzer extends ClassCodeVisitorSupport { checkPrePostfixOperation(expression.getExpression(), expression); } + /** + * {@inheritDoc} + */ @Override public void visitPostfixExpression(final PostfixExpression expression) { inAssignmentRHS = expression.getExpression() instanceof VariableExpression; @@ -252,6 +297,9 @@ public class FinalVariableAnalyzer extends ClassCodeVisitorSupport { } } + /** + * {@inheritDoc} + */ @Override public void visitVariableExpression(final VariableExpression expression) { super.visitVariableExpression(expression); @@ -269,6 +317,9 @@ public class FinalVariableAnalyzer extends ClassCodeVisitorSupport { } } + /** + * {@inheritDoc} + */ @Override public void visitIfElse(final IfStatement ifElse) { visitStatement(ifElse); @@ -306,6 +357,9 @@ public class FinalVariableAnalyzer extends ClassCodeVisitorSupport { } } + /** + * {@inheritDoc} + */ @Override public void visitSwitch(SwitchStatement switchS) { visitStatement(switchS); @@ -366,6 +420,9 @@ public class FinalVariableAnalyzer extends ClassCodeVisitorSupport { } } + /** + * {@inheritDoc} + */ @Override public void visitTryCatchFinally(final TryCatchStatement statement) { visitStatement(statement); @@ -523,6 +580,9 @@ public class FinalVariableAnalyzer extends ClassCodeVisitorSupport { } } + /** + * Callback interface notified when effectively final analysis detects a problem. + */ public interface VariableNotFinalCallback { /** * Callback called whenever an assignment transforms an effectively final variable into a non-final variable diff --git a/src/main/java/org/codehaus/groovy/classgen/GeneratorContext.java b/src/main/java/org/codehaus/groovy/classgen/GeneratorContext.java index ab21252094..362b3c6940 100644 --- a/src/main/java/org/codehaus/groovy/classgen/GeneratorContext.java +++ b/src/main/java/org/codehaus/groovy/classgen/GeneratorContext.java @@ -34,10 +34,21 @@ public class GeneratorContext { private int syntheticMethodIdx = 0; private final CompileUnit compileUnit; + /** + * Creates a new generator context for the given compile unit. + * + * @param compileUnit the compile unit this context is associated with + */ public GeneratorContext(final CompileUnit compileUnit) { this.compileUnit = compileUnit; } + /** + * Creates a new generator context with a custom inner class index offset. + * + * @param compileUnit the compile unit this context is associated with + * @param innerClassOffset the starting index for inner class naming + */ public GeneratorContext(final CompileUnit compileUnit, final int innerClassOffset) { this.compileUnit = compileUnit; this.innerClassIdx = innerClassOffset; @@ -48,18 +59,44 @@ public class GeneratorContext { return closureClassIdx; } + /** + * Returns and increments the inner class index for generating unique inner class names. + * + * @return the next available inner class index + */ public int getNextInnerClassIdx() { return innerClassIdx++; } + /** + * Returns the compile unit associated with this context. + * + * @return the compile unit + */ public CompileUnit getCompileUnit() { return compileUnit; } + /** + * Generates the next unique closure inner class name. + * + * @param owner the owner class (currently unused but kept for API compatibility) + * @param enclosingClass the class that encloses the closure + * @param enclosingMethod the method that encloses the closure, or null if at class level + * @return a unique name for the closure inner class + */ public String getNextClosureInnerName(final ClassNode owner, final ClassNode enclosingClass, final MethodNode enclosingMethod) { return getNextInnerName(enclosingClass, enclosingMethod, "closure"); } + /** + * Generates the next unique lambda inner class name. + * + * @param owner the owner class (currently unused but kept for API compatibility) + * @param enclosingClass the class that encloses the lambda + * @param enclosingMethod the method that encloses the lambda, or null if at class level + * @return a unique name for the lambda inner class + */ public String getNextLambdaInnerName(final ClassNode owner, final ClassNode enclosingClass, final MethodNode enclosingMethod) { return getNextInnerName(enclosingClass, enclosingMethod, "lambda"); } @@ -72,6 +109,12 @@ public class GeneratorContext { return typeName; } + /** + * Generates a unique synthetic method name for a constructor reference. + * + * @param enclosingMethodNode the method that contains the constructor reference, or null if at class level + * @return a unique synthetic method name for the constructor reference + */ public String getNextConstructorReferenceSyntheticMethodName(final MethodNode enclosingMethodNode) { return "ctorRef$" + (null == enclosingMethodNode @@ -94,6 +137,14 @@ public class GeneratorContext { } } + /** + * Encodes a name to be a valid Java class name by replacing special characters with underscores. + * Characters such as operators, punctuation, and other invalid class name characters are encoded. + * The special names "module-info" and "package-info" are preserved unchanged. + * + * @param name the name to encode + * @return the encoded class name safe for use as a Java identifier + */ public static String encodeAsValidClassName(final String name) { if ("module-info".equals(name) || "package-info".equals(name)) return name; diff --git a/src/main/java/org/codehaus/groovy/classgen/InnerClassCompletionVisitor.java b/src/main/java/org/codehaus/groovy/classgen/InnerClassCompletionVisitor.java index 399a82d438..db613a03c8 100644 --- a/src/main/java/org/codehaus/groovy/classgen/InnerClassCompletionVisitor.java +++ b/src/main/java/org/codehaus/groovy/classgen/InnerClassCompletionVisitor.java @@ -51,21 +51,38 @@ import static org.objectweb.asm.Opcodes.ACC_PUBLIC; import static org.objectweb.asm.Opcodes.ACC_STATIC; import static org.objectweb.asm.Opcodes.ACC_SYNTHETIC; +/** + * Completes the transformation of inner classes by adding synthetic fields and constructor + * parameters needed to maintain references to outer class instances. This visitor is run + * after {@link InnerClassVisitor} to finalize inner class construction. + */ public class InnerClassCompletionVisitor extends InnerClassVisitorHelper { private ClassNode classNode; private FieldNode thisField; private final SourceUnit sourceUnit; + /** + * Creates a new inner class completion visitor. + * + * @param cu the compilation unit (currently unused but kept for API compatibility) + * @param su the source unit for error reporting + */ public InnerClassCompletionVisitor(CompilationUnit cu, SourceUnit su) { sourceUnit = su; } + /** + * {@inheritDoc} + */ @Override protected SourceUnit getSourceUnit() { return sourceUnit; } + /** + * {@inheritDoc} + */ @Override public void visitClass(final ClassNode node) { classNode = node; @@ -83,6 +100,9 @@ public class InnerClassCompletionVisitor extends InnerClassVisitorHelper { } } + /** + * {@inheritDoc} + */ @Override public void visitConstructor(final ConstructorNode node) { addThisReference(node); diff --git a/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitor.java b/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitor.java index ff00bf9f15..bb4e55fec7 100644 --- a/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitor.java +++ b/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitor.java @@ -55,6 +55,12 @@ import static org.objectweb.asm.Opcodes.ACC_PUBLIC; import static org.objectweb.asm.Opcodes.ACC_STATIC; import static org.objectweb.asm.Opcodes.ACC_SYNTHETIC; +/** + * Processes inner classes during compilation, handling the creation of synthetic fields + * and parameters needed for inner class instances to reference their enclosing instances. + * This visitor identifies and transforms inner class constructor calls to pass the + * appropriate enclosing instance references. + */ public class InnerClassVisitor extends InnerClassVisitorHelper { private ClassNode classNode; @@ -63,10 +69,19 @@ public class InnerClassVisitor extends InnerClassVisitorHelper { private final SourceUnit sourceUnit; private boolean inClosure, processingObjInitStatements; + /** + * Creates a new inner class visitor. + * + * @param cu the compilation unit (currently unused but kept for API compatibility) + * @param su the source unit for error reporting + */ public InnerClassVisitor(CompilationUnit cu, SourceUnit su) { sourceUnit = su; } + /** + * {@inheritDoc} + */ @Override protected SourceUnit getSourceUnit() { return sourceUnit; @@ -74,6 +89,9 @@ public class InnerClassVisitor extends InnerClassVisitorHelper { //-------------------------------------------------------------------------- + /** + * {@inheritDoc} + */ @Override public void visitClass(ClassNode node) { classNode = node; @@ -96,6 +114,9 @@ public class InnerClassVisitor extends InnerClassVisitorHelper { } } + /** + * {@inheritDoc} + */ @Override public void visitField(FieldNode node) { currentField = node; @@ -103,6 +124,9 @@ public class InnerClassVisitor extends InnerClassVisitorHelper { currentField = null; } + /** + * {@inheritDoc} + */ @Override public void visitProperty(PropertyNode node) { final FieldNode field = node.getField(); @@ -112,6 +136,9 @@ public class InnerClassVisitor extends InnerClassVisitorHelper { field.setInitialValueExpression(init); } + /** + * {@inheritDoc} + */ @Override public void visitClosureExpression(ClosureExpression closure) { boolean inClosurePrevious = inClosure; @@ -120,6 +147,9 @@ public class InnerClassVisitor extends InnerClassVisitorHelper { inClosure = inClosurePrevious; } + /** + * {@inheritDoc} + */ @Override protected void visitObjectInitializerStatements(ClassNode node) { processingObjInitStatements = true; @@ -127,6 +157,9 @@ public class InnerClassVisitor extends InnerClassVisitorHelper { processingObjInitStatements = false; } + /** + * {@inheritDoc} + */ @Override protected void visitConstructorOrMethod(MethodNode node, boolean isConstructor) { currentMethod = node; @@ -142,6 +175,9 @@ public class InnerClassVisitor extends InnerClassVisitorHelper { currentMethod = null; } + /** + * {@inheritDoc} + */ @Override public void visitConstructorCallExpression(final ConstructorCallExpression call) { super.visitConstructorCallExpression(call); diff --git a/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitorHelper.java b/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitorHelper.java index e507af6416..0b43ea5f3a 100644 --- a/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitorHelper.java +++ b/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitorHelper.java @@ -45,22 +45,56 @@ import static org.codehaus.groovy.ast.tools.GeneralUtils.returnS; import static org.codehaus.groovy.ast.tools.GeneralUtils.stmt; import static org.codehaus.groovy.ast.tools.GeneralUtils.varX; +/** + * Abstract base class providing helper methods for inner class visitors. + * This class contains utility methods for generating dispatcher code that + * allows inner classes to access members of their enclosing classes. + */ public abstract class InnerClassVisitorHelper extends ClassCodeVisitorSupport { private static final ClassNode OBJECT_ARRAY = ClassHelper.OBJECT_TYPE.makeArray(); + /** + * Adds a statement to initialize a field from a constructor parameter. + * + * @param p the parameter to read from + * @param fn the field to initialize + * @param block the block statement to add the initialization to + */ protected static void addFieldInit(final Parameter p, final FieldNode fn, final BlockStatement block) { block.addStatement(assignS(fieldX(fn), varX(p))); } + /** + * Generates property getter dispatcher code for dynamic property access. + * + * @param block the block to add the dispatcher code to + * @param target the target object to get the property from + * @param parameters the dispatcher method parameters (property name) + */ protected static void setPropertyGetterDispatcher(final BlockStatement block, final Expression target, final Parameter[] parameters) { block.addStatement(returnS(propX(target, varX(parameters[0])))); } + /** + * Generates property setter dispatcher code for dynamic property access. + * + * @param block the block to add the dispatcher code to + * @param target the target object to set the property on + * @param parameters the dispatcher method parameters (property name, value) + */ protected static void setPropertySetterDispatcher(final BlockStatement block, final Expression target, final Parameter[] parameters) { block.addStatement(stmt(assignX(propX(target, varX(parameters[0])), varX(parameters[1])))); } + /** + * Generates method dispatcher code for dynamic method invocation. + * Handles both single arguments and spread arguments. + * + * @param block the block to add the dispatcher code to + * @param target the target object to invoke methods on + * @param parameters the dispatcher method parameters (method name, arguments) + */ protected static void setMethodDispatcherCode (final BlockStatement block, final Expression target, final Parameter[] parameters) { // if (!(args instanceof Object[])) return target.(name)(args) block.addStatement(ifS( @@ -78,10 +112,23 @@ public abstract class InnerClassVisitorHelper extends ClassCodeVisitorSupport { //-------------------------------------------------------------------------- + /** + * Returns the class node to expose when wiring dispatch methods for an inner class. + * + * @param cn the enclosing class node + * @param isStatic whether the generated access is static + * @return the effective dispatch receiver type + */ protected static ClassNode getClassNode(final ClassNode cn, final boolean isStatic) { return isStatic ? ClassHelper.CLASS_Type : cn; // TODO: Set class type parameter? } + /** + * Calculates the inheritance distance from the supplied type to {@code Object}. + * + * @param cn the class node to measure + * @return the number of superclass hops to {@code Object} + */ protected static int getObjectDistance(ClassNode cn) { int count = 0; while (cn != null && !ClassHelper.isObjectType(cn)) { @@ -91,10 +138,22 @@ public abstract class InnerClassVisitorHelper extends ClassCodeVisitorSupport { return count; } + /** + * Determines whether the supplied inner class behaves as a static nested class. + * + * @param cn the inner class node to test + * @return {@code true} if no outer-instance field is required + */ protected static boolean isStatic(final InnerClassNode cn) { return cn.getDeclaredField("this$0") == null; } + /** + * Determines whether synthetic outer-instance handling should be applied to the inner class. + * + * @param cn the class node to test + * @return {@code true} if implicit {@code this$0} handling is required + */ protected static boolean shouldHandleImplicitThisForInnerClass(final ClassNode cn) { final int explicitOrImplicitStatic = Opcodes.ACC_ENUM | Opcodes.ACC_INTERFACE | Opcodes.ACC_RECORD | Opcodes.ACC_STATIC; return (cn.getModifiers() & explicitOrImplicitStatic) == 0 && (cn instanceof InnerClassNode inner && !inner.isAnonymous()) diff --git a/src/main/java/org/codehaus/groovy/classgen/ReturnAdder.java b/src/main/java/org/codehaus/groovy/classgen/ReturnAdder.java index 4ba9b5e6af..bbaadba173 100644 --- a/src/main/java/org/codehaus/groovy/classgen/ReturnAdder.java +++ b/src/main/java/org/codehaus/groovy/classgen/ReturnAdder.java @@ -51,6 +51,9 @@ import static org.codehaus.groovy.runtime.DefaultGroovyMethods.last; */ public class ReturnAdder { + /** + * Listener notified when a synthetic return statement is created. + */ @FunctionalInterface public interface ReturnStatementListener { /** @@ -70,17 +73,29 @@ public class ReturnAdder { */ private final boolean doAdd; + /** + * Creates a new return adder that adds return statements to methods. + */ public ReturnAdder() { this.listener = DEFAULT_LISTENER; this.doAdd = true; } + /** + * Creates a new return adder with a listener. Returns are not actually added when using + * a listener; instead, the listener is notified of what return statements would be added. + * + * @param listener the listener to notify of return statement additions + */ public ReturnAdder(final ReturnStatementListener listener) { this.listener = Objects.requireNonNull(listener); this.doAdd = false; } /** + * Adds return statements to a method whenever an implicit return is detected. + * + * @param node the method to process * @deprecated Use {@link #visitMethod(MethodNode)} instead. */ @Deprecated @@ -90,6 +105,8 @@ public class ReturnAdder { /** * Adds return statements to given method whenever an implicit return is detected. + * + * @param node the method node to visit and add returns to */ public void visitMethod(final MethodNode node) { if (!node.isVoidMethod()) { diff --git a/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java b/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java index 820a6499a6..b9c7126c37 100644 --- a/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java +++ b/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java @@ -104,16 +104,30 @@ public class VariableScopeVisitor extends ClassCodeVisitorSupport { } } + /** + * Creates a new variable scope visitor with optional recursion into inner classes. + * + * @param source the source unit being processed + * @param recurseInnerClasses whether to recurse into inner classes + */ public VariableScopeVisitor(SourceUnit source, boolean recurseInnerClasses) { this.source = source; this.currentScope = new VariableScope(); this.recurseInnerClasses = recurseInnerClasses; } + /** + * Creates a new variable scope visitor that does not recurse into inner classes. + * + * @param source the source unit being processed + */ public VariableScopeVisitor(SourceUnit source) { this(source, false); } + /** + * {@inheritDoc} + */ @Override protected SourceUnit getSourceUnit() { return source; @@ -433,6 +447,9 @@ public class VariableScopeVisitor extends ClassCodeVisitorSupport { currentScope.setClassScope(node); } + /** + * {@inheritDoc} + */ @Override public void visitClass(final ClassNode node) { // AIC are already done, doing them here again will lead to wrong scopes @@ -464,6 +481,9 @@ public class VariableScopeVisitor extends ClassCodeVisitorSupport { popState(); } + /** + * {@inheritDoc} + */ @Override public void visitField(final FieldNode node) { pushState(node.isStatic()); @@ -472,6 +492,9 @@ public class VariableScopeVisitor extends ClassCodeVisitorSupport { popState(); } + /** + * {@inheritDoc} + */ @Override public void visitProperty(final PropertyNode node) { pushState(node.isStatic()); @@ -479,12 +502,18 @@ public class VariableScopeVisitor extends ClassCodeVisitorSupport { popState(); } + /** + * {@inheritDoc} + */ @Override protected void visitAnnotation(final AnnotationNode node) { visitTypeReference(node.getClassNode()); super.visitAnnotation(node); } + /** + * {@inheritDoc} + */ @Override protected void visitConstructorOrMethod(final MethodNode node, final boolean isConstructor) { pushState(node.isStatic()); @@ -517,6 +546,9 @@ public class VariableScopeVisitor extends ClassCodeVisitorSupport { // statements: + /** + * {@inheritDoc} + */ @Override public void visitAssertStatement(final AssertStatement statement) { pushState(); @@ -524,6 +556,9 @@ public class VariableScopeVisitor extends ClassCodeVisitorSupport { popState(); } + /** + * {@inheritDoc} + */ @Override public void visitBlockStatement(final BlockStatement statement) { pushState(); @@ -532,6 +567,9 @@ public class VariableScopeVisitor extends ClassCodeVisitorSupport { popState(); } + /** + * {@inheritDoc} + */ @Override public void visitCatchStatement(final CatchStatement statement) { pushState(); @@ -542,6 +580,9 @@ public class VariableScopeVisitor extends ClassCodeVisitorSupport { popState(); } + /** + * {@inheritDoc} + */ @Override public void visitDoWhileLoop(final DoWhileStatement statement) { pushState(); @@ -553,6 +594,9 @@ public class VariableScopeVisitor extends ClassCodeVisitorSupport { popState(); } + /** + * {@inheritDoc} + */ @Override public void visitExpressionStatement(final ExpressionStatement statement) { boolean declaresVariable = statement.getExpression() instanceof DeclarationExpression; @@ -561,6 +605,9 @@ public class VariableScopeVisitor extends ClassCodeVisitorSupport { if (!declaresVariable) popState(); } + /** + * {@inheritDoc} + */ @Override public void visitForLoop(final ForStatement statement) { pushState(); @@ -575,6 +622,9 @@ public class VariableScopeVisitor extends ClassCodeVisitorSupport { popState(); } + /** + * {@inheritDoc} + */ @Override public void visitIfElse(final IfStatement statement) { pushState(); @@ -589,6 +639,9 @@ public class VariableScopeVisitor extends ClassCodeVisitorSupport { popState(); } + /** + * {@inheritDoc} + */ @Override public void visitReturnStatement(final ReturnStatement statement) { pushState(); @@ -596,6 +649,9 @@ public class VariableScopeVisitor extends ClassCodeVisitorSupport { popState(); } + /** + * {@inheritDoc} + */ @Override public void visitSwitch(final SwitchStatement statement) { pushState(); @@ -603,6 +659,9 @@ public class VariableScopeVisitor extends ClassCodeVisitorSupport { popState(); } + /** + * {@inheritDoc} + */ @Override public void visitWhileLoop(final WhileStatement statement) { pushState(); @@ -612,12 +671,18 @@ public class VariableScopeVisitor extends ClassCodeVisitorSupport { // expressions: + /** + * {@inheritDoc} + */ @Override public void visitArrayExpression(final ArrayExpression expression) { visitTypeReference(expression.getType()); super.visitArrayExpression(expression); } + /** + * {@inheritDoc} + */ @Override public void visitBinaryExpression(final BinaryExpression expression) { super.visitBinaryExpression(expression); @@ -627,18 +692,27 @@ public class VariableScopeVisitor extends ClassCodeVisitorSupport { } } + /** + * {@inheritDoc} + */ @Override public void visitCastExpression(final CastExpression expression) { visitTypeReference(expression.getType()); super.visitCastExpression(expression); } + /** + * {@inheritDoc} + */ @Override public void visitClassExpression(final ClassExpression expression) { visitTypeReference(expression.getType()); super.visitClassExpression(expression); } + /** + * {@inheritDoc} + */ @Override public void visitClosureExpression(final ClosureExpression expression) { pushState(); @@ -661,6 +735,9 @@ public class VariableScopeVisitor extends ClassCodeVisitorSupport { popState(); } + /** + * {@inheritDoc} + */ @Override public void visitConstantExpression(final ConstantExpression expression) { if (expression instanceof AnnotationConstantExpression) { @@ -669,6 +746,9 @@ public class VariableScopeVisitor extends ClassCodeVisitorSupport { super.visitConstantExpression(expression); } + /** + * {@inheritDoc} + */ @Override public void visitConstructorCallExpression(final ConstructorCallExpression expression) { if (!expression.isSpecialCall()) visitTypeReference(expression.getType()); @@ -715,6 +795,9 @@ public class VariableScopeVisitor extends ClassCodeVisitorSupport { popState(); } + /** + * {@inheritDoc} + */ @Override public void visitDeclarationExpression(final DeclarationExpression expression) { pushState(); // GROOVY-11229 @@ -733,6 +816,9 @@ public class VariableScopeVisitor extends ClassCodeVisitorSupport { } } + /** + * {@inheritDoc} + */ @Override public void visitFieldExpression(final FieldExpression expression) { String name = expression.getFieldName(); @@ -741,6 +827,9 @@ public class VariableScopeVisitor extends ClassCodeVisitorSupport { if (variable != null) checkVariableContextAccess(variable, expression); } + /** + * {@inheritDoc} + */ @Override public void visitMethodCallExpression(final MethodCallExpression expression) { String methodName = expression.getMethodAsString(); @@ -769,6 +858,9 @@ public class VariableScopeVisitor extends ClassCodeVisitorSupport { super.visitMethodCallExpression(expression); } + /** + * {@inheritDoc} + */ @Override public void visitPropertyExpression(final PropertyExpression expression) { expression.getObjectExpression().visit(this); @@ -776,6 +868,9 @@ public class VariableScopeVisitor extends ClassCodeVisitorSupport { checkPropertyOnExplicitThis(expression); } + /** + * {@inheritDoc} + */ @Override public void visitVariableExpression(final VariableExpression expression) { var variable = findVariableDeclaration(expression.getName()); diff --git a/src/main/java/org/codehaus/groovy/classgen/Verifier.java b/src/main/java/org/codehaus/groovy/classgen/Verifier.java index 108b0fb826..9846516203 100644 --- a/src/main/java/org/codehaus/groovy/classgen/Verifier.java +++ b/src/main/java/org/codehaus/groovy/classgen/Verifier.java @@ -153,9 +153,21 @@ import static org.codehaus.groovy.transform.stc.StaticTypesMarker.DIRECT_METHOD_ */ public class Verifier implements GroovyClassVisitor, Opcodes { + /** + * Metadata key used when swapping initializer statements during verification. + */ public static final String SWAP_INIT = "__$swapInit"; + /** + * Synthetic field name used to cache static metaclass initialization checks. + */ public static final String STATIC_METACLASS_BOOL = "__$stMC"; + /** + * Metadata key used to retain a property's original initializer expression. + */ public static final String INITIAL_EXPRESSION = "INITIAL_EXPRESSION"; + /** + * Metadata key marking methods generated to support default arguments. + */ public static final String DEFAULT_PARAMETER_GENERATED = "DEFAULT_PARAMETER_GENERATED"; private static final ClassNode GENERATED_ANNOTATION = ClassHelper.make(Generated.class); @@ -165,7 +177,13 @@ public class Verifier implements GroovyClassVisitor, Opcodes { private static final ClassNode COMPILESTATIC_ANNOTATION = ClassHelper.make(CompileStatic.class); // NOTE: timeStamp constants shouldn't belong to Verifier but kept here for binary compatibility + /** + * Synthetic timestamp field used for backwards-compatible script metadata. + */ public static final String __TIMESTAMP = "__timeStamp"; + /** + * Alternate synthetic timestamp field retained for binary compatibility. + */ public static final String __TIMESTAMP__ = "__timeStamp__239_neverHappen"; private static final Parameter[] SET_METACLASS_PARAMS = {new Parameter(ClassHelper.METACLASS_TYPE, "mc")}; @@ -173,14 +191,29 @@ public class Verifier implements GroovyClassVisitor, Opcodes { private ClassNode classNode; private MethodNode methodNode; + /** + * Returns the class node currently being verified. + * + * @return the current class node + */ public ClassNode getClassNode() { return classNode; } + /** + * Sets the class node to be verified. + * + * @param classNode the class node to verify + */ protected void setClassNode(final ClassNode classNode) { this.classNode = classNode; } + /** + * Returns the method node currently being verified. + * + * @return the current method node + */ public MethodNode getMethodNode() { return methodNode; } @@ -225,6 +258,9 @@ public class Verifier implements GroovyClassVisitor, Opcodes { //-------------------------------------------------------------------------- + /** + * {@inheritDoc} + */ @Override public void visitClass(final ClassNode node) { this.classNode = node; @@ -343,6 +379,11 @@ public class Verifier implements GroovyClassVisitor, Opcodes { visitor.visitClass(node); } + /** + * Creates the callback used when final-variable analysis finds invalid assignments. + * + * @return the callback passed to {@link FinalVariableAnalyzer} + */ protected FinalVariableAnalyzer.VariableNotFinalCallback getFinalVariablesCallback() { return new FinalVariableAnalyzer.VariableNotFinalCallback() { @Override @@ -503,6 +544,11 @@ public class Verifier implements GroovyClassVisitor, Opcodes { } } + /** + * Adds a synthetic no-arg constructor when the class requires one. + * + * @param node the class being verified + */ protected void addDefaultConstructor(final ClassNode node) { if (!node.getDeclaredConstructors().isEmpty()) return; @@ -569,6 +615,12 @@ public class Verifier implements GroovyClassVisitor, Opcodes { ); } + /** + * Adds the {@code GroovyObject} contract and supporting methods when needed. + * + * @param node the class being enhanced + * @param classInternalName the internal JVM name of the class + */ protected void addGroovyObjectInterfaceAndMethods(final ClassNode node, final String classInternalName) { if (!node.isDerivedFromGroovyObject()) node.addInterface(ClassHelper.GROOVY_OBJECT_TYPE); FieldNode metaClassField = getMetaClassField(node); @@ -662,11 +714,28 @@ public class Verifier implements GroovyClassVisitor, Opcodes { } } + /** + * Adds a method while preserving the legacy {@code addMethod$$bridge} entry point. + * + * @param node the target class + * @param shouldBeSynthetic whether the generated method should be marked synthetic + * @param name the method name + * @param modifiers the method modifiers + * @param returnType the method return type + * @param parameters the method parameters + * @param exceptions the declared exceptions + * @param code the method body + */ @Deprecated // for binary compatibility only; do not use or override protected void addMethod$$bridge(final ClassNode node, final boolean shouldBeSynthetic, final String name, final int modifiers, final ClassNode returnType, final Parameter[] parameters, final ClassNode[] exceptions, final Statement code) { addMethod(node, shouldBeSynthetic, name, modifiers, returnType, parameters, exceptions, code); } + /** + * Adds legacy synthetic timestamp fields for scripts and generated classes. + * + * @param node the class being enhanced + */ @Deprecated(since = "2.4.0") protected void addTimeStamp(final ClassNode node) { } @@ -687,6 +756,9 @@ public class Verifier implements GroovyClassVisitor, Opcodes { } } + /** + * {@inheritDoc} + */ @Override public void visitConstructor(final ConstructorNode node) { Statement stmt = node.getCode(); @@ -773,6 +845,9 @@ public class Verifier implements GroovyClassVisitor, Opcodes { } } + /** + * {@inheritDoc} + */ @Override public void visitMethod(final MethodNode node) { // GROOVY-3712: if it's a MOP method, it's an error as they aren't supposed to exist before ACG is invoked @@ -805,15 +880,26 @@ public class Verifier implements GroovyClassVisitor, Opcodes { } } + /** + * Ensures the supplied method has an explicit return statement when required. + * + * @param node the method to normalize + */ protected void addReturnIfNeeded(final MethodNode node) { ReturnAdder adder = new ReturnAdder(); adder.visitMethod(node); } + /** + * {@inheritDoc} + */ @Override public void visitField(final FieldNode node) { } + /** + * {@inheritDoc} + */ @Override public void visitProperty(final PropertyNode node) { String name = node.getName(); @@ -902,6 +988,11 @@ public class Verifier implements GroovyClassVisitor, Opcodes { accessor.putNodeMetaData("_SKIPPABLE_ANNOTATIONS", Boolean.TRUE); } + /** + * Registers a generated property accessor or mutator with the current class. + * + * @param method the generated property method + */ protected void addPropertyMethod(final MethodNode method) { classNode.addMethod(method); markAsGenerated(classNode, method); @@ -933,6 +1024,9 @@ public class Verifier implements GroovyClassVisitor, Opcodes { } } + /** + * Strategy invoked for each synthetic method or constructor generated for default arguments. + */ @FunctionalInterface public interface DefaultArgsAction { void call(ArgumentListExpression arguments, Parameter[] parameters, MethodNode method); @@ -1092,6 +1186,14 @@ public class Verifier implements GroovyClassVisitor, Opcodes { }); } + /** + * Adds a synthetic constructor variant for default arguments. + * + * @param newParams the parameters of the generated constructor + * @param ctor the source constructor + * @param code the generated constructor body + * @param type the declaring type + */ protected void addConstructor(final Parameter[] newParams, final ConstructorNode ctor, final Statement code, final ClassNode type) { ConstructorNode newConstructor = type.addConstructor(ctor.getModifiers(), newParams, ctor.getExceptions(), code); newConstructor.putNodeMetaData(STATIC_COMPILE_NODE, ctor.getNodeMetaData(STATIC_COMPILE_NODE)); @@ -1122,6 +1224,12 @@ public class Verifier implements GroovyClassVisitor, Opcodes { } } + /** + * Applies default-argument generation to a single method or constructor. + * + * @param action the generation strategy + * @param method the method or constructor to expand + */ protected void addDefaultParameters(final DefaultArgsAction action, final MethodNode method) { Parameter[] parameters = method.getParameters(); @@ -1162,10 +1270,20 @@ public class Verifier implements GroovyClassVisitor, Opcodes { } } + /** + * Adds the synthetic support code required by a generated closure class. + * + * @param node the closure class node + */ protected void addClosureCode(InnerClassNode node) { // add a new invoke } + /** + * Adds object and static initializer wiring for the supplied class. + * + * @param node the class being enhanced + */ protected void addInitialization(final ClassNode node) { boolean addSwapInit = moveOptimizedConstantsInitialization(node); @@ -1187,6 +1305,12 @@ public class Verifier implements GroovyClassVisitor, Opcodes { } } + /** + * Adds initializer statements to the supplied constructor context. + * + * @param node the class being enhanced + * @param constructorNode the constructor receiving initialization code + */ protected void addInitialization(final ClassNode node, final ConstructorNode constructorNode) { Statement firstStatement = constructorNode.getFirstStatement(); @@ -1329,6 +1453,16 @@ public class Verifier implements GroovyClassVisitor, Opcodes { } // TODO: add generics to collections + /** + * Routes a field initializer into the appropriate instance or static initialization block. + * + * @param list the instance-initializer statements + * @param staticList the static-initializer statements + * @param fieldNode the field whose initializer is being processed + * @param isEnumClassNode whether the declaring class is an enum + * @param initStmtsAfterEnumValuesInit enum statements that must run after constant initialization + * @param explicitStaticPropsInEnum explicitly declared static enum properties + */ 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(); if (expression != null) { @@ -1378,6 +1512,13 @@ public class Verifier implements GroovyClassVisitor, Opcodes { return BeanUtils.capitalize(name); } + /** + * Creates the bytecode-backed statement block for a generated property getter. + * + * @param propertyNode the property being served + * @param field the backing field + * @return the generated getter body + */ protected Statement createGetterBlock(final PropertyNode propertyNode, final FieldNode field) { String owner = BytecodeHelper.getClassInternalName(classNode); return new BytecodeSequence(new BytecodeInstruction() { @@ -1394,6 +1535,13 @@ public class Verifier implements GroovyClassVisitor, Opcodes { }); } + /** + * Creates the bytecode-backed statement block for a generated property setter. + * + * @param propertyNode the property being updated + * @param field the backing field + * @return the generated setter body + */ protected Statement createSetterBlock(final PropertyNode propertyNode, final FieldNode field) { String owner = BytecodeHelper.getClassInternalName(classNode); return new BytecodeSequence(new BytecodeInstruction() { @@ -1412,9 +1560,18 @@ public class Verifier implements GroovyClassVisitor, Opcodes { }); } + /** + * {@inheritDoc} + */ public void visitGenericType(final GenericsType genericsType) { } + /** + * Extracts a timestamp value from a synthetic timestamp field name. + * + * @param fieldName the field name to inspect + * @return the parsed timestamp, or {@code null} if the name is not a timestamp field + */ public static Long getTimestampFromFieldName(final String fieldName) { if (fieldName.startsWith(__TIMESTAMP__)) { try { @@ -1426,6 +1583,12 @@ public class Verifier implements GroovyClassVisitor, Opcodes { return null; } + /** + * Looks up the synthetic timestamp stored on a generated class. + * + * @param clazz the generated class to inspect + * @return the stored timestamp, or {@code Long.MAX_VALUE} if none is available + */ public static long getTimestamp(final Class<?> clazz) { if (clazz.getClassLoader() instanceof GroovyClassLoader.InnerLoader innerLoader) { return innerLoader.getTimeStamp(); @@ -1442,6 +1605,11 @@ public class Verifier implements GroovyClassVisitor, Opcodes { return Long.MAX_VALUE; } + /** + * Adds bridge methods needed to support covariant overrides. + * + * @param classNode the class being enhanced + */ protected void addCovariantMethods(final ClassNode classNode) { Map<String, MethodNode> absInterfaceMethods = new HashMap<>(); Map<String, MethodNode> allInterfaceMethods = new HashMap<>(); diff --git a/src/main/java/org/codehaus/groovy/classgen/VerifierCodeVisitor.java b/src/main/java/org/codehaus/groovy/classgen/VerifierCodeVisitor.java index be87099c6a..869f0d6dd5 100644 --- a/src/main/java/org/codehaus/groovy/classgen/VerifierCodeVisitor.java +++ b/src/main/java/org/codehaus/groovy/classgen/VerifierCodeVisitor.java @@ -42,10 +42,18 @@ public class VerifierCodeVisitor extends CodeVisitorSupport { private final ClassNode classNode; + /** + * Creates a new verifier code visitor for the given class. + * + * @param classNode the class node being verified + */ public VerifierCodeVisitor(ClassNode classNode) { this.classNode = classNode; } + /** + * {@inheritDoc} + */ @Override public void visitForLoop(ForStatement statement) { Optional.ofNullable(statement.getIndexVariable()).map(Variable::getName) @@ -55,6 +63,9 @@ public class VerifierCodeVisitor extends CodeVisitorSupport { super.visitForLoop(statement); } + /** + * {@inheritDoc} + */ @Override public void visitFieldExpression(FieldExpression expression) { if (!expression.getField().isSynthetic()) { @@ -63,12 +74,18 @@ public class VerifierCodeVisitor extends CodeVisitorSupport { super.visitFieldExpression(expression); } + /** + * {@inheritDoc} + */ @Override public void visitVariableExpression(VariableExpression expression) { assertValidIdentifier(expression.getName(), "variable name", expression); super.visitVariableExpression(expression); } + /** + * {@inheritDoc} + */ @Override public void visitListExpression(ListExpression expression) { for (Expression element : expression.getExpressions()) { @@ -79,6 +96,9 @@ public class VerifierCodeVisitor extends CodeVisitorSupport { super.visitListExpression(expression); } + /** + * {@inheritDoc} + */ @Override public void visitConstructorCallExpression(ConstructorCallExpression call) { ClassNode callType = call.getType(); @@ -87,6 +107,13 @@ public class VerifierCodeVisitor extends CodeVisitorSupport { } } + /** + * Verifies that the supplied name is a valid Java identifier. + * + * @param name the identifier text to validate + * @param message the error context to include in failures + * @param node the node to associate with any parse error + */ public static void assertValidIdentifier(String name, String message, ASTNode node) { int size = name.length(); if (size <= 0) {
