Skip to content

Commit 6181c98

Browse files
committed
Fix missing newline for opening quote for multilines strings
1 parent 574efdf commit 6181c98

File tree

3 files changed

+83
-25
lines changed

3 files changed

+83
-25
lines changed

Sources/SwiftBasicFormat/BasicFormat.swift

Lines changed: 42 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -180,20 +180,41 @@ open class BasicFormat: SyntaxRewriter {
180180
}
181181
}
182182

183-
/// Whether a trailing newline on `token` should be added.
184-
open func requiresTrailingNewline(_ token: TokenSyntax) -> Bool {
185-
// We don't want to add newlines inside string interpolation
186-
if isInsideStringInterpolation(token) && token.tokenKind != .multilineStringQuote {
187-
return false
188-
}
189-
190-
let syntaxToken: Syntax = Syntax(token)
191-
switch syntaxToken.keyPathInParent {
192-
case \StringLiteralExprSyntax.openQuote:
193-
return token.tokenKind == .multilineStringQuote
194-
default:
195-
return false
196-
}
183+
open func requiresNewline(between first: TokenSyntax?, and second: TokenSyntax?) -> Bool {
184+
switch (first?.tokenKind, second?.tokenKind) {
185+
case (.atSign, _),
186+
(.colon, _),
187+
(.comma, _),
188+
(.eof, _),
189+
(.equal, _),
190+
(.identifier, .comma),
191+
(.identifier, .leftBrace),
192+
(.identifier, .leftParen),
193+
(.identifier, .period),
194+
(.identifier, .rightParen),
195+
(.keyword, .arrow),
196+
(.keyword(.await), .identifier),
197+
(.keyword(.async), _),
198+
(.keyword(.false), _),
199+
(.keyword(.func), _),
200+
(.keyword(.let), .identifier),
201+
(.keyword(.let), .wildcard),
202+
(.keyword(.throws), .rightBrace),
203+
(.keyword(.true), _),
204+
(.keyword(.var), .identifier),
205+
(.keyword(.var), .wildcard),
206+
(.leftParen, _),
207+
(.period, .identifier),
208+
(.rightParen, .identifier),
209+
(.rightParen, .keyword(.async)),
210+
(.rightSquareBracket, _),
211+
(_, .colon),
212+
(_, .eof),
213+
(_, .equal):
214+
return false
215+
default:
216+
return true
217+
}
197218
}
198219

199220
open func requiresWhitespace(between first: TokenSyntax?, and second: TokenSyntax?) -> Bool {
@@ -281,15 +302,6 @@ open class BasicFormat: SyntaxRewriter {
281302
return true
282303
}
283304

284-
open func requiresNewline(between first: TokenSyntax?, and second: TokenSyntax?) -> Bool {
285-
switch (first?.tokenKind, second?.tokenKind) {
286-
case (.multilineStringQuote, .stringSegment):
287-
return true
288-
default:
289-
return false
290-
}
291-
}
292-
293305
/// Whether the formatter should consider this token as being mutable.
294306
/// This allows the diagnostic generator to only assume that missing nodes
295307
/// will be mutated. Thus, if two tokens need to be separated by a space, it
@@ -368,7 +380,7 @@ open class BasicFormat: SyntaxRewriter {
368380
var leadingTrivia = token.leadingTrivia
369381
var trailingTrivia = token.trailingTrivia
370382

371-
if requiresLeadingNewline(token) {
383+
if requiresNewline(between: previousToken, and: token) {
372384
// Add a leading newline if the token requires it unless
373385
// - it already starts with a newline or
374386
// - the previous token ends with a newline
@@ -393,6 +405,12 @@ open class BasicFormat: SyntaxRewriter {
393405
anchorPoints[token] = currentIndentationLevel
394406
}
395407

408+
if requiresNewline(between: token, and: nextToken) {
409+
if !trailingTrivia.endsWithNewline && !nextTokenWillStartWithNewline {
410+
trailingTrivia += .newline
411+
}
412+
}
413+
396414
// Add a trailing space to the token unless
397415
// - it already ends with a whitespace or
398416
// - the next token will start starts with a newline after the rewrite

Sources/SwiftParserDiagnostics/MissingNodesError.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ fileprivate func findCommonAncestor(_ nodes: [Syntax]) -> Syntax? {
2222
}
2323

2424
class NoNewlinesFormat: BasicFormat {
25-
override func requiresLeadingNewline(_ token: TokenSyntax) -> Bool {
25+
override func requiresNewline(between first: TokenSyntax?, and second: TokenSyntax?) -> Bool {
2626
return false
2727
}
2828
}

Tests/SwiftSyntaxBuilderTest/StringLiteralExprSyntaxTests.swift

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,4 +334,44 @@ final class StringLiteralExprSyntaxTests: XCTestCase {
334334
"""#
335335
)
336336
}
337+
338+
func testMultiStringOpeningQuote() {
339+
assertBuildResult(
340+
StringLiteralExprSyntax(openQuote: .multilineStringQuoteToken(), content: "a", closeQuote: .multilineStringQuoteToken()),
341+
#"""
342+
"""
343+
a
344+
"""
345+
"""#
346+
)
347+
348+
assertBuildResult(
349+
StringLiteralExprSyntax(
350+
openQuote: .multilineStringQuoteToken(),
351+
segments: StringLiteralSegmentsSyntax {
352+
.expressionSegment(
353+
ExpressionSegmentSyntax(
354+
expressions: TupleExprElementListSyntax {
355+
TupleExprElementSyntax(
356+
expression: StringLiteralExprSyntax(
357+
openQuote: .multilineStringQuoteToken(),
358+
content: "a",
359+
closeQuote: .multilineStringQuoteToken()
360+
)
361+
)
362+
}
363+
)
364+
)
365+
},
366+
closeQuote: .multilineStringQuoteToken()
367+
),
368+
#"""
369+
"""
370+
\("""
371+
a
372+
""")
373+
"""
374+
"""#
375+
)
376+
}
337377
}

0 commit comments

Comments
 (0)