Skip to content

Commit 1198bf7

Browse files
authored
Handle trailing commas in for-loop updaters. (#1616)
Fix #1354.
1 parent 04883d6 commit 1198bf7

File tree

7 files changed

+79
-12
lines changed

7 files changed

+79
-12
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
## 3.0.1-wip
22

3+
* Handle trailing commas in for-loop updaters (#1354).
34
* Handle comments and metadata before variables more gracefully (#1604).
45
* Ensure comment formatting is idempotent (#1606).
56
* Better indentation of leading comments on property accesses in binary operator

lib/src/front_end/delimited_list_builder.dart

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -143,18 +143,18 @@ final class DelimitedListBuilder {
143143
pieces.forEach(add);
144144
}
145145

146-
/// Adds the contents of [lineBuilder] to this outer [DelimitedListBuilder].
146+
/// Adds the contents of [inner] to this outer [DelimitedListBuilder].
147147
///
148-
/// This is used when preserving newlines inside a collection literal. The
149-
/// [lineBuilder] will be used for the elements that should be packed onto a
150-
/// single line, and this builder is for the rows that are each on their own
151-
/// line.
152-
void addLineBuilder(DelimitedListBuilder lineBuilder) {
148+
/// This is used when a [DelimiterListBuilder] is building a piece that will
149+
/// then become an element in a surrounding [DelimitedListBuilder]. It ensures
150+
/// that any comments around a trailing comma after [inner] don't get lost and
151+
/// are instead hoisted up to be captured by this builder.
152+
void addInnerBuilder(DelimitedListBuilder inner) {
153153
// Add the elements of the line to this builder.
154-
add(lineBuilder.build());
154+
add(inner.build());
155155

156156
// Make sure that any trailing comments on the line aren't lost.
157-
_commentsBeforeComma = lineBuilder._commentsBeforeComma;
157+
_commentsBeforeComma = inner._commentsBeforeComma;
158158
}
159159

160160
/// Writes any comments appearing before [token] to the list.

lib/src/front_end/piece_factory.dart

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,16 @@ mixin PieceFactory {
420420
// The update clauses.
421421
if (forParts.updaters.isNotEmpty) {
422422
partsList.addCommentsBefore(forParts.updaters.first.beginToken);
423-
partsList.add(createCommaSeparated(forParts.updaters));
423+
424+
// Create a nested list builder for the updaters so that they can
425+
// remain unsplit even while the clauses split.
426+
var updaterBuilder = DelimitedListBuilder(
427+
this, const ListStyle(commas: Commas.nonTrailing));
428+
forParts.updaters.forEach(updaterBuilder.visit);
429+
430+
// Add the updater builder to the clause builder so that any comments
431+
// around a trailing comma after the updaters don't get dropped.
432+
partsList.addInnerBuilder(updaterBuilder);
424433
}
425434

426435
partsList.rightBracket(rightParenthesis);
@@ -1076,7 +1085,7 @@ mixin PieceFactory {
10761085
elements[i - 1].endToken, element.beginToken)) {
10771086
// This element begins a new line. Add the elements on the previous
10781087
// line to the list builder and start a new line.
1079-
builder.addLineBuilder(lineBuilder);
1088+
builder.addInnerBuilder(lineBuilder);
10801089
lineBuilder = DelimitedListBuilder(this, lineStyle);
10811090
atLineStart = true;
10821091
}
@@ -1092,7 +1101,7 @@ mixin PieceFactory {
10921101
}
10931102

10941103
// Finish the last line if there is anything on it.
1095-
if (!atLineStart) builder.addLineBuilder(lineBuilder);
1104+
if (!atLineStart) builder.addInnerBuilder(lineBuilder);
10961105
}
10971106

10981107
/// Writes a [VariablePiece] for a named or wildcard variable pattern.

test/tall/expression/collection_for.stmt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,4 +170,18 @@ var list = [
170170
inc
171171
)
172172
element,
173+
];
174+
>>> Trailing comma in increments.
175+
var list = [
176+
for (
177+
x = 1;
178+
true;
179+
x += 1, x += 2,
180+
)
181+
element,
182+
];
183+
<<<
184+
var list = [
185+
for (x = 1; true; x += 1, x += 2)
186+
element,
173187
];

test/tall/regression/1300/1354.stmt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
>>>
2+
void main() {
3+
for (int i; i < 10; print("foo"), ++i, print("bar"),) {
4+
break;
5+
}
6+
}
7+
<<<
8+
void main() {
9+
for (int i; i < 10; print("foo"), ++i, print("bar")) {
10+
break;
11+
}
12+
}

test/tall/statement/for_comment.stmt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,22 @@ for (
223223
) {
224224
body;
225225
}
226+
>>> Preserve comments around discarded increment trailing comma.
227+
for (
228+
init;
229+
cond;
230+
incr /* c1 */ , /* c2 */
231+
) {
232+
body;
233+
}
234+
<<<
235+
for (
236+
init;
237+
cond;
238+
incr /* c1 */ /* c2 */
239+
) {
240+
body;
241+
}
226242
>>> Line comment before first `;` in fully empty clauses.
227243
for ( // comment
228244
; ; ) { body; }

test/tall/statement/for_initializer.stmt

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,4 +155,19 @@ for (
155155
second = 2,
156156
third = 3,
157157
fourth = 4
158-
) {}
158+
) {}
159+
>>> Discard trailing comma in unsplit increments.
160+
for (foo; bar; first = 1, second = 2,) {}
161+
<<<
162+
for (foo; bar; first = 1, second = 2) {}
163+
>>> Discard trailing comma in split increments.
164+
for (foo; bar; first = 1, second = 2, third = 3, fourth = 4,) {}
165+
<<<
166+
for (
167+
foo;
168+
bar;
169+
first = 1,
170+
second = 2,
171+
third = 3,
172+
fourth = 4
173+
) {}

0 commit comments

Comments
 (0)