Skip to content

Commit 44cfdf8

Browse files
authored
Merge pull request #141 from dylansturg/absorb_more_tokens
Absorb condition element trailing commas and case label colons in grouped compound exprs
2 parents b6c05ed + 408b216 commit 44cfdf8

File tree

5 files changed

+138
-13
lines changed

5 files changed

+138
-13
lines changed

Sources/SwiftFormatPrettyPrint/TokenStreamCreator.swift

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,10 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
4545
/// breaks and start/end contextual breaking tokens have been inserted.
4646
private var preVisitedExprs = [ExprSyntax]()
4747

48-
/// Lists the tokens that are the closing or right parens of a parenthesized expression (i.e. a
49-
/// tuple expression with 1 element).
50-
private var parenthesizedExprParens = Set<TokenSyntax>()
48+
/// Lists the tokens that are the closing or final delimiter of a node that shouldn't be split
49+
/// from the preceding token. When breaks are inserted around compound expressions, the breaks are
50+
/// moved past these tokens.
51+
private var closingDelimiterTokens = Set<TokenSyntax>()
5152

5253
init(configuration: Configuration, operatorContext: OperatorContext) {
5354
self.config = configuration
@@ -624,6 +625,7 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
624625
}
625626

626627
after(node.colon, tokens: .close)
628+
closingDelimiterTokens.insert(node.colon)
627629
return .visitChildren
628630
}
629631

@@ -649,7 +651,7 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
649651
// `stackedIndentationBehavior`).
650652
after(node.leftParen, tokens: .open)
651653
before(node.rightParen, tokens: .close)
652-
parenthesizedExprParens.insert(node.rightParen)
654+
closingDelimiterTokens.insert(node.rightParen)
653655

654656
// When there's a comment inside of a parenthesized expression, we want to allow the comment
655657
// to exist at the EOL with the left paren or on its own line. The contents are always
@@ -1321,6 +1323,7 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
13211323
before(node.firstToken, tokens: .open)
13221324
if let comma = node.trailingComma {
13231325
after(comma, tokens: .close, .break(.same))
1326+
closingDelimiterTokens.insert(comma)
13241327
} else {
13251328
after(node.lastToken, tokens: .close)
13261329
}
@@ -1357,7 +1360,7 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
13571360
// When the ternary is wrapped in parens, absorb the closing paren into the ternary's group so
13581361
// that it is glued to the last token of the ternary.
13591362
let closeScopeToken: TokenSyntax?
1360-
if let parenExpr = outerMostEnclosingParenthesizedExpr(from: Syntax(node.secondChoice)) {
1363+
if let parenExpr = outermostEnclosingNode(from: Syntax(node.secondChoice)) {
13611364
closeScopeToken = parenExpr.lastToken
13621365
} else {
13631366
closeScopeToken = node.secondChoice.lastToken
@@ -2878,17 +2881,17 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
28782881
}
28792882
}
28802883

2881-
/// Returns the node for the outermost parenthesized expr (i.e. a single element tuple) that is
2882-
/// ended at the given node. When the given node is not the last component of a parenthesized
2883-
/// expression, this method returns nil.
2884-
private func outerMostEnclosingParenthesizedExpr(from node: Syntax) -> Syntax? {
2885-
guard let afterToken = node.lastToken?.nextToken, parenthesizedExprParens.contains(afterToken)
2884+
/// Returns the outermost node enclosing the given node whose closing delimiter(s) must be kept
2885+
/// alongside the last token of the given node. Any tokens between `node.lastToken` and the
2886+
/// returned node's `lastToken` are delimiter tokens that shouldn't be preceded by a break.
2887+
private func outermostEnclosingNode(from node: Syntax) -> Syntax? {
2888+
guard let afterToken = node.lastToken?.nextToken, closingDelimiterTokens.contains(afterToken)
28862889
else {
28872890
return nil
28882891
}
28892892
var parenthesizedExpr = afterToken.parent
28902893
while let nextToken = parenthesizedExpr?.lastToken?.nextToken,
2891-
parenthesizedExprParens.contains(nextToken),
2894+
closingDelimiterTokens.contains(nextToken),
28922895
let nextExpr = nextToken.parent
28932896
{
28942897
parenthesizedExpr = nextExpr
@@ -2925,7 +2928,7 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
29252928
// When `rhs` side is the last sequence in an enclosing parenthesized expression, absorb the
29262929
// paren into the right hand side by unindenting after the final closing paren. This glues
29272930
// the paren to the last token of `rhs`.
2928-
if let unindentingParenExpr = outerMostEnclosingParenthesizedExpr(from: Syntax(rhs)) {
2931+
if let unindentingParenExpr = outermostEnclosingNode(from: Syntax(rhs)) {
29292932
return (unindentingNode: unindentingParenExpr, shouldReset: true)
29302933
}
29312934
return (unindentingNode: Syntax(rhs), shouldReset: true)
@@ -2947,7 +2950,7 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
29472950
// When `rhs` side is the last sequence in an enclosing parenthesized expression, absorb the
29482951
// paren into the right hand side by unindenting after the final closing paren. This glues the
29492952
// paren to the last token of `rhs`.
2950-
if let unindentingParenExpr = outerMostEnclosingParenthesizedExpr(from: Syntax(rhs)) {
2953+
if let unindentingParenExpr = outermostEnclosingNode(from: Syntax(rhs)) {
29512954
return (unindentingNode: unindentingParenExpr, shouldReset: true)
29522955
}
29532956
return (unindentingNode: Syntax(parenthesizedExpr), shouldReset: false)

Tests/SwiftFormatPrettyPrintTests/GuardStmtTests.swift

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,4 +259,49 @@ final class GuardStmtTests: PrettyPrintTestCase {
259259

260260
assertPrettyPrintEqual(input: input, expected: expected, linelength: 50)
261261
}
262+
263+
func testCompoundClauses() {
264+
let input =
265+
"""
266+
guard foo &&
267+
bar < 1 || bar
268+
> 1,
269+
let quxxe = 0
270+
else {
271+
// do something
272+
}
273+
guard
274+
bar < 1 && (
275+
baz
276+
> 1
277+
),
278+
let quxxe = 0
279+
else {
280+
// blah
281+
}
282+
"""
283+
284+
let expected =
285+
"""
286+
guard
287+
foo && bar < 1
288+
|| bar
289+
> 1,
290+
let quxxe = 0
291+
else {
292+
// do something
293+
}
294+
guard
295+
bar < 1
296+
&& (baz
297+
> 1),
298+
let quxxe = 0
299+
else {
300+
// blah
301+
}
302+
303+
"""
304+
305+
assertPrettyPrintEqual(input: input, expected: expected, linelength: 50)
306+
}
262307
}

Tests/SwiftFormatPrettyPrintTests/IfStmtTests.swift

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,4 +446,46 @@ final class IfStmtTests: PrettyPrintTestCase {
446446

447447
assertPrettyPrintEqual(input: input, expected: expected, linelength: 50)
448448
}
449+
450+
func testCompoundClauses() {
451+
let input =
452+
"""
453+
if foo &&
454+
bar < 1 || bar
455+
> 1,
456+
let quxxe = 0
457+
{
458+
// do something
459+
}
460+
if bar < 1 && (
461+
baz
462+
> 1
463+
),
464+
let quxxe = 0
465+
{
466+
// blah
467+
}
468+
"""
469+
470+
let expected =
471+
"""
472+
if foo && bar < 1
473+
|| bar
474+
> 1,
475+
let quxxe = 0
476+
{
477+
// do something
478+
}
479+
if bar < 1
480+
&& (baz
481+
> 1),
482+
let quxxe = 0
483+
{
484+
// blah
485+
}
486+
487+
"""
488+
489+
assertPrettyPrintEqual(input: input, expected: expected, linelength: 50)
490+
}
449491
}

Tests/SwiftFormatPrettyPrintTests/SwitchStmtTests.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,4 +256,36 @@ final class SwitchStmtTests: PrettyPrintTestCase {
256256

257257
assertPrettyPrintEqual(input: input, expected: expected, linelength: 80)
258258
}
259+
260+
func testSwitchSequenceExprCases() {
261+
let input =
262+
"""
263+
switch foo {
264+
case bar && baz
265+
+ quxxe:
266+
break
267+
case baz where bar && (quxxe
268+
+ 10000):
269+
break
270+
}
271+
"""
272+
273+
let expected =
274+
"""
275+
switch foo {
276+
case bar
277+
&& baz
278+
+ quxxe:
279+
break
280+
case baz
281+
where bar
282+
&& (quxxe
283+
+ 10000):
284+
break
285+
}
286+
287+
"""
288+
289+
assertPrettyPrintEqual(input: input, expected: expected, linelength: 40)
290+
}
259291
}

Tests/SwiftFormatPrettyPrintTests/XCTestManifests.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,7 @@ extension GuardStmtTests {
336336
// `swift test --generate-linuxmain`
337337
// to regenerate.
338338
static let __allTests__GuardStmtTests = [
339+
("testCompoundClauses", testCompoundClauses),
339340
("testContinuationLineBreaking", testContinuationLineBreaking),
340341
("testGuardStatement", testGuardStatement),
341342
("testGuardWithFuncCall", testGuardWithFuncCall),
@@ -364,6 +365,7 @@ extension IfStmtTests {
364365
// `swift test --generate-linuxmain`
365366
// to regenerate.
366367
static let __allTests__IfStmtTests = [
368+
("testCompoundClauses", testCompoundClauses),
367369
("testConditionExpressionOperatorGrouping", testConditionExpressionOperatorGrouping),
368370
("testConditionExpressionOperatorGroupingMixedWithParentheses", testConditionExpressionOperatorGroupingMixedWithParentheses),
369371
("testContinuationLineBreakIndentation", testContinuationLineBreakIndentation),
@@ -667,6 +669,7 @@ extension SwitchStmtTests {
667669
("testNewlinesDisambiguatingWhereClauses", testNewlinesDisambiguatingWhereClauses),
668670
("testSwitchCases", testSwitchCases),
669671
("testSwitchCompoundCases", testSwitchCompoundCases),
672+
("testSwitchSequenceExprCases", testSwitchSequenceExprCases),
670673
("testSwitchValueBinding", testSwitchValueBinding),
671674
("testUnknownDefault", testUnknownDefault),
672675
]

0 commit comments

Comments
 (0)