Skip to content

Commit cd793ad

Browse files
authored
Merge pull request #1345 from ahoppen/ahoppen/5.8-fixes-found-by-source-alteration
[5.8] Fix bugs found by mutating source in SwiftParserTest using alternative token choices
2 parents e1ee3cf + 42c113d commit cd793ad

File tree

10 files changed

+67
-17
lines changed

10 files changed

+67
-17
lines changed

Sources/SwiftParser/Attributes.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ extension Parser {
3232
mutating func parseAttribute() -> RawAttributeListSyntax.Element {
3333
if self.at(.poundIfKeyword) {
3434
return .ifConfigDecl(
35-
self.parsePoundIfDirective { parser -> RawAttributeListSyntax.Element in
35+
self.parsePoundIfDirective { (parser, _) -> RawAttributeListSyntax.Element in
3636
return parser.parseAttribute()
3737
} syntax: { parser, attributes in
3838
return .attributes(RawAttributeListSyntax(elements: attributes, arena: parser.arena))
@@ -494,7 +494,7 @@ extension Parser {
494494
mutating func parseObjectiveCSelector() -> RawObjCSelectorSyntax {
495495
var elements = [RawObjCSelectorPieceSyntax]()
496496
var loopProgress = LoopProgressCondition()
497-
while !self.at(any: [.eof, .rightParen]) && loopProgress.evaluate(currentToken) {
497+
while loopProgress.evaluate(currentToken) {
498498
// Empty selector piece.
499499
if let colon = self.consume(if: .colon) {
500500
elements.append(
@@ -507,7 +507,7 @@ extension Parser {
507507
continue
508508
}
509509

510-
if self.at(.identifier) || self.currentToken.isKeyword {
510+
if self.at(any: [.identifier, .wildcardKeyword]) || self.currentToken.isKeyword {
511511
let name = self.consumeAnyToken()
512512

513513
// If we hit a ')' we may have a zero-argument selector.
@@ -531,6 +531,8 @@ extension Parser {
531531
arena: self.arena
532532
)
533533
)
534+
} else {
535+
break
534536
}
535537
}
536538
return RawObjCSelectorSyntax(elements: elements, arena: self.arena)

Sources/SwiftParser/Declarations.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ extension Parser {
165165
public mutating func parseDeclaration(inMemberDeclList: Bool = false) -> RawDeclSyntax {
166166
switch self.at(anyIn: PoundDeclarationStart.self) {
167167
case (.poundIfKeyword, _)?:
168-
let directive = self.parsePoundIfDirective { parser in
168+
let directive = self.parsePoundIfDirective { (parser, _) in
169169
let parsedDecl = parser.parseDeclaration()
170170
let semicolon = parser.consume(if: .semicolon)
171171
return RawMemberDeclListItemSyntax(

Sources/SwiftParser/Directives.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ extension Parser {
6666
/// into a syntax collection.
6767
@_spi(RawSyntax)
6868
public mutating func parsePoundIfDirective<Element: RawSyntaxNodeProtocol>(
69-
_ parseElement: (inout Parser) -> Element?,
69+
_ parseElement: (_ parser: inout Parser, _ isFirstElement: Bool) -> Element?,
7070
addSemicolonIfNeeded: (_ lastElement: Element, _ newItemAtStartOfLine: Bool, _ parser: inout Parser) -> Element? = { _, _, _ in nil },
7171
syntax: (inout Parser, [Element]) -> RawIfConfigClauseSyntax.Elements?
7272
) -> RawIfConfigDeclSyntax {
@@ -83,7 +83,7 @@ extension Parser {
8383
do {
8484
var firstIteration = true
8585
var loopProgress = LoopProgressCondition()
86-
while let poundIfHandle = self.canRecoverTo(any: firstIteration ? [.poundIfKeyword] : [.poundIfKeyword, .poundElseifKeyword, .poundElseKeyword]),
86+
while let poundIfHandle = self.canRecoverTo(any: firstIteration ? [.poundIfKeyword] : [.poundElseifKeyword, .poundElseKeyword]),
8787
loopProgress.evaluate(self.currentToken)
8888
{
8989
let (unexpectedBeforePoundIf, poundIf) = self.eat(poundIfHandle)
@@ -104,7 +104,7 @@ extension Parser {
104104
var elementsProgress = LoopProgressCondition()
105105
while !self.at(any: [.eof, .poundElseKeyword, .poundElseifKeyword, .poundEndifKeyword]) && elementsProgress.evaluate(currentToken) {
106106
let newItemAtStartOfLine = self.currentToken.isAtStartOfLine
107-
guard let element = parseElement(&self), !element.isEmpty else {
107+
guard let element = parseElement(&self, elements.isEmpty), !element.isEmpty else {
108108
break
109109
}
110110
if let lastElement = elements.last, let fixedUpLastItem = addSemicolonIfNeeded(lastElement, newItemAtStartOfLine, &self) {

Sources/SwiftParser/Expressions.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -624,7 +624,10 @@ extension Parser {
624624
) -> RawExprSyntax {
625625
assert(self.at(.poundIfKeyword))
626626

627-
let config = self.parsePoundIfDirective { parser -> RawExprSyntax? in
627+
let config = self.parsePoundIfDirective { (parser, isFirstElement) -> RawExprSyntax? in
628+
if !isFirstElement {
629+
return nil
630+
}
628631
let head: RawExprSyntax
629632
if parser.at(any: [.period, .prefixPeriod]) {
630633
head = parser.parseDottedExpressionSuffix(nil)

Sources/SwiftParser/RawTokenKindSubset.swift

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -773,16 +773,13 @@ enum PrimaryExpressionStart: RawTokenKindSubset {
773773
enum ExpressionStart: RawTokenKindSubset {
774774
case awaitTryMove(AwaitTryMove)
775775
case expressionPrefixOperator(ExpressionPrefixOperator)
776-
case matchingPatternStart(MatchingPatternStart)
777776
case primaryExpressionStart(PrimaryExpressionStart)
778777

779778
init?(lexeme: Lexer.Lexeme) {
780779
if let subset = AwaitTryMove(lexeme: lexeme) {
781780
self = .awaitTryMove(subset)
782781
} else if let subset = ExpressionPrefixOperator(lexeme: lexeme) {
783782
self = .expressionPrefixOperator(subset)
784-
} else if let subset = MatchingPatternStart(lexeme: lexeme) {
785-
self = .matchingPatternStart(subset)
786783
} else if let subset = PrimaryExpressionStart(lexeme: lexeme) {
787784
self = .primaryExpressionStart(subset)
788785
} else {
@@ -793,15 +790,13 @@ enum ExpressionStart: RawTokenKindSubset {
793790
static var allCases: [ExpressionStart] {
794791
return AwaitTryMove.allCases.map(Self.awaitTryMove)
795792
+ ExpressionPrefixOperator.allCases.map(Self.expressionPrefixOperator)
796-
+ MatchingPatternStart.allCases.map(Self.matchingPatternStart)
797793
+ PrimaryExpressionStart.allCases.map(Self.primaryExpressionStart)
798794
}
799795

800796
var rawTokenKind: RawTokenKind {
801797
switch self {
802798
case .awaitTryMove(let underlyingKind): return underlyingKind.rawTokenKind
803799
case .expressionPrefixOperator(let underlyingKind): return underlyingKind.rawTokenKind
804-
case .matchingPatternStart(let underlyingKind): return underlyingKind.rawTokenKind
805800
case .primaryExpressionStart(let underlyingKind): return underlyingKind.rawTokenKind
806801
}
807802
}
@@ -810,7 +805,6 @@ enum ExpressionStart: RawTokenKindSubset {
810805
switch self {
811806
case .awaitTryMove(let underlyingKind): return underlyingKind.contextualKeyword
812807
case .expressionPrefixOperator(let underlyingKind): return underlyingKind.contextualKeyword
813-
case .matchingPatternStart(let underlyingKind): return underlyingKind.contextualKeyword
814808
case .primaryExpressionStart(let underlyingKind): return underlyingKind.contextualKeyword
815809
}
816810
}

Sources/SwiftParser/Statements.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -752,7 +752,7 @@ extension Parser {
752752
elements.append(
753753
.ifConfigDecl(
754754
self.parsePoundIfDirective(
755-
{ $0.parseSwitchCases(allowStandaloneStmtRecovery: allowStandaloneStmtRecovery) },
755+
{ (parser, _) in parser.parseSwitchCases(allowStandaloneStmtRecovery: allowStandaloneStmtRecovery) },
756756
syntax: { parser, cases in
757757
guard cases.count == 1, let firstCase = cases.first else {
758758
assert(cases.isEmpty)
@@ -766,6 +766,9 @@ extension Parser {
766766
} else if allowStandaloneStmtRecovery && (self.atStartOfExpression() || self.atStartOfStatement() || self.atStartOfDeclaration()) {
767767
// Synthesize a label for the stamenent or declaration that isn't coverd by a case right now.
768768
let statements = parseSwitchCaseBody()
769+
if statements.isEmpty {
770+
break
771+
}
769772
elements.append(
770773
.switchCase(
771774
RawSwitchCaseSyntax(

Sources/SwiftParser/TopLevel.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,8 +201,8 @@ extension Parser {
201201
/// wrapping declaration instead of being consumed by lookeahead.
202202
private mutating func parseItem(isAtTopLevel: Bool = false, allowInitDecl: Bool = true) -> RawCodeBlockItemSyntax.Item {
203203
if self.at(.poundIfKeyword) {
204-
let directive = self.parsePoundIfDirective {
205-
$0.parseCodeBlockItem()
204+
let directive = self.parsePoundIfDirective { (parser, _) in
205+
parser.parseCodeBlockItem()
206206
} addSemicolonIfNeeded: { lastElement, newItemAtStartOfLine, parser in
207207
if lastElement.semicolon == nil && !newItemAtStartOfLine {
208208
return RawCodeBlockItemSyntax(

Tests/SwiftParserTest/AttributeTests.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,13 @@ final class AttributeTests: XCTestCase {
9090
func f(_: Int, _: Int, _: Int, _: Int, _: Int) { }
9191
"""
9292
)
93+
94+
AssertParse(
95+
"""
96+
@objc(_:)
97+
func f(_: Int)
98+
"""
99+
)
93100
}
94101

95102
func testRethrowsAttribute() {

Tests/SwiftParserTest/DirectiveTests.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,22 @@ final class DirectiveTests: XCTestCase {
6969
)
7070
}
7171

72+
func testPostfixIfConfigExpressionContainsPoundIf() {
73+
AssertParse(
74+
"""
75+
b
76+
#if true
77+
.a
78+
1️⃣#if true
79+
#endif
80+
#endif
81+
""",
82+
diagnostics: [
83+
DiagnosticSpec(message: "unexpected code in conditional compilation block")
84+
]
85+
)
86+
}
87+
7288
func testSourceLocation() {
7389
AssertParse(
7490
"""

Tests/SwiftParserTest/StatementTests.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,4 +603,29 @@ final class StatementTests: XCTestCase {
603603
)
604604
)
605605
}
606+
607+
func testPatternExprInSwitchCaseItem() {
608+
AssertParse(
609+
"""
610+
switch x {
611+
case a:
612+
1️⃣is
613+
}
614+
""",
615+
diagnostics: [
616+
DiagnosticSpec(message: "unexpected 'is' keyword in 'switch' statement")
617+
]
618+
)
619+
}
620+
621+
func testStandaloneAtCaseInSwitch() {
622+
AssertParse(
623+
"""
624+
switch x {
625+
1️⃣@case
626+
}
627+
""",
628+
diagnostics: [DiagnosticSpec(message: "unexpected code '@case' in 'switch' statement")]
629+
)
630+
}
606631
}

0 commit comments

Comments
 (0)