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