@@ -255,7 +255,7 @@ class SourceVisitor extends ThrowingAstVisitor {
255
255
// and the ")" ends up on its own line.
256
256
if (node.arguments.hasCommaAfter) {
257
257
_visitCollectionLiteral (
258
- null , node.leftParenthesis, node.arguments, node.rightParenthesis);
258
+ node.leftParenthesis, node.arguments, node.rightParenthesis);
259
259
return ;
260
260
}
261
261
@@ -289,7 +289,7 @@ class SourceVisitor extends ThrowingAstVisitor {
289
289
// and the ")" ends up on its own line.
290
290
if (arguments.hasCommaAfter) {
291
291
_visitCollectionLiteral (
292
- null , node.leftParenthesis, arguments, node.rightParenthesis);
292
+ node.leftParenthesis, arguments, node.rightParenthesis);
293
293
return ;
294
294
}
295
295
@@ -313,7 +313,7 @@ class SourceVisitor extends ThrowingAstVisitor {
313
313
// and the ")" ends up on its own line.
314
314
if (arguments.hasCommaAfter) {
315
315
_visitCollectionLiteral (
316
- null , node.leftParenthesis, arguments, node.rightParenthesis);
316
+ node.leftParenthesis, arguments, node.rightParenthesis);
317
317
return ;
318
318
}
319
319
@@ -2108,8 +2108,17 @@ class SourceVisitor extends ThrowingAstVisitor {
2108
2108
// Corner case: Splitting inside a list looks bad if there's only one
2109
2109
// element, so make those more costly.
2110
2110
var cost = node.elements.length <= 1 ? Cost .singleElementList : Cost .normal;
2111
- _visitCollectionLiteral (
2112
- node, node.leftBracket, node.elements, node.rightBracket, cost);
2111
+ _visitCollectionLiteral (node.leftBracket, node.elements, node.rightBracket,
2112
+ constKeyword: node.constKeyword,
2113
+ typeArguments: node.typeArguments,
2114
+ splitOuterCollection: true ,
2115
+ cost: cost);
2116
+ }
2117
+
2118
+ @override
2119
+ void visitListPattern (ListPattern node) {
2120
+ _visitCollectionLiteral (node.leftBracket, node.elements, node.rightBracket,
2121
+ typeArguments: node.typeArguments);
2113
2122
}
2114
2123
2115
2124
@override
@@ -2122,6 +2131,22 @@ class SourceVisitor extends ThrowingAstVisitor {
2122
2131
builder.unnest ();
2123
2132
}
2124
2133
2134
+ @override
2135
+ void visitMapPattern (MapPattern node) {
2136
+ _visitCollectionLiteral (node.leftBracket, node.elements, node.rightBracket,
2137
+ typeArguments: node.typeArguments);
2138
+ }
2139
+
2140
+ @override
2141
+ void visitMapPatternEntry (MapPatternEntry node) {
2142
+ builder.nestExpression ();
2143
+ visit (node.key);
2144
+ token (node.separator);
2145
+ soloSplit ();
2146
+ visit (node.value);
2147
+ builder.unnest ();
2148
+ }
2149
+
2125
2150
@override
2126
2151
void visitMethodDeclaration (MethodDeclaration node) {
2127
2152
_visitFunctionOrMethodDeclaration (
@@ -2232,7 +2257,7 @@ class SourceVisitor extends ThrowingAstVisitor {
2232
2257
2233
2258
@override
2234
2259
void visitNamedExpression (NamedExpression node) {
2235
- visitNamedArgument (node);
2260
+ visitNamedNode (node.name.label.token, node.name.colon, node.expression );
2236
2261
}
2237
2262
2238
2263
@override
@@ -2373,7 +2398,34 @@ class SourceVisitor extends ThrowingAstVisitor {
2373
2398
void visitRecordLiteral (RecordLiteral node) {
2374
2399
modifier (node.constKeyword);
2375
2400
_visitCollectionLiteral (
2376
- node, node.leftParenthesis, node.fields, node.rightParenthesis);
2401
+ node.leftParenthesis, node.fields, node.rightParenthesis,
2402
+ isRecord: true );
2403
+ }
2404
+
2405
+ @override
2406
+ void visitRecordPattern (RecordPattern node) {
2407
+ _visitCollectionLiteral (
2408
+ node.leftParenthesis, node.fields, node.rightParenthesis,
2409
+ isRecord: true );
2410
+ }
2411
+
2412
+ @override
2413
+ void visitRecordPatternField (RecordPatternField node) {
2414
+ var fieldName = node.fieldName;
2415
+ if (fieldName != null ) {
2416
+ var name = fieldName.name;
2417
+ if (name != null ) {
2418
+ visitNamedNode (fieldName.name! , fieldName.colon, node.pattern);
2419
+ } else {
2420
+ // Named field with inferred name, like:
2421
+ //
2422
+ // var (:x) = (x: 1);
2423
+ token (fieldName.colon);
2424
+ visit (node.pattern);
2425
+ }
2426
+ } else {
2427
+ visit (node.pattern);
2428
+ }
2377
2429
}
2378
2430
2379
2431
@override
@@ -2485,6 +2537,12 @@ class SourceVisitor extends ThrowingAstVisitor {
2485
2537
token (node.rethrowKeyword);
2486
2538
}
2487
2539
2540
+ @override
2541
+ void visitRestPatternElement (RestPatternElement node) {
2542
+ token (node.operator );
2543
+ visit (node.pattern);
2544
+ }
2545
+
2488
2546
@override
2489
2547
void visitReturnStatement (ReturnStatement node) {
2490
2548
_simpleStatement (node, () {
@@ -2505,8 +2563,10 @@ class SourceVisitor extends ThrowingAstVisitor {
2505
2563
2506
2564
@override
2507
2565
void visitSetOrMapLiteral (SetOrMapLiteral node) {
2508
- _visitCollectionLiteral (
2509
- node, node.leftBracket, node.elements, node.rightBracket);
2566
+ _visitCollectionLiteral (node.leftBracket, node.elements, node.rightBracket,
2567
+ constKeyword: node.constKeyword,
2568
+ typeArguments: node.typeArguments,
2569
+ splitOuterCollection: true );
2510
2570
}
2511
2571
2512
2572
@override
@@ -2642,11 +2702,13 @@ class SourceVisitor extends ThrowingAstVisitor {
2642
2702
token (node.keyword);
2643
2703
space ();
2644
2704
2705
+ builder.indent ();
2645
2706
builder.startBlockArgumentNesting ();
2646
2707
builder.nestExpression ();
2647
2708
visit (node.guardedPattern.pattern);
2648
2709
builder.unnest ();
2649
2710
builder.endBlockArgumentNesting ();
2711
+ builder.unindent ();
2650
2712
2651
2713
visit (node.guardedPattern.whenClause);
2652
2714
token (node.colon);
@@ -2927,20 +2989,31 @@ class SourceVisitor extends ThrowingAstVisitor {
2927
2989
/// split between the name and argument forces the argument list to split
2928
2990
/// too.
2929
2991
void visitNamedArgument (NamedExpression node, [NamedRule ? rule]) {
2992
+ visitNamedNode (
2993
+ node.name.label.token, node.name.colon, node.expression, rule);
2994
+ }
2995
+
2996
+ /// Visits syntax of the form `identifier: <node>` : a named argument or a
2997
+ /// named record field.
2998
+ void visitNamedNode (Token name, Token colon, AstNode node,
2999
+ [NamedRule ? rule]) {
2930
3000
builder.nestExpression ();
2931
3001
builder.startSpan ();
2932
- visit (node.name);
3002
+ token (name);
3003
+ token (colon);
2933
3004
2934
3005
// Don't allow a split between a name and a collection. Instead, we want
2935
3006
// the collection itself to split, or to split before the argument.
2936
- if (node.expression is ListLiteral || node.expression is SetOrMapLiteral ) {
3007
+ if (node is ListLiteral ||
3008
+ node is SetOrMapLiteral ||
3009
+ node is RecordLiteral ) {
2937
3010
space ();
2938
3011
} else {
2939
3012
var split = soloSplit ();
2940
3013
if (rule != null ) split.constrainWhenSplit (rule);
2941
3014
}
2942
3015
2943
- visit (node.expression );
3016
+ visit (node);
2944
3017
builder.endSpan ();
2945
3018
builder.unnest ();
2946
3019
}
@@ -3207,26 +3280,67 @@ class SourceVisitor extends ThrowingAstVisitor {
3207
3280
}
3208
3281
}
3209
3282
3210
- /// Visits the collection literal [node] whose body starts with [leftBracket] ,
3283
+ /// Visits the construct whose body starts with [leftBracket] ,
3211
3284
/// ends with [rightBracket] and contains [elements] .
3212
3285
///
3213
- /// This is also used for argument lists with a trailing comma which are
3214
- /// considered "collection-like". In that case, [node] is `null` .
3215
- void _visitCollectionLiteral (Literal ? node, Token leftBracket,
3216
- List <AstNode > elements, Token rightBracket,
3217
- [int ? cost]) {
3218
- if (node is TypedLiteral ) {
3219
- // See if `const` should be removed.
3220
- if (node.constKeyword != null &&
3221
- _constNesting > 0 &&
3222
- _formatter.fixes.contains (StyleFix .optionalConst)) {
3223
- // Don't lose comments before the discarded keyword, if any.
3224
- writePrecedingCommentsAndNewlines (node.constKeyword! );
3225
- } else {
3226
- modifier (node.constKeyword);
3286
+ /// This is used for collection literals, collection patterns, and argument
3287
+ /// lists with a trailing comma which are considered "collection-like".
3288
+ ///
3289
+ /// If [splitOuterCollection] is `true` then this collection forces any
3290
+ /// surrounding collections to split even if this one doesn't. We do this for
3291
+ /// collection literals, but not other collection-like constructs.
3292
+ void _visitCollectionLiteral (
3293
+ Token leftBracket, List <AstNode > elements, Token rightBracket,
3294
+ {Token ? constKeyword,
3295
+ TypeArgumentList ? typeArguments,
3296
+ int ? cost,
3297
+ bool splitOuterCollection = false ,
3298
+ bool isRecord = false }) {
3299
+ // See if `const` should be removed.
3300
+ if (constKeyword != null &&
3301
+ _constNesting > 0 &&
3302
+ _formatter.fixes.contains (StyleFix .optionalConst)) {
3303
+ // Don't lose comments before the discarded keyword, if any.
3304
+ writePrecedingCommentsAndNewlines (constKeyword);
3305
+ } else {
3306
+ modifier (constKeyword);
3307
+ }
3308
+
3309
+ // Don't use the normal type argument list formatting code because we don't
3310
+ // want to allow splitting before the "<" since there is no preceding
3311
+ // identifier and it looks weird to have a "<" hanging by itself. Prevents:
3312
+ //
3313
+ // var list = <
3314
+ // LongTypeName<
3315
+ // TypeArgument,
3316
+ // TypeArgument>>[];
3317
+ if (typeArguments != null ) {
3318
+ builder.startSpan ();
3319
+ builder.nestExpression ();
3320
+ token (typeArguments.leftBracket);
3321
+ builder.startRule (Rule (Cost .typeArgument));
3322
+
3323
+ for (var typeArgument in typeArguments.arguments) {
3324
+ visit (typeArgument);
3325
+
3326
+ // Write the comma separator.
3327
+ if (typeArgument != typeArguments.arguments.last) {
3328
+ var comma = typeArgument.endToken.next;
3329
+
3330
+ // TODO(rnystrom): There is a bug in analyzer where the end token of a
3331
+ // nullable record type is the ")" and not the "?". This works around
3332
+ // that. Remove that's fixed.
3333
+ if (comma? .lexeme == '?' ) comma = comma? .next;
3334
+
3335
+ token (comma);
3336
+ split ();
3337
+ }
3227
3338
}
3228
3339
3229
- visit (node.typeArguments);
3340
+ token (typeArguments.rightBracket);
3341
+ builder.endRule ();
3342
+ builder.unnest ();
3343
+ builder.endSpan ();
3230
3344
}
3231
3345
3232
3346
// Handle empty collections, with or without comments.
@@ -3236,7 +3350,7 @@ class SourceVisitor extends ThrowingAstVisitor {
3236
3350
}
3237
3351
3238
3352
// Unlike other collections, records don't force outer ones to split.
3239
- if (node is ! RecordLiteral ) {
3353
+ if (splitOuterCollection ) {
3240
3354
// Force all of the surrounding collections to split.
3241
3355
_collectionSplits.fillRange (0 , _collectionSplits.length, true );
3242
3356
@@ -3245,7 +3359,7 @@ class SourceVisitor extends ThrowingAstVisitor {
3245
3359
}
3246
3360
3247
3361
_beginBody (leftBracket);
3248
- if (node is TypedLiteral ) _startPossibleConstContext (node. constKeyword);
3362
+ _startPossibleConstContext (constKeyword);
3249
3363
3250
3364
// If a collection contains a line comment, we assume it's a big complex
3251
3365
// blob of data with some documented structure. In that case, the user
@@ -3285,20 +3399,19 @@ class SourceVisitor extends ThrowingAstVisitor {
3285
3399
}
3286
3400
}
3287
3401
3288
- var force = false ;
3289
-
3290
3402
// If there is a collection inside this one, it forces this one to split.
3291
- if (node is ! RecordLiteral ) {
3403
+ var force = false ;
3404
+ if (splitOuterCollection) {
3292
3405
force = _collectionSplits.removeLast ();
3293
3406
}
3294
3407
3295
3408
// If the collection has a trailing comma, the user must want it to split.
3296
3409
// (Unless it's a single-element record literal, in which case the trailing
3297
3410
// comma is required for disambiguation.)
3298
- var isSingleElementRecord = node is RecordLiteral && elements.length == 1 ;
3411
+ var isSingleElementRecord = isRecord && elements.length == 1 ;
3299
3412
if (elements.hasCommaAfter && ! isSingleElementRecord) force = true ;
3300
3413
3301
- if (node is TypedLiteral ) _endPossibleConstContext (node. constKeyword);
3414
+ _endPossibleConstContext (constKeyword);
3302
3415
_endBody (rightBracket, forceSplit: force);
3303
3416
}
3304
3417
0 commit comments