Skip to content

Commit 50b2897

Browse files
committed
Use SourceLocationConverter for whitespace linter diagnostics.
Previously, we were scanning the input string to compute the line and column number for diagnostics emitted by the whitespace linter (and doing this scan for _every_ diagnostic). Since we already have a `SourceLocationConverter` from the parsed source tree, we can just use it instead—it's already cached a mapping from UTF-8 offsets to line/column numbers.
1 parent a2606bb commit 50b2897

File tree

2 files changed

+19
-61
lines changed

2 files changed

+19
-61
lines changed

Sources/SwiftFormatWhitespaceLinter/WhitespaceLinter.swift

Lines changed: 13 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -201,10 +201,8 @@ public class WhitespaceLinter {
201201
return
202202
}
203203

204-
let pos = calculatePosition(offset: adjustedUserOffset, data: self.userText)
205-
206204
isLineTooLong = true
207-
diagnose(.lineLengthError, line: pos.line, column: pos.column, utf8Offset: 0)
205+
diagnose(.lineLengthError, utf8Offset: adjustedUserOffset)
208206
}
209207

210208
/// Compare user and formatted whitespace buffers, and check for indentation errors.
@@ -231,11 +229,7 @@ public class WhitespaceLinter {
231229
if form[0] != user[0] {
232230
let actual = indentation(of: user[0])
233231
let expected = indentation(of: form[0])
234-
diagnose(
235-
.indentationError(expected: expected, actual: actual),
236-
line: 1,
237-
column: 1,
238-
utf8Offset: 0)
232+
diagnose(.indentationError(expected: expected, actual: actual), utf8Offset: 0)
239233
}
240234
}
241235
return
@@ -245,14 +239,10 @@ public class WhitespaceLinter {
245239
offset += user[i].count + 1
246240
}
247241
if form.last != user.last {
248-
let pos = calculatePosition(offset: userOffset + offset, data: self.userText)
249242
let actual = indentation(of: user.last ?? [])
250243
let expected = indentation(of: form.last ?? [])
251244
diagnose(
252-
.indentationError(expected: expected, actual: actual),
253-
line: pos.line,
254-
column: pos.column,
255-
utf8Offset: 0)
245+
.indentationError(expected: expected, actual: actual), utf8Offset: userOffset + offset)
256246
}
257247
}
258248

@@ -269,8 +259,7 @@ public class WhitespaceLinter {
269259
var offset = 0
270260
for i in 0..<(user.count - 1) {
271261
if user[i].count > 0 {
272-
let pos = calculatePosition(offset: userOffset + offset, data: self.userText)
273-
diagnose(.trailingWhitespaceError, line: pos.line, column: pos.column, utf8Offset: 0)
262+
diagnose(.trailingWhitespaceError, utf8Offset: userOffset + offset)
274263
}
275264
offset += user[i].count + 1
276265
}
@@ -295,13 +284,12 @@ public class WhitespaceLinter {
295284
guard form.count == 1 && user.count == 1 && !isFirstCharacter else { return }
296285
guard form[0] != user[0] else { return }
297286

298-
let pos = calculatePosition(offset: userOffset, data: self.userText)
299287
let illegalSpacingCharacters: [UTF8.CodeUnit] = [utf8Tab]
300288
if illegalSpacingCharacters.contains(where: { user[0].contains($0) }) {
301-
diagnose(.spacingCharError, line: pos.line, column: pos.column, utf8Offset: 0)
289+
diagnose(.spacingCharError, utf8Offset: userOffset)
302290
} else if form[0].count != user[0].count {
303291
let delta = form[0].count - user[0].count
304-
diagnose(.spacingError(delta), line: pos.line, column: pos.column, utf8Offset: 0)
292+
diagnose(.spacingError(delta), utf8Offset: userOffset)
305293
}
306294
}
307295

@@ -328,8 +316,7 @@ public class WhitespaceLinter {
328316
guard form.count < user.count else { return }
329317
var offset = 0
330318
for i in 0..<(user.count - form.count) {
331-
let pos = calculatePosition(offset: userOffset + offset, data: self.userText)
332-
diagnose(.removeLineError, line: pos.line, column: pos.column, utf8Offset: 0)
319+
diagnose(.removeLineError, utf8Offset: userOffset + offset)
333320
offset += user[i].count + 1
334321
}
335322
}
@@ -356,10 +343,7 @@ public class WhitespaceLinter {
356343
userOffset: Int, user: [ArraySlice<UTF8.CodeUnit>], form: [ArraySlice<UTF8.CodeUnit>]
357344
) {
358345
guard form.count > user.count && !isLineTooLong else { return }
359-
let pos = calculatePosition(offset: userOffset, data: self.userText)
360-
diagnose(
361-
.addLinesError(form.count - user.count), line: pos.line, column: pos.column, utf8Offset: 0
362-
)
346+
diagnose(.addLinesError(form.count - user.count), utf8Offset: userOffset)
363347
}
364348

365349
/// Find the next non-whitespace character in a given string, and any leading whitespace before
@@ -392,28 +376,6 @@ public class WhitespaceLinter {
392376
return (offset: data.count - 1, char: nil, whitespace: whitespaceBuffer)
393377
}
394378

395-
/// Given a string and a printable charater offset, calculate the line and column number.
396-
///
397-
/// - Parameters:
398-
/// - offset: The printable character offset.
399-
/// - data: The input string for which we want the line and column numbers.
400-
/// - Returns a tuple with the line and column numbers within `data`.
401-
private func calculatePosition(offset: Int, data: [UTF8.CodeUnit]) -> (line: Int, column: Int) {
402-
var line = 1
403-
var column = 0
404-
405-
for (index, char) in data.enumerated() {
406-
if char == utf8Newline {
407-
line += 1
408-
column = 0
409-
} else {
410-
column += 1
411-
}
412-
if index == offset { break }
413-
}
414-
return (line: line, column: column)
415-
}
416-
417379
/// Emits the provided diagnostic message to the DiagnosticEngine. The message will correspond to
418380
/// a specific location (line and column number) in the input Swift source file (`userText`).
419381
///
@@ -425,18 +387,14 @@ public class WhitespaceLinter {
425387
/// - actions: Used for attaching notes, highlights, etc.
426388
private func diagnose(
427389
_ message: Diagnostic.Message,
428-
line: Int,
429-
column: Int,
430390
utf8Offset: Int,
431391
actions: ((inout Diagnostic.Builder) -> Void)? = nil
432392
) {
433-
let loc = SourceLocation(
434-
line: line, column: column, offset: utf8Offset, file: context.fileURL.path)
435-
context.diagnosticEngine?.diagnose(
436-
message,
437-
location: loc,
438-
actions: actions
439-
)
393+
guard let diagnosticEngine = context.diagnosticEngine else { return }
394+
395+
let absolutePosition = AbsolutePosition(utf8Offset: utf8Offset)
396+
let sourceLocation = context.sourceLocationConverter.location(for: absolutePosition)
397+
diagnosticEngine.diagnose(message, location: sourceLocation, actions: actions)
440398
}
441399

442400
/// Returns the indentation that represents the indentation of the given whitespace, which is the

Tests/SwiftFormatWhitespaceLinterTests/WhitespaceLintTests.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ final class WhitespaceLintTests: WhitespaceTestCase {
206206
"""
207207

208208
performWhitespaceLint(input: input, expected: expected)
209-
XCTAssertDiagnosed(.addLinesError(1), line: 2, column: 0)
209+
XCTAssertDiagnosed(.addLinesError(1), line: 1, column: 12)
210210
XCTAssertDiagnosed(.addLinesError(1), line: 3, column: 15)
211211
XCTAssertDiagnosed(.addLinesError(1), line: 3, column: 22)
212212
}
@@ -236,11 +236,11 @@ final class WhitespaceLintTests: WhitespaceTestCase {
236236
"""
237237

238238
performWhitespaceLint(input: input, expected: expected)
239-
XCTAssertDiagnosed(.removeLineError, line: 2, column: 0)
240-
XCTAssertDiagnosed(.removeLineError, line: 4, column: 0)
241-
XCTAssertDiagnosed(.removeLineError, line: 5, column: 0)
242-
XCTAssertDiagnosed(.removeLineError, line: 8, column: 0)
243-
XCTAssertDiagnosed(.removeLineError, line: 9, column: 0)
239+
XCTAssertDiagnosed(.removeLineError, line: 1, column: 12)
240+
XCTAssertDiagnosed(.removeLineError, line: 3, column: 14)
241+
XCTAssertDiagnosed(.removeLineError, line: 4, column: 1)
242+
XCTAssertDiagnosed(.removeLineError, line: 7, column: 15)
243+
XCTAssertDiagnosed(.removeLineError, line: 8, column: 19)
244244
}
245245

246246
func testLineLength() {

0 commit comments

Comments
 (0)