Skip to content

Commit 7ac2bf3

Browse files
committed
Fix indentation of multiline strings when part of a larger expression.
The stacked indentation behavior wasn't robust enough to catch other kinds of subexpressions that a multiline string could be in and our tests weren't thorough enough to catch this. The most common occurrence was when a multiline string was followed by a dotted member access, which caused the string to become unindented one level from where it should have been.
1 parent 420ca57 commit 7ac2bf3

File tree

2 files changed

+70
-1
lines changed

2 files changed

+70
-1
lines changed

Sources/SwiftFormatPrettyPrint/TokenStreamCreator.swift

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3298,7 +3298,8 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
32983298
}
32993299

33003300
/// Walks the expression and returns the leftmost multiline string literal (which might be the
3301-
/// expression itself) if the leftmost child is a multiline string literal.
3301+
/// expression itself) if the leftmost child is a multiline string literal or if it is a unary
3302+
/// operation applied to a multiline string literal.
33023303
///
33033304
/// - Parameter expr: The expression whose leftmost multiline string literal should be returned.
33043305
/// - Returns: The leftmost multiline string literal, or nil if the leftmost subexpression was
@@ -3310,8 +3311,24 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
33103311
return stringLiteralExpr
33113312
case .infixOperatorExpr(let infixOperatorExpr):
33123313
return leftmostMultilineStringLiteral(of: infixOperatorExpr.leftOperand)
3314+
case .forcedValueExpr(let forcedValueExpr):
3315+
return leftmostMultilineStringLiteral(of: forcedValueExpr.expression)
3316+
case .optionalChainingExpr(let optionalChainingExpr):
3317+
return leftmostMultilineStringLiteral(of: optionalChainingExpr.expression)
3318+
case .postfixUnaryExpr(let postfixUnaryExpr):
3319+
return leftmostMultilineStringLiteral(of: postfixUnaryExpr.expression)
3320+
case .prefixOperatorExpr(let prefixOperatorExpr):
3321+
return leftmostMultilineStringLiteral(of: prefixOperatorExpr.postfixExpression)
33133322
case .ternaryExpr(let ternaryExpr):
33143323
return leftmostMultilineStringLiteral(of: ternaryExpr.conditionExpression)
3324+
case .functionCallExpr(let functionCallExpr):
3325+
return leftmostMultilineStringLiteral(of: functionCallExpr.calledExpression)
3326+
case .subscriptExpr(let subscriptExpr):
3327+
return leftmostMultilineStringLiteral(of: subscriptExpr.calledExpression)
3328+
case .memberAccessExpr(let memberAccessExpr):
3329+
return memberAccessExpr.base.flatMap { leftmostMultilineStringLiteral(of: $0) }
3330+
case .postfixIfConfigExpr(let postfixIfConfigExpr):
3331+
return postfixIfConfigExpr.base.flatMap { leftmostMultilineStringLiteral(of: $0) }
33153332
default:
33163333
return nil
33173334
}

Tests/SwiftFormatPrettyPrintTests/StringTests.swift

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,4 +327,56 @@ final class StringTests: PrettyPrintTestCase {
327327

328328
assertPrettyPrintEqual(input: input, expected: expected, linelength: 20)
329329
}
330+
331+
func testLeadingMultilineStringsInOtherExpressions() {
332+
// The stacked indentation behavior needs to drill down into different node types to find the
333+
// leftmost multiline string literal. This makes sure that we cover various cases.
334+
let input =
335+
#"""
336+
let bytes = """
337+
{
338+
"key": "value"
339+
}
340+
""".utf8.count
341+
let json = """
342+
{
343+
"key": "value"
344+
}
345+
""".data(using: .utf8)
346+
let slice = """
347+
{
348+
"key": "value"
349+
}
350+
"""[...]
351+
let forceUnwrap = """
352+
{
353+
"key": "value"
354+
}
355+
"""!
356+
let optionalChaining = """
357+
{
358+
"key": "value"
359+
}
360+
"""?
361+
let postfix = """
362+
{
363+
"key": "value"
364+
}
365+
"""^*^
366+
let prefix = +"""
367+
{
368+
"key": "value"
369+
}
370+
"""
371+
let postfixIf = """
372+
{
373+
"key": "value"
374+
}
375+
"""
376+
#if FLAG
377+
.someMethod
378+
#endif
379+
"""#
380+
assertPrettyPrintEqual(input: input, expected: input + "\n", linelength: 100)
381+
}
330382
}

0 commit comments

Comments
 (0)