Skip to content

Fixed testRecovery157 #1512

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Sources/SwiftParser/Expressions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ extension TokenConsumer {
} else {
return true
}
case (.primaryExpressionStart(.atSign), let handle)?:
break
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added this lines

case (_, _)?:
return true
case nil:
Expand Down Expand Up @@ -1168,6 +1170,8 @@ extension Parser {
arena: self.arena
)
)
case (.atSign, _)?:
return RawExprSyntax(self.parseStringLiteral())
case (.rawStringDelimiter, _)?, (.stringQuote, _)?, (.multilineStringQuote, _)?, (.singleQuote, _)?:
return RawExprSyntax(self.parseStringLiteral())
case (.extendedRegexDelimiter, _)?, (.regexSlash, _)?:
Expand Down
4 changes: 4 additions & 0 deletions Sources/SwiftParser/StringLiterals.swift
Original file line number Diff line number Diff line change
Expand Up @@ -467,8 +467,12 @@ extension Parser {
/// Parse opening raw string delimiter if exist.
let openDelimiter = self.consume(if: .rawStringDelimiter)

/// Try to parse @ in order to recover from Objective-C style literals
let unexpectedAtSign = self.consume(if: .atSign)

/// Parse open quote.
var (unexpectedBeforeOpenQuote, openQuote) = self.expect(.stringQuote, .multilineStringQuote, default: .stringQuote)
unexpectedBeforeOpenQuote = RawUnexpectedNodesSyntax(combining: unexpectedAtSign, unexpectedBeforeOpenQuote, arena: self.arena)
var openQuoteKind: RawTokenKind = openQuote.tokenKind
if openQuote.isMissing, let singleQuote = self.consume(if: .singleQuote) {
unexpectedBeforeOpenQuote = RawUnexpectedNodesSyntax(combining: unexpectedBeforeOpenQuote, singleQuote, arena: self.arena)
Expand Down
3 changes: 3 additions & 0 deletions Sources/SwiftParser/TokenSpecSet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,7 @@ enum ParameterModifier: TokenSpecSet {

enum PrimaryExpressionStart: TokenSpecSet {
case anyKeyword
case atSign // For recovery
case capitalSelfKeyword
case dollarIdentifier
case falseKeyword
Expand Down Expand Up @@ -598,6 +599,7 @@ enum PrimaryExpressionStart: TokenSpecSet {
init?(lexeme: Lexer.Lexeme) {
switch PrepareForKeywordMatch(lexeme) {
case TokenSpec(.Any): self = .anyKeyword
case TokenSpec(.atSign): self = .atSign
case TokenSpec(.Self): self = .capitalSelfKeyword
case TokenSpec(.dollarIdentifier): self = .dollarIdentifier
case TokenSpec(.false): self = .falseKeyword
Expand Down Expand Up @@ -630,6 +632,7 @@ enum PrimaryExpressionStart: TokenSpecSet {
var spec: TokenSpec {
switch self {
case .anyKeyword: return .keyword(.Any)
case .atSign: return .atSign
case .capitalSelfKeyword: return .keyword(.Self)
case .dollarIdentifier: return .dollarIdentifier
case .falseKeyword: return .keyword(.false)
Expand Down
11 changes: 11 additions & 0 deletions Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1003,6 +1003,17 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
if shouldSkip(node) {
return .skipChildren
}
// recover from Objective-C style literals
if let atSign = node.unexpectedBetweenOpenDelimiterAndOpenQuote?.onlyToken(where: { $0.tokenKind == .atSign }) {
addDiagnostic(
node,
.stringLiteralAtSign,
fixIts: [
FixIt(message: RemoveNodesFixIt(atSign), changes: .makeMissing(atSign))
],
handledNodes: [atSign.id]
)
}
if let singleQuote = node.unexpectedBetweenOpenDelimiterAndOpenQuote?.onlyToken(where: { $0.tokenKind == .singleQuote }) {
let fixIt = FixIt(
message: ReplaceTokensFixIt(replaceTokens: [singleQuote], replacement: node.openQuote),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,9 @@ extension DiagnosticMessage where Self == StaticParserError {
public static var standaloneSemicolonStatement: Self {
.init("standalone ';' statements are not allowed")
}
public static var stringLiteralAtSign: Self {
.init("string literals in Swift are not preceded by an '@' sign")
}
public static var subscriptsCannotHaveNames: Self {
.init("subscripts cannot have a name")
}
Expand Down
14 changes: 9 additions & 5 deletions Tests/SwiftParserTest/translated/RecoveryTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1881,16 +1881,20 @@ final class RecoveryTests: XCTestCase {
}

func testRecovery157() {
// <rdar://problem/19833424> QoI: Bad error message when using Objective-C literals (@"Hello")
assertParse(
#"""
// <rdar://problem/19833424> QoI: Bad error message when using Objective-C literals (@"Hello") in Swift files
let myString = 1️⃣@"foo"
"""#,
diagnostics: [
// TODO: Old parser expected error on line 2: string literals in Swift are not preceded by an '@' sign, Fix-It replacements: 16 - 17 = ''
DiagnosticSpec(message: "expected expression in variable"),
DiagnosticSpec(message: #"extraneous code '@"foo"' at top level"#),
]
DiagnosticSpec(
message: "string literals in Swift are not preceded by an '@' sign",
fixIts: ["remove '@'"]
)
],
fixedSource: """
let myString = "foo"
"""
)
}

Expand Down