mirror of
https://github.com/nicklockwood/SwiftFormat.git
synced 2026-05-17 10:30:35 +00:00
Fix off-by-one errors in format range
This commit is contained in:
committed by
Cal Stephens
parent
04743b591e
commit
5d8d83ef2f
@@ -431,8 +431,9 @@ public func tokenRange(forLineRange lineRange: ClosedRange<Int>, in tokens: [Tok
|
||||
let startOffset = SourceOffset(line: lineRange.lowerBound, column: 0)
|
||||
let endOffset = SourceOffset(line: lineRange.upperBound + 1, column: 0)
|
||||
// NOTE: tab width is not relevant for line-based offsets
|
||||
return tokenIndex(for: startOffset, in: tokens, tabWidth: 1)
|
||||
..< tokenIndex(for: endOffset, in: tokens, tabWidth: 1)
|
||||
let tokenStart = max(0, tokenIndex(for: startOffset, in: tokens, tabWidth: 1) - 1)
|
||||
let tokenEnd = max(tokenStart, tokenIndex(for: endOffset, in: tokens, tabWidth: 1) - 1)
|
||||
return tokenStart ..< tokenEnd
|
||||
}
|
||||
|
||||
/// Get new offset for an original offset (before formatting)
|
||||
@@ -499,13 +500,14 @@ public func applyRules(
|
||||
to originalTokens: [Token],
|
||||
with options: FormatOptions,
|
||||
trackChanges: Bool,
|
||||
range: Range<Int>?,
|
||||
range originalRange: Range<Int>?,
|
||||
maxIterations: Int = 10
|
||||
) throws -> (tokens: [Token], changes: [Formatter.Change]) {
|
||||
precondition(maxIterations > 1)
|
||||
|
||||
let originalRules = originalRules.sorted()
|
||||
var tokens = originalTokens
|
||||
var range = originalRange
|
||||
|
||||
// Ensure rule names have been set
|
||||
if originalRules.first?.name == FormatRule.unnamedRule {
|
||||
@@ -637,8 +639,9 @@ public func applyRules(
|
||||
return (tokens, changes)
|
||||
}
|
||||
|
||||
// Update tokens
|
||||
// Update tokens and range
|
||||
tokens = newTokens
|
||||
range = formatter.range
|
||||
|
||||
// Remove rules that should only be run once
|
||||
if iteration == 0 {
|
||||
|
||||
@@ -519,7 +519,7 @@ class FormatterTests: XCTestCase {
|
||||
])
|
||||
}
|
||||
|
||||
// MARK: range
|
||||
// MARK: Format range
|
||||
|
||||
func testCodeOutsideRangeNotFormatted() throws {
|
||||
let input = tokenize("""
|
||||
@@ -529,9 +529,14 @@ class FormatterTests: XCTestCase {
|
||||
}
|
||||
""")
|
||||
for range in [0 ..< 2, 5 ..< 7, 14 ..< 16, 17 ..< 19] {
|
||||
XCTAssertEqual(try format(input,
|
||||
rules: FormatRules.all,
|
||||
range: range).tokens, input)
|
||||
XCTAssertEqual(try sourceCode(
|
||||
for: format(
|
||||
input,
|
||||
rules: FormatRules.all,
|
||||
range: range
|
||||
).tokens
|
||||
),
|
||||
sourceCode(for: input), "range \(range)")
|
||||
}
|
||||
let output1 = tokenize("""
|
||||
func foo () {
|
||||
@@ -556,6 +561,63 @@ class FormatterTests: XCTestCase {
|
||||
).tokens), output2)
|
||||
}
|
||||
|
||||
// MARK: format line range
|
||||
|
||||
func testFormattingRange() {
|
||||
let input = """
|
||||
let badlySpaced1:Int = 5
|
||||
let badlySpaced2:Int=5
|
||||
let badlySpaced3 : Int = 5
|
||||
"""
|
||||
let output = """
|
||||
let badlySpaced1:Int = 5
|
||||
let badlySpaced2: Int = 5
|
||||
let badlySpaced3 : Int = 5
|
||||
"""
|
||||
XCTAssertEqual(try format(input, lineRange: 2 ... 2).output, output)
|
||||
}
|
||||
|
||||
func testFormattingRange2() {
|
||||
let input = """
|
||||
enum ImagesToShow {
|
||||
case none
|
||||
case mentioned
|
||||
case all
|
||||
}
|
||||
"""
|
||||
let output = """
|
||||
enum ImagesToShow
|
||||
{
|
||||
case none
|
||||
case mentioned
|
||||
case all
|
||||
}
|
||||
"""
|
||||
let options = FormatOptions(allmanBraces: true)
|
||||
XCTAssertEqual(try format(input, options: options, lineRange: 1 ... 2).output, output)
|
||||
}
|
||||
|
||||
func testFormattingRangeNoCrash() {
|
||||
let input = """
|
||||
func foo() {
|
||||
if bar {
|
||||
print( "foo")
|
||||
}
|
||||
}
|
||||
"""
|
||||
let output = """
|
||||
func foo() {
|
||||
if bar {
|
||||
print("foo")
|
||||
}
|
||||
}
|
||||
"""
|
||||
let inputTokens = tokenize(input), outputTokens = tokenize(output)
|
||||
XCTAssertEqual(tokenRange(forLineRange: 3 ... 4, in: inputTokens), 14 ..< 26)
|
||||
XCTAssertEqual(tokenRange(forLineRange: 3 ... 4, in: outputTokens), 14 ..< 25)
|
||||
XCTAssertEqual(try format(input, lineRange: 3 ... 4).output, output)
|
||||
}
|
||||
|
||||
// MARK: endOfScope
|
||||
|
||||
func testEndOfScopeInSwitch() throws {
|
||||
|
||||
@@ -155,33 +155,6 @@ class SwiftFormatTests: XCTestCase {
|
||||
XCTAssertEqual(try format(input, rules: [], options: options).output, input)
|
||||
}
|
||||
|
||||
// MARK: format line range
|
||||
|
||||
func testFormattingRange() {
|
||||
let input = """
|
||||
let badlySpaced1:Int = 5
|
||||
let badlySpaced2:Int=5
|
||||
let badlySpaced3 : Int = 5
|
||||
"""
|
||||
let output = """
|
||||
let badlySpaced1:Int = 5
|
||||
let badlySpaced2: Int = 5
|
||||
let badlySpaced3 : Int = 5
|
||||
"""
|
||||
XCTAssertEqual(try format(input, lineRange: 2 ... 2).output, output)
|
||||
}
|
||||
|
||||
func testFormattingRangeNoCrash() {
|
||||
let input = """
|
||||
func foo() {
|
||||
if bar {
|
||||
print( "foo")
|
||||
}
|
||||
}
|
||||
"""
|
||||
XCTAssertNoThrow(try format(input, lineRange: 3 ... 4))
|
||||
}
|
||||
|
||||
// MARK: conflict markers
|
||||
|
||||
func testFormattingFailsForConflict() {
|
||||
@@ -264,7 +237,7 @@ class SwiftFormatTests: XCTestCase {
|
||||
|
||||
func testTokenRange() {
|
||||
let tokens = tokenize("// a comment\n let foo = 5\n")
|
||||
XCTAssertEqual(tokenRange(forLineRange: 1 ... 1, in: tokens), 0 ..< 4)
|
||||
XCTAssertEqual(tokenRange(forLineRange: 1 ... 1, in: tokens), 0 ..< 3)
|
||||
}
|
||||
|
||||
// MARK: newOffset
|
||||
|
||||
Reference in New Issue
Block a user