@@ -401,6 +401,25 @@ final class DeclarationTests: XCTestCase {
401
401
func withParameters() {}
402
402
}
403
403
""" ,
404
+ substructure: Syntax ( FunctionDeclSyntax (
405
+ attributes: nil ,
406
+ modifiers: nil ,
407
+ funcKeyword: . funcKeyword( ) ,
408
+ identifier: . identifier( " withoutParameters " ) ,
409
+ genericParameterClause: nil ,
410
+ signature: FunctionSignatureSyntax (
411
+ input: ParameterClauseSyntax (
412
+ leftParen: . leftParenToken( presence: . missing) ,
413
+ parameterList: FunctionParameterListSyntax ( [ ] ) ,
414
+ rightParen: . rightParenToken( presence: . missing)
415
+ ) ,
416
+ asyncOrReasyncKeyword: nil ,
417
+ throwsOrRethrowsKeyword: nil ,
418
+ output: nil
419
+ ) ,
420
+ genericWhereClause: nil ,
421
+ body: nil
422
+ ) ) ,
404
423
diagnostics: [
405
424
DiagnosticSpec ( message: " Expected argument list in function declaration " )
406
425
]
@@ -516,6 +535,146 @@ final class DeclarationTests: XCTestCase {
516
535
]
517
536
)
518
537
}
538
+
539
+ func testRecoverOneExtraLabel( ) {
540
+ AssertParse (
541
+ " (first second #^DIAG^#third: Int) " ,
542
+ { $0. parseFunctionSignature ( ) } ,
543
+ substructure: Syntax ( FunctionParameterSyntax (
544
+ attributes: nil ,
545
+ firstName: TokenSyntax . identifier ( " first " ) ,
546
+ secondName: TokenSyntax . identifier ( " second " ) ,
547
+ UnexpectedNodesSyntax ( [ Syntax ( TokenSyntax . identifier ( " third " ) ) ] ) ,
548
+ colon: TokenSyntax . colonToken ( ) ,
549
+ type: TypeSyntax ( SimpleTypeIdentifierSyntax ( name: TokenSyntax . identifier ( " Int " ) , genericArgumentClause: nil ) ) ,
550
+ ellipsis: nil ,
551
+ defaultArgument: nil ,
552
+ trailingComma: nil
553
+ ) ) ,
554
+ diagnostics: [
555
+ DiagnosticSpec ( message: " Unexpected text 'third' found in function parameter " )
556
+ ]
557
+ )
558
+ }
559
+
560
+ func testRecoverTwoExtraLabels( ) {
561
+ AssertParse (
562
+ " (first second #^DIAG^#third fourth: Int) " ,
563
+ { $0. parseFunctionSignature ( ) } ,
564
+ substructure: Syntax ( FunctionParameterSyntax (
565
+ attributes: nil ,
566
+ firstName: TokenSyntax . identifier ( " first " ) ,
567
+ secondName: TokenSyntax . identifier ( " second " ) ,
568
+ UnexpectedNodesSyntax ( [ Syntax ( TokenSyntax . identifier ( " third " ) ) , Syntax ( TokenSyntax . identifier ( " fourth " ) ) ] ) ,
569
+ colon: TokenSyntax . colonToken ( ) ,
570
+ type: TypeSyntax ( SimpleTypeIdentifierSyntax ( name: TokenSyntax . identifier ( " Int " ) , genericArgumentClause: nil ) ) ,
571
+ ellipsis: nil ,
572
+ defaultArgument: nil ,
573
+ trailingComma: nil
574
+ ) ) ,
575
+ diagnostics: [
576
+ DiagnosticSpec ( message: " Unexpected text 'third fourth' found in function parameter " )
577
+ ]
578
+ )
579
+ }
580
+
581
+ func testDontRecoverFromDeclKeyword( ) {
582
+ AssertParse (
583
+ " func foo(first second #^MISSING_COLON^#third #^MISSING_RPAREN^#struct#^MISSING_IDENTIFIER^##^BRACES^#: Int) {} " ,
584
+ substructure: Syntax ( FunctionParameterSyntax (
585
+ attributes: nil ,
586
+ firstName: . identifier( " first " ) ,
587
+ secondName: . identifier( " second " ) ,
588
+ colon: . colonToken( presence: . missing) ,
589
+ type: TypeSyntax ( SimpleTypeIdentifierSyntax ( name: . identifier( " third " ) , genericArgumentClause: nil ) ) ,
590
+ ellipsis: nil ,
591
+ defaultArgument: nil ,
592
+ trailingComma: nil
593
+ ) ) ,
594
+ diagnostics: [
595
+ DiagnosticSpec ( locationMarker: " MISSING_COLON " , message: " Expected ':' in function parameter " ) ,
596
+ DiagnosticSpec ( locationMarker: " MISSING_RPAREN " , message: " Expected ')' to end parameter clause " ) ,
597
+ // FIXME: We should issues something like "Expected identifier in declaration"
598
+ DiagnosticSpec ( locationMarker: " MISSING_IDENTIFIER " , message: " Expected '' in declaration " ) ,
599
+ DiagnosticSpec ( locationMarker: " BRACES " , message: " Expected '{' " ) ,
600
+ DiagnosticSpec ( locationMarker: " BRACES " , message: " Expected '}' " ) ,
601
+ ]
602
+ )
603
+ }
604
+
605
+ func testRecoverFromParens( ) {
606
+ AssertParse (
607
+ " (first second #^DIAG^#[third fourth]: Int) " ,
608
+ { $0. parseFunctionSignature ( ) } ,
609
+ substructure: Syntax ( FunctionParameterSyntax (
610
+ attributes: nil ,
611
+ firstName: TokenSyntax . identifier ( " first " ) ,
612
+ secondName: TokenSyntax . identifier ( " second " ) ,
613
+ UnexpectedNodesSyntax ( [
614
+ Syntax ( TokenSyntax . leftSquareBracketToken ( ) ) ,
615
+ Syntax ( TokenSyntax . identifier ( " third " ) ) ,
616
+ Syntax ( TokenSyntax . identifier ( " fourth " ) ) ,
617
+ Syntax ( TokenSyntax . rightSquareBracketToken ( ) )
618
+ ] ) ,
619
+ colon: TokenSyntax . colonToken ( ) ,
620
+ type: TypeSyntax ( SimpleTypeIdentifierSyntax ( name: TokenSyntax . identifier ( " Int " ) , genericArgumentClause: nil ) ) ,
621
+ ellipsis: nil ,
622
+ defaultArgument: nil ,
623
+ trailingComma: nil
624
+ ) ) ,
625
+ diagnostics: [
626
+ DiagnosticSpec ( message: " Unexpected text '[third fourth]' found in function parameter " )
627
+ ]
628
+ )
629
+ }
630
+
631
+ func testDontRecoverFromUnbalancedParens( ) {
632
+ AssertParse (
633
+ " func foo(first second #^COLON^#[third #^RSQUARE_COLON^#fourth: Int) {} " ,
634
+ substructure: Syntax ( FunctionParameterSyntax (
635
+ attributes: nil ,
636
+ firstName: TokenSyntax . identifier ( " first " ) ,
637
+ secondName: TokenSyntax . identifier ( " second " ) ,
638
+ colon: TokenSyntax ( . colon, presence: . missing) ,
639
+ type: TypeSyntax ( ArrayTypeSyntax (
640
+ leftSquareBracket: TokenSyntax . leftSquareBracketToken ( ) ,
641
+ elementType: TypeSyntax ( SimpleTypeIdentifierSyntax ( name: TokenSyntax . identifier ( " third " ) , genericArgumentClause: nil ) ) ,
642
+ rightSquareBracket: TokenSyntax ( . rightSquareBracket, presence: . missing)
643
+ ) ) ,
644
+ ellipsis: nil ,
645
+ defaultArgument: nil ,
646
+ trailingComma: nil
647
+ ) ) ,
648
+ diagnostics: [
649
+ DiagnosticSpec ( locationMarker: " COLON " , message: " Expected ':' in function parameter " ) ,
650
+ DiagnosticSpec ( locationMarker: " RSQUARE_COLON " , message: " Expected ']' to end type " ) ,
651
+ DiagnosticSpec ( locationMarker: " RSQUARE_COLON " , message: " Expected ')' to end parameter clause " ) ,
652
+ ]
653
+ )
654
+ }
655
+
656
+ func testDontRecoverIfNewlineIsBeforeColon( ) {
657
+ AssertParse (
658
+ """
659
+ func foo(first second #^COLON^#third#^RPAREN^#
660
+ : Int) {}
661
+ """ ,
662
+ substructure: Syntax ( FunctionParameterSyntax (
663
+ attributes: nil ,
664
+ firstName: TokenSyntax . identifier ( " first " ) ,
665
+ secondName: TokenSyntax . identifier ( " second " ) ,
666
+ colon: TokenSyntax ( . colon, presence: . missing) ,
667
+ type: TypeSyntax ( SimpleTypeIdentifierSyntax ( name: TokenSyntax . identifier ( " third " ) , genericArgumentClause: nil ) ) ,
668
+ ellipsis: nil ,
669
+ defaultArgument: nil ,
670
+ trailingComma: nil
671
+ ) ) ,
672
+ diagnostics: [
673
+ DiagnosticSpec ( locationMarker: " COLON " , message: " Expected ':' in function parameter " ) ,
674
+ DiagnosticSpec ( locationMarker: " RPAREN " , message: " Expected ')' to end parameter clause " ) ,
675
+ ]
676
+ )
677
+ }
519
678
}
520
679
521
680
extension Parser . DeclAttributes {
0 commit comments