forked from realm/SwiftLint
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCommandVisitor.swift
46 lines (41 loc) · 1.79 KB
/
CommandVisitor.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import SwiftSyntax
// MARK: - CommandVisitor
/// Visits the source syntax tree to collect all SwiftLint-style comment commands.
final class CommandVisitor: SyntaxVisitor {
private(set) var commands: [Command] = []
let locationConverter: SourceLocationConverter
init(locationConverter: SourceLocationConverter) {
self.locationConverter = locationConverter
super.init(viewMode: .sourceAccurate)
}
override func visitPost(_ node: TokenSyntax) {
collectCommands(in: node.leadingTrivia, offset: node.position)
collectCommands(in: node.trailingTrivia, offset: node.endPositionBeforeTrailingTrivia)
}
private func collectCommands(in trivia: Trivia, offset: AbsolutePosition) {
var position = offset
for piece in trivia {
switch piece {
case .lineComment(let comment):
guard let lower = comment.range(of: "swiftlint:")?.lowerBound.samePosition(in: comment.utf8) else {
break
}
let offset = comment.utf8.distance(from: comment.utf8.startIndex, to: lower)
let location = locationConverter.location(for: position.advanced(by: offset))
let line = locationConverter.sourceLines[location.line - 1]
guard let character = line.characterPosition(of: location.column) else {
break
}
let command = Command(
commandString: String(comment[lower...]),
line: location.line,
range: character..<(character + piece.sourceLength.utf8Length - offset)
)
commands.append(command)
default:
break
}
position += piece.sourceLength
}
}
}