Skip to content

Commit 38bd131

Browse files
committed
Add diagnostic for unexpected second identifier
1 parent 07c08da commit 38bd131

File tree

7 files changed

+45
-17
lines changed

7 files changed

+45
-17
lines changed

Sources/SwiftParser/Patterns.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,12 @@ extension Parser {
219219
let labelAndColon = self.consume(if: .identifier, followedBy: .colon)
220220
let (label, colon) = (labelAndColon?.0, labelAndColon?.1)
221221
let pattern = self.parsePattern()
222-
let trailingComma = self.consume(if: .comma)
222+
var trailingComma = self.consume(if: .comma)
223+
224+
if trailingComma == nil && currentToken.rawTokenKind == .identifier {
225+
trailingComma = self.missingToken(RawTokenKind.comma)
226+
}
227+
223228
keepGoing = trailingComma != nil
224229
elements.append(
225230
RawTuplePatternElementSyntax(

Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -878,6 +878,24 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
878878
return .visitChildren
879879
}
880880

881+
public override func visit(_ node: PatternBindingSyntax) -> SyntaxVisitorContinueKind {
882+
if shouldSkip(node) {
883+
return .skipChildren
884+
}
885+
886+
if let tuplePatternSyntax = node.pattern.as(TuplePatternSyntax.self) {
887+
for element in tuplePatternSyntax.elements where element.hasError && element.trailingComma?.isMissingAllTokens == true {
888+
if let previousToken = node.previousToken(viewMode: .sourceAccurate) {
889+
addDiagnostic(element, position: element.nextToken?.position, SpaceSeparatedIdentifiersError(firstToken: previousToken, additionalTokens: []))
890+
}
891+
}
892+
} else if node.typeAnnotation?.hasError == true, let typeAnnotation = node.typeAnnotation, let previousToken = node.previousToken(viewMode: .sourceAccurate), typeAnnotation.colon.hasError {
893+
addDiagnostic(typeAnnotation.type, SpaceSeparatedIdentifiersError(firstToken: previousToken, additionalTokens: []))
894+
}
895+
896+
return .visitChildren
897+
}
898+
881899
public override func visit(_ node: PrecedenceGroupAssignmentSyntax) -> SyntaxVisitorContinueKind {
882900
if shouldSkip(node) {
883901
return .skipChildren

Sources/SwiftParserDiagnostics/ParserDiagnosticMessages.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -341,13 +341,16 @@ public struct SpaceSeparatedIdentifiersError: ParserError {
341341
public let additionalTokens: [TokenSyntax]
342342

343343
public var message: String {
344+
let text: String
344345
if let name = firstToken.parent?.ancestorOrSelf(mapping: {
345346
$0.nodeTypeNameForDiagnostics(allowBlockNames: false)
346347
}) {
347-
return "found an unexpected second identifier in \(name)"
348+
text = "found an unexpected second identifier in \(name)"
348349
} else {
349-
return "found an unexpected second identifier"
350+
text = "found an unexpected second identifier"
350351
}
352+
353+
return "\(text); is there an accidental break?"
351354
}
352355
}
353356

Tests/SwiftParserTest/ParserTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public class ParserTests: XCTestCase {
5454
}
5555
}
5656

57-
/// Run parsr tests on all of the Swift files in the given path, recursively.
57+
/// Run parser tests on all of the Swift files in the given path, recursively.
5858
func runParserTests(
5959
name: String,
6060
path: URL,

Tests/SwiftParserTest/TypeTests.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ final class TypeTests: XCTestCase {
2222
var foo 1️⃣Bar = 1
2323
""",
2424
diagnostics: [
25-
DiagnosticSpec(message: "expected ':' in type annotation")
25+
DiagnosticSpec(message: "expected ':' in type annotation"),
26+
DiagnosticSpec(message: "found an unexpected second identifier in variable; is there an accidental break?"),
2627
]
2728
)
2829
}

Tests/SwiftParserTest/translated/InvalidTests.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,7 @@ final class InvalidTests: XCTestCase {
394394
""",
395395
diagnostics: [
396396
DiagnosticSpec(
397-
message: "found an unexpected second identifier in function",
397+
message: "found an unexpected second identifier in function; is there an accidental break?",
398398
fixIts: [
399399
"join the identifiers together",
400400
"join the identifiers together with camel-case",
@@ -413,7 +413,7 @@ final class InvalidTests: XCTestCase {
413413
""",
414414
diagnostics: [
415415
DiagnosticSpec(
416-
message: "found an unexpected second identifier in function",
416+
message: "found an unexpected second identifier in function; is there an accidental break?",
417417
fixIts: [
418418
"join the identifiers together",
419419
"join the identifiers together with camel-case",
@@ -432,7 +432,7 @@ final class InvalidTests: XCTestCase {
432432
""",
433433
diagnostics: [
434434
DiagnosticSpec(
435-
message: "found an unexpected second identifier in function",
435+
message: "found an unexpected second identifier in function; is there an accidental break?",
436436
fixIts: [
437437
"join the identifiers together",
438438
"join the identifiers together with camel-case",
@@ -450,7 +450,7 @@ final class InvalidTests: XCTestCase {
450450
func cat 1️⃣Mouse() {}
451451
""",
452452
diagnostics: [
453-
DiagnosticSpec(message: "found an unexpected second identifier in function", fixIts: ["join the identifiers together"])
453+
DiagnosticSpec(message: "found an unexpected second identifier in function; is there an accidental break?", fixIts: ["join the identifiers together"])
454454
],
455455
fixedSource: "func catMouse() {}"
456456
)
@@ -463,7 +463,7 @@ final class InvalidTests: XCTestCase {
463463
""",
464464
diagnostics: [
465465
DiagnosticSpec(
466-
message: "found an unexpected second identifier in function",
466+
message: "found an unexpected second identifier in function; is there an accidental break?",
467467
fixIts: [
468468
"join the identifiers together",
469469
"join the identifiers together with camel-case",

Tests/SwiftParserTest/translated/RecoveryTests.swift

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -765,7 +765,7 @@ final class RecoveryTests: XCTestCase {
765765
protocol Multi 1️⃣ident {}
766766
""",
767767
diagnostics: [
768-
DiagnosticSpec(message: "found an unexpected second identifier in protocol")
768+
DiagnosticSpec(message: "found an unexpected second identifier in protocol; is there an accidental break?")
769769
]
770770
)
771771
}
@@ -776,7 +776,7 @@ final class RecoveryTests: XCTestCase {
776776
class CCC 1️⃣CCC<T> {}
777777
""",
778778
diagnostics: [
779-
DiagnosticSpec(message: "found an unexpected second identifier in class")
779+
DiagnosticSpec(message: "found an unexpected second identifier in class; is there an accidental break?")
780780
],
781781
fixedSource: """
782782
class CCCCCC<T> {}
@@ -793,7 +793,7 @@ final class RecoveryTests: XCTestCase {
793793
}
794794
""",
795795
diagnostics: [
796-
DiagnosticSpec(locationMarker: "1️⃣", message: "found an unexpected second identifier in enum"),
796+
DiagnosticSpec(locationMarker: "1️⃣", message: "found an unexpected second identifier in enum; is there an accidental break?"),
797797
DiagnosticSpec(locationMarker: "2️⃣", message: "consecutive declarations on a line must be separated by ';'"),
798798
DiagnosticSpec(locationMarker: "3️⃣", message: "unexpected code 'a' before enum case"),
799799
]
@@ -812,11 +812,12 @@ final class RecoveryTests: XCTestCase {
812812
}
813813
"""#,
814814
diagnostics: [
815-
DiagnosticSpec(locationMarker: "1️⃣", message: "found an unexpected second identifier in struct"),
815+
DiagnosticSpec(locationMarker: "1️⃣", message: "found an unexpected second identifier in struct; is there an accidental break?"),
816816
DiagnosticSpec(locationMarker: "2️⃣", message: "expected ':' in type annotation"),
817+
DiagnosticSpec(locationMarker: "2️⃣", message: "found an unexpected second identifier in variable; is there an accidental break?"),
817818
DiagnosticSpec(locationMarker: "3️⃣", message: #"unexpected code ': Int = ""' before function"#),
818-
// TODO: (good first issue) Old parser expected error on line 4: found an unexpected second identifier in variable declaration; is there an accidental break?
819819
DiagnosticSpec(locationMarker: "4️⃣", message: "expected ':' in type annotation"),
820+
DiagnosticSpec(locationMarker: "4️⃣", message: "found an unexpected second identifier in variable; is there an accidental break?"),
820821
]
821822
)
822823
}
@@ -827,8 +828,8 @@ final class RecoveryTests: XCTestCase {
827828
let (efg 1️⃣hij, foobar) = (5, 6)
828829
""",
829830
diagnostics: [
830-
// TODO: (good first issue) Old parser expected error on line 1: found an unexpected second identifier in constant declaration; is there an accidental break?
831-
DiagnosticSpec(message: "unexpected code 'hij, foobar' in tuple pattern")
831+
DiagnosticSpec(message: "expected ',' in tuple pattern"),
832+
DiagnosticSpec(message: "found an unexpected second identifier in variable; is there an accidental break?"),
832833
]
833834
)
834835
}

0 commit comments

Comments
 (0)