diff --git a/Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift b/Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift index 70d2df47bf1..61228720d9d 100644 --- a/Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift +++ b/Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift @@ -1257,7 +1257,31 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor { node.closeQuote.id, ].compactMap { $0 } ) + } else if node.openQuote.presence == .missing, + node.unexpectedBetweenOpenDelimiterAndOpenQuote == nil, + node.closeQuote.presence == .missing, + node.unexpectedBetweenCloseQuoteAndCloseDelimiter == nil, + !node.segments.isMissingAllTokens + { + addDiagnostic( + node, + MissingBothStringQuotesOfStringSegments(stringSegments: node.segments), + fixIts: [ + FixIt( + message: InsertTokenFixIt(missingNodes: [Syntax(node.openQuote), Syntax(node.closeQuote)]), + changes: [ + .makePresent(node.openQuote), + .makePresent(node.closeQuote), + ] + ) + ], + handledNodes: [ + node.openQuote.id, + node.closeQuote.id, + ] + ) } + for (diagnostic, handledNodes) in MultiLineStringLiteralIndentatinDiagnosticsGenerator.diagnose(node) { addDiagnostic(diagnostic, handledNodes: handledNodes) } diff --git a/Sources/SwiftParserDiagnostics/ParserDiagnosticMessages.swift b/Sources/SwiftParserDiagnostics/ParserDiagnosticMessages.swift index 442cfde55da..80f5e7622da 100644 --- a/Sources/SwiftParserDiagnostics/ParserDiagnosticMessages.swift +++ b/Sources/SwiftParserDiagnostics/ParserDiagnosticMessages.swift @@ -386,6 +386,14 @@ public struct MissingAttributeArgument: ParserError { } } +public struct MissingBothStringQuotesOfStringSegments: ParserError { + public let stringSegments: StringLiteralSegmentsSyntax + + public var message: String { + return #"expected \#(stringSegments.shortSingleLineContentDescription) to be surrounded by '"'"# + } +} + public struct MissingConditionInStatement: ParserError { let node: SyntaxProtocol diff --git a/Tests/SwiftParserTest/AttributeTests.swift b/Tests/SwiftParserTest/AttributeTests.swift index 46fc15627ea..8901150cd76 100644 --- a/Tests/SwiftParserTest/AttributeTests.swift +++ b/Tests/SwiftParserTest/AttributeTests.swift @@ -454,19 +454,14 @@ final class AttributeTests: XCTestCase { assertParse( """ - @_expose(Cxx, 1️⃣baz2️⃣) func foo() {} + @_expose(Cxx, 1️⃣baz) func foo() {} """, diagnostics: [ DiagnosticSpec( locationMarker: "1️⃣", - message: #"expected '"' in string literal"#, - fixIts: [#"insert '"'"#] - ), - DiagnosticSpec( - locationMarker: "2️⃣", - message: #"expected '"' to end string literal"#, - fixIts: [#"insert '"'"#] - ), + message: #"expected code 'baz' to be surrounded by '"'"#, + fixIts: [#"insert '"' and '"'"#] + ) ], fixedSource: """ @_expose(Cxx, "baz") func foo() {} @@ -543,20 +538,15 @@ final class AttributeTests: XCTestCase { assertParse( """ - @_unavailableFromAsync(message: 1️⃣abc2️⃣) + @_unavailableFromAsync(message: 1️⃣abc) func foo() {} """, diagnostics: [ DiagnosticSpec( locationMarker: "1️⃣", - message: #"expected '"' in string literal"#, - fixIts: [#"insert '"'"#] - ), - DiagnosticSpec( - locationMarker: "2️⃣", - message: #"expected '"' to end string literal"#, - fixIts: [#"insert '"'"#] - ), + message: #"expected code 'abc' to be surrounded by '"'"#, + fixIts: [#"insert '"' and '"'"#] + ) ], fixedSource: """ @_unavailableFromAsync(message: "abc") diff --git a/Tests/SwiftParserTest/translated/OriginalDefinedInAttrTests.swift b/Tests/SwiftParserTest/translated/OriginalDefinedInAttrTests.swift index 2d471a6b8d4..5af8c3e2e3e 100644 --- a/Tests/SwiftParserTest/translated/OriginalDefinedInAttrTests.swift +++ b/Tests/SwiftParserTest/translated/OriginalDefinedInAttrTests.swift @@ -86,13 +86,8 @@ final class OriginalDefinedInAttrTests: XCTestCase { ), DiagnosticSpec( locationMarker: "1️⃣", - message: #"expected '"' in string literal"#, - fixIts: [#"insert '"'"#] - ), - DiagnosticSpec( - locationMarker: "2️⃣", - message: #"expected '"' to end string literal"#, - fixIts: [#"insert '"'"#] + message: #"expected code 'OSX' to be surrounded by '"'"#, + fixIts: [#"insert '"' and '"'"#] ), DiagnosticSpec( locationMarker: "2️⃣",