Skip to content

Commit

Permalink
Fix issue where for loop would break conditional assignment rule
Browse files Browse the repository at this point in the history
  • Loading branch information
calda authored and nicklockwood committed Nov 18, 2023
1 parent 36344de commit 3bf9d4b
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 7 deletions.
6 changes: 2 additions & 4 deletions Sources/FormattingHelpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1267,11 +1267,9 @@ extension Formatter {
func startOfBody(atStartOfScope startOfScopeIndex: Int) -> Int {
// If this is a closure that has an `in` clause, the body scope starts after that
if isStartOfClosure(at: startOfScopeIndex),
let endOfScopeIndex = endOfScope(at: startOfScopeIndex),
let inToken = index(of: .keyword("in"), in: (startOfScopeIndex + 1) ..< endOfScopeIndex),
!indexIsWithinNestedClosure(inToken, startOfScopeIndex: startOfScopeIndex)
let inKeywordIndex = parseClosureArgumentList(at: startOfScopeIndex)?.inKeywordIndex
{
return inToken
return inKeywordIndex
} else {
return startOfScopeIndex
}
Expand Down
10 changes: 7 additions & 3 deletions Sources/ParsingHelpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1589,14 +1589,18 @@ extension Formatter {
tokens[indexAfterOpenBrace] == .startOfScope("("),
let endOfArgumentsScopeIndex = endOfScope(at: indexAfterOpenBrace),
let firstTokenInArgumentsList = index(of: .nonSpaceOrCommentOrLinebreak, after: indexAfterOpenBrace),
let lastTokenInArgumentsList = index(of: .nonSpaceOrCommentOrLinebreak, before: endOfArgumentsScopeIndex),
let indexAfterArguments = index(of: .nonSpaceOrCommentOrLinebreak, after: endOfArgumentsScopeIndex),
tokens[indexAfterArguments] == .keyword("in")
{
inKeywordIndex = indexAfterArguments

let argumentTokens = tokens[firstTokenInArgumentsList ... lastTokenInArgumentsList].split(separator: .delimiter(","))
argumentNames = argumentTokens.map { $0.first(where: \.isIdentifier)?.string ?? $0[0].string }
// This can be a completely empty argument list, like `{ () in ... }`.
if firstTokenInArgumentsList == endOfArgumentsScopeIndex {
return (argumentNames: [], inKeywordIndex: inKeywordIndex)
}

let argumentTokens = tokens[firstTokenInArgumentsList ... endOfArgumentsScopeIndex].split(separator: .delimiter(","))
argumentNames = argumentTokens.compactMap { $0.first(where: \.isIdentifier)?.string ?? $0[0].string }
}

// Otherwise this is an anonymous closure
Expand Down
16 changes: 16 additions & 0 deletions Tests/RulesTests+Syntax.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3884,6 +3884,22 @@ class SyntaxTests: RulesTests {
testFormatting(for: input, output, rule: FormatRules.conditionalAssignment, options: options)
}

func testDoesntConvertIfStatementWithForLoopInBranch() {
let input = """
var foo: Foo?
if condition {
foo = Foo("foo")
for foo in foos {
print(foo)
}
} else {
foo = Foo("bar")
}
"""
let options = FormatOptions(swiftVersion: "5.9")
testFormatting(for: input, rule: FormatRules.conditionalAssignment, options: options)
}

// MARK: - forLoop

func testConvertSimpleForEachToForLoop() {
Expand Down

0 comments on commit 3bf9d4b

Please sign in to comment.