Skip to content

Commit 883f4cf

Browse files
authored
Merge pull request swiftlang#180 from dylansturg/nested_trailing_closure_calls
Recursively apply NoEmptyTrailingClosureParentheses rule.
2 parents e6a95c3 + 4058f31 commit 883f4cf

File tree

2 files changed

+63
-9
lines changed

2 files changed

+63
-9
lines changed

Sources/SwiftFormatRules/NoEmptyTrailingClosureParentheses.swift

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,22 +22,31 @@ import SwiftSyntax
2222
public final class NoEmptyTrailingClosureParentheses: SyntaxFormatRule {
2323

2424
public override func visit(_ node: FunctionCallExprSyntax) -> ExprSyntax {
25-
guard node.argumentList.count == 0 else { return ExprSyntax(node) }
25+
guard node.argumentList.count == 0 else { return super.visit(node) }
2626

27-
guard node.trailingClosure != nil && node.argumentList.isEmpty && node.leftParen != nil else {
28-
return ExprSyntax(node)
27+
guard let trailingClosure = node.trailingClosure,
28+
node.argumentList.isEmpty && node.leftParen != nil else
29+
{
30+
return super.visit(node)
2931
}
3032
guard let name = node.calledExpression.lastToken?.withoutTrivia() else {
31-
return ExprSyntax(node)
33+
return super.visit(node)
3234
}
3335

3436
diagnose(.removeEmptyTrailingParentheses(name: "\(name)"), on: node)
3537

38+
// Need to visit `calledExpression` before creating a new node so that the location data (column
39+
// and line numbers) is available.
40+
guard let rewrittenCalledExpr = ExprSyntax(visit(Syntax(node.calledExpression))) else {
41+
return super.visit(node)
42+
}
3643
let formattedExp = replaceTrivia(
37-
on: node.calledExpression,
38-
token: node.calledExpression.lastToken,
44+
on: rewrittenCalledExpr,
45+
token: rewrittenCalledExpr.lastToken,
3946
trailingTrivia: .spaces(1))
47+
let formattedClosure = visit(trailingClosure).as(ClosureExprSyntax.self)
4048
let result = node.withLeftParen(nil).withRightParen(nil).withCalledExpression(formattedExp)
49+
.withTrailingClosure(formattedClosure)
4150
return ExprSyntax(result)
4251
}
4352
}

Tests/SwiftFormatRulesTests/NoEmptyTrailingClosureParenthesesTests.swift

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,21 @@ final class NoEmptyTrailingClosureParenthesesTests: LintOrFormatRuleTestCase {
1919
func myfunc(cls: MyClass) {
2020
cls.myBadClosure() { $0 }
2121
}
22+
DispatchQueue.main.async() {
23+
greetEnthusiastically() { "John" }
24+
DispatchQueue.main.async() {
25+
greetEnthusiastically() { "Willis" }
26+
}
27+
}
28+
DispatchQueue.global.async(inGroup: blah) {
29+
DispatchQueue.main.async() {
30+
greetEnthusiastically() { "Willis" }
31+
}
32+
DispatchQueue.main.async {
33+
greetEnthusiastically() { "Willis" }
34+
}
35+
}
36+
foo(bar() { baz })() { blah }
2237
""",
2338
expected: """
2439
func greetEnthusiastically(_ nameProvider: () -> String) {
@@ -35,9 +50,39 @@ final class NoEmptyTrailingClosureParenthesesTests: LintOrFormatRuleTestCase {
3550
func myfunc(cls: MyClass) {
3651
cls.myBadClosure { $0 }
3752
}
38-
""")
39-
XCTAssertDiagnosed(.removeEmptyTrailingParentheses(name: "greetEnthusiastically"))
40-
XCTAssertDiagnosed(.removeEmptyTrailingParentheses(name: "myBadClosure"))
53+
DispatchQueue.main.async {
54+
greetEnthusiastically { "John" }
55+
DispatchQueue.main.async {
56+
greetEnthusiastically { "Willis" }
57+
}
58+
}
59+
DispatchQueue.global.async(inGroup: blah) {
60+
DispatchQueue.main.async {
61+
greetEnthusiastically { "Willis" }
62+
}
63+
DispatchQueue.main.async {
64+
greetEnthusiastically { "Willis" }
65+
}
66+
}
67+
foo(bar { baz }) { blah }
68+
""",
69+
checkForUnassertedDiagnostics: true)
70+
XCTAssertDiagnosed(
71+
.removeEmptyTrailingParentheses(name: "greetEnthusiastically"), line: 7, column: 1)
72+
XCTAssertDiagnosed(.removeEmptyTrailingParentheses(name: "myBadClosure"), line: 13, column: 3)
4173
XCTAssertNotDiagnosed(.removeEmptyTrailingParentheses(name: "myClosure"))
74+
XCTAssertDiagnosed(.removeEmptyTrailingParentheses(name: "async"), line: 15, column: 1)
75+
XCTAssertDiagnosed(
76+
.removeEmptyTrailingParentheses(name: "greetEnthusiastically"), line: 16, column: 3)
77+
XCTAssertDiagnosed(.removeEmptyTrailingParentheses(name: "async"), line: 17, column: 3)
78+
XCTAssertDiagnosed(
79+
.removeEmptyTrailingParentheses(name: "greetEnthusiastically"), line: 18, column: 5)
80+
XCTAssertDiagnosed(.removeEmptyTrailingParentheses(name: "async"), line: 22, column: 3)
81+
XCTAssertDiagnosed(
82+
.removeEmptyTrailingParentheses(name: "greetEnthusiastically"), line: 23, column: 5)
83+
XCTAssertDiagnosed(
84+
.removeEmptyTrailingParentheses(name: "greetEnthusiastically"), line: 26, column: 5)
85+
XCTAssertDiagnosed(.removeEmptyTrailingParentheses(name: ")"), line: 29, column: 1)
86+
XCTAssertDiagnosed(.removeEmptyTrailingParentheses(name: "bar"), line: 29, column: 5)
4287
}
4388
}

0 commit comments

Comments
 (0)