Skip to content

Commit b4b07dd

Browse files
committed
Add diagnostic for empty switch cases
1 parent 7ad2a4f commit b4b07dd

File tree

5 files changed

+34
-20
lines changed

5 files changed

+34
-20
lines changed

Sources/SwiftParser/Expressions.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2222,8 +2222,9 @@ extension Parser {
22222222
) -> RawSwitchExprSyntax {
22232223
let (unexpectedBeforeSwitchKeyword, switchKeyword) = self.eat(switchHandle)
22242224

2225+
// if there is no expression, like `switch { default: return false }` then left brace will be parsed as
2226+
// an `RawClosureExprSyntax`.
22252227
let subject: RawExprSyntax
2226-
22272228
if self.at(.leftBrace) {
22282229
subject = RawExprSyntax(RawMissingExprSyntax(arena: self.arena))
22292230
} else {

Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,6 +1034,10 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
10341034
addDiagnostic(node.expression, .missingExpressionInSwitchStatement, handledNodes: [node.expression.id])
10351035
}
10361036

1037+
if node.cases.isEmpty && !node.leftBrace.isMissingAllTokens && !node.rightBrace.isMissingAllTokens {
1038+
addDiagnostic(node.cases, .emptySwitchExprBody, handledNodes: [node.cases.id])
1039+
}
1040+
10371041
return .visitChildren
10381042
}
10391043

Sources/SwiftParserDiagnostics/ParserDiagnosticMessages.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,9 @@ extension DiagnosticMessage where Self == StaticParserError {
122122
public static var editorPlaceholderInSourceFile: Self {
123123
.init("editor placeholder in source file")
124124
}
125+
public static var emptySwitchExprBody: Self {
126+
.init("'switch' statement body must have at least one 'case' or 'default' block")
127+
}
125128
public static var escapedNewlineAtLatlineOfMultiLineStringLiteralNotAllowed: Self {
126129
.init("escaped newline at the last line of a multi-line string literal is not allowed")
127130
}

Tests/SwiftParserTest/ExpressionTests.swift

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1645,11 +1645,14 @@ final class StatementExpressionTests: XCTestCase {
16451645
func testStandaloneAtCaseInSwitch() {
16461646
AssertParse(
16471647
"""
1648-
switch x {
1649-
1️⃣@case
1648+
switch x {1️⃣
1649+
2️⃣@case
16501650
}
16511651
""",
1652-
diagnostics: [DiagnosticSpec(message: "unexpected code '@case' in 'switch' statement")]
1652+
diagnostics: [
1653+
DiagnosticSpec(locationMarker: "1️⃣", message: "'switch' statement body must have at least one 'case' or 'default' block"),
1654+
DiagnosticSpec(locationMarker: "2️⃣", message: "unexpected code '@case' in 'switch' statement"),
1655+
]
16531656
)
16541657
}
16551658

Tests/SwiftParserTest/translated/RecoveryTests.swift

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -613,20 +613,20 @@ final class RecoveryTests: XCTestCase {
613613
switch1️⃣
614614
""",
615615
diagnostics: [
616-
DiagnosticSpec(message: "expected expression and '{}' to end 'switch' statement")
616+
DiagnosticSpec(locationMarker: "1️⃣", message: "expected expression and '{}' to end 'switch' statement")
617617
]
618618
)
619619
}
620620

621621
func testRecovery46() {
622622
AssertParse(
623623
"""
624-
switch 1️⃣{
624+
switch 1️⃣{2️⃣
625625
}
626626
""",
627627
diagnostics: [
628-
DiagnosticSpec(message: "expected expression in 'switch' statement")
629-
// TODO: Old parser expected error on line 1: 'switch' statement body must have at least one 'case' or 'default' block
628+
DiagnosticSpec(locationMarker: "1️⃣", message: "expected expression in 'switch' statement"),
629+
DiagnosticSpec(locationMarker: "2️⃣", message: "'switch' statement body must have at least one 'case' or 'default' block"),
630630
]
631631
)
632632
}
@@ -635,12 +635,12 @@ final class RecoveryTests: XCTestCase {
635635
AssertParse(
636636
"""
637637
switch 1️⃣
638-
{
638+
{2️⃣
639639
}
640640
""",
641641
diagnostics: [
642-
DiagnosticSpec(message: "expected expression in 'switch' statement")
643-
// TODO: Old parser expected error on line 1: 'switch' statement body must have at least one 'case' or 'default' block
642+
DiagnosticSpec(locationMarker: "1️⃣", message: "expected expression in 'switch' statement"),
643+
DiagnosticSpec(locationMarker: "2️⃣", message: "'switch' statement body must have at least one 'case' or 'default' block"),
644644
]
645645
)
646646
}
@@ -667,36 +667,39 @@ final class RecoveryTests: XCTestCase {
667667
}
668668
""",
669669
diagnostics: [
670-
DiagnosticSpec(locationMarker: "1️⃣", message: "expected expression in 'switch' statement"),
670+
DiagnosticSpec(locationMarker: "1️⃣", message: "expected expression in 'switch' statement")
671671
// TODO: Old parser expected error on line 2: 'is' keyword required to pattern match against type name, Fix-It replacements: 10 - 10 = 'is '
672-
DiagnosticSpec(locationMarker: "2️⃣", message: "'case' can only appear inside a 'switch' statement or 'enum' declaration"),
673-
DiagnosticSpec(locationMarker: "3️⃣", message: "'case' can only appear inside a 'switch' statement or 'enum' declaration"),
674672
]
675673
)
676674
}
677675

678676
func testRecovery50() {
679677
AssertParse(
680678
"""
681-
switch 1️⃣{ 42 } {
682-
case _: return
679+
switch 1️⃣{ 2️⃣42 } {
680+
3️⃣case _: return
683681
}
684682
""",
685683
diagnostics: [
686-
DiagnosticSpec(locationMarker: "1️⃣", message: "expected expression in 'switch' statement")
684+
DiagnosticSpec(locationMarker: "1️⃣", message: "expected expression in 'switch' statement"),
685+
DiagnosticSpec(locationMarker: "2️⃣", message: "all statements inside a switch must be covered by a 'case' or 'default' label"),
686+
DiagnosticSpec(locationMarker: "3️⃣", message: "'case' can only appear inside a 'switch' statement or 'enum' declaration"),
687687
]
688688
)
689689
}
690690

691691
func testRecovery51() {
692692
AssertParse(
693693
"""
694-
switch 1️⃣{ 42 }() {
695-
case _: return
694+
switch 1️⃣{ 2️⃣42 }()3️⃣ {
695+
4️⃣case _: return
696696
}
697697
""",
698698
diagnostics: [
699-
DiagnosticSpec(locationMarker: "1️⃣", message: "expected expression in 'switch' statement")
699+
DiagnosticSpec(locationMarker: "1️⃣", message: "expected expression in 'switch' statement"),
700+
DiagnosticSpec(locationMarker: "2️⃣", message: "all statements inside a switch must be covered by a 'case' or 'default' label"),
701+
DiagnosticSpec(locationMarker: "3️⃣", message: "consecutive statements on a line must be separated by ';'"),
702+
DiagnosticSpec(locationMarker: "4️⃣", message: "'case' can only appear inside a 'switch' statement or 'enum' declaration"),
700703
]
701704
)
702705
}

0 commit comments

Comments
 (0)