diff --git a/Sources/Rules.swift b/Sources/Rules.swift index 704ed996c..16c6b59ee 100644 --- a/Sources/Rules.swift +++ b/Sources/Rules.swift @@ -8012,7 +8012,8 @@ public struct _FormatRules { // 1. an identifier like `foo.` // 2. a function call like `foo(...).` // 3. a subscript like `foo[...]. - // 4. Some other combination of parens / subscript like `(foo).` + // 4. a trailing closure like `map { ... }` + // 5. Some other combination of parens / subscript like `(foo).` // or even `foo["bar"]()()`. // And any of these can be preceeded by one of the others switch formatter.tokens[index] { @@ -8045,6 +8046,15 @@ public struct _FormatRules { // - If the previous token is a newline then this isn't a function call // and we'd stop parsing. `foo ()` is a function call but `foo\n()` isn't. return startOfChainComponent(at: previousNonSpaceNonCommentIndex) ?? startOfScopeIndex + + case .endOfScope("}"): + // Stop parsing if we reach a trailing closure. + // Converting this to a for loop would result in unusual looking syntax like + // `for string in strings.map { $0.uppercased() } { print(string) }` + // which causes a warning to be emitted: "trailing closure in this context is + // confusable with the body of the statement; pass as a parenthesized argument + // to silence this warning". + return nil default: return nil diff --git a/Tests/RulesTests+Syntax.swift b/Tests/RulesTests+Syntax.swift index 08a9b8646..235bbdf49 100644 --- a/Tests/RulesTests+Syntax.swift +++ b/Tests/RulesTests+Syntax.swift @@ -3705,7 +3705,7 @@ class SyntaxTests: RulesTests { func testPreservesChainWithClosure() { let input = """ // Converting this to a for loop would result in unusual looking syntax like - // `for string in strings.map { $0.uppercased() } { print($0) }` + // `for string in strings.map { $0.uppercased() } { print(string) }` // which causes a warning to be emitted: "trailing closure in this context is // confusable with the body of the statement; pass as a parenthesized argument // to silence this warning". @@ -3714,6 +3714,18 @@ class SyntaxTests: RulesTests { testFormatting(for: input, rule: FormatRules.forLoop) } + func testPreservesChainWithClosureInMiddleOfChain() { + let input = """ + // Converting this to a for loop would result in unusual looking syntax like + // `for string in strings.map { $0.uppercased() }.values { print(string) }` + // which causes a warning to be emitted: "trailing closure in this context is + // confusable with the body of the statement; pass as a parenthesized argument + // to silence this warning". + strings.map { $0.uppercased() }.values.forEach { print($0) } + """ + testFormatting(for: input, rule: FormatRules.forLoop) + } + func testHandlesTryBeforeForEach() { let input = """ try planets.forEach {