Skip to content

Commit a666fd3

Browse files
committed
[SwiftParser] Ignore '(' on newline after attribute name
Some builtin attributes mistakingly accepted '(' on newline, while custom attribute didn't. For consistency, ignore '(' on next line.
1 parent 9453f46 commit a666fd3

File tree

5 files changed

+70
-4
lines changed

5 files changed

+70
-4
lines changed

Sources/SwiftParser/Attributes.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,12 +203,12 @@ extension Parser {
203203
case .customAttribute:
204204
shouldParseArgument = self.withLookahead { $0.atAttributeOrSpecifierArgument() }
205205
case .optional:
206-
shouldParseArgument = self.at(.leftParen)
206+
shouldParseArgument = self.at(TokenSpec(.leftParen, allowAtStartOfLine: false))
207207
case .noArgument:
208208
shouldParseArgument = false
209209
}
210210
if shouldParseArgument {
211-
var (unexpectedBeforeLeftParen, leftParen) = self.expect(.leftParen)
211+
var (unexpectedBeforeLeftParen, leftParen) = self.expect(TokenSpec(.leftParen, allowAtStartOfLine: false))
212212
if unexpectedBeforeLeftParen == nil
213213
&& (attributeName.raw.trailingTriviaByteLength > 0 || leftParen.leadingTriviaByteLength > 0)
214214
{

Sources/SwiftParser/Directives.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ extension Parser {
213213
/// Parse a line control directive.
214214
mutating func parsePoundSourceLocationDirective() -> RawPoundSourceLocationSyntax {
215215
let line = self.consumeAnyToken()
216-
let (unexpectedBeforeLParen, lparen) = self.expect(.leftParen)
216+
let (unexpectedBeforeLParen, lparen) = self.expect(TokenSpec(.leftParen, allowAtStartOfLine: false))
217217
let arguments: RawPoundSourceLocationArgumentsSyntax?
218218
if !self.at(.rightParen) {
219219
let (unexpectedBeforeFile, file) = self.expect(.keyword(.file))

Tests/SwiftParserTest/AttributeTests.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,21 @@ final class AttributeTests: ParserTestCase {
213213
)
214214
}
215215

216+
func testObjCAttributeNewlineParen() {
217+
assertParse(
218+
"""
219+
@objc
220+
1️⃣(foo) func foo()
221+
""",
222+
diagnostics: [
223+
DiagnosticSpec(
224+
locationMarker: "1️⃣",
225+
message: "unexpected code '(foo)' in function"
226+
)
227+
]
228+
)
229+
}
230+
216231
func testRethrowsAttribute() {
217232
assertParse(
218233
"""

Tests/SwiftParserTest/AvailabilityTests.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,4 +204,33 @@ final class AvailabilityTests: ParserTestCase {
204204
]
205205
)
206206
}
207+
208+
func testAvailableNewlineParen() {
209+
assertParse(
210+
"""
211+
@available1️⃣
212+
2️⃣(*, unavailable) func foo() {}
213+
""",
214+
diagnostics: [
215+
DiagnosticSpec(
216+
locationMarker: "1️⃣",
217+
message: "expected '()' in attribute",
218+
fixIts: ["insert '()'"]
219+
),
220+
DiagnosticSpec(
221+
locationMarker: "1️⃣",
222+
message: "expected argument for '@available' attribute",
223+
fixIts: ["insert attribute argument"]
224+
),
225+
DiagnosticSpec(
226+
locationMarker: "2️⃣",
227+
message: "unexpected code '(*, unavailable)' in function"
228+
),
229+
],
230+
fixedSource: """
231+
@available()
232+
(*, unavailable) func foo() {}
233+
"""
234+
)
235+
}
207236
}

Tests/SwiftParserTest/DirectiveTests.swift

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ final class DirectiveTests: ParserTestCase {
358358
)
359359
}
360360

361-
func testIfConfigRRR() {
361+
func testIfConfigAfterAttribute() {
362362
assertParse(
363363
"""
364364
@frozen1️⃣
@@ -436,4 +436,26 @@ final class DirectiveTests: ParserTestCase {
436436
"""
437437
)
438438
}
439+
440+
func testSourcelocationDirectiveNewlineParen() {
441+
assertParse(
442+
"""
443+
#sourceLocation1️⃣
444+
(file: "other.swift", line: 1)
445+
var someName: Int
446+
""",
447+
diagnostics: [
448+
DiagnosticSpec(
449+
locationMarker: "1️⃣",
450+
message: "expected '(', arguments, and ')' in '#sourceLocation' directive",
451+
fixIts: ["insert '(', arguments, and ')'"]
452+
)
453+
],
454+
fixedSource: """
455+
#sourceLocation(file: "", line: <#integer literal#>)
456+
(file: "other.swift", line: 1)
457+
var someName: Int
458+
"""
459+
)
460+
}
439461
}

0 commit comments

Comments
 (0)