@@ -527,8 +527,16 @@ mixin PieceFactory {
527
527
/// If [fieldKeyword] and [period] are given, the former should be the `this`
528
528
/// or `super` keyword for an initializing formal or super parameter.
529
529
void writeFormalParameter (
530
- NormalFormalParameter node, TypeAnnotation ? type, Token ? name,
530
+ FormalParameter node, TypeAnnotation ? type, Token ? name,
531
531
{Token ? mutableKeyword, Token ? fieldKeyword, Token ? period}) {
532
+ // If the parameter has a default value, the parameter node will be wrapped
533
+ // in a DefaultFormalParameter node containing the default.
534
+ (Token separator, Expression value)? defaultValueRecord;
535
+ if (node.parent
536
+ case DefaultFormalParameter (: var separator? , : var defaultValue? )) {
537
+ defaultValueRecord = (separator, defaultValue);
538
+ }
539
+
532
540
writeParameter (
533
541
metadata: node.metadata,
534
542
modifiers: [
@@ -539,7 +547,8 @@ mixin PieceFactory {
539
547
type,
540
548
fieldKeyword: fieldKeyword,
541
549
period: period,
542
- name);
550
+ name,
551
+ defaultValue: defaultValueRecord);
543
552
}
544
553
545
554
/// Writes a function, method, getter, or setter declaration.
@@ -604,10 +613,38 @@ mixin PieceFactory {
604
613
});
605
614
}
606
615
616
+ /// If [parameter] has a [defaultValue] then writes a piece for the parameter
617
+ /// followed by that default value.
618
+ ///
619
+ /// Otherwise, just writes [parameter] .
620
+ void writeDefaultValue (
621
+ Piece parameter, (Token separator, Expression value)? defaultValue) {
622
+ if (defaultValue == null ) {
623
+ pieces.add (parameter);
624
+ return ;
625
+ }
626
+
627
+ var (separator, value) = defaultValue;
628
+ var operatorPiece = pieces.build (() {
629
+ if (separator.type == TokenType .EQ ) pieces.space ();
630
+ pieces.token (separator);
631
+ if (separator.type != TokenType .EQ ) pieces.space ();
632
+ });
633
+
634
+ var valuePiece = nodePiece (value, context: NodeContext .assignment);
635
+
636
+ pieces.add (AssignPiece (
637
+ left: parameter,
638
+ operatorPiece,
639
+ valuePiece,
640
+ canBlockSplitRight: value.canBlockSplit));
641
+ }
642
+
607
643
/// Writes a function type or function-typed formal.
608
644
///
609
645
/// If creating a piece for a function-typed formal, then [parameter] is the
610
- /// formal parameter.
646
+ /// formal parameter. If there is a default value, then [defaultValue] is
647
+ /// the `=` or `:` separator followed by the constant expression.
611
648
///
612
649
/// If this is a function-typed initializing formal (`this.foo()` ), then
613
650
/// [fieldKeyword] is `this` and [period] is the `.` . Likewise, for a
@@ -621,44 +658,58 @@ mixin PieceFactory {
621
658
{FormalParameter ? parameter,
622
659
Token ? fieldKeyword,
623
660
Token ? period}) {
624
- Piece ? returnTypePiece;
625
- if (parameter != null && returnType != null ) {
626
- // Attach any parameter metadata and modifiers to the return type.
627
- returnTypePiece =
628
- pieces.build (metadata: parameter.metadata, inlineMetadata: true , () {
629
- pieces.modifier (parameter.requiredKeyword);
630
- pieces.modifier (parameter.covariantKeyword);
631
- pieces.visit (returnType);
632
- });
633
- } else if (returnType != null ) {
634
- returnTypePiece = nodePiece (returnType);
661
+ // If the type is a function-typed parameter with a default value, then
662
+ // grab the default value from the parent node.
663
+ (Token separator, Expression value)? defaultValueRecord;
664
+ if (parameter? .parent
665
+ case DefaultFormalParameter (: var separator? , : var defaultValue? )) {
666
+ defaultValueRecord = (separator, defaultValue);
635
667
}
636
668
637
- // If there's no return type, attach the metadata to the signature.
638
- var signatureMetadata = const < Annotation > [];
639
- if (parameter != null && returnType == null ) {
640
- signatureMetadata = parameter.metadata;
641
- }
669
+ var metadata = parameter? .metadata ?? const < Annotation > [];
670
+ pieces.withMetadata (metadata, inlineMetadata: true , () {
671
+ Piece ? returnTypePiece;
672
+ if (returnType != null ) {
673
+ returnTypePiece = pieces.build (() {
674
+ // Attach any parameter modifiers to the return type.
675
+ if (parameter != null ) {
676
+ pieces.modifier (parameter.requiredKeyword);
677
+ pieces.modifier (parameter.covariantKeyword);
678
+ }
642
679
643
- var signature =
644
- pieces.build (metadata: signatureMetadata, inlineMetadata: true , () {
645
- // If there's no return type, attach the parameter modifiers to the
646
- // signature.
647
- if (parameter != null && returnType == null ) {
648
- pieces.modifier (parameter.requiredKeyword);
649
- pieces.modifier (parameter.covariantKeyword);
680
+ pieces.visit (returnType);
681
+ });
650
682
}
651
683
652
- pieces.token (fieldKeyword);
653
- pieces. token (period);
654
- pieces. token (functionKeywordOrName);
655
- pieces. visit (typeParameters);
656
- pieces.visit (parameters );
657
- pieces.token (question );
658
- });
684
+ var signature = pieces.build (() {
685
+ // If there's no return type, attach the parameter modifiers to the
686
+ // signature.
687
+ if (parameter != null && returnType == null ) {
688
+ pieces.modifier (parameter.requiredKeyword );
689
+ pieces.modifier (parameter.covariantKeyword );
690
+ }
659
691
660
- pieces.add (FunctionPiece (returnTypePiece, signature,
661
- isReturnTypeFunctionType: returnType is GenericFunctionType ));
692
+ pieces.token (fieldKeyword);
693
+ pieces.token (period);
694
+ pieces.token (functionKeywordOrName);
695
+ pieces.visit (typeParameters);
696
+ pieces.visit (parameters);
697
+ pieces.token (question);
698
+ });
699
+
700
+ var function = FunctionPiece (returnTypePiece, signature,
701
+ isReturnTypeFunctionType: returnType is GenericFunctionType );
702
+
703
+ // TODO(rnystrom): It would be good if the AssignPiece created for the
704
+ // default value could treat the parameter list on the left-hand side as
705
+ // block-splittable. But since it's a FunctionPiece and not directly a
706
+ // ListPiece, AssignPiece doesn't support block-splitting it. If #1466 is
707
+ // fixed, that may enable us to handle block-splitting here too. In
708
+ // practice, it doesn't really matter since function-typed formals are
709
+ // deprecated, default values on function-typed parameters are rare, and
710
+ // when both occur, they rarely split.
711
+ writeDefaultValue (function, defaultValueRecord);
712
+ });
662
713
}
663
714
664
715
/// Writes a piece for the header -- everything from the `if` keyword to the
@@ -1316,11 +1367,15 @@ mixin PieceFactory {
1316
1367
/// Writes a piece for a parameter-like constructor: Either a simple formal
1317
1368
/// parameter or a record type field, which is syntactically similar to a
1318
1369
/// parameter.
1370
+ ///
1371
+ /// If the parameter has a default value, then [defaultValue] contains the
1372
+ /// `:` or `=` separator and the constant value expression.
1319
1373
void writeParameter (TypeAnnotation ? type, Token ? name,
1320
1374
{List <Annotation > metadata = const [],
1321
1375
List <Token ?> modifiers = const [],
1322
1376
Token ? fieldKeyword,
1323
- Token ? period}) {
1377
+ Token ? period,
1378
+ (Token separator, Expression value)? defaultValue}) {
1324
1379
// Begin a piece to attach metadata to the parameter.
1325
1380
pieces.withMetadata (metadata, inlineMetadata: true , () {
1326
1381
Piece ? typePiece;
@@ -1351,14 +1406,20 @@ mixin PieceFactory {
1351
1406
});
1352
1407
}
1353
1408
1409
+ Piece parameterPiece;
1354
1410
if (typePiece != null && namePiece != null ) {
1355
1411
// We have both a type and name, allow splitting between them.
1356
- pieces.add (VariablePiece (typePiece, [namePiece], hasType: true ));
1357
- } else if (typePiece != null ) {
1358
- pieces.add (typePiece);
1359
- } else if (namePiece != null ) {
1360
- pieces.add (namePiece);
1412
+ parameterPiece = VariablePiece (typePiece, [namePiece], hasType: true );
1413
+ } else {
1414
+ // Will have at least a type or name.
1415
+ parameterPiece = typePiece ?? namePiece! ;
1361
1416
}
1417
+
1418
+ // If there's a default value, include it. We do that inside here so that
1419
+ // any metadata surrounds the entire assignment instead of being part of
1420
+ // the assignment's left-hand side where a split in the metadata would
1421
+ // force a split at the default value separator.
1422
+ writeDefaultValue (parameterPiece, defaultValue);
1362
1423
});
1363
1424
}
1364
1425
0 commit comments