Skip to content

Commit 31770ca

Browse files
authored
Merge pull request swiftlang#194 from google/format-tweaks-if-stmts
[Tweaks] Modify control flow wrapping.
2 parents 3257332 + 8f98606 commit 31770ca

File tree

7 files changed

+151
-137
lines changed

7 files changed

+151
-137
lines changed

Sources/SwiftFormatPrettyPrint/TokenStreamCreator.swift

Lines changed: 78 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -367,157 +367,125 @@ private final class TokenStreamCreator: SyntaxVisitor {
367367
// MARK: - Control flow statement nodes
368368

369369
override func visit(_ node: IfStmtSyntax) {
370-
before(node.ifKeyword, tokens: .open(.inconsistent, 3))
371370
after(node.ifKeyword, tokens: .space)
372-
before(node.body.leftBrace, tokens: .break(offset: -3), .close)
373371

374-
if !areBracesCompletelyEmpty(node.body, contentsKeyPath: \.statements) {
375-
after(node.body.leftBrace, tokens: .break(offset: 2), .open(.consistent, 0))
376-
before(node.body.rightBrace, tokens: .break(offset: -2), .close)
377-
} else {
378-
before(node.body.rightBrace, tokens: .break(size: 0))
379-
}
372+
before(node.conditions.firstToken, tokens: .open(.consistent, 0), .open(.inconsistent, 2))
373+
after(node.conditions.lastToken, tokens: .close)
374+
before(node.body.leftBrace, tokens: .break(size: 0), .close, .break)
380375

381-
before(node.elseKeyword, tokens: .break)
382-
after(node.elseKeyword, tokens: .break)
376+
arrangeBracesAndContents(of: node.body, contentsKeyPath: \.statements)
377+
378+
before(node.elseKeyword, tokens: .break(size: maxlinelength))
379+
after(node.elseKeyword, tokens: .space)
383380

384381
if let elseBody = node.elseBody as? CodeBlockSyntax {
385-
if !areBracesCompletelyEmpty(elseBody, contentsKeyPath: \.statements) {
386-
after(elseBody.leftBrace, tokens: .break(offset: 2), .open(.consistent, 0))
387-
before(elseBody.rightBrace, tokens: .break(offset: -2), .close)
388-
} else {
389-
before(elseBody.rightBrace, tokens: .break(size: 0))
390-
}
382+
arrangeBracesAndContents(of: elseBody, contentsKeyPath: \.statements)
391383
}
392384

393385
super.visit(node)
394386
}
395387

396388
override func visit(_ node: GuardStmtSyntax) {
397-
before(node.guardKeyword, tokens: .open(.inconsistent, 6))
398-
after(node.guardKeyword, tokens: .break)
399-
before(node.elseKeyword, tokens: .close, .break)
400-
after(node.elseKeyword, tokens: .break)
401-
402-
if !areBracesCompletelyEmpty(node.body, contentsKeyPath: \.statements) {
403-
after(node.body.leftBrace, tokens: .break(offset: 2), .open(.consistent, 0))
404-
before(node.body.rightBrace, tokens: .break(offset: -2), .close)
405-
} else {
406-
before(node.body.rightBrace, tokens: .break(size: 0))
407-
}
389+
after(node.guardKeyword, tokens: .space)
390+
after(node.elseKeyword, tokens: .space)
391+
392+
before(node.conditions.firstToken, tokens: .open(.consistent, 0), .open(.inconsistent, 2))
393+
after(node.conditions.lastToken, tokens: .close)
394+
before(node.elseKeyword, tokens: .break(size: 0), .close, .break)
395+
396+
arrangeBracesAndContents(of: node.body, contentsKeyPath: \.statements)
408397

409398
super.visit(node)
410399
}
411400

412401
override func visit(_ node: ForInStmtSyntax) {
413-
before(node.firstToken, tokens: .open(.inconsistent, 4))
414-
after(node.labelColon, tokens: .break)
402+
after(node.labelColon, tokens: .space)
415403
after(node.forKeyword, tokens: .space)
416-
before(node.inKeyword, tokens: .break)
404+
405+
before(node.pattern.firstToken, tokens: .open(.consistent, 0), .open(.inconsistent, 0))
406+
407+
before(node.inKeyword, tokens: .break(offset: 2), .open(.inconsistent, 2))
417408
after(node.inKeyword, tokens: .space)
409+
after(node.sequenceExpr.lastToken, tokens: .close)
418410

419-
if let whereClause = node.whereClause {
420-
before(
421-
whereClause.firstToken,
422-
tokens: .close, .break, .open(.inconsistent, 0), .break(size: 0), .open(.consistent, 0)
423-
)
424-
before(node.body.leftBrace, tokens: .break, .close, .close)
425-
} else {
426-
before(node.body.leftBrace, tokens: .close, .break)
427-
}
411+
before(node.whereClause?.whereKeyword, tokens: .break)
412+
before(node.body.leftBrace, tokens: .close, .break(size: 0), .close, .break)
428413

429-
if !areBracesCompletelyEmpty(node.body, contentsKeyPath: \.statements) {
430-
after(node.body.leftBrace, tokens: .break(offset: 2), .open(.consistent, 0))
431-
before(node.body.rightBrace, tokens: .break(offset: -2), .close)
432-
} else {
433-
before(node.body.rightBrace, tokens: .break(size: 0))
434-
}
414+
arrangeBracesAndContents(of: node.body, contentsKeyPath: \.statements)
435415

436416
super.visit(node)
437417
}
438418

439419
override func visit(_ node: WhileStmtSyntax) {
440-
before(node.firstToken, tokens: .open(.inconsistent, 6))
441420
after(node.labelColon, tokens: .space)
442421
after(node.whileKeyword, tokens: .space)
443-
before(node.body.leftBrace, tokens: .break(offset: -6), .close)
444422

445-
if !areBracesCompletelyEmpty(node.body, contentsKeyPath: \.statements) {
446-
after(node.body.leftBrace, tokens: .break(offset: 2), .open(.consistent, 0))
447-
before(node.body.rightBrace, tokens: .break(offset: -2), .close)
448-
} else {
449-
before(node.body.rightBrace, tokens: .break(size: 0))
450-
}
423+
before(node.conditions.firstToken, tokens: .open(.consistent, 0), .open(.inconsistent, 2))
424+
after(node.conditions.lastToken, tokens: .close)
425+
before(node.body.leftBrace, tokens: .break(size: 0), .close, .break)
426+
427+
arrangeBracesAndContents(of: node.body, contentsKeyPath: \.statements)
451428

452429
super.visit(node)
453430
}
454431

455432
override func visit(_ node: RepeatWhileStmtSyntax) {
456-
after(node.repeatKeyword, tokens: .break)
433+
before(node.repeatKeyword, tokens: .reset, .open(.consistent, 0), .open(.inconsistent, 0))
434+
after(node.repeatKeyword, tokens: .space)
457435

458-
if !areBracesCompletelyEmpty(node.body, contentsKeyPath: \.statements) {
459-
after(node.body.leftBrace, tokens: .break(offset: 2), .open(.consistent, 0))
460-
before(node.body.rightBrace, tokens: .break(offset: -2), .close, .open(.inconsistent, 8))
461-
} else {
462-
before(node.body.rightBrace, tokens: .break(size: 0), .open(.inconsistent, 0))
463-
}
436+
arrangeBracesAndContents(of: node.body, contentsKeyPath: \.statements)
464437

465-
before(node.whileKeyword, tokens: .space)
438+
before(node.whileKeyword, tokens: .close, .break, .open(.inconsistent, 0))
466439
after(node.whileKeyword, tokens: .space)
467-
after(node.condition.lastToken, tokens: .close)
440+
441+
before(node.condition.firstToken, tokens: .open(.inconsistent, 2))
442+
after(node.condition.lastToken, tokens: .close, .close, .close)
443+
468444
super.visit(node)
469445
}
470446

471447
override func visit(_ node: DoStmtSyntax) {
448+
before(node.doKeyword, tokens: .reset, .open(.consistent, 0), .open(.inconsistent, 0))
472449
after(node.doKeyword, tokens: .space)
473450

474-
if !areBracesCompletelyEmpty(node.body, contentsKeyPath: \.statements) {
475-
// Use a maxlinelength break to force the body of a "do" to wrap even if it would fit on one
476-
// line, unlike the other braced constructs.
477-
after(
478-
node.body.leftBrace, tokens: .break(size: maxlinelength, offset: 2), .open(.consistent, 0))
479-
before(node.body.rightBrace, tokens: .break(size: maxlinelength, offset: -2), .close)
480-
} else {
481-
before(node.body.rightBrace, tokens: .break(size: 0))
451+
arrangeBracesAndContents(of: node.body, contentsKeyPath: \.statements)
452+
453+
if let catchClauses = node.catchClauses {
454+
// If there is only a single `catch` clause, we precede it with a default break so that it
455+
// only moves to the next line if necessary. If there are multiple `catch` clauses, we use a
456+
// max-line-length break so that each case is forced onto its own line.
457+
if catchClauses.count > 1 {
458+
for catchClause in catchClauses {
459+
before(catchClause.catchKeyword, tokens: .break(size: maxlinelength))
460+
}
461+
} else {
462+
before(catchClauses[0].catchKeyword, tokens: .close, .break, .open(.inconsistent, 0))
463+
}
482464
}
483465

466+
after(node.lastToken, tokens: .close, .close)
467+
484468
super.visit(node)
485469
}
486470

487471
override func visit(_ node: CatchClauseSyntax) {
488-
before(node.catchKeyword, tokens: .space)
489472
before(node.pattern?.firstToken, tokens: .break)
490473

491474
if let whereClause = node.whereClause {
492-
// Use a maxlinelength break to force the body of a "catch" to wrap even if it would fit on
493-
// one line, unlike the other braced constructs.
494-
before(whereClause.firstToken, tokens: .break(offset: 2), .open(.consistent, 0))
495-
before(node.body.leftBrace, tokens: .break(offset: -2), .close)
475+
before(whereClause.whereKeyword, tokens: .break, .open(.consistent, 0))
476+
before(node.body.leftBrace, tokens: .break, .close)
496477
} else {
497478
before(node.body.leftBrace, tokens: .break)
498479
}
499480

500-
if !areBracesCompletelyEmpty(node.body, contentsKeyPath: \.statements) {
501-
after(
502-
node.body.leftBrace, tokens: .break(size: maxlinelength, offset: 2), .open(.consistent, 0))
503-
before(node.body.rightBrace, tokens: .break(size: maxlinelength, offset: -2), .close)
504-
} else {
505-
before(node.body.rightBrace, tokens: .break(size: 0))
506-
}
481+
arrangeBracesAndContents(of: node.body, contentsKeyPath: \.statements)
507482

508483
super.visit(node)
509484
}
510485

511486
override func visit(_ node: DeferStmtSyntax) {
512-
after(node.deferKeyword, tokens: .break)
513-
514-
if !areBracesCompletelyEmpty(node.body, contentsKeyPath: \.statements) {
515-
after(node.body.leftBrace, tokens: .break(offset: 2), .open(.consistent, 0))
516-
before(node.body.rightBrace, tokens: .break(offset: -2), .close)
517-
} else {
518-
before(node.body.rightBrace, tokens: .break(size: 0))
519-
}
520-
487+
after(node.deferKeyword, tokens: .space)
488+
arrangeBracesAndContents(of: node.body, contentsKeyPath: \.statements)
521489
super.visit(node)
522490
}
523491

@@ -1510,6 +1478,25 @@ private final class TokenStreamCreator: SyntaxVisitor {
15101478
return node[keyPath: contentsKeyPath].isEmpty && !commentPrecedesRightBrace
15111479
}
15121480

1481+
/// Applies consistent formatting to the braces and contents of the given node.
1482+
///
1483+
/// - Parameters:
1484+
/// - node: A node that conforms to `BracedSyntax`.
1485+
/// - contentsKeyPath: A keypath describing how to get from `node` to the contents of the node
1486+
/// (a `Collection` whose elements conform to `Syntax`; this will most likely be an instance
1487+
/// of one of the `*ListSyntax` types).
1488+
private func arrangeBracesAndContents<Node: BracedSyntax, BodyContents: Collection>(
1489+
of node: Node,
1490+
contentsKeyPath: KeyPath<Node, BodyContents>
1491+
) where BodyContents.Element: Syntax {
1492+
if !areBracesCompletelyEmpty(node, contentsKeyPath: contentsKeyPath) {
1493+
after(node.leftBrace, tokens: .break(offset: 2), .open(.consistent, 0))
1494+
before(node.rightBrace, tokens: .break(offset: -2), .close)
1495+
} else {
1496+
before(node.rightBrace, tokens: .break(size: 0))
1497+
}
1498+
}
1499+
15131500
private func extractTrailingComment(_ token: TokenSyntax) {
15141501
let nextToken = token.nextToken
15151502
guard let trivia = nextToken?.leadingTrivia,

Tests/SwiftFormatPrettyPrintTests/ForInStmtTests.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ public class ForInStmtTests: PrettyPrintTestCase {
2121
}
2222
2323
for item
24-
in mylargecontainer {
24+
in mylargecontainer
25+
{
2526
let a = 123
2627
let b = item
2728
}
@@ -55,7 +56,8 @@ public class ForInStmtTests: PrettyPrintTestCase {
5556
let b = 456
5657
}
5758
for i in longerarray
58-
where longerarray.isContainer() {
59+
where longerarray.isContainer()
60+
{
5961
let a = 123
6062
let b = 456
6163
}
@@ -84,7 +86,7 @@ public class ForInStmtTests: PrettyPrintTestCase {
8486
let expected =
8587
"""
8688
for item
87-
in aVeryLargeContainterObject
89+
in aVeryLargeContainterObject
8890
where largeObject.hasProperty()
8991
&& condition
9092
{

Tests/SwiftFormatPrettyPrintTests/GuardStmtTests.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,13 @@ public class GuardStmtTests: PrettyPrintTestCase {
3131
var b = "abc"
3232
}
3333
guard let var1 = someFunction(),
34-
let var2 = myFun() else {
34+
let var2 = myFun()
35+
else {
3536
let a = 23
3637
var b = "abc"
3738
}
3839
guard let var1 = someFunction(),
39-
let var2 = myLongFunction()
40+
let var2 = myLongFunction()
4041
else {
4142
let a = 23
4243
var b = "abc"

Tests/SwiftFormatPrettyPrintTests/IfStmtTests.swift

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ public class IfStmtTests: PrettyPrintTestCase {
4848
}
4949
5050
if a123456789 >
51-
b123456 {
51+
b123456
52+
{
5253
let a = 23
5354
var b = "abc"
5455
}
@@ -71,26 +72,31 @@ public class IfStmtTests: PrettyPrintTestCase {
7172
7273
if var1 < var2 {
7374
let a = 23
75+
var c = 45
7476
} else if var3 < var4 {
7577
var b = 123
78+
var c = 456
7679
}
7780
"""
7881

7982
let expected =
8083
"""
8184
if var1 < var2 {
8285
let a = 23
83-
} else if d < e {
86+
}
87+
else if d < e {
8488
var b = 123
85-
} else {
86-
var c = 456
8789
}
90+
else { var c = 456 }
8891
8992
if var1 < var2 {
9093
let a = 23
91-
} else
92-
if var3 < var4 {
94+
var c = 45
95+
}
96+
else if var3 < var4
97+
{
9398
var b = 123
99+
var c = 456
94100
}
95101
96102
"""
@@ -118,7 +124,8 @@ public class IfStmtTests: PrettyPrintTestCase {
118124
var b = "abc"
119125
}
120126
if case .reallyLongCaseName =
121-
reallyLongVariableName {
127+
reallyLongVariableName
128+
{
122129
let a = 123
123130
var b = "abc"
124131
}

Tests/SwiftFormatPrettyPrintTests/RepeatStmtTests.swift

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,17 @@ public class RepeatStmtTests: PrettyPrintTestCase {
22
public func testBasicRepeatTests() {
33
let input =
44
"""
5+
repeat {} while x
6+
7+
repeat { f() } while x
8+
9+
repeat { foo() } while longcondition
10+
511
repeat {
612
let a = 123
713
var b = "abc"
814
} while condition
15+
916
repeat {
1017
let a = 123
1118
var b = "abc"
@@ -14,18 +21,28 @@ public class RepeatStmtTests: PrettyPrintTestCase {
1421

1522
let expected =
1623
"""
24+
repeat {} while x
25+
26+
repeat { f() } while x
27+
28+
repeat { foo() }
29+
while longcondition
30+
1731
repeat {
1832
let a = 123
1933
var b = "abc"
20-
} while condition
34+
}
35+
while condition
36+
2137
repeat {
2238
let a = 123
2339
var b = "abc"
24-
} while condition &&
25-
condition2
40+
}
41+
while condition &&
42+
condition2
2643
2744
"""
2845

29-
assertPrettyPrintEqual(input: input, expected: expected, linelength: 20)
46+
assertPrettyPrintEqual(input: input, expected: expected, linelength: 25)
3047
}
3148
}

0 commit comments

Comments
 (0)