Skip to content

Commit 47fd448

Browse files
committed
GROOVY-11857: encapsulate ForStatement without value variable
1 parent 9ffefbc commit 47fd448

10 files changed

Lines changed: 72 additions & 47 deletions

File tree

src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -521,7 +521,7 @@ public Function<Statement, ForStatement> visitOriginalForControl(final OriginalF
521521
.map(e -> (Expression) this.visit(e)).orElse(EmptyExpression.INSTANCE));
522522
closureListExpression.addExpression(this.visitForUpdate(ctx.forUpdate()));
523523

524-
return (body) -> new ForStatement(ForStatement.FOR_LOOP_DUMMY, closureListExpression, body);
524+
return (body) -> new ForStatement(closureListExpression, body);
525525
}
526526

527527
@Override

src/main/java/org/codehaus/groovy/ast/ClassCodeExpressionTransformer.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,9 @@ public void visitExpressionStatement(final ExpressionStatement stmt) {
137137

138138
@Override
139139
public void visitForLoop(final ForStatement stmt) {
140-
visitAnnotations(stmt.getVariable()); // "for(T x : y)" or "for(x in y)"
140+
if (stmt.getValueVariable() != null) {
141+
visitAnnotations(stmt.getValueVariable()); // "for(T x : y)" or "for(x in y)"
142+
}
141143
stmt.setCollectionExpression(transform(stmt.getCollectionExpression()));
142144
stmt.getLoopBlock().visit(this);
143145
}

src/main/java/org/codehaus/groovy/ast/ClassCodeVisitorSupport.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,9 @@ public void visitExpressionStatement(ExpressionStatement statement) {
215215
@Override
216216
public void visitForLoop(ForStatement statement) {
217217
visitStatement(statement);
218-
visitAnnotations(statement.getVariable());
218+
if (statement.getValueVariable() != null) {
219+
visitAnnotations(statement.getValueVariable());
220+
}
219221
super.visitForLoop(statement);
220222
}
221223

src/main/java/org/codehaus/groovy/ast/stmt/ForStatement.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.codehaus.groovy.ast.GroovyCodeVisitor;
2424
import org.codehaus.groovy.ast.Parameter;
2525
import org.codehaus.groovy.ast.VariableScope;
26+
import org.codehaus.groovy.ast.expr.ClosureListExpression;
2627
import org.codehaus.groovy.ast.expr.Expression;
2728

2829
import static java.util.Objects.requireNonNull;
@@ -32,7 +33,9 @@
3233
*/
3334
public class ForStatement extends Statement implements LoopingStatement {
3435

35-
public static final Parameter FOR_LOOP_DUMMY = new Parameter(ClassHelper.OBJECT_TYPE, "forLoopDummyParameter");
36+
private static final Parameter DUMMY_VALUE_VARIABLE = new Parameter(ClassHelper.OBJECT_TYPE, "forLoopDummyParameter");
37+
@Deprecated(since = "6.0.0")
38+
public static final Parameter FOR_LOOP_DUMMY = DUMMY_VALUE_VARIABLE;
3639

3740
private final Parameter indexVariable, valueVariable;
3841
private Expression collectionExpression;
@@ -52,6 +55,15 @@ public ForStatement(final Parameter variable, final Expression collectionExpress
5255
this(null, variable, collectionExpression, loopBlock);
5356
}
5457

58+
/**
59+
* A constructor for C-style for loops.
60+
*
61+
* @since 6.0.0
62+
*/
63+
public ForStatement(final ClosureListExpression closureListExpression, final Statement loopBlock) {
64+
this(DUMMY_VALUE_VARIABLE, closureListExpression, loopBlock);
65+
}
66+
5567
public void setCollectionExpression(final Expression collectionExpression) {
5668
this.collectionExpression = requireNonNull(collectionExpression);
5769
}
@@ -74,7 +86,7 @@ public Parameter getIndexVariable() {
7486
* @since 5.0.0
7587
*/
7688
public Parameter getValueVariable() {
77-
return valueVariable != FOR_LOOP_DUMMY ? valueVariable : null;
89+
return valueVariable != DUMMY_VALUE_VARIABLE ? valueVariable : null;
7890
}
7991

8092
@Deprecated(since = "5.0.0")

src/main/java/org/codehaus/groovy/classgen/ClassCompletionVerifier.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -792,9 +792,15 @@ public void visitCatchStatement(final CatchStatement cs) {
792792

793793
@Override
794794
public void visitForLoop(final ForStatement fs) {
795-
List<String> modifiers = new ArrayList<>();
796-
int mods = fs.getVariable().getModifiers();
795+
if (fs.getValueVariable() != null) {
796+
checkModifiers(fs, fs.getValueVariable());
797+
}
798+
super.visitForLoop(fs);
799+
}
797800

801+
private void checkModifiers(ForStatement fs, Parameter p) {
802+
List<String> modifiers = new ArrayList<>();
803+
int mods = p.getModifiers();
798804
if (isAbstract (mods)) modifiers.add("abstract" );
799805
if (isPrivate (mods)) modifiers.add("private" );
800806
if (isProtected(mods)) modifiers.add("protected");
@@ -803,10 +809,8 @@ public void visitForLoop(final ForStatement fs) {
803809
if (isStrict (mods)) modifiers.add("strictfp" );
804810

805811
for (String modifier : modifiers) {
806-
addError("The variable '" + fs.getVariable().getName() + "' has invalid modifier " + modifier + ".", fs);
812+
addError("The variable '" + p.getName() + "' has invalid modifier " + modifier + ".", fs);
807813
}
808-
809-
super.visitForLoop(fs);
810814
}
811815

812816
@Override

src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesStatementWriter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ protected void writeForInLoop(final ForStatement loop) {
9797
ClassNode collectionType = controller.getTypeChooser().resolveType(collectionExpression, controller.getClassNode());
9898

9999
int mark = operandStack.getStackLength();
100-
if (collectionType.isArray() && collectionType.getComponentType().equals(loop.getVariableType())) {
100+
if (collectionType.isArray() && collectionType.getComponentType().equals(loop.getValueVariable().getType())) {
101101
writeOptimizedForEachLoop(loop, collectionExpression, collectionType);
102102
} else if (GeneralUtils.isOrImplements(collectionType, ENUMERATION_CLASSNODE)) {
103103
writeEnumerationBasedForEachLoop(loop, collectionExpression, collectionType);

src/main/java/org/codehaus/groovy/control/ResolveVisitor.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1392,7 +1392,9 @@ public void visitCatchStatement(final CatchStatement cs) {
13921392

13931393
@Override
13941394
public void visitForLoop(final ForStatement forLoop) {
1395-
resolveOrFail(forLoop.getVariableType(), forLoop);
1395+
if (forLoop.getValueVariable() != null) {
1396+
resolveOrFail(forLoop.getValueVariable().getType(), forLoop);
1397+
}
13961398
super.visitForLoop(forLoop);
13971399
}
13981400

src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2176,7 +2176,7 @@ public void visitForLoop(final ForStatement forLoop) {
21762176
visitStatement(forLoop);
21772177
collectionExpression.visit(this);
21782178
ClassNode collectionType = getType(collectionExpression);
2179-
ClassNode forLoopVariableType = forLoop.getVariableType();
2179+
ClassNode forLoopVariableType = forLoop.getValueVariable().getType();
21802180
ClassNode componentType;
21812181
if (isStringType(collectionType)) {
21822182
if (isWrapperCharacter(getWrapper(forLoopVariableType))) {

src/testFixtures/groovy/org/codehaus/groovy/ast/builder/AstAssert.groovy

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,11 @@ class AstAssert {
237237
assertSyntaxTree([expected.arguments], [actual.arguments])
238238
},
239239
ForStatement : { expected, actual ->
240-
assertSyntaxTree([expected.variable], [actual.variable])
240+
assert expected.valueVariable.asBoolean() == actual.valueVariable.asBoolean()
241+
if (expected.valueVariable) {
242+
assertSyntaxTree([expected.valueVariable], [actual.valueVariable])
243+
}
244+
assertSyntaxTree([expected.indexVariable], [actual.indexVariable])
241245
assertSyntaxTree([expected.collectionExpression], [actual.collectionExpression])
242246
assertSyntaxTree([expected.loopBlock], [actual.loopBlock])
243247
},

subprojects/groovy-astbuilder/src/test/groovy/org/codehaus/groovy/ast/builder/AstBuilderFromCodeTest.groovy

Lines changed: 32 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -413,39 +413,38 @@ class AstBuilderFromCodeTest {
413413
}
414414

415415
def expected = new BlockStatement([new ForStatement(
416-
new Parameter(ClassHelper.OBJECT_TYPE, "forLoopDummyParameter"),
417-
new ClosureListExpression(
418-
[
419-
new DeclarationExpression(
420-
new VariableExpression("x"),
421-
new Token(Types.EQUALS, "=", -1, -1),
422-
new ConstantExpression(0)
423-
),
424-
new BinaryExpression(
425-
new VariableExpression("x"),
426-
new Token(Types.COMPARE_LESS_THAN, "<", -1, -1),
427-
new ConstantExpression(10)
428-
),
429-
new PostfixExpression(
430-
new VariableExpression("x"),
431-
new Token(Types.PLUS_PLUS, "++", -1, -1)
432-
)
433-
]
434-
),
435-
new BlockStatement(
436-
[
437-
new ExpressionStatement(
438-
new MethodCallExpression(
439-
new VariableExpression("this"),
440-
new ConstantExpression("println"),
441-
new ArgumentListExpression(
442-
new VariableExpression("x"),
443-
)
444-
)
445-
)
446-
],
447-
new VariableScope()
448-
)
416+
new ClosureListExpression(
417+
[
418+
new DeclarationExpression(
419+
new VariableExpression("x"),
420+
new Token(Types.EQUALS, "=", -1, -1),
421+
new ConstantExpression(0)
422+
),
423+
new BinaryExpression(
424+
new VariableExpression("x"),
425+
new Token(Types.COMPARE_LESS_THAN, "<", -1, -1),
426+
new ConstantExpression(10)
427+
),
428+
new PostfixExpression(
429+
new VariableExpression("x"),
430+
new Token(Types.PLUS_PLUS, "++", -1, -1)
431+
)
432+
]
433+
),
434+
new BlockStatement(
435+
[
436+
new ExpressionStatement(
437+
new MethodCallExpression(
438+
new VariableExpression("this"),
439+
new ConstantExpression("println"),
440+
new ArgumentListExpression(
441+
new VariableExpression("x"),
442+
)
443+
)
444+
)
445+
],
446+
new VariableScope()
447+
)
449448
)], new VariableScope())
450449

451450
AstAssert.assertSyntaxTree([expected], result)

0 commit comments

Comments
 (0)