Skip to content

Commit 8adae77

Browse files
committed
Add diagnostic for missing conditions for if statement
1 parent 5faade8 commit 8adae77

File tree

4 files changed

+59
-22
lines changed

4 files changed

+59
-22
lines changed

Sources/SwiftParser/Expressions.swift

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2174,9 +2174,24 @@ extension Parser {
21742174
ifHandle: RecoveryConsumptionHandle
21752175
) -> RawIfExprSyntax {
21762176
let (unexpectedBeforeIfKeyword, ifKeyword) = self.eat(ifHandle)
2177-
// A scope encloses the condition and true branch for any variables bound
2178-
// by a conditional binding. The else branch does *not* see these variables.
2179-
let conditions = self.parseConditionList()
2177+
2178+
let conditions: RawConditionElementListSyntax
2179+
2180+
if self.at(.leftBrace) {
2181+
conditions = RawConditionElementListSyntax(
2182+
elements: [
2183+
RawConditionElementSyntax(
2184+
condition: .expression(RawExprSyntax(RawMissingExprSyntax(arena: self.arena))),
2185+
trailingComma: nil,
2186+
arena: self.arena
2187+
)
2188+
],
2189+
arena: self.arena
2190+
)
2191+
} else {
2192+
conditions = self.parseConditionList()
2193+
}
2194+
21802195
let body = self.parseCodeBlock(introducer: ifKeyword)
21812196

21822197
// The else branch, if any, is outside of the scope of the condition.

Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -755,6 +755,18 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
755755
return .visitChildren
756756
}
757757

758+
public override func visit(_ node: IfExprSyntax) -> SyntaxVisitorContinueKind {
759+
if shouldSkip(node) {
760+
return .skipChildren
761+
}
762+
763+
if node.conditions.count == 1, node.conditions.first?.as(ConditionElementSyntax.self)?.condition.is(MissingExprSyntax.self) == true, !node.body.leftBrace.isMissingAllTokens {
764+
addDiagnostic(node.conditions, MissingConditionInStatement(firstToken: node.ifKeyword), handledNodes: [node.conditions.id])
765+
}
766+
767+
return .visitChildren
768+
}
769+
758770
public override func visit(_ node: InitializerClauseSyntax) -> SyntaxVisitorContinueKind {
759771
if shouldSkip(node) {
760772
return .skipChildren

Sources/SwiftParserDiagnostics/ParserDiagnosticMessages.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,20 @@ public struct MissingAttributeArgument: ParserError {
333333
}
334334
}
335335

336+
public struct MissingConditionInStatement: ParserError {
337+
let firstToken: TokenSyntax
338+
339+
public var message: String {
340+
if let name = firstToken.parent?.ancestorOrSelf(mapping: {
341+
$0.nodeTypeNameForDiagnostics(allowBlockNames: false)
342+
}) {
343+
return "missing condition in \(name)"
344+
} else {
345+
return "missing condition in statement"
346+
}
347+
}
348+
}
349+
336350
public struct MissingExpressionInStatement: ParserError {
337351
let firstToken: TokenSyntax
338352

Tests/SwiftParserTest/translated/RecoveryTests.swift

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -175,26 +175,24 @@ final class RecoveryTests: XCTestCase {
175175
func testRecovery14() {
176176
assertParse(
177177
"""
178-
if {
179-
}1️⃣
178+
if 1️⃣{
179+
}
180180
""",
181181
diagnostics: [
182-
// TODO: Old parser expected error on line 1: missing condition in 'if' statement
183-
DiagnosticSpec(message: "expected code block in 'if' statement")
182+
DiagnosticSpec(message: "missing condition in 'if' statement")
184183
]
185184
)
186185
}
187186

188187
func testRecovery15() {
189188
assertParse(
190189
"""
191-
if
190+
if 1️⃣
192191
{
193-
}1️⃣
192+
}
194193
""",
195194
diagnostics: [
196-
// TODO: Old parser expected error on line 1: missing condition in 'if' statement
197-
DiagnosticSpec(message: "expected code block in 'if' statement")
195+
DiagnosticSpec(message: "missing condition in 'if' statement")
198196
]
199197
)
200198
}
@@ -203,12 +201,11 @@ final class RecoveryTests: XCTestCase {
203201
assertParse(
204202
"""
205203
if true {
206-
} else if {
207-
}1️⃣
204+
} else if 1️⃣{
205+
}
208206
""",
209207
diagnostics: [
210-
// TODO: Old parser expected error on line 2: missing condition in 'if' statement
211-
DiagnosticSpec(message: "expected code block in 'if' statement")
208+
DiagnosticSpec(message: "missing condition in 'if' statement")
212209
]
213210
)
214211
}
@@ -218,11 +215,11 @@ final class RecoveryTests: XCTestCase {
218215
// body, but the error message should be sensible.
219216
assertParse(
220217
"""
221-
if { true } {
218+
if 1️⃣{ true } {
222219
}
223220
""",
224221
diagnostics: [
225-
// TODO: Old parser expected error on line 3: missing condition in 'if' statement
222+
DiagnosticSpec(message: "missing condition in 'if' statement")
226223
// TODO: Old parser expected error on line 3: consecutive statements on a line must be separated by ';', Fix-It replacements: 14 - 14 = ';'
227224
// TODO: Old parser expected error on line 3: closure expression is unused
228225
// TODO: Old parser expected note on line 3: did you mean to use a 'do' statement?, Fix-It replacements: 15 - 15 = 'do '
@@ -234,11 +231,11 @@ final class RecoveryTests: XCTestCase {
234231
func testRecovery18() {
235232
assertParse(
236233
"""
237-
if { true }() {
234+
if 1️⃣{ true }() {
238235
}
239236
""",
240237
diagnostics: [
241-
// TODO: Old parser expected error on line 1: missing condition in 'if' statement
238+
DiagnosticSpec(message: "missing condition in 'if' statement")
242239
]
243240
)
244241
}
@@ -247,13 +244,12 @@ final class RecoveryTests: XCTestCase {
247244
assertParse(
248245
"""
249246
// <rdar://problem/18940198>
250-
if { { } }1️⃣
247+
if 1️⃣{ { } }
251248
""",
252249
diagnostics: [
253-
// TODO: Old parser expected error on line 2: missing condition in 'if' statement
250+
DiagnosticSpec(message: "missing condition in 'if' statement")
254251
// TODO: Old parser expected error on line 2: closure expression is unused
255252
// TODO: Old parser expected note on line 2: did you mean to use a 'do' statement?, Fix-It replacements: 8 - 8 = 'do '
256-
DiagnosticSpec(message: "expected code block in 'if' statement")
257253
]
258254
)
259255
}

0 commit comments

Comments
 (0)