Skip to content

Commit ef12dea

Browse files
authored
Merge pull request #1302 from TiagoMaiaL/fix-else_if-diagnostic
2 parents 544f92e + 1ee6a45 commit ef12dea

File tree

4 files changed

+71
-2
lines changed

4 files changed

+71
-2
lines changed

Sources/SwiftParser/Directives.swift

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,15 +106,21 @@ extension Parser {
106106
while let poundIfHandle = firstIteration ? self.canRecoverTo(.poundIfKeyword) : self.canRecoverTo(anyIn: IfConfigContinuationClauseStartKeyword.self)?.handle,
107107
loopProgress.evaluate(self.currentToken)
108108
{
109-
let (unexpectedBeforePoundIf, poundIf) = self.eat(poundIfHandle)
109+
var (unexpectedBeforePoundIf, poundIf) = self.eat(poundIfHandle)
110110
firstIteration = false
111111
// Parse the condition.
112112
let condition: RawExprSyntax?
113113
switch poundIf.tokenKind {
114114
case .poundIfKeyword, .poundElseifKeyword:
115115
condition = RawExprSyntax(self.parseSequenceExpression(.basic, forDirective: true))
116116
case .poundElseKeyword:
117-
condition = nil
117+
if let ifToken = self.consume(if: .init(.if, allowAtStartOfLine: false)) {
118+
unexpectedBeforePoundIf = RawUnexpectedNodesSyntax(combining: unexpectedBeforePoundIf, poundIf, ifToken, arena: self.arena)
119+
poundIf = self.missingToken(.poundElseifKeyword)
120+
condition = RawExprSyntax(self.parseSequenceExpression(.basic, forDirective: true))
121+
} else {
122+
condition = nil
123+
}
118124
default:
119125
preconditionFailure("The loop condition should guarantee that we are at one of these tokens")
120126
}

Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -668,6 +668,37 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
668668
return .visitChildren
669669
}
670670

671+
public override func visit(_ node: IfConfigDeclSyntax) -> SyntaxVisitorContinueKind {
672+
for clause in node.clauses where clause.hasError {
673+
if let unexpectedBeforePoundKeyword = clause.unexpectedBeforePoundKeyword,
674+
clause.poundKeyword.tokenKind == .poundElseifKeyword,
675+
clause.poundKeyword.presence == .missing
676+
{
677+
let unexpectedTokens =
678+
unexpectedBeforePoundKeyword
679+
.suffix(2)
680+
.compactMap { $0.as(TokenSyntax.self) }
681+
if unexpectedTokens.map(\.tokenKind) == [.poundElseKeyword, .keyword(.if)] {
682+
addDiagnostic(
683+
unexpectedBeforePoundKeyword,
684+
StaticParserError.unexpectedPoundElseSpaceIf,
685+
fixIts: [
686+
FixIt(
687+
message: ReplaceTokensFixIt(replaceTokens: unexpectedTokens, replacement: clause.poundKeyword),
688+
changes: [
689+
.makeMissing(unexpectedBeforePoundKeyword, transferTrivia: false),
690+
.makePresent(clause.poundKeyword, leadingTrivia: unexpectedBeforePoundKeyword.leadingTrivia),
691+
]
692+
)
693+
],
694+
handledNodes: [unexpectedBeforePoundKeyword.id, clause.poundKeyword.id]
695+
)
696+
}
697+
}
698+
}
699+
return .visitChildren
700+
}
701+
671702
public override func visit(_ node: InitializerClauseSyntax) -> SyntaxVisitorContinueKind {
672703
if shouldSkip(node) {
673704
return .skipChildren

Sources/SwiftParserDiagnostics/ParserDiagnosticMessages.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,9 @@ extension DiagnosticMessage where Self == StaticParserError {
197197
public static var tryOnInitialValueExpression: Self {
198198
.init("'try' must be placed on the initial value expression")
199199
}
200+
public static var unexpectedPoundElseSpaceIf: Self {
201+
.init("unexpected 'if' keyword following '#else' conditional compilation directive; did you mean '#elseif'?")
202+
}
200203
public static var unexpectedSemicolon: Self {
201204
.init("unexpected ';' separator")
202205
}

Tests/SwiftParserTest/translated/IfconfigExprTests.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,35 @@ final class IfconfigExprTests: XCTestCase {
428428
)
429429
}
430430

431+
func testIfconfigExpr31() {
432+
AssertParse(
433+
"""
434+
#if arch(x86_64)
435+
debugPrint("x86_64")
436+
1️⃣#else if arch(arm64)
437+
debugPrint("arm64")
438+
#else
439+
debugPrint("Some other architecture.")
440+
#endif
441+
""",
442+
diagnostics: [
443+
DiagnosticSpec(
444+
message: "unexpected 'if' keyword following '#else' conditional compilation directive; did you mean '#elseif'?",
445+
fixIts: ["replace '#else if' with '#elseif'"]
446+
)
447+
],
448+
fixedSource: """
449+
#if arch(x86_64)
450+
debugPrint("x86_64")
451+
#elseif arch(arm64)
452+
debugPrint("arm64")
453+
#else
454+
debugPrint("Some other architecture.")
455+
#endif
456+
"""
457+
)
458+
}
459+
431460
func testUnknownPlatform1() {
432461
AssertParse(
433462
"""

0 commit comments

Comments
 (0)