Skip to content

Commit 8b3428f

Browse files
committed
Add diagnostic if #sourceLocation is followed by any declarations
1 parent 116e6a6 commit 8b3428f

File tree

4 files changed

+60
-9
lines changed

4 files changed

+60
-9
lines changed

Sources/SwiftParser/Directives.swift

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -163,16 +163,8 @@ extension Parser {
163163
}
164164

165165
let (unexpectedBeforePoundEndIf, poundEndIf) = self.expect(.poundEndifKeyword)
166-
var unexpectedAfterPoundEndif: RawUnexpectedNodesSyntax?
167-
if !self.currentToken.isAtStartOfLine {
168-
var unexpectedTokens = [RawTokenSyntax]()
169-
var loopProgress = LoopProgressCondition()
170-
while !self.at(.eof), !currentToken.isAtStartOfLine, loopProgress.evaluate(self.currentToken) {
171-
unexpectedTokens += [self.consumeAnyToken()]
172-
}
166+
let unexpectedAfterPoundEndif = self.consumeRemainingTokenOnLine()
173167

174-
unexpectedAfterPoundEndif = RawUnexpectedNodesSyntax(unexpectedTokens, arena: self.arena)
175-
}
176168
return RawIfConfigDeclSyntax(
177169
clauses: RawIfConfigClauseListSyntax(elements: clauses, arena: self.arena),
178170
unexpectedBeforePoundEndIf,
@@ -267,14 +259,33 @@ extension Parser {
267259
args = nil
268260
}
269261
let (unexpectedBeforeRParen, rparen) = self.expect(.rightParen)
262+
let unexpectedAfterRightParen = self.consumeRemainingTokenOnLine()
263+
270264
return RawPoundSourceLocationSyntax(
271265
poundSourceLocation: line,
272266
unexpectedBeforeLParen,
273267
leftParen: lparen,
274268
args: args,
275269
unexpectedBeforeRParen,
276270
rightParen: rparen,
271+
unexpectedAfterRightParen,
277272
arena: self.arena
278273
)
279274
}
275+
276+
/// Consumes remaining token on the line and returns a ``RawUnexpectedNodesSyntax``
277+
/// if there is any tokens conrumed.
278+
private mutating func consumeRemainingTokenOnLine() -> RawUnexpectedNodesSyntax? {
279+
guard !self.currentToken.isAtStartOfLine else {
280+
return nil
281+
}
282+
283+
var unexpectedTokens = [RawTokenSyntax]()
284+
var loopProgress = LoopProgressCondition()
285+
while !self.at(.eof), !currentToken.isAtStartOfLine, loopProgress.evaluate(self.currentToken) {
286+
unexpectedTokens += [self.consumeAnyToken()]
287+
}
288+
289+
return RawUnexpectedNodesSyntax(unexpectedTokens, arena: self.arena)
290+
}
280291
}

Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1424,6 +1424,22 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
14241424
return .visitChildren
14251425
}
14261426

1427+
public override func visit(_ node: PoundSourceLocationSyntax) -> SyntaxVisitorContinueKind {
1428+
if shouldSkip(node) {
1429+
return .skipChildren
1430+
}
1431+
1432+
if let unexpectedAfterRightParen = node.unexpectedAfterRightParen {
1433+
addDiagnostic(
1434+
unexpectedAfterRightParen,
1435+
.extraTokensAtTheEndOfSourceLocationDirective,
1436+
handledNodes: [unexpectedAfterRightParen.id]
1437+
)
1438+
}
1439+
1440+
return .visitChildren
1441+
}
1442+
14271443
public override func visit(_ node: PrecedenceGroupAssignmentSyntax) -> SyntaxVisitorContinueKind {
14281444
if shouldSkip(node) {
14291445
return .skipChildren

Sources/SwiftParserDiagnostics/ParserDiagnosticMessages.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,9 @@ extension DiagnosticMessage where Self == StaticParserError {
156156
public static var expectedSequenceExpressionInForEachLoop: Self {
157157
.init("expected Sequence expression for for-each loop")
158158
}
159+
public static var extraTokensAtTheEndOfSourceLocationDirective: Self {
160+
.init("extra tokens at the end of #sourceLocation directive")
161+
}
159162
public static var extraTokensFollowingConditionalCompilationDirective: Self {
160163
.init("extra tokens following conditional compilation directive")
161164
}

Tests/SwiftParserTest/DirectiveTests.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,4 +213,25 @@ final class DirectiveTests: XCTestCase {
213213
]
214214
)
215215
}
216+
217+
func testSourcelocationDirectiveFollowedByDeclarations() {
218+
assertParse(
219+
"""
220+
var sometName: Int
221+
#sourceLocation(file: "other.swift", line: 1)
222+
var someName: Int
223+
"""
224+
)
225+
226+
assertParse(
227+
"""
228+
#sourceLocation(file: "other.swift", line: 1)1️⃣; let x = 1
229+
""",
230+
diagnostics: [
231+
DiagnosticSpec(
232+
message: "extra tokens at the end of #sourceLocation directive"
233+
)
234+
]
235+
)
236+
}
216237
}

0 commit comments

Comments
 (0)