Compare commits
3 Commits
main
...
pt-byte-ap
Author | SHA1 | Date |
---|---|---|
![]() |
6240b5a606 | |
![]() |
4e01095004 | |
![]() |
1a28275891 |
|
@ -9,7 +9,7 @@
|
|||
url = https://github.com/Carthage/Commandant.git
|
||||
[submodule "Carthage/Checkouts/SourceKitten"]
|
||||
path = Carthage/Checkouts/SourceKitten
|
||||
url = https://github.com/jpsim/SourceKitten.git
|
||||
url = https://github.com/PaulTaykalo/SourceKitten.git
|
||||
[submodule "Carthage/Checkouts/SwiftyTextTable"]
|
||||
path = Carthage/Checkouts/SwiftyTextTable
|
||||
url = https://github.com/scottrhoyt/SwiftyTextTable.git
|
||||
|
|
2
Cartfile
2
Cartfile
|
@ -1,2 +1,2 @@
|
|||
github "jpsim/SourceKitten" ~> 0.28.0
|
||||
github "PaulTaykalo/SourceKitten" "update/framework-api-visibility"
|
||||
github "scottrhoyt/SwiftyTextTable" ~> 0.9.0
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
github "Carthage/Commandant" "0.17.0"
|
||||
github "PaulTaykalo/SourceKitten" "76350746e111778cc9e5893d35ddbcabe5f366dd"
|
||||
github "drmohundro/SWXMLHash" "5.0.1"
|
||||
github "jpsim/SourceKitten" "0.28.0"
|
||||
github "jpsim/Yams" "2.0.0"
|
||||
github "jspahrsummers/xcconfigs" "0.12"
|
||||
github "scottrhoyt/SwiftyTextTable" "0.9.0"
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 97b5848e5692150d75b5cf0b81d7ebef5f4d5071
|
||||
Subproject commit 003611a7f24b192ba86eba27e88b39718cd16eba
|
|
@ -33,8 +33,8 @@
|
|||
"repositoryURL": "https://github.com/Quick/Nimble.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "b02b00b30b6353632aa4a5fb6124f8147f7140c0",
|
||||
"version": "8.0.5"
|
||||
"revision": "6abeb3f5c03beba2b9e4dbe20886e773b5b629b6",
|
||||
"version": "8.0.4"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -48,11 +48,11 @@
|
|||
},
|
||||
{
|
||||
"package": "SourceKitten",
|
||||
"repositoryURL": "https://github.com/jpsim/SourceKitten.git",
|
||||
"repositoryURL": "https://github.com/PaulTaykalo/SourceKitten.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "97b5848e5692150d75b5cf0b81d7ebef5f4d5071",
|
||||
"version": "0.28.0"
|
||||
"branch": "update/framework-api-visibility",
|
||||
"revision": "76350746e111778cc9e5893d35ddbcabe5f366dd",
|
||||
"version": null
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
@ -15,7 +15,7 @@ let package = Package(
|
|||
],
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/Carthage/Commandant.git", .upToNextMinor(from: "0.17.0")),
|
||||
.package(url: "https://github.com/jpsim/SourceKitten.git", from: "0.28.0"),
|
||||
.package(url: "https://github.com/PaulTaykalo/SourceKitten.git", .branch("update/framework-api-visibility")),
|
||||
.package(url: "https://github.com/jpsim/Yams.git", from: "2.0.0"),
|
||||
.package(url: "https://github.com/scottrhoyt/SwiftyTextTable.git", from: "0.9.0"),
|
||||
] + (addCryptoSwift ? [.package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", .upToNextMinor(from: "1.0.0"))] : []),
|
||||
|
|
|
@ -38,13 +38,19 @@ public struct SourceKittenDictionary {
|
|||
}
|
||||
|
||||
/// Body length
|
||||
var bodyLength: Int? {
|
||||
return (value["key.bodylength"] as? Int64).flatMap({ Int($0) })
|
||||
var bodyLength: ByteCount? {
|
||||
return (value["key.bodylength"] as? Int64).map(ByteCount.init)
|
||||
}
|
||||
|
||||
/// Body offset.
|
||||
var bodyOffset: Int? {
|
||||
return (value["key.bodyoffset"] as? Int64).flatMap({ Int($0) })
|
||||
var bodyOffset: ByteCount? {
|
||||
return (value["key.bodyoffset"] as? Int64).map(ByteCount.init)
|
||||
}
|
||||
|
||||
/// Body byte range.
|
||||
var bodyByteRange: ByteRange? {
|
||||
guard let offset = bodyOffset, let length = bodyLength else { return nil }
|
||||
return ByteRange(location: offset, length: length)
|
||||
}
|
||||
|
||||
/// Kind.
|
||||
|
@ -53,8 +59,8 @@ public struct SourceKittenDictionary {
|
|||
}
|
||||
|
||||
/// Length.
|
||||
var length: Int? {
|
||||
return (value["key.length"] as? Int64).flatMap({ Int($0) })
|
||||
var length: ByteCount? {
|
||||
return (value["key.length"] as? Int64).map(ByteCount.init)
|
||||
}
|
||||
/// Name.
|
||||
var name: String? {
|
||||
|
@ -62,24 +68,30 @@ public struct SourceKittenDictionary {
|
|||
}
|
||||
|
||||
/// Name length.
|
||||
var nameLength: Int? {
|
||||
return (value["key.namelength"] as? Int64).flatMap({ Int($0) })
|
||||
var nameLength: ByteCount? {
|
||||
return (value["key.namelength"] as? Int64).map(ByteCount.init)
|
||||
}
|
||||
|
||||
/// Name offset.
|
||||
var nameOffset: Int? {
|
||||
return (value["key.nameoffset"] as? Int64).flatMap({ Int($0) })
|
||||
var nameOffset: ByteCount? {
|
||||
return (value["key.nameoffset"] as? Int64).map(ByteCount.init)
|
||||
}
|
||||
|
||||
/// Byte range of name.
|
||||
var nameByteRange: ByteRange? {
|
||||
guard let offset = nameOffset, let length = nameLength else { return nil }
|
||||
return ByteRange(location: offset, length: length)
|
||||
}
|
||||
|
||||
/// Offset.
|
||||
var offset: Int? {
|
||||
return (value["key.offset"] as? Int64).flatMap({ Int($0) })
|
||||
var offset: ByteCount? {
|
||||
return (value["key.offset"] as? Int64).map(ByteCount.init)
|
||||
}
|
||||
|
||||
/// Returns byte range starting from `offset` with `length` bytes
|
||||
var byteRange: NSRange? {
|
||||
var byteRange: ByteRange? {
|
||||
guard let offset = offset, let length = length else { return nil }
|
||||
return NSRange(location: offset, length: length)
|
||||
return ByteRange(location: offset, length: length)
|
||||
}
|
||||
|
||||
/// Setter accessibility.
|
||||
|
@ -93,13 +105,13 @@ public struct SourceKittenDictionary {
|
|||
}
|
||||
|
||||
/// Documentation offset.
|
||||
var docOffset: Int? {
|
||||
return (value["key.docoffset"] as? Int64).flatMap({ Int($0) })
|
||||
var docOffset: ByteCount? {
|
||||
return (value["key.docoffset"] as? Int64).flatMap(ByteCount.init)
|
||||
}
|
||||
|
||||
/// Documentation length.
|
||||
var docLength: Int? {
|
||||
return (value["key.doclength"] as? Int64).flatMap({ Int($0) })
|
||||
var docLength: ByteCount? {
|
||||
return (value["key.doclength"] as? Int64).flatMap(ByteCount.init)
|
||||
}
|
||||
|
||||
/// The attribute for this dictionary, as returned by SourceKit.
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import Foundation
|
||||
import SourceKittenFramework
|
||||
|
||||
extension SourceKittenDictionary {
|
||||
/// Returns array of tuples containing "key.kind" and "byteRange" from Structure
|
||||
|
@ -7,20 +8,19 @@ extension SourceKittenDictionary {
|
|||
/// - parameter byteOffset: Int?
|
||||
///
|
||||
/// - returns: The kinds and byte ranges.
|
||||
internal func kinds(forByteOffset byteOffset: Int? = nil)
|
||||
-> [(kind: String, byteRange: NSRange)] {
|
||||
var results = [(kind: String, byteRange: NSRange)]()
|
||||
internal func kinds(forByteOffset byteOffset: ByteCount? = nil)
|
||||
-> [(kind: String, byteRange: ByteRange)] {
|
||||
var results = [(kind: String, byteRange: ByteRange)]()
|
||||
|
||||
func parse(_ dictionary: SourceKittenDictionary) {
|
||||
guard let offset = dictionary.offset,
|
||||
let byteRange = dictionary.length.map({ NSRange(location: offset, length: $0) }) else {
|
||||
return
|
||||
guard let range = dictionary.byteRange else {
|
||||
return
|
||||
}
|
||||
if let byteOffset = byteOffset, !NSLocationInRange(byteOffset, byteRange) {
|
||||
if let byteOffset = byteOffset, !range.contains(byteOffset) {
|
||||
return
|
||||
}
|
||||
if let kind = dictionary.kind {
|
||||
results.append((kind: kind, byteRange: byteRange))
|
||||
results.append((kind: kind, byteRange: range))
|
||||
}
|
||||
dictionary.substructure.forEach(parse)
|
||||
}
|
||||
|
@ -28,14 +28,12 @@ extension SourceKittenDictionary {
|
|||
return results
|
||||
}
|
||||
|
||||
internal func structures(forByteOffset byteOffset: Int) -> [SourceKittenDictionary] {
|
||||
internal func structures(forByteOffset byteOffset: ByteCount) -> [SourceKittenDictionary] {
|
||||
var results = [SourceKittenDictionary]()
|
||||
|
||||
func parse(_ dictionary: SourceKittenDictionary) {
|
||||
guard let offset = dictionary.offset,
|
||||
let byteRange = dictionary.length.map({ NSRange(location: offset, length: $0) }),
|
||||
NSLocationInRange(byteOffset, byteRange) else {
|
||||
return
|
||||
guard let byteRange = dictionary.byteRange, byteRange.contains(byteOffset) else {
|
||||
return
|
||||
}
|
||||
|
||||
results.append(dictionary)
|
||||
|
|
|
@ -109,8 +109,10 @@ extension SwiftLintFile {
|
|||
let syntax = syntaxMap
|
||||
return regex(pattern).matches(in: contents, options: [], range: range).map { match in
|
||||
let matchByteRange = contents.NSRangeToByteRange(start: match.range.location,
|
||||
length: match.range.length) ?? match.range
|
||||
let tokensInRange = syntax.tokens(inByteRange: matchByteRange)
|
||||
length: match.range.length)
|
||||
let fallbackRange = ByteRange(location: ByteCount(match.range.location),
|
||||
length: ByteCount(match.range.length))
|
||||
let tokensInRange = syntax.tokens(inByteRange: matchByteRange ?? fallbackRange)
|
||||
return (match, tokensInRange)
|
||||
}
|
||||
}
|
||||
|
@ -143,12 +145,11 @@ extension SwiftLintFile {
|
|||
var maybeLine = lineIterator.next()
|
||||
var maybeStructure = structureIterator.next()
|
||||
while let line = maybeLine, let structure = maybeStructure {
|
||||
if NSLocationInRange(structure.byteRange.location, line.byteRange),
|
||||
if line.byteRange.contains(structure.byteRange.location),
|
||||
let swiftDeclarationKind = SwiftDeclarationKind(rawValue: structure.kind) {
|
||||
results[line.index].append(swiftDeclarationKind)
|
||||
}
|
||||
let lineEnd = NSMaxRange(line.byteRange)
|
||||
if structure.byteRange.location >= lineEnd {
|
||||
if structure.byteRange.location >= line.byteRange.upperBound {
|
||||
maybeLine = lineIterator.next()
|
||||
} else {
|
||||
maybeStructure = structureIterator.next()
|
||||
|
@ -168,12 +169,12 @@ extension SwiftLintFile {
|
|||
var maybeToken = tokenGenerator.next()
|
||||
while let line = maybeLine, let token = maybeToken {
|
||||
let tokenRange = token.range
|
||||
if NSLocationInRange(token.offset, line.byteRange) ||
|
||||
NSLocationInRange(line.byteRange.location, tokenRange) {
|
||||
if line.byteRange.contains(token.offset) ||
|
||||
tokenRange.contains(line.byteRange.location) {
|
||||
results[line.index].append(token)
|
||||
}
|
||||
let tokenEnd = NSMaxRange(tokenRange)
|
||||
let lineEnd = NSMaxRange(line.byteRange)
|
||||
let tokenEnd = tokenRange.upperBound
|
||||
let lineEnd = line.byteRange.upperBound
|
||||
if tokenEnd < lineEnd {
|
||||
maybeToken = tokenGenerator.next()
|
||||
} else if tokenEnd > lineEnd {
|
||||
|
@ -337,6 +338,6 @@ extension SwiftLintFile {
|
|||
}
|
||||
|
||||
internal func contents(for token: SwiftLintSyntaxToken) -> String? {
|
||||
return stringView.substringWithByteRange(start: token.offset, length: token.length)
|
||||
return stringView.substringWithByteRange(token.range)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ struct NamespaceCollector {
|
|||
struct Element {
|
||||
let name: String
|
||||
let kind: SwiftDeclarationKind
|
||||
let offset: Int
|
||||
let offset: ByteCount
|
||||
let dictionary: SourceKittenDictionary
|
||||
|
||||
init?(dictionary: SourceKittenDictionary, namespace: [String]) {
|
||||
|
|
|
@ -37,11 +37,11 @@ public struct Location: CustomStringConvertible, Comparable, Codable {
|
|||
}
|
||||
|
||||
/// Creates a `Location` based on a `SwiftLintFile` and a byte-offset into the file.
|
||||
/// Fails if tthe specified offset was not a valid location in the file.
|
||||
/// Fails if the specified offset was not a valid location in the file.
|
||||
///
|
||||
/// - parameter file: The file for this location.
|
||||
/// - parameter offset: The offset in bytes into the file for this location.
|
||||
public init(file: SwiftLintFile, byteOffset offset: Int) {
|
||||
public init(file: SwiftLintFile, byteOffset offset: ByteCount) {
|
||||
self.file = file.path
|
||||
if let lineAndCharacter = file.stringView.lineAndCharacter(forByteOffset: offset) {
|
||||
line = lineAndCharacter.line
|
||||
|
|
|
@ -22,7 +22,7 @@ public struct SwiftLintSyntaxMap {
|
|||
/// - parameter byteRange: Byte-based NSRange.
|
||||
///
|
||||
/// - returns: The array of syntax tokens intersecting with byte range.
|
||||
internal func tokens(inByteRange byteRange: NSRange) -> [SwiftLintSyntaxToken] {
|
||||
internal func tokens(inByteRange byteRange: ByteRange) -> [SwiftLintSyntaxToken] {
|
||||
func intersect(_ token: SwiftLintSyntaxToken) -> Bool {
|
||||
return token.range.intersects(byteRange)
|
||||
}
|
||||
|
@ -46,10 +46,39 @@ public struct SwiftLintSyntaxMap {
|
|||
|
||||
/// Returns the syntax kinds in the specified byte range.
|
||||
///
|
||||
/// - parameter byteRange: Byte-based NSRange.
|
||||
/// - parameter byteRange: Byte range.
|
||||
///
|
||||
/// - returns: The syntax kinds in the specified byte range.
|
||||
internal func kinds(inByteRange byteRange: NSRange) -> [SyntaxKind] {
|
||||
internal func kinds(inByteRange byteRange: ByteRange) -> [SyntaxKind] {
|
||||
return tokens(inByteRange: byteRange).compactMap { $0.kind }
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Move to SourceKitten
|
||||
|
||||
extension ByteRange {
|
||||
func contains(_ value: ByteCount) -> Bool {
|
||||
return location <= value && upperBound >= value
|
||||
}
|
||||
|
||||
func intersects(_ otherRange: ByteRange) -> Bool {
|
||||
return contains(otherRange.location) ||
|
||||
contains(otherRange.location + otherRange.length) ||
|
||||
otherRange.contains(location) ||
|
||||
otherRange.contains(location + length)
|
||||
}
|
||||
|
||||
func intersects(_ ranges: [ByteRange]) -> Bool {
|
||||
return ranges.contains { intersects($0) }
|
||||
}
|
||||
|
||||
func union(with otherRange: ByteRange) -> ByteRange {
|
||||
let maxUpperBound = max(upperBound, otherRange.upperBound)
|
||||
let minLocation = min(location, otherRange.location)
|
||||
return ByteRange(location: minLocation, length: maxUpperBound - minLocation)
|
||||
}
|
||||
|
||||
var upperBound: ByteCount {
|
||||
return location + length
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,17 +18,17 @@ public struct SwiftLintSyntaxToken {
|
|||
}
|
||||
|
||||
/// The byte range in a source file for this token.
|
||||
public var range: NSRange {
|
||||
return NSRange(location: value.offset, length: value.length)
|
||||
public var range: ByteRange {
|
||||
return value.range
|
||||
}
|
||||
|
||||
/// The starting byte offset in a source file for this token.
|
||||
public var offset: Int {
|
||||
public var offset: ByteCount {
|
||||
return value.offset
|
||||
}
|
||||
|
||||
/// The length in bytes for this token.
|
||||
public var length: Int {
|
||||
public var length: ByteCount {
|
||||
return value.length
|
||||
}
|
||||
}
|
||||
|
|
|
@ -111,7 +111,8 @@ public extension SwiftVersion {
|
|||
let decl = file.structureDictionary.kinds()
|
||||
.first(where: { $0.kind == SwiftDeclarationKind.varGlobal.rawValue }),
|
||||
let token = file.syntaxMap.tokens(inByteRange: decl.byteRange).first(where: { $0.kind == .string }) {
|
||||
return .init(rawValue: file.contents.substring(from: token.offset + 1, length: token.length - 2))
|
||||
let offsetRange = ByteRange(location: token.offset + 1, length: token.length - 2)
|
||||
return .init(rawValue: file.stringView.substringWithByteRange(offsetRange)!)
|
||||
}
|
||||
|
||||
return .three
|
||||
|
|
|
@ -36,7 +36,7 @@ extension CallPairRule {
|
|||
let stringView = file.stringView
|
||||
let dictionary = file.structureDictionary
|
||||
|
||||
let violatingLocations: [Int] = firstRanges.compactMap { range in
|
||||
let violatingLocations: [ByteCount] = firstRanges.compactMap { range in
|
||||
guard let bodyByteRange = stringView.NSRangeToByteRange(start: range.location, length: range.length),
|
||||
case let firstLocation = range.location + range.length - 1,
|
||||
let firstByteRange = stringView.NSRangeToByteRange(start: firstLocation, length: 1) else {
|
||||
|
@ -63,18 +63,14 @@ extension CallPairRule {
|
|||
}
|
||||
}
|
||||
|
||||
private func methodCall(forByteOffset byteOffset: Int, excludingOffset: Int,
|
||||
private func methodCall(forByteOffset byteOffset: ByteCount, excludingOffset: ByteCount,
|
||||
dictionary: SourceKittenDictionary,
|
||||
predicate: (SourceKittenDictionary) -> Bool) -> Int? {
|
||||
if dictionary.expressionKind == .call,
|
||||
let bodyOffset = dictionary.offset,
|
||||
let bodyLength = dictionary.length,
|
||||
let offset = dictionary.offset {
|
||||
let byteRange = NSRange(location: bodyOffset, length: bodyLength)
|
||||
|
||||
if NSLocationInRange(byteOffset, byteRange) &&
|
||||
!NSLocationInRange(excludingOffset, byteRange) && predicate(dictionary) {
|
||||
return offset
|
||||
predicate: (SourceKittenDictionary) -> Bool) -> ByteCount? {
|
||||
if dictionary.expressionKind == .call, let byteRange = dictionary.byteRange {
|
||||
if byteRange.contains(byteOffset) &&
|
||||
!byteRange.contains(excludingOffset) &&
|
||||
predicate(dictionary) {
|
||||
return dictionary.offset
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -97,9 +97,9 @@ public struct ConvenienceTypeRule: ASTRule, OptInRule, ConfigurationProviderRule
|
|||
private func isFunctionUnavailable(file: SwiftLintFile, dictionary: SourceKittenDictionary) -> Bool {
|
||||
return dictionary.swiftAttributes.contains { dict -> Bool in
|
||||
guard dict.attribute.flatMap(SwiftDeclarationAttributeKind.init(rawValue:)) == .available,
|
||||
let offset = dict.offset, let length = dict.length,
|
||||
let contents = file.stringView.substringWithByteRange(start: offset, length: length) else {
|
||||
return false
|
||||
let contents = dict.byteRange.flatMap(file.stringView.substringWithByteRange)
|
||||
else {
|
||||
return false
|
||||
}
|
||||
|
||||
return contents.contains("unavailable")
|
||||
|
|
|
@ -31,7 +31,7 @@ public struct DiscouragedOptionalCollectionRule: ASTRule, OptInRule, Configurati
|
|||
|
||||
private func variableViolations(file: SwiftLintFile,
|
||||
kind: SwiftDeclarationKind,
|
||||
dictionary: SourceKittenDictionary) -> [Int] {
|
||||
dictionary: SourceKittenDictionary) -> [ByteCount] {
|
||||
guard
|
||||
SwiftDeclarationKind.variableKinds.contains(kind),
|
||||
let offset = dictionary.offset,
|
||||
|
@ -42,7 +42,7 @@ public struct DiscouragedOptionalCollectionRule: ASTRule, OptInRule, Configurati
|
|||
|
||||
private func functionViolations(file: SwiftLintFile,
|
||||
kind: SwiftDeclarationKind,
|
||||
dictionary: SourceKittenDictionary) -> [Int] {
|
||||
dictionary: SourceKittenDictionary) -> [ByteCount] {
|
||||
guard
|
||||
SwiftDeclarationKind.functionKinds.contains(kind),
|
||||
let nameOffset = dictionary.nameOffset,
|
||||
|
@ -51,8 +51,9 @@ public struct DiscouragedOptionalCollectionRule: ASTRule, OptInRule, Configurati
|
|||
let offset = dictionary.offset,
|
||||
case let start = nameOffset + nameLength,
|
||||
case let end = dictionary.bodyOffset ?? offset + length,
|
||||
case let byteRange = ByteRange(location: start, length: end - start),
|
||||
case let contents = file.stringView,
|
||||
let range = file.stringView.byteRangeToNSRange(start: start, length: end - start),
|
||||
let range = file.stringView.byteRangeToNSRange(byteRange),
|
||||
let match = file.match(pattern: "->\\s*(.*?)\\{", excludingSyntaxKinds: excludingKinds, range: range).first
|
||||
else { return [] }
|
||||
|
||||
|
|
|
@ -22,19 +22,18 @@ public struct DuplicateImportsRule: ConfigurationProviderRule, AutomaticTestable
|
|||
triggeringExamples: DuplicateImportsRuleExamples.triggeringExamples
|
||||
)
|
||||
|
||||
private func rangesInConditionalCompilation(file: SwiftLintFile) -> [NSRange] {
|
||||
private func rangesInConditionalCompilation(file: SwiftLintFile) -> [ByteRange] {
|
||||
let contents = file.stringView
|
||||
|
||||
let ranges = file.syntaxMap.tokens
|
||||
.filter { $0.kind == .buildconfigKeyword }
|
||||
.map { $0.range }
|
||||
.filter { range in
|
||||
let keyword = contents.substringWithByteRange(start: range.location, length: range.length)
|
||||
return ["#if", "#endif"].contains(keyword)
|
||||
return ["#if", "#endif"].contains(contents.substringWithByteRange(range))
|
||||
}
|
||||
|
||||
return stride(from: 0, to: ranges.count, by: 2).reduce(into: []) { result, rangeIndex in
|
||||
result.append(NSUnionRange(ranges[rangeIndex], ranges[rangeIndex + 1]))
|
||||
result.append(ranges[rangeIndex].union(with: ranges[rangeIndex + 1]))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ public struct ExplicitACLRule: OptInRule, ConfigurationProviderRule, AutomaticTe
|
|||
]
|
||||
)
|
||||
|
||||
private func findAllExplicitInternalTokens(in file: SwiftLintFile) -> [NSRange] {
|
||||
private func findAllExplicitInternalTokens(in file: SwiftLintFile) -> [ByteRange] {
|
||||
let contents = file.stringView
|
||||
return file.match(pattern: "internal", with: [.attributeBuiltin]).compactMap {
|
||||
contents.NSRangeToByteRange(start: $0.location, length: $0.length)
|
||||
|
@ -61,7 +61,7 @@ public struct ExplicitACLRule: OptInRule, ConfigurationProviderRule, AutomaticTe
|
|||
}
|
||||
|
||||
private func offsetOfElements(from elements: [SourceKittenElement], in file: SwiftLintFile,
|
||||
thatAreNotInRanges ranges: [NSRange]) -> [Int] {
|
||||
thatAreNotInRanges ranges: [ByteRange]) -> [ByteCount] {
|
||||
let extensionKinds: Set<SwiftDeclarationKind> = [.extension, .extensionClass, .extensionEnum,
|
||||
.extensionProtocol, .extensionStruct]
|
||||
|
||||
|
@ -83,7 +83,7 @@ public struct ExplicitACLRule: OptInRule, ConfigurationProviderRule, AutomaticTe
|
|||
// the "internal" token correspond to the type if there're only
|
||||
// attributeBuiltin (`final` for example) tokens between them
|
||||
let length = typeOffset - previousInternalByteRange.location
|
||||
let range = NSRange(location: previousInternalByteRange.location, length: length)
|
||||
let range = ByteRange(location: previousInternalByteRange.location, length: length)
|
||||
let internalDoesntBelongToType = Set(file.syntaxMap.kinds(inByteRange: range)) != [.attributeBuiltin]
|
||||
|
||||
return internalDoesntBelongToType ? typeOffset : nil
|
||||
|
@ -109,7 +109,7 @@ public struct ExplicitACLRule: OptInRule, ConfigurationProviderRule, AutomaticTe
|
|||
}
|
||||
}
|
||||
|
||||
private func lastInternalByteRange(before typeOffset: Int, in ranges: [NSRange]) -> NSRange? {
|
||||
private func lastInternalByteRange(before typeOffset: ByteCount, in ranges: [ByteRange]) -> ByteRange? {
|
||||
let firstPartition = ranges.prefix(while: { typeOffset > $0.location })
|
||||
return firstPartition.last
|
||||
}
|
||||
|
|
|
@ -100,7 +100,7 @@ public struct ExplicitEnumRawValueRule: ASTRule, OptInRule, ConfigurationProvide
|
|||
}
|
||||
}
|
||||
|
||||
private func violatingOffsetsForEnum(dictionary: SourceKittenDictionary) -> [Int] {
|
||||
private func violatingOffsetsForEnum(dictionary: SourceKittenDictionary) -> [ByteCount] {
|
||||
let locs = substructureElements(of: dictionary, matching: .enumcase)
|
||||
.compactMap { substructureElements(of: $0, matching: .enumelement) }
|
||||
.flatMap(enumElementsMissingInitExpr)
|
||||
|
|
|
@ -71,14 +71,14 @@ public struct ExplicitInitRule: SubstitutionCorrectableASTRule, ConfigurationPro
|
|||
&& initializerWithType.numberOfMatches(in: name, options: [], range: range) != 0
|
||||
}
|
||||
|
||||
let length = ".init".utf8.count
|
||||
let length = ByteCount(".init".utf8.count)
|
||||
|
||||
guard kind == .call,
|
||||
let name = dictionary.name, isExpected(name),
|
||||
let nameOffset = dictionary.nameOffset,
|
||||
let nameLength = dictionary.nameLength,
|
||||
let range = file.stringView
|
||||
.byteRangeToNSRange(start: nameOffset + nameLength - length, length: length)
|
||||
.byteRangeToNSRange(ByteRange(location: nameOffset + nameLength - length, length: length))
|
||||
else { return [] }
|
||||
return [range]
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ public struct ExplicitTopLevelACLRule: OptInRule, ConfigurationProviderRule, Aut
|
|||
|
||||
// find all top-level types marked as internal (either explictly or implictly)
|
||||
let dictionary = file.structureDictionary
|
||||
let internalTypesOffsets = dictionary.substructure.compactMap { element -> Int? in
|
||||
let internalTypesOffsets = dictionary.substructure.compactMap { element -> ByteCount? in
|
||||
// ignore extensions
|
||||
guard let kind = element.declarationKind,
|
||||
!extensionKinds.contains(kind) else {
|
||||
|
@ -72,7 +72,7 @@ public struct ExplicitTopLevelACLRule: OptInRule, ConfigurationProviderRule, Aut
|
|||
// the "internal" token correspond to the type if there're only
|
||||
// attributeBuiltin (`final` for example) tokens between them
|
||||
let length = typeOffset - previousInternalByteRange.location
|
||||
let range = NSRange(location: previousInternalByteRange.location, length: length)
|
||||
let range = ByteRange(location: previousInternalByteRange.location, length: length)
|
||||
let internalDoesntBelongToType = Set(file.syntaxMap.kinds(inByteRange: range)) != [.attributeBuiltin]
|
||||
|
||||
return internalDoesntBelongToType
|
||||
|
@ -85,7 +85,7 @@ public struct ExplicitTopLevelACLRule: OptInRule, ConfigurationProviderRule, Aut
|
|||
}
|
||||
}
|
||||
|
||||
private func lastInternalByteRange(before typeOffset: Int, in ranges: [NSRange]) -> NSRange? {
|
||||
private func lastInternalByteRange(before typeOffset: ByteCount, in ranges: [ByteRange]) -> ByteRange? {
|
||||
let firstPartition = ranges.prefix(while: { typeOffset > $0.location })
|
||||
return firstPartition.last
|
||||
}
|
||||
|
|
|
@ -108,7 +108,8 @@ private extension SourceKittenDictionary {
|
|||
guard
|
||||
let nameOffset = nameOffset,
|
||||
let nameLength = nameLength,
|
||||
let afterNameRange = file.stringView.byteRangeToNSRange(start: nameOffset + nameLength, length: 0)
|
||||
case let afterNameByteRange = ByteRange(location: nameOffset + nameLength, length: 0),
|
||||
let afterNameRange = file.stringView.byteRangeToNSRange(afterNameByteRange)
|
||||
else {
|
||||
return false
|
||||
}
|
||||
|
@ -125,7 +126,8 @@ private extension SourceKittenDictionary {
|
|||
guard
|
||||
let nameOffset = nameOffset,
|
||||
let nameLength = nameLength,
|
||||
let afterNameRange = file.stringView.byteRangeToNSRange(start: nameOffset + nameLength, length: 0)
|
||||
case let afterNameByteRange = ByteRange(location: nameOffset + nameLength, length: 0),
|
||||
let afterNameRange = file.stringView.byteRangeToNSRange(afterNameByteRange)
|
||||
else {
|
||||
return false
|
||||
}
|
||||
|
@ -137,11 +139,11 @@ private extension SourceKittenDictionary {
|
|||
return typeAssignment.firstMatch(in: contentAfterName, options: [], range: contentAfterName.fullNSRange) != nil
|
||||
}
|
||||
|
||||
var caseStatementPatternRanges: [NSRange] {
|
||||
var caseStatementPatternRanges: [ByteRange] {
|
||||
return ranges(with: StatementKind.case.rawValue, for: "source.lang.swift.structure.elem.pattern")
|
||||
}
|
||||
|
||||
var caseExpressionRanges: [NSRange] {
|
||||
var caseExpressionRanges: [ByteRange] {
|
||||
return ranges(with: SwiftExpressionKind.tuple.rawValue, for: "source.lang.swift.structure.elem.expr")
|
||||
}
|
||||
|
||||
|
@ -152,30 +154,27 @@ private extension SourceKittenDictionary {
|
|||
return statements.contains(statement)
|
||||
}
|
||||
|
||||
func ranges(with parentKind: String, for elementKind: String) -> [NSRange] {
|
||||
func ranges(with parentKind: String, for elementKind: String) -> [ByteRange] {
|
||||
guard parentKind == kind else {
|
||||
return []
|
||||
}
|
||||
|
||||
return elements
|
||||
.filter { elementKind == $0.kind }
|
||||
.compactMap {
|
||||
guard let location = $0.offset, let length = $0.length else { return nil }
|
||||
return NSRange(location: location, length: length)
|
||||
}
|
||||
.compactMap { $0.byteRange }
|
||||
}
|
||||
}
|
||||
|
||||
private extension SwiftLintFile {
|
||||
var captureGroupByteRanges: [NSRange] {
|
||||
var captureGroupByteRanges: [ByteRange] {
|
||||
return match(pattern: "\\{\\s*\\[(\\s*\\w+\\s+\\w+,*)+\\]",
|
||||
excludingSyntaxKinds: SyntaxKind.commentKinds)
|
||||
.compactMap { stringView.NSRangeToByteRange(start: $0.location, length: $0.length) }
|
||||
}
|
||||
}
|
||||
|
||||
private extension Collection where Element == NSRange {
|
||||
func contains(_ index: Int) -> Bool {
|
||||
private extension Collection where Element == ByteRange {
|
||||
func contains(_ index: ByteCount) -> Bool {
|
||||
return contains { $0.contains(index) }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,20 +79,23 @@ public struct ExtensionAccessModifierRule: ASTRule, ConfigurationProviderRule, O
|
|||
public func validate(file: SwiftLintFile, kind: SwiftDeclarationKind,
|
||||
dictionary: SourceKittenDictionary) -> [StyleViolation] {
|
||||
guard kind == .extension, let offset = dictionary.offset,
|
||||
dictionary.inheritedTypes.isEmpty else {
|
||||
return []
|
||||
dictionary.inheritedTypes.isEmpty
|
||||
else {
|
||||
return []
|
||||
}
|
||||
|
||||
let declarations = dictionary.substructure.compactMap { entry -> (acl: AccessControlLevel, offset: Int)? in
|
||||
guard entry.declarationKind != nil,
|
||||
let acl = entry.accessibility,
|
||||
let offset = entry.offset else {
|
||||
return nil
|
||||
let declarations = dictionary.substructure
|
||||
.compactMap { entry -> (acl: AccessControlLevel, offset: ByteCount)? in
|
||||
guard entry.declarationKind != nil,
|
||||
let acl = entry.accessibility,
|
||||
let offset = entry.offset
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return (acl: acl, offset: offset)
|
||||
}
|
||||
|
||||
return (acl: acl, offset: offset)
|
||||
}
|
||||
|
||||
let declarationsACLs = declarations.map { $0.acl }.unique
|
||||
let allowedACLs: Set<AccessControlLevel> = [.internal, .private, .open]
|
||||
guard declarationsACLs.count == 1, !allowedACLs.contains(declarationsACLs[0]) else {
|
||||
|
@ -115,11 +118,11 @@ public struct ExtensionAccessModifierRule: ASTRule, ConfigurationProviderRule, O
|
|||
}
|
||||
|
||||
private func declarationsViolations(file: SwiftLintFile, acl: AccessControlLevel,
|
||||
declarationOffsets: [Int],
|
||||
declarationOffsets: [ByteCount],
|
||||
dictionary: SourceKittenDictionary) -> [StyleViolation] {
|
||||
guard let offset = dictionary.offset, let length = dictionary.length,
|
||||
guard let byteRange = dictionary.byteRange,
|
||||
case let contents = file.stringView,
|
||||
let range = contents.byteRangeToNSRange(start: offset, length: length) else {
|
||||
let range = contents.byteRangeToNSRange(byteRange) else {
|
||||
return []
|
||||
}
|
||||
|
||||
|
@ -138,7 +141,7 @@ public struct ExtensionAccessModifierRule: ASTRule, ConfigurationProviderRule, O
|
|||
// the ACL token correspond to the type if there're only
|
||||
// attributeBuiltin (`final` for example) tokens between them
|
||||
let length = typeOffset - previousInternalByteRange.location
|
||||
let range = NSRange(location: previousInternalByteRange.location, length: length)
|
||||
let range = ByteRange(location: previousInternalByteRange.location, length: length)
|
||||
let internalBelongsToType = Set(file.syntaxMap.kinds(inByteRange: range)) == [.attributeBuiltin]
|
||||
|
||||
return internalBelongsToType
|
||||
|
@ -151,7 +154,7 @@ public struct ExtensionAccessModifierRule: ASTRule, ConfigurationProviderRule, O
|
|||
}
|
||||
}
|
||||
|
||||
private func lastACLByteRange(before typeOffset: Int, in ranges: [NSRange]) -> NSRange? {
|
||||
private func lastACLByteRange(before typeOffset: ByteCount, in ranges: [ByteRange]) -> ByteRange? {
|
||||
let firstPartition = ranges.partitioned(by: { $0.location > typeOffset }).first
|
||||
return firstPartition.last
|
||||
}
|
||||
|
|
|
@ -53,16 +53,15 @@ public struct FatalErrorMessageRule: ASTRule, ConfigurationProviderRule, OptInRu
|
|||
}
|
||||
|
||||
private func hasEmptyBody(dictionary: SourceKittenDictionary, file: SwiftLintFile) -> Bool {
|
||||
guard let bodyOffset = dictionary.bodyOffset,
|
||||
let bodyLength = dictionary.bodyLength else {
|
||||
return false
|
||||
guard let bodyRange = dictionary.bodyByteRange else {
|
||||
return false
|
||||
}
|
||||
|
||||
if bodyLength == 0 {
|
||||
if bodyRange.length == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
let body = file.stringView.substringWithByteRange(start: bodyOffset, length: bodyLength)
|
||||
let body = file.stringView.substringWithByteRange(bodyRange)
|
||||
return body == "\"\""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -133,9 +133,9 @@ public struct ForWhereRule: ASTRule, ConfigurationProviderRule, AutomaticTestabl
|
|||
return false
|
||||
}
|
||||
|
||||
let beforeIfRange = NSRange(location: offset, length: ifOffset - offset)
|
||||
let beforeIfRange = ByteRange(location: offset, length: ifOffset - offset)
|
||||
let ifFinalPosition = ifOffset + ifLength
|
||||
let afterIfRange = NSRange(location: ifFinalPosition, length: offset + length - ifFinalPosition)
|
||||
let afterIfRange = ByteRange(location: ifFinalPosition, length: offset + length - ifFinalPosition)
|
||||
let allKinds = file.syntaxMap.kinds(inByteRange: beforeIfRange) +
|
||||
file.syntaxMap.kinds(inByteRange: afterIfRange)
|
||||
|
||||
|
@ -148,13 +148,11 @@ public struct ForWhereRule: ASTRule, ConfigurationProviderRule, AutomaticTestabl
|
|||
|
||||
private func isComplexCondition(dictionary: SourceKittenDictionary, file: SwiftLintFile) -> Bool {
|
||||
let kind = "source.lang.swift.structure.elem.condition_expr"
|
||||
let contents = file.stringView
|
||||
return dictionary.elements.contains { element in
|
||||
guard element.kind == kind,
|
||||
let offset = element.offset,
|
||||
let length = element.length,
|
||||
let range = contents.byteRangeToNSRange(start: offset, length: length) else {
|
||||
return false
|
||||
let range = element.byteRange.flatMap(file.stringView.byteRangeToNSRange)
|
||||
else {
|
||||
return false
|
||||
}
|
||||
|
||||
let containsKeyword = !file.match(pattern: "\\blet|var|case\\b", with: [.keyword], range: range).isEmpty
|
||||
|
|
|
@ -152,7 +152,7 @@ public struct ForceUnwrappingRule: OptInRule, ConfigurationProviderRule, Automat
|
|||
}
|
||||
|
||||
// check if first captured range is comment, string, typeidentifier, or a keyword that is not `self`.
|
||||
private func isFirstRangeExcludedToken(byteRange: NSRange, syntaxMap: SwiftLintSyntaxMap,
|
||||
private func isFirstRangeExcludedToken(byteRange: ByteRange, syntaxMap: SwiftLintSyntaxMap,
|
||||
file: SwiftLintFile) -> Bool {
|
||||
let tokens = syntaxMap.tokens(inByteRange: byteRange)
|
||||
return tokens.contains { token in
|
||||
|
@ -166,7 +166,7 @@ public struct ForceUnwrappingRule: OptInRule, ConfigurationProviderRule, Automat
|
|||
}
|
||||
|
||||
// check deepest kind matching range in structure is a typeAnnotation
|
||||
private func isTypeAnnotation(in file: SwiftLintFile, byteRange: NSRange) -> Bool {
|
||||
private func isTypeAnnotation(in file: SwiftLintFile, byteRange: ByteRange) -> Bool {
|
||||
let kinds = file.structureDictionary.kinds(forByteOffset: byteRange.location)
|
||||
guard let lastItem = kinds.last,
|
||||
let lastKind = SwiftDeclarationKind(rawValue: lastItem.kind),
|
||||
|
@ -175,9 +175,9 @@ public struct ForceUnwrappingRule: OptInRule, ConfigurationProviderRule, Automat
|
|||
}
|
||||
|
||||
// range is in some "source.lang.swift.decl.var.*"
|
||||
let byteOffset = lastItem.byteRange.location
|
||||
let byteLength = byteRange.location - byteOffset
|
||||
if let varDeclarationString = file.stringView.substringWithByteRange(start: byteOffset, length: byteLength),
|
||||
let varRange = ByteRange(location: lastItem.byteRange.location,
|
||||
length: byteRange.location - lastItem.byteRange.location)
|
||||
if let varDeclarationString = file.stringView.substringWithByteRange(varRange),
|
||||
varDeclarationString.contains("=") {
|
||||
// if declarations contains "=", range is not type annotation
|
||||
return false
|
||||
|
|
|
@ -97,10 +97,8 @@ public struct FunctionDefaultParameterAtEndRule: ASTRule, ConfigurationProviderR
|
|||
}
|
||||
|
||||
private func isDefaultParameter(file: SwiftLintFile, dictionary: SourceKittenDictionary) -> Bool {
|
||||
let contents = file.stringView
|
||||
guard let offset = dictionary.offset, let length = dictionary.length,
|
||||
let range = contents.byteRangeToNSRange(start: offset, length: length) else {
|
||||
return false
|
||||
guard let range = dictionary.byteRange.flatMap(file.stringView.byteRangeToNSRange) else {
|
||||
return false
|
||||
}
|
||||
|
||||
return regex("=").firstMatch(in: file.contents, options: [], range: range) != nil
|
||||
|
|
|
@ -71,15 +71,16 @@ public struct GenericTypeNameRule: ASTRule, ConfigurationProviderRule {
|
|||
} else {
|
||||
guard kind == .genericTypeParam,
|
||||
let name = dictionary.name,
|
||||
let offset = dictionary.offset else {
|
||||
return []
|
||||
let offset = dictionary.offset
|
||||
else {
|
||||
return []
|
||||
}
|
||||
|
||||
return validate(name: name, file: file, offset: offset)
|
||||
}
|
||||
}
|
||||
|
||||
private func validate(name: String, file: SwiftLintFile, offset: Int) -> [StyleViolation] {
|
||||
private func validate(name: String, file: SwiftLintFile, offset: ByteCount) -> [StyleViolation] {
|
||||
guard !configuration.excluded.contains(name) else {
|
||||
return []
|
||||
}
|
||||
|
@ -122,7 +123,7 @@ extension GenericTypeNameRule {
|
|||
|
||||
private func validateGenericTypeAliases(in file: SwiftLintFile) -> [StyleViolation] {
|
||||
let pattern = "typealias\\s+\\w+?\\s*" + type(of: self).genericTypePattern + "\\s*="
|
||||
return file.match(pattern: pattern).flatMap { range, tokens -> [(String, Int)] in
|
||||
return file.match(pattern: pattern).flatMap { range, tokens -> [(String, ByteCount)] in
|
||||
guard tokens.first == .keyword,
|
||||
Set(tokens.dropFirst()) == [.identifier],
|
||||
let match = type(of: self).genericTypeRegex.firstMatch(in: file.contents, options: [],
|
||||
|
@ -136,7 +137,7 @@ extension GenericTypeNameRule {
|
|||
}
|
||||
|
||||
private func genericTypesForType(in file: SwiftLintFile, kind: SwiftDeclarationKind,
|
||||
dictionary: SourceKittenDictionary) -> [(String, Int)] {
|
||||
dictionary: SourceKittenDictionary) -> [(String, ByteCount)] {
|
||||
guard SwiftDeclarationKind.typeKinds.contains(kind),
|
||||
let nameOffset = dictionary.nameOffset,
|
||||
let nameLength = dictionary.nameLength,
|
||||
|
@ -144,7 +145,8 @@ extension GenericTypeNameRule {
|
|||
case let contents = file.stringView,
|
||||
case let start = nameOffset + nameLength,
|
||||
case let length = bodyOffset - start,
|
||||
let range = file.stringView.byteRangeToNSRange(start: start, length: length),
|
||||
case let byteRange = ByteRange(location: start, length: length),
|
||||
let range = file.stringView.byteRangeToNSRange(byteRange),
|
||||
let match = type(of: self).genericTypeRegex.firstMatch(in: file.contents, options: [],
|
||||
range: range)?.range(at: 1) else {
|
||||
return []
|
||||
|
@ -155,16 +157,18 @@ extension GenericTypeNameRule {
|
|||
}
|
||||
|
||||
private func genericTypesForFunction(in file: SwiftLintFile, kind: SwiftDeclarationKind,
|
||||
dictionary: SourceKittenDictionary) -> [(String, Int)] {
|
||||
dictionary: SourceKittenDictionary) -> [(String, ByteCount)] {
|
||||
guard SwiftDeclarationKind.functionKinds.contains(kind),
|
||||
let offset = dictionary.nameOffset,
|
||||
let length = dictionary.nameLength,
|
||||
case let contents = file.stringView,
|
||||
let range = contents.byteRangeToNSRange(start: offset, length: length),
|
||||
case let byteRange = ByteRange(location: offset, length: length),
|
||||
let range = contents.byteRangeToNSRange(byteRange),
|
||||
let match = type(of: self).genericTypeRegex.firstMatch(in: file.contents,
|
||||
options: [], range: range)?.range(at: 1),
|
||||
match.location < minParameterOffset(parameters: dictionary.enclosedVarParameters, file: file) else {
|
||||
return []
|
||||
match.location < minParameterOffset(parameters: dictionary.enclosedVarParameters, file: file)
|
||||
else {
|
||||
return []
|
||||
}
|
||||
|
||||
let genericConstraint = contents.substring(with: match)
|
||||
|
@ -174,7 +178,7 @@ extension GenericTypeNameRule {
|
|||
private func minParameterOffset(parameters: [SourceKittenDictionary], file: SwiftLintFile) -> Int {
|
||||
let offsets = parameters.compactMap { param -> Int? in
|
||||
return param.offset.flatMap {
|
||||
file.stringView.byteRangeToNSRange(start: $0, length: 0)?.location
|
||||
file.stringView.byteRangeToNSRange(ByteRange(location: $0, length: 0))?.location
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -182,7 +186,7 @@ extension GenericTypeNameRule {
|
|||
}
|
||||
|
||||
private func extractTypes(fromGenericConstraint constraint: String, offset: Int,
|
||||
file: SwiftLintFile) -> [(String, Int)] {
|
||||
file: SwiftLintFile) -> [(String, ByteCount)] {
|
||||
guard let beforeWhere = constraint.components(separatedBy: "where").first else {
|
||||
return []
|
||||
}
|
||||
|
@ -196,7 +200,7 @@ extension GenericTypeNameRule {
|
|||
}
|
||||
|
||||
let contents = file.stringView
|
||||
return namesAndRanges.compactMap { name, range -> (String, Int)? in
|
||||
return namesAndRanges.compactMap { name, range -> (String, ByteCount)? in
|
||||
guard let byteRange = contents.NSRangeToByteRange(start: range.location + offset,
|
||||
length: range.length),
|
||||
file.syntaxMap.kinds(inByteRange: byteRange) == [.identifier] else {
|
||||
|
@ -228,8 +232,9 @@ private extension String {
|
|||
let bridged = bridge()
|
||||
let range = NSRange(location: 0, length: bridged.length)
|
||||
guard let match = regex("^\\s*(\\S*)\\s*$").firstMatch(in: self, options: [], range: range),
|
||||
NSEqualRanges(range, match.range) else {
|
||||
return (self, range)
|
||||
NSEqualRanges(range, match.range)
|
||||
else {
|
||||
return (self, range)
|
||||
}
|
||||
|
||||
let trimmedRange = match.range(at: 1)
|
||||
|
|
|
@ -70,23 +70,18 @@ public struct JoinedDefaultParameterRule: SubstitutionCorrectableASTRule, Config
|
|||
guard
|
||||
// is this single argument called 'separator'?
|
||||
let argument = dictionary.enclosedArguments.first,
|
||||
let offset = argument.offset,
|
||||
let length = argument.length,
|
||||
argument.name == "separator"
|
||||
let argumentByteRange = argument.byteRange,
|
||||
argument.name == "separator",
|
||||
let argumentNSRange = file.stringView.byteRangeToNSRange(argumentByteRange)
|
||||
else { return [] }
|
||||
|
||||
guard
|
||||
// is this single argument the default parameter?
|
||||
let bodyOffset = argument.bodyOffset,
|
||||
let bodyLength = argument.bodyLength,
|
||||
let body = file.stringView.substringWithByteRange(start: bodyOffset, length: bodyLength),
|
||||
let bodyRange = argument.bodyByteRange,
|
||||
let body = file.stringView.substringWithByteRange(bodyRange),
|
||||
body == "\"\""
|
||||
else { return [] }
|
||||
|
||||
guard
|
||||
let range = file.stringView.byteRangeToNSRange(start: offset, length: length)
|
||||
else { return [] }
|
||||
|
||||
return [range]
|
||||
return [argumentNSRange]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -181,8 +181,8 @@ public struct LegacyConstructorRule: ASTRule, CorrectableRule, ConfigurationProv
|
|||
var adjustedLocations = [Int]()
|
||||
|
||||
for dictionary in violatingDictionaries.reversed() {
|
||||
guard let offset = dictionary.offset, let length = dictionary.length,
|
||||
let range = file.stringView.byteRangeToNSRange(start: offset, length: length),
|
||||
guard let byteRange = dictionary.byteRange,
|
||||
let range = file.stringView.byteRangeToNSRange(byteRange),
|
||||
let name = dictionary.name,
|
||||
let correctedName = type(of: self).constructorsToCorrectedNames[name],
|
||||
file.ruleEnabled(violatingRanges: [range], for: self) == [range],
|
||||
|
@ -213,13 +213,11 @@ public struct LegacyConstructorRule: ASTRule, CorrectableRule, ConfigurationProv
|
|||
private func argumentsContents(file: SwiftLintFile, arguments: [SourceKittenDictionary]) -> [String] {
|
||||
let contents = file.stringView
|
||||
return arguments.compactMap { argument -> String? in
|
||||
guard argument.name == nil,
|
||||
let offset = argument.offset,
|
||||
let length = argument.length else {
|
||||
return nil
|
||||
guard argument.name == nil, let byteRange = argument.byteRange else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return contents.substringWithByteRange(start: offset, length: length)
|
||||
return contents.substringWithByteRange(byteRange)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,10 +19,9 @@ public struct NoFallthroughOnlyRule: ASTRule, ConfigurationProviderRule, Automat
|
|||
kind: StatementKind,
|
||||
dictionary: SourceKittenDictionary) -> [StyleViolation] {
|
||||
guard kind == .case,
|
||||
let length = dictionary.length,
|
||||
let offset = dictionary.offset,
|
||||
let byteRange = dictionary.byteRange,
|
||||
case let contents = file.stringView,
|
||||
let range = contents.byteRangeToNSRange(start: offset, length: length),
|
||||
let range = contents.byteRangeToNSRange(byteRange),
|
||||
let colonLocation = findCaseColon(text: file.stringView.nsString, range: range)
|
||||
else {
|
||||
return []
|
||||
|
@ -40,7 +39,7 @@ public struct NoFallthroughOnlyRule: ASTRule, ConfigurationProviderRule, Automat
|
|||
|
||||
let nsRange = nonCommentCaseBody[0].0
|
||||
if contents.substring(with: nsRange) == "fallthrough" && nonCommentCaseBody[0].1 == [.keyword] &&
|
||||
!isNextTokenUnknownAttribute(afterOffset: offset + length, file: file) {
|
||||
!isNextTokenUnknownAttribute(afterOffset: byteRange.upperBound, file: file) {
|
||||
return [StyleViolation(ruleDescription: type(of: self).description,
|
||||
severity: configuration.severity,
|
||||
location: Location(file: file, characterOffset: nsRange.location))]
|
||||
|
@ -49,13 +48,12 @@ public struct NoFallthroughOnlyRule: ASTRule, ConfigurationProviderRule, Automat
|
|||
return []
|
||||
}
|
||||
|
||||
private func isNextTokenUnknownAttribute(afterOffset offset: Int, file: SwiftLintFile) -> Bool {
|
||||
private func isNextTokenUnknownAttribute(afterOffset offset: ByteCount, file: SwiftLintFile) -> Bool {
|
||||
let nextNonCommentToken = file.syntaxMap.tokens
|
||||
.first { token in
|
||||
guard let kind = token.kind, !kind.isCommentLike else {
|
||||
return false
|
||||
}
|
||||
|
||||
return token.offset > offset
|
||||
}
|
||||
|
||||
|
|
|
@ -45,18 +45,14 @@ public struct NoGroupingExtensionRule: OptInRule, ConfigurationProviderRule, Aut
|
|||
}
|
||||
|
||||
private func hasWhereClause(dictionary: SourceKittenDictionary, file: SwiftLintFile) -> Bool {
|
||||
let contents = file.stringView
|
||||
|
||||
guard let nameOffset = dictionary.nameOffset,
|
||||
let nameLength = dictionary.nameLength,
|
||||
let bodyOffset = dictionary.bodyOffset else {
|
||||
return false
|
||||
}
|
||||
|
||||
let rangeStart = nameOffset + nameLength
|
||||
let rangeLength = bodyOffset - rangeStart
|
||||
|
||||
guard let range = contents.byteRangeToNSRange(start: rangeStart, length: rangeLength) else {
|
||||
let bodyOffset = dictionary.bodyOffset,
|
||||
case let contents = file.stringView,
|
||||
case let rangeStart = nameOffset + nameLength,
|
||||
case let rangeLength = bodyOffset - rangeStart,
|
||||
let range = contents.byteRangeToNSRange(ByteRange(location: rangeStart, length: rangeLength))
|
||||
else {
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
|
@ -94,11 +94,6 @@ public struct ObjectLiteralRule: ASTRule, ConfigurationProviderRule, OptInRule {
|
|||
}
|
||||
|
||||
private func kinds(forArgument argument: SourceKittenDictionary, file: SwiftLintFile) -> Set<SyntaxKind> {
|
||||
guard let offset = argument.bodyOffset, let length = argument.bodyLength else {
|
||||
return []
|
||||
}
|
||||
|
||||
let range = NSRange(location: offset, length: length)
|
||||
return Set(file.syntaxMap.kinds(inByteRange: range))
|
||||
return argument.bodyByteRange.map { Set(file.syntaxMap.kinds(inByteRange: $0)) } ?? []
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,10 +43,10 @@ public struct PatternMatchingKeywordsRule: ASTRule, ConfigurationProviderRule, O
|
|||
let contents = file.stringView
|
||||
return dictionary.elements.flatMap { subDictionary -> [StyleViolation] in
|
||||
guard subDictionary.kind == "source.lang.swift.structure.elem.pattern",
|
||||
let offset = subDictionary.offset,
|
||||
let length = subDictionary.length,
|
||||
let caseRange = contents.byteRangeToNSRange(start: offset, length: length) else {
|
||||
return []
|
||||
let caseByteRange = subDictionary.byteRange,
|
||||
let caseRange = contents.byteRangeToNSRange(caseByteRange)
|
||||
else {
|
||||
return []
|
||||
}
|
||||
|
||||
let letMatches = file.match(pattern: "\\blet\\b", with: [.keyword], range: caseRange)
|
||||
|
|
|
@ -81,10 +81,11 @@ public struct PrivateOverFilePrivateRule: ConfigurationProviderRule, Substitutio
|
|||
let parts = syntaxTokens.prefix { offset > $0.offset }
|
||||
guard let lastKind = parts.last,
|
||||
lastKind.kind == .attributeBuiltin,
|
||||
let aclName = contents.substringWithByteRange(start: lastKind.offset, length: lastKind.length),
|
||||
let aclName = contents.substringWithByteRange(lastKind.range),
|
||||
AccessControlLevel(description: aclName) == .fileprivate,
|
||||
let range = contents.byteRangeToNSRange(start: lastKind.offset, length: lastKind.length) else {
|
||||
return nil
|
||||
let range = contents.byteRangeToNSRange(lastKind.range)
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return range
|
||||
|
|
|
@ -41,10 +41,10 @@ public struct RedundantObjcAttributeRule: SubstitutionCorrectableRule, Configura
|
|||
parentStructure: SourceKittenDictionary?) -> [NSRange] {
|
||||
let objcAttribute = dictionary.swiftAttributes
|
||||
.first(where: { $0.attribute == SwiftDeclarationAttributeKind.objc.rawValue })
|
||||
guard let objcOffset = objcAttribute?.offset,
|
||||
let objcLength = objcAttribute?.length,
|
||||
let range = file.stringView.byteRangeToNSRange(start: objcOffset, length: objcLength),
|
||||
!dictionary.isObjcAndIBDesignableDeclaredExtension else {
|
||||
guard let objcByteRange = objcAttribute?.byteRange,
|
||||
let range = file.stringView.byteRangeToNSRange(objcByteRange),
|
||||
!dictionary.isObjcAndIBDesignableDeclaredExtension
|
||||
else {
|
||||
return []
|
||||
}
|
||||
|
||||
|
|
|
@ -127,9 +127,9 @@ public struct RedundantOptionalInitializationRule: SubstitutionCorrectableASTRul
|
|||
|
||||
let contents = file.stringView
|
||||
if let bodyOffset = dictionary.bodyOffset {
|
||||
return contents.byteRangeToNSRange(start: offset, length: bodyOffset - offset)
|
||||
return contents.byteRangeToNSRange(ByteRange(location: offset, length: bodyOffset - offset))
|
||||
} else {
|
||||
return contents.byteRangeToNSRange(start: offset, length: length)
|
||||
return contents.byteRangeToNSRange(ByteRange(location: offset, length: length))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -148,9 +148,9 @@ extension SourceKittenDictionary {
|
|||
}
|
||||
|
||||
private func isVariable(file: SwiftLintFile) -> Bool {
|
||||
guard let start = offset, let length = length,
|
||||
guard let byteRange = byteRange,
|
||||
case let contents = file.stringView,
|
||||
let range = contents.byteRangeToNSRange(start: start, length: length),
|
||||
let range = contents.byteRangeToNSRange(byteRange),
|
||||
!file.match(pattern: "\\Avar\\b", with: [.keyword], range: range).isEmpty else {
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -90,9 +90,9 @@ public struct RedundantStringEnumValueRule: ASTRule, ConfigurationProviderRule,
|
|||
}
|
||||
}
|
||||
|
||||
private func violatingOffsetsForEnum(dictionary: SourceKittenDictionary, file: SwiftLintFile) -> [Int] {
|
||||
private func violatingOffsetsForEnum(dictionary: SourceKittenDictionary, file: SwiftLintFile) -> [ByteCount] {
|
||||
var caseCount = 0
|
||||
var violations = [Int]()
|
||||
var violations = [ByteCount]()
|
||||
|
||||
for enumCase in children(of: dictionary, matching: .enumcase) {
|
||||
caseCount += enumElementsCount(dictionary: enumCase)
|
||||
|
@ -112,8 +112,8 @@ public struct RedundantStringEnumValueRule: ASTRule, ConfigurationProviderRule,
|
|||
}).count
|
||||
}
|
||||
|
||||
private func violatingOffsetsForEnumCase(dictionary: SourceKittenDictionary, file: SwiftLintFile) -> [Int] {
|
||||
return children(of: dictionary, matching: .enumelement).flatMap { element -> [Int] in
|
||||
private func violatingOffsetsForEnumCase(dictionary: SourceKittenDictionary, file: SwiftLintFile) -> [ByteCount] {
|
||||
return children(of: dictionary, matching: .enumelement).flatMap { element -> [ByteCount] in
|
||||
guard let name = element.name else {
|
||||
return []
|
||||
}
|
||||
|
@ -122,18 +122,18 @@ public struct RedundantStringEnumValueRule: ASTRule, ConfigurationProviderRule,
|
|||
}
|
||||
|
||||
private func violatingOffsetsForEnumElement(dictionary: SourceKittenDictionary, name: String,
|
||||
file: SwiftLintFile) -> [Int] {
|
||||
file: SwiftLintFile) -> [ByteCount] {
|
||||
let enumInits = filterEnumInits(dictionary: dictionary)
|
||||
|
||||
return enumInits.compactMap { dictionary -> Int? in
|
||||
return enumInits.compactMap { dictionary -> ByteCount? in
|
||||
guard let offset = dictionary.offset,
|
||||
let length = dictionary.length else {
|
||||
return nil
|
||||
}
|
||||
|
||||
// the string would be quoted if offset and length were used directly
|
||||
let enumCaseName = file.stringView
|
||||
.substringWithByteRange(start: offset + 1, length: length - 2) ?? ""
|
||||
let rangeWithoutQuotes = ByteRange(location: offset + 1, length: length - 2)
|
||||
let enumCaseName = file.stringView.substringWithByteRange(rangeWithoutQuotes) ?? ""
|
||||
guard enumCaseName == name else {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -81,7 +81,8 @@ public struct RedundantVoidReturnRule: ConfigurationProviderRule, SubstitutionCo
|
|||
case let start = nameOffset + nameLength,
|
||||
case let end = dictionary.bodyOffset ?? offset + length,
|
||||
case let contents = file.stringView,
|
||||
let range = contents.byteRangeToNSRange(start: start, length: end - start),
|
||||
case let byteRange = ByteRange(location: start, length: end - start),
|
||||
let range = contents.byteRangeToNSRange(byteRange),
|
||||
file.match(pattern: "->", excludingSyntaxKinds: excludingKinds, range: range).count == 1,
|
||||
let match = file.match(pattern: pattern, excludingSyntaxKinds: excludingKinds, range: range).first else {
|
||||
return []
|
||||
|
|
|
@ -61,7 +61,7 @@ public struct TypeNameRule: ASTRule, ConfigurationProviderRule {
|
|||
}
|
||||
|
||||
private func validate(name: String, dictionary: SourceKittenDictionary = SourceKittenDictionary([:]),
|
||||
file: SwiftLintFile, offset: Int) -> [StyleViolation] {
|
||||
file: SwiftLintFile, offset: ByteCount) -> [StyleViolation] {
|
||||
guard !configuration.excluded.contains(name) else {
|
||||
return []
|
||||
}
|
||||
|
|
|
@ -65,8 +65,8 @@ public struct UnavailableFunctionRule: ASTRule, ConfigurationProviderRule, OptIn
|
|||
|
||||
guard let offset = dictionary.offset, containsFatalError,
|
||||
!isFunctionUnavailable(file: file, dictionary: dictionary),
|
||||
let bodyOffset = dictionary.bodyOffset, let bodyLength = dictionary.bodyLength,
|
||||
let range = file.stringView.byteRangeToNSRange(start: bodyOffset, length: bodyLength),
|
||||
let bodyRange = dictionary.bodyByteRange,
|
||||
let range = file.stringView.byteRangeToNSRange(bodyRange),
|
||||
file.match(pattern: "\\breturn\\b", with: [.keyword], range: range).isEmpty else {
|
||||
return []
|
||||
}
|
||||
|
@ -81,8 +81,8 @@ public struct UnavailableFunctionRule: ASTRule, ConfigurationProviderRule, OptIn
|
|||
private func isFunctionUnavailable(file: SwiftLintFile, dictionary: SourceKittenDictionary) -> Bool {
|
||||
return dictionary.swiftAttributes.contains { dict -> Bool in
|
||||
guard dict.attribute.flatMap(SwiftDeclarationAttributeKind.init(rawValue:)) == .available,
|
||||
let offset = dict.offset, let length = dict.length,
|
||||
let contents = file.stringView.substringWithByteRange(start: offset, length: length) else {
|
||||
let byteRange = dict.byteRange,
|
||||
let contents = file.stringView.substringWithByteRange(byteRange) else {
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
|
@ -38,13 +38,11 @@ public struct UnneededBreakInSwitchRule: ConfigurationProviderRule, AutomaticTes
|
|||
guard let byteRange = contents.NSRangeToByteRange(start: range.location, length: range.length),
|
||||
let innerStructure = file.structureDictionary.structures(forByteOffset: byteRange.location).last,
|
||||
innerStructure.statementKind == .case,
|
||||
let caseOffset = innerStructure.offset,
|
||||
let caseLength = innerStructure.length,
|
||||
let caseRange = innerStructure.byteRange,
|
||||
let lastPatternEnd = patternEnd(dictionary: innerStructure) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let caseRange = NSRange(location: caseOffset, length: caseLength)
|
||||
let tokens = file.syntaxMap.tokens(inByteRange: caseRange).filter { token in
|
||||
guard let kind = token.kind,
|
||||
token.offset > lastPatternEnd else {
|
||||
|
@ -73,8 +71,8 @@ public struct UnneededBreakInSwitchRule: ConfigurationProviderRule, AutomaticTes
|
|||
}
|
||||
}
|
||||
|
||||
private func patternEnd(dictionary: SourceKittenDictionary) -> Int? {
|
||||
let patternEnds = dictionary.elements.compactMap { subDictionary -> Int? in
|
||||
private func patternEnd(dictionary: SourceKittenDictionary) -> ByteCount? {
|
||||
let patternEnds = dictionary.elements.compactMap { subDictionary -> ByteCount? in
|
||||
guard subDictionary.kind == "source.lang.swift.structure.elem.pattern",
|
||||
let offset = subDictionary.offset,
|
||||
let length = subDictionary.length else {
|
||||
|
|
|
@ -44,7 +44,7 @@ public struct UnusedEnumeratedRule: ASTRule, ConfigurationProviderRule, Automati
|
|||
return []
|
||||
}
|
||||
|
||||
let offset: Int
|
||||
let offset: ByteCount
|
||||
let reason: String
|
||||
if firstTokenIsUnderscore {
|
||||
offset = tokens[0].offset
|
||||
|
@ -83,7 +83,7 @@ public struct UnusedEnumeratedRule: ASTRule, ConfigurationProviderRule, Automati
|
|||
return false
|
||||
}
|
||||
|
||||
private func byteRangeForVariables(dictionary: SourceKittenDictionary) -> NSRange? {
|
||||
private func byteRangeForVariables(dictionary: SourceKittenDictionary) -> ByteRange? {
|
||||
let expectedKind = "source.lang.swift.structure.elem.id"
|
||||
for subDict in dictionary.elements where subDict.kind == expectedKind {
|
||||
guard let offset = subDict.offset,
|
||||
|
@ -91,7 +91,7 @@ public struct UnusedEnumeratedRule: ASTRule, ConfigurationProviderRule, Automati
|
|||
continue
|
||||
}
|
||||
|
||||
return NSRange(location: offset, length: length)
|
||||
return ByteRange(location: offset, length: length)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -54,13 +54,13 @@ public struct XCTFailMessageRule: ASTRule, ConfigurationProviderRule, AutomaticT
|
|||
}
|
||||
|
||||
private func hasEmptyMessage(dictionary: SourceKittenDictionary, file: SwiftLintFile) -> Bool {
|
||||
guard
|
||||
let bodyOffset = dictionary.bodyOffset,
|
||||
let bodyLength = dictionary.bodyLength else { return false }
|
||||
guard let bodyRange = dictionary.bodyByteRange else {
|
||||
return false
|
||||
}
|
||||
|
||||
guard bodyLength > 0 else { return true }
|
||||
guard bodyRange.length > 0 else { return true }
|
||||
|
||||
let body = file.stringView.substringWithByteRange(start: bodyOffset, length: bodyLength)
|
||||
let body = file.stringView.substringWithByteRange(bodyRange)
|
||||
return body == "\"\""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,15 +46,7 @@ public struct XCTSpecificMatcherRule: ASTRule, OptInRule, ConfigurationProviderR
|
|||
return firstOffset < secondOffset
|
||||
}
|
||||
.prefix(2)
|
||||
.compactMap { argument -> String? in
|
||||
guard
|
||||
let argOffset = argument.offset,
|
||||
let argLength = argument.length,
|
||||
let body = file.stringView.substringWithByteRange(start: argOffset, length: argLength)
|
||||
else { return nil }
|
||||
|
||||
return body
|
||||
}
|
||||
.compactMap { $0.byteRange.flatMap(file.stringView.substringWithByteRange) }
|
||||
.sorted { arg1, _ -> Bool in
|
||||
return protectedArguments.contains(arg1)
|
||||
}
|
||||
|
|
|
@ -61,15 +61,14 @@ public struct AnyObjectProtocolRule: SubstitutionCorrectableASTRule, OptInRule,
|
|||
|
||||
return dictionary.elements.compactMap { subDict -> NSRange? in
|
||||
guard
|
||||
let offset = subDict.offset,
|
||||
let length = subDict.length,
|
||||
let content = file.stringView.substringWithByteRange(start: offset, length: length),
|
||||
let byteRange = subDict.byteRange,
|
||||
let content = file.stringView.substringWithByteRange(byteRange),
|
||||
content == "class"
|
||||
else {
|
||||
return nil
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return file.stringView.byteRangeToNSRange(start: offset, length: length)
|
||||
return file.stringView.byteRangeToNSRange(byteRange)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,14 +49,14 @@ public struct ArrayInitRule: ASTRule, ConfigurationProviderRule, OptInRule, Auto
|
|||
guard kind == .call, let name = dictionary.name, name.hasSuffix(".map"),
|
||||
let bodyOffset = dictionary.bodyOffset,
|
||||
let bodyLength = dictionary.bodyLength,
|
||||
let bodyRange = dictionary.bodyByteRange,
|
||||
let nameOffset = dictionary.nameOffset,
|
||||
let nameLength = dictionary.nameLength,
|
||||
let offset = dictionary.offset else {
|
||||
return []
|
||||
}
|
||||
|
||||
let range = NSRange(location: bodyOffset, length: bodyLength)
|
||||
let tokens = file.syntaxMap.tokens(inByteRange: range).filter { token in
|
||||
let tokens = file.syntaxMap.tokens(inByteRange: bodyRange).filter { token in
|
||||
guard let kind = token.kind else {
|
||||
return false
|
||||
}
|
||||
|
@ -84,37 +84,39 @@ public struct ArrayInitRule: ASTRule, ConfigurationProviderRule, OptInRule, Auto
|
|||
}
|
||||
|
||||
private func isClosureParameter(firstToken: SwiftLintSyntaxToken,
|
||||
nameEndPosition: Int,
|
||||
nameEndPosition: ByteCount,
|
||||
file: SwiftLintFile) -> Bool {
|
||||
let length = firstToken.offset - nameEndPosition
|
||||
guard length > 0,
|
||||
case let contents = file.stringView,
|
||||
let byteRange = contents.byteRangeToNSRange(start: nameEndPosition, length: length) else {
|
||||
return false
|
||||
case let byteRange = ByteRange(location: nameEndPosition, length: length),
|
||||
let nsRange = contents.byteRangeToNSRange(byteRange)
|
||||
else {
|
||||
return false
|
||||
}
|
||||
|
||||
let pattern = regex("\\A\\s*\\(?\\s*\\{")
|
||||
return pattern.firstMatch(in: file.contents, options: .anchored, range: byteRange) != nil
|
||||
return pattern.firstMatch(in: file.contents, options: .anchored, range: nsRange) != nil
|
||||
}
|
||||
|
||||
private func containsTrailingContent(lastToken: SwiftLintSyntaxToken,
|
||||
bodyEndPosition: Int,
|
||||
bodyEndPosition: ByteCount,
|
||||
file: SwiftLintFile) -> Bool {
|
||||
let lastTokenEnd = lastToken.offset + lastToken.length
|
||||
let remainingLength = bodyEndPosition - lastTokenEnd
|
||||
let remainingRange = NSRange(location: lastTokenEnd, length: remainingLength)
|
||||
let remainingRange = ByteRange(location: lastTokenEnd, length: remainingLength)
|
||||
return containsContent(inByteRange: remainingRange, file: file)
|
||||
}
|
||||
|
||||
private func containsLeadingContent(tokens: [SwiftLintSyntaxToken],
|
||||
bodyStartPosition: Int,
|
||||
bodyStartPosition: ByteCount,
|
||||
file: SwiftLintFile) -> Bool {
|
||||
let inTokenPosition = tokens.firstIndex(where: { token in
|
||||
token.kind == .keyword && file.contents(for: token) == "in"
|
||||
})
|
||||
|
||||
let firstToken: SwiftLintSyntaxToken
|
||||
let start: Int
|
||||
let start: ByteCount
|
||||
if let position = inTokenPosition {
|
||||
let index = tokens.index(after: position)
|
||||
firstToken = tokens[index]
|
||||
|
@ -126,25 +128,26 @@ public struct ArrayInitRule: ASTRule, ConfigurationProviderRule, OptInRule, Auto
|
|||
}
|
||||
|
||||
let length = firstToken.offset - start
|
||||
let remainingRange = NSRange(location: start, length: length)
|
||||
let remainingRange = ByteRange(location: start, length: length)
|
||||
return containsContent(inByteRange: remainingRange, file: file)
|
||||
}
|
||||
|
||||
private func containsContent(inByteRange byteRange: NSRange, file: SwiftLintFile) -> Bool {
|
||||
let nsstring = file.stringView
|
||||
private func containsContent(inByteRange byteRange: ByteRange, file: SwiftLintFile) -> Bool {
|
||||
let stringView = file.stringView
|
||||
let remainingTokens = file.syntaxMap.tokens(inByteRange: byteRange)
|
||||
let ranges = NSMutableIndexSet(indexesIn: byteRange)
|
||||
guard let nsRange = stringView.byteRangeToNSRange(byteRange) else {
|
||||
return false
|
||||
}
|
||||
|
||||
for token in remainingTokens {
|
||||
ranges.remove(in: token.range)
|
||||
let ranges = NSMutableIndexSet(indexesIn: nsRange)
|
||||
|
||||
for tokenNSRange in remainingTokens.compactMap({ stringView.byteRangeToNSRange($0.range) }) {
|
||||
ranges.remove(in: tokenNSRange)
|
||||
}
|
||||
|
||||
var containsContent = false
|
||||
ranges.enumerateRanges(options: []) { range, stop in
|
||||
guard let substring = nsstring.substringWithByteRange(start: range.location, length: range.length) else {
|
||||
return
|
||||
}
|
||||
|
||||
let substring = stringView.substring(with: range)
|
||||
let processedSubstring = substring
|
||||
.trimmingCharacters(in: CharacterSet(charactersIn: "{}"))
|
||||
.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
|
|
|
@ -65,8 +65,10 @@ public struct ClassDelegateProtocolRule: ASTRule, ConfigurationProviderRule, Aut
|
|||
let bodyOffset = dictionary.bodyOffset,
|
||||
case let contents = file.stringView,
|
||||
case let start = nameOffset + nameLength,
|
||||
let range = contents.byteRangeToNSRange(start: start, length: bodyOffset - start),
|
||||
!isClassProtocol(file: file, range: range) else {
|
||||
case let byteRange = ByteRange(location: start, length: bodyOffset - start),
|
||||
let range = contents.byteRangeToNSRange(byteRange),
|
||||
!isClassProtocol(file: file, range: range)
|
||||
else {
|
||||
return []
|
||||
}
|
||||
|
||||
|
|
|
@ -52,10 +52,9 @@ public struct CompilerProtocolInitRule: ASTRule, ConfigurationProviderRule {
|
|||
guard compilerProtocol.initCallNames.contains(name),
|
||||
case let arguments = dictionary.enclosedArguments.compactMap({ $0.name }),
|
||||
compilerProtocol.match(arguments: arguments),
|
||||
let offset = dictionary.offset,
|
||||
let length = dictionary.length,
|
||||
let range = file.stringView.byteRangeToNSRange(start: offset, length: length) else {
|
||||
continue
|
||||
let range = dictionary.byteRange.flatMap(file.stringView.byteRangeToNSRange)
|
||||
else {
|
||||
continue
|
||||
}
|
||||
|
||||
return [(compilerProtocol, range)]
|
||||
|
|
|
@ -53,9 +53,9 @@ public struct DeploymentTargetRule: ConfigurationProviderRule {
|
|||
return file.rangesAndTokens(matching: pattern).flatMap { range, tokens -> [StyleViolation] in
|
||||
guard let availabilityToken = tokens.first,
|
||||
availabilityToken.kind == .keyword,
|
||||
let tokenRange = file.stringView.byteRangeToNSRange(start: availabilityToken.offset,
|
||||
length: availabilityToken.length) else {
|
||||
return []
|
||||
let tokenRange = file.stringView.byteRangeToNSRange(availabilityToken.range)
|
||||
else {
|
||||
return []
|
||||
}
|
||||
|
||||
let rangeToSearch = NSRange(location: tokenRange.upperBound, length: range.length - tokenRange.length)
|
||||
|
@ -83,17 +83,19 @@ public struct DeploymentTargetRule: ConfigurationProviderRule {
|
|||
|
||||
let contents = file.stringView
|
||||
return attributes.flatMap { dictionary -> [StyleViolation] in
|
||||
guard let offset = dictionary.offset, let length = dictionary.length,
|
||||
let range = contents.byteRangeToNSRange(start: offset, length: length) else {
|
||||
return []
|
||||
guard let byteRange = dictionary.byteRange,
|
||||
let range = contents.byteRangeToNSRange(byteRange)
|
||||
else {
|
||||
return []
|
||||
}
|
||||
|
||||
return validate(range: range, file: file, violationType: "attribute", byteOffsetToReport: offset)
|
||||
return validate(range: range, file: file, violationType: "attribute",
|
||||
byteOffsetToReport: byteRange.location)
|
||||
}.unique
|
||||
}
|
||||
|
||||
private func validate(range: NSRange, file: SwiftLintFile, violationType: String,
|
||||
byteOffsetToReport: Int) -> [StyleViolation] {
|
||||
byteOffsetToReport: ByteCount) -> [StyleViolation] {
|
||||
let platformToConfiguredMinVersion = self.platformToConfiguredMinVersion
|
||||
let allPlatforms = "(?:" + platformToConfiguredMinVersion.keys.joined(separator: "|") + ")"
|
||||
let pattern = "\(allPlatforms) [\\d\\.]+"
|
||||
|
|
|
@ -48,7 +48,7 @@ public struct DiscardedNotificationCenterObserverRule: ASTRule, ConfigurationPro
|
|||
}
|
||||
|
||||
private func violationOffsets(in file: SwiftLintFile, dictionary: SourceKittenDictionary,
|
||||
kind: SwiftExpressionKind) -> [Int] {
|
||||
kind: SwiftExpressionKind) -> [ByteCount] {
|
||||
guard kind == .call,
|
||||
let name = dictionary.name,
|
||||
name.hasSuffix(".addObserver"),
|
||||
|
@ -57,7 +57,7 @@ public struct DiscardedNotificationCenterObserverRule: ASTRule, ConfigurationPro
|
|||
argumentsNames == ["forName", "object", "queue"] ||
|
||||
argumentsNames == ["forName", "object", "queue", "using"],
|
||||
let offset = dictionary.offset,
|
||||
let range = file.stringView.byteRangeToNSRange(start: 0, length: offset) else {
|
||||
let range = file.stringView.byteRangeToNSRange(ByteRange(location: 0, length: offset)) else {
|
||||
return []
|
||||
}
|
||||
|
||||
|
@ -83,7 +83,7 @@ public struct DiscardedNotificationCenterObserverRule: ASTRule, ConfigurationPro
|
|||
}
|
||||
|
||||
private extension SourceKittenDictionary {
|
||||
func functions(forByteOffset byteOffset: Int) -> [SourceKittenDictionary] {
|
||||
func functions(forByteOffset byteOffset: ByteCount) -> [SourceKittenDictionary] {
|
||||
return structures(forByteOffset: byteOffset)
|
||||
.filter { $0.declarationKind.map(SwiftDeclarationKind.functionKinds.contains) == true }
|
||||
}
|
||||
|
|
|
@ -47,11 +47,12 @@ public struct DuplicateEnumCasesRule: ConfigurationProviderRule, ASTRule, Automa
|
|||
.compactMap { substructureElements(of: $0, matching: .enumelement) }
|
||||
.flatMap { $0 }
|
||||
|
||||
var elementsByName: [String: [Int]] = [:]
|
||||
var elementsByName: [String: [ByteCount]] = [:]
|
||||
for element in enumElements {
|
||||
guard let name = element.name,
|
||||
let nameWithoutParameters = name.split(separator: "(").first,
|
||||
let offset = element.offset else {
|
||||
let offset = element.offset
|
||||
else {
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
|
@ -34,9 +34,7 @@ public struct DynamicInlineRule: ASTRule, ConfigurationProviderRule, AutomaticTe
|
|||
case let attributes = dictionary.enclosedSwiftAttributes,
|
||||
attributes.contains(.dynamic),
|
||||
attributes.contains(.inline),
|
||||
let funcByteOffset = dictionary.offset,
|
||||
let funcOffset = file.stringView
|
||||
.byteRangeToNSRange(start: funcByteOffset, length: 0)?.location,
|
||||
let funcOffset = dictionary.offset.flatMap(file.stringView.location),
|
||||
case let inlinePattern = regex("@inline"),
|
||||
case let range = NSRange(location: 0, length: funcOffset),
|
||||
let inlineMatch = inlinePattern.matches(in: file.contents, options: [], range: range)
|
||||
|
|
|
@ -131,8 +131,7 @@ public struct IdenticalOperandsRule: ConfigurationProviderRule, OptInRule, Autom
|
|||
}
|
||||
}
|
||||
|
||||
let violationRange = file.stringView.byteRangeToNSRange(start: leftmostToken.offset,
|
||||
length: leftmostToken.length)
|
||||
let violationRange = file.stringView.byteRangeToNSRange(leftmostToken.range)
|
||||
return violationRange
|
||||
}
|
||||
|
||||
|
@ -175,12 +174,13 @@ public struct IdenticalOperandsRule: ConfigurationProviderRule, OptInRule, Autom
|
|||
|
||||
private extension StringView {
|
||||
func subStringWithSyntaxToken(_ syntaxToken: SwiftLintSyntaxToken) -> String? {
|
||||
return substringWithByteRange(start: syntaxToken.offset, length: syntaxToken.length)
|
||||
return substringWithByteRange(syntaxToken.range)
|
||||
}
|
||||
|
||||
func subStringBetweenTokens(_ startToken: SwiftLintSyntaxToken, _ endToken: SwiftLintSyntaxToken) -> String? {
|
||||
return substringWithByteRange(start: startToken.offset + startToken.length,
|
||||
length: endToken.offset - startToken.offset - startToken.length)
|
||||
let byteRange = ByteRange(location: startToken.range.upperBound,
|
||||
length: endToken.offset - startToken.range.upperBound)
|
||||
return substringWithByteRange(byteRange)
|
||||
}
|
||||
|
||||
func isDotOrOptionalChainingBetweenTokens(_ startToken: SwiftLintSyntaxToken,
|
||||
|
|
|
@ -63,7 +63,7 @@ public struct InertDeferRule: ConfigurationProviderRule, AutomaticTestableRule {
|
|||
case let outerKindIndex = kinds.index(before: brace.offset),
|
||||
case let outerKind = kinds[outerKindIndex],
|
||||
case let braceEnd = brace.element.byteRange.upperBound,
|
||||
case let tokensRange = NSRange(location: braceEnd, length: outerKind.byteRange.upperBound - braceEnd),
|
||||
case let tokensRange = ByteRange(location: braceEnd, length: outerKind.byteRange.upperBound - braceEnd),
|
||||
case let tokens = file.syntaxMap.tokens(inByteRange: tokensRange),
|
||||
!tokens.contains(where: isNotComment) else {
|
||||
return nil
|
||||
|
@ -76,7 +76,7 @@ public struct InertDeferRule: ConfigurationProviderRule, AutomaticTestableRule {
|
|||
}
|
||||
}
|
||||
|
||||
private func isBrace(offset: Int, element: (kind: String, byteRange: NSRange)) -> Bool {
|
||||
private func isBrace(offset: Int, element: (kind: String, byteRange: ByteRange)) -> Bool {
|
||||
return StatementKind(rawValue: element.kind) == .brace
|
||||
}
|
||||
|
||||
|
|
|
@ -41,14 +41,14 @@ public struct LowerACLThanParentRule: OptInRule, ConfigurationProviderRule, Auto
|
|||
}
|
||||
|
||||
private func validateACL(isHigherThan parentAccessibility: AccessControlLevel,
|
||||
in substructure: SourceKittenDictionary) -> [Int] {
|
||||
return substructure.substructure.flatMap { element -> [Int] in
|
||||
in substructure: SourceKittenDictionary) -> [ByteCount] {
|
||||
return substructure.substructure.flatMap { element -> [ByteCount] in
|
||||
guard let elementKind = element.declarationKind,
|
||||
elementKind.isRelevantDeclaration else {
|
||||
return []
|
||||
}
|
||||
|
||||
var violationOffset: Int?
|
||||
var violationOffset: ByteCount?
|
||||
let accessibility = element.accessibility ?? .internal
|
||||
// Swift 5 infers members of private types with no explicit ACL attribute to be `internal`.
|
||||
let isInferredACL = accessibility == .internal && !element.enclosedSwiftAttributes.contains(.internal)
|
||||
|
|
|
@ -189,8 +189,8 @@ public struct MarkRule: CorrectableRule, ConfigurationProviderRule {
|
|||
}
|
||||
return !syntaxTokens.isEmpty && SyntaxKind.commentKinds.contains(syntaxKind)
|
||||
}.compactMap { range, syntaxTokens in
|
||||
let identifierRange = file.stringView
|
||||
.byteRangeToNSRange(start: syntaxTokens[0].offset, length: 0)
|
||||
let byteRange = ByteRange(location: syntaxTokens[0].offset, length: 0)
|
||||
let identifierRange = file.stringView.byteRangeToNSRange(byteRange)
|
||||
return identifierRange.map { NSUnionRange($0, range) }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ import SourceKittenFramework
|
|||
|
||||
private extension SwiftLintFile {
|
||||
func missingDocOffsets(in dictionary: SourceKittenDictionary,
|
||||
acls: [AccessControlLevel]) -> [(Int, AccessControlLevel)] {
|
||||
acls: [AccessControlLevel]) -> [(ByteCount, AccessControlLevel)] {
|
||||
if dictionary.enclosedSwiftAttributes.contains(.override) ||
|
||||
!dictionary.inheritedTypes.isEmpty {
|
||||
return []
|
||||
|
@ -77,8 +77,7 @@ public struct MissingDocsRule: OptInRule, ConfigurationProviderRule, AutomaticTe
|
|||
public func validate(file: SwiftLintFile) -> [StyleViolation] {
|
||||
let acls = configuration.parameters.map { $0.value }
|
||||
let dict = file.structureDictionary
|
||||
return file.missingDocOffsets(in: dict,
|
||||
acls: acls).map { (offset: Int, acl: AccessControlLevel) in
|
||||
return file.missingDocOffsets(in: dict, acls: acls).map { offset, acl in
|
||||
StyleViolation(ruleDescription: type(of: self).description,
|
||||
severity: configuration.parameters.first { $0.value == acl }?.severity ?? .warning,
|
||||
location: Location(file: file, byteOffset: offset),
|
||||
|
|
|
@ -28,9 +28,8 @@ public struct NSLocalizedStringKeyRule: ASTRule, OptInRule, ConfigurationProvide
|
|||
dictionary.name == "NSLocalizedString",
|
||||
let firstArgument = dictionary.enclosedArguments.first,
|
||||
firstArgument.name == nil,
|
||||
let offset = firstArgument.offset,
|
||||
let length = firstArgument.length,
|
||||
case let kinds = file.syntaxMap.kinds(inByteRange: NSRange(location: offset, length: length)),
|
||||
let byteRange = firstArgument.byteRange,
|
||||
case let kinds = file.syntaxMap.kinds(inByteRange: byteRange),
|
||||
!kinds.allSatisfy({ $0 == .string }) else {
|
||||
return []
|
||||
}
|
||||
|
@ -38,7 +37,7 @@ public struct NSLocalizedStringKeyRule: ASTRule, OptInRule, ConfigurationProvide
|
|||
return [
|
||||
StyleViolation(ruleDescription: type(of: self).description,
|
||||
severity: configuration.severity,
|
||||
location: Location(file: file, byteOffset: offset))
|
||||
location: Location(file: file, byteOffset: byteRange.location))
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,8 +29,8 @@ public struct NotificationCenterDetachmentRule: ASTRule, ConfigurationProviderRu
|
|||
}
|
||||
|
||||
private func violationOffsets(file: SwiftLintFile,
|
||||
dictionary: SourceKittenDictionary) -> [Int] {
|
||||
return dictionary.substructure.flatMap { subDict -> [Int] in
|
||||
dictionary: SourceKittenDictionary) -> [ByteCount] {
|
||||
return dictionary.substructure.flatMap { subDict -> [ByteCount] in
|
||||
// complete detachment is allowed on `deinit`
|
||||
if subDict.declarationKind == .functionMethodInstance,
|
||||
subDict.name == "deinit" {
|
||||
|
@ -51,16 +51,11 @@ public struct NotificationCenterDetachmentRule: ASTRule, ConfigurationProviderRu
|
|||
private var methodName = "NotificationCenter.default.removeObserver"
|
||||
|
||||
private func parameterIsSelf(dictionary: SourceKittenDictionary, file: SwiftLintFile) -> Bool {
|
||||
guard let bodyOffset = dictionary.bodyOffset,
|
||||
let bodyLength = dictionary.bodyLength else {
|
||||
return false
|
||||
}
|
||||
|
||||
let range = NSRange(location: bodyOffset, length: bodyLength)
|
||||
let tokens = file.syntaxMap.tokens(inByteRange: range)
|
||||
let types = tokens.kinds
|
||||
|
||||
guard types == [.keyword], let token = tokens.first else {
|
||||
guard let bodyRange = dictionary.bodyByteRange,
|
||||
case let tokens = file.syntaxMap.tokens(inByteRange: bodyRange),
|
||||
tokens.kinds == [.keyword],
|
||||
let token = tokens.first
|
||||
else {
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
|
@ -55,12 +55,12 @@ public struct OrphanedDocCommentRule: ConfigurationProviderRule {
|
|||
return token.kind == .docComment || token.kind == .docCommentField
|
||||
}
|
||||
|
||||
let docummentedDeclsRanges = file.structureDictionary.traverseDepthFirst { dictionary -> [NSRange]? in
|
||||
let docummentedDeclsRanges = file.structureDictionary.traverseDepthFirst { dictionary -> [ByteRange]? in
|
||||
guard let docOffset = dictionary.docOffset, let docLength = dictionary.docLength else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return [NSRange(location: docOffset, length: docLength)]
|
||||
return [ByteRange(location: docOffset, length: docLength)]
|
||||
}.sorted { $0.location < $1.location }
|
||||
|
||||
return docStringsTokens
|
||||
|
|
|
@ -40,11 +40,12 @@ public struct OverrideInExtensionRule: ConfigurationProviderRule, OptInRule, Aut
|
|||
return elements
|
||||
.filter { $0.kind == .extension && !susceptibleNames.contains($0.name) }
|
||||
.flatMap { element in
|
||||
return element.dictionary.substructure.compactMap { element -> Int? in
|
||||
return element.dictionary.substructure.compactMap { element -> ByteCount? in
|
||||
guard element.declarationKind != nil,
|
||||
element.enclosedSwiftAttributes.contains(.override),
|
||||
let offset = element.offset else {
|
||||
return nil
|
||||
let offset = element.offset
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return offset
|
||||
|
|
|
@ -60,8 +60,8 @@ public struct QuickDiscouragedCallRule: OptInRule, ConfigurationProviderRule, Au
|
|||
}
|
||||
}
|
||||
|
||||
private func violationOffsets(in substructure: [SourceKittenDictionary]) -> [Int] {
|
||||
return substructure.flatMap { dictionary -> [Int] in
|
||||
private func violationOffsets(in substructure: [SourceKittenDictionary]) -> [ByteCount] {
|
||||
return substructure.flatMap { dictionary -> [ByteCount] in
|
||||
let substructure = dictionary.substructure.flatMap { dict -> [SourceKittenDictionary] in
|
||||
if dict.expressionKind == .closure {
|
||||
return dict.substructure
|
||||
|
@ -74,7 +74,7 @@ public struct QuickDiscouragedCallRule: OptInRule, ConfigurationProviderRule, Au
|
|||
}
|
||||
}
|
||||
|
||||
private func toViolationOffsets(dictionary: SourceKittenDictionary) -> [Int] {
|
||||
private func toViolationOffsets(dictionary: SourceKittenDictionary) -> [ByteCount] {
|
||||
guard
|
||||
dictionary.kind != nil,
|
||||
let offset = dictionary.offset
|
||||
|
@ -90,7 +90,7 @@ public struct QuickDiscouragedCallRule: OptInRule, ConfigurationProviderRule, Au
|
|||
return dictionary.substructure.compactMap(toViolationOffset)
|
||||
}
|
||||
|
||||
private func toViolationOffset(dictionary: SourceKittenDictionary) -> Int? {
|
||||
private func toViolationOffset(dictionary: SourceKittenDictionary) -> ByteCount? {
|
||||
guard
|
||||
let name = dictionary.name,
|
||||
let offset = dictionary.offset,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import SourceKittenFramework
|
||||
|
||||
public struct RawValueForCamelCasedCodableEnumRule: ASTRule, OptInRule, ConfigurationProviderRule,
|
||||
AutomaticTestableRule {
|
||||
AutomaticTestableRule {
|
||||
public var configuration = SeverityConfiguration(.warning)
|
||||
|
||||
public init() {}
|
||||
|
@ -104,13 +104,11 @@ AutomaticTestableRule {
|
|||
}
|
||||
}
|
||||
|
||||
private func violatingOffsetsForEnum(dictionary: SourceKittenDictionary) -> [Int] {
|
||||
let locs = substructureElements(of: dictionary, matching: .enumcase)
|
||||
private func violatingOffsetsForEnum(dictionary: SourceKittenDictionary) -> [ByteCount] {
|
||||
return substructureElements(of: dictionary, matching: .enumcase)
|
||||
.compactMap { substructureElements(of: $0, matching: .enumelement) }
|
||||
.flatMap(camelCasedEnumCasesMissingRawValue)
|
||||
.compactMap { $0.offset }
|
||||
|
||||
return locs
|
||||
}
|
||||
|
||||
private func substructureElements(of dict: SourceKittenDictionary,
|
||||
|
|
|
@ -89,7 +89,7 @@ public struct RequiredEnumCaseRule: ASTRule, OptInRule, ConfigurationProviderRul
|
|||
///
|
||||
/// - returns: Location of where the enum declaration starts.
|
||||
static func location(from dictionary: SourceKittenDictionary, in file: SwiftLintFile) -> Location {
|
||||
return Location(file: file, characterOffset: dictionary.offset ?? 0)
|
||||
return Location(file: file, byteOffset: dictionary.offset ?? 0)
|
||||
}
|
||||
|
||||
/// Determines the names of cases found in the enum.
|
||||
|
|
|
@ -27,8 +27,9 @@ public struct StrongIBOutletRule: ConfigurationProviderRule, ASTRule, OptInRule,
|
|||
case let attributes = dictionary.enclosedSwiftAttributes,
|
||||
attributes.contains(.iboutlet),
|
||||
attributes.contains(.weak),
|
||||
let offset = dictionary.offset else {
|
||||
return []
|
||||
let offset = dictionary.offset
|
||||
else {
|
||||
return []
|
||||
}
|
||||
|
||||
return [
|
||||
|
|
|
@ -29,26 +29,28 @@ public struct UnownedVariableCaptureRule: ASTRule, OptInRule, ConfigurationProvi
|
|||
|
||||
public func validate(file: SwiftLintFile, kind: SwiftExpressionKind,
|
||||
dictionary: SourceKittenDictionary) -> [StyleViolation] {
|
||||
guard kind == .closure, let bodyOffset = dictionary.bodyOffset, let bodyLength = dictionary.bodyLength,
|
||||
guard kind == .closure, let bodyRange = dictionary.bodyByteRange,
|
||||
case let contents = file.stringView,
|
||||
let closureRange = contents.byteRangeToNSRange(start: bodyOffset, length: bodyLength),
|
||||
let closureRange = contents.byteRangeToNSRange(bodyRange),
|
||||
let inTokenRange = file.match(pattern: "\\bin\\b", with: [.keyword], range: closureRange).first,
|
||||
let inTokenByteRange = contents.NSRangeToByteRange(start: inTokenRange.location,
|
||||
length: inTokenRange.length) else {
|
||||
return []
|
||||
length: inTokenRange.length)
|
||||
else {
|
||||
return []
|
||||
}
|
||||
|
||||
let length = inTokenByteRange.location - bodyOffset
|
||||
let variables = localVariableDeclarations(inByteRange: NSRange(location: bodyOffset, length: length),
|
||||
let length = inTokenByteRange.location - bodyRange.location
|
||||
let variables = localVariableDeclarations(inByteRange: ByteRange(location: bodyRange.location, length: length),
|
||||
structureDictionary: file.structureDictionary)
|
||||
let unownedVariableOffsets = variables.compactMap { dictionary in
|
||||
return dictionary.swiftAttributes.first { attributeDict in
|
||||
guard attributeDict.attribute.flatMap(SwiftDeclarationAttributeKind.init) == .weak,
|
||||
let offset = attributeDict.offset, let length = attributeDict.length else {
|
||||
return false
|
||||
let attributeByteRange = attributeDict.byteRange
|
||||
else {
|
||||
return false
|
||||
}
|
||||
|
||||
return contents.substringWithByteRange(start: offset, length: length) == "unowned"
|
||||
return contents.substringWithByteRange(attributeByteRange) == "unowned"
|
||||
}?.offset
|
||||
}
|
||||
|
||||
|
@ -59,13 +61,14 @@ public struct UnownedVariableCaptureRule: ASTRule, OptInRule, ConfigurationProvi
|
|||
}
|
||||
}
|
||||
|
||||
private func localVariableDeclarations(inByteRange byteRange: NSRange,
|
||||
private func localVariableDeclarations(inByteRange byteRange: ByteRange,
|
||||
structureDictionary: SourceKittenDictionary) -> [SourceKittenDictionary] {
|
||||
return structureDictionary.traverseBreadthFirst { dictionary in
|
||||
guard dictionary.declarationKind == .varLocal,
|
||||
let variableByteRange = dictionary.byteRange,
|
||||
byteRange.intersects(variableByteRange) else {
|
||||
return nil
|
||||
byteRange.intersects(variableByteRange)
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
return [dictionary]
|
||||
}
|
||||
|
|
|
@ -80,12 +80,14 @@ public struct UnusedCaptureListRule: ASTRule, ConfigurationProviderRule, Automat
|
|||
guard kind == .closure,
|
||||
let offset = dictionary.offset,
|
||||
let length = dictionary.length,
|
||||
let closureRange = contents.byteRangeToNSRange(start: offset, length: length)
|
||||
let closureByteRange = dictionary.byteRange,
|
||||
let closureRange = contents.byteRangeToNSRange(closureByteRange)
|
||||
else { return [] }
|
||||
|
||||
let firstSubstructureOffset = dictionary.substructure.first?.offset ?? (offset + length)
|
||||
let captureListSearchLength = firstSubstructureOffset - offset
|
||||
guard let captureListSearchRange = contents.byteRangeToNSRange(start: offset, length: captureListSearchLength),
|
||||
let captureListSearchByteRange = ByteRange(location: offset, length: captureListSearchLength)
|
||||
guard let captureListSearchRange = contents.byteRangeToNSRange(captureListSearchByteRange),
|
||||
let match = captureListRegex.firstMatch(in: file.contents, options: [], range: captureListSearchRange)
|
||||
else { return [] }
|
||||
|
||||
|
@ -131,7 +133,7 @@ public struct UnusedCaptureListRule: ASTRule, ConfigurationProviderRule, Automat
|
|||
}
|
||||
}
|
||||
|
||||
private func identifierStrings(in file: SwiftLintFile, byteRange: NSRange) -> Set<String> {
|
||||
private func identifierStrings(in file: SwiftLintFile, byteRange: ByteRange) -> Set<String> {
|
||||
let identifiers = file.syntaxMap
|
||||
.tokens(inByteRange: byteRange)
|
||||
.compactMap { token -> String? in
|
||||
|
|
|
@ -127,54 +127,62 @@ public struct UnusedClosureParameterRule: SubstitutionCorrectableASTRule, Config
|
|||
let nameOffset = dictionary.nameOffset,
|
||||
let nameLength = dictionary.nameLength,
|
||||
let bodyLength = dictionary.bodyLength,
|
||||
bodyLength > 0 else {
|
||||
return []
|
||||
bodyLength > 0
|
||||
else {
|
||||
return []
|
||||
}
|
||||
|
||||
let rangeStart = nameOffset + nameLength
|
||||
let rangeLength = (offset + length) - (nameOffset + nameLength)
|
||||
let byteRange = ByteRange(location: rangeStart, length: rangeLength)
|
||||
let parameters = dictionary.enclosedVarParameters
|
||||
let contents = file.stringView
|
||||
|
||||
return parameters.compactMap { param -> (NSRange, String)? in
|
||||
guard let paramOffset = param.offset,
|
||||
let name = param.name,
|
||||
name != "_",
|
||||
let regex = try? NSRegularExpression(pattern: name,
|
||||
options: [.ignoreMetacharacters]),
|
||||
let range = contents.byteRangeToNSRange(start: rangeStart, length: rangeLength)
|
||||
self.rangeAndName(parameter: param, contents: contents, byteRange: byteRange, file: file)
|
||||
}
|
||||
}
|
||||
|
||||
private func rangeAndName(parameter: SourceKittenDictionary, contents: StringView, byteRange: ByteRange,
|
||||
file: SwiftLintFile) -> (range: NSRange, name: String)? {
|
||||
guard let paramOffset = parameter.offset,
|
||||
let name = parameter.name,
|
||||
name != "_",
|
||||
let regex = try? NSRegularExpression(pattern: name,
|
||||
options: [.ignoreMetacharacters]),
|
||||
let range = contents.byteRangeToNSRange(byteRange)
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let paramLength = ByteCount(name.lengthOfBytes(using: .utf8))
|
||||
|
||||
let matches = regex.matches(in: file.contents, options: [], range: range).ranges()
|
||||
for range in matches {
|
||||
guard let byteRange = contents.NSRangeToByteRange(start: range.location,
|
||||
length: range.length),
|
||||
// if it's the parameter declaration itself, we should skip
|
||||
byteRange.location > paramOffset,
|
||||
case let tokens = file.syntaxMap.tokens(inByteRange: byteRange)
|
||||
else {
|
||||
continue
|
||||
}
|
||||
|
||||
let token = tokens.first(where: { token -> Bool in
|
||||
return (token.kind == .identifier
|
||||
|| (token.kind == .keyword && name == "self")) &&
|
||||
token.offset == byteRange.location &&
|
||||
token.length == byteRange.length
|
||||
})
|
||||
|
||||
// found a usage, there's no violation!
|
||||
guard token == nil else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let paramLength = name.lengthOfBytes(using: .utf8)
|
||||
|
||||
let matches = regex.matches(in: file.contents, options: [], range: range).ranges()
|
||||
for range in matches {
|
||||
guard let byteRange = contents.NSRangeToByteRange(start: range.location,
|
||||
length: range.length),
|
||||
// if it's the parameter declaration itself, we should skip
|
||||
byteRange.location > paramOffset,
|
||||
case let tokens = file.syntaxMap.tokens(inByteRange: byteRange) else {
|
||||
continue
|
||||
}
|
||||
|
||||
let token = tokens.first(where: { token -> Bool in
|
||||
return (token.kind == .identifier
|
||||
|| (token.kind == .keyword && name == "self")) &&
|
||||
token.offset == byteRange.location &&
|
||||
token.length == byteRange.length
|
||||
})
|
||||
|
||||
// found a usage, there's no violation!
|
||||
guard token == nil else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if let range = contents.byteRangeToNSRange(start: paramOffset, length: paramLength) {
|
||||
return (range, name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
let violationByteRange = ByteRange(location: paramOffset, length: paramLength)
|
||||
return contents.byteRangeToNSRange(violationByteRange).map { range in
|
||||
return (range, name)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -103,9 +103,9 @@ public struct UnusedControlFlowLabelRule: SubstitutionCorrectableASTRule, Config
|
|||
let contentsNSString = file.stringView
|
||||
if let byteRange = contentsNSString.NSRangeToByteRange(start: violationRange.location,
|
||||
length: violationRange.length),
|
||||
let nextToken = file.syntaxMap.tokens.first(where: { $0.offset > byteRange.location }),
|
||||
let nextTokenLocation = contentsNSString.byteRangeToNSRange(start: nextToken.offset, length: 0) {
|
||||
rangeToRemove.length = nextTokenLocation.location - violationRange.location
|
||||
let nextToken = file.syntaxMap.tokens.first(where: { $0.offset > byteRange.location }) {
|
||||
let nextTokenLocation = contentsNSString.location(fromByteOffset: nextToken.offset)
|
||||
rangeToRemove.length = nextTokenLocation - violationRange.location
|
||||
}
|
||||
|
||||
return (rangeToRemove, "")
|
||||
|
@ -114,22 +114,18 @@ public struct UnusedControlFlowLabelRule: SubstitutionCorrectableASTRule, Config
|
|||
public func violationRanges(in file: SwiftLintFile, kind: StatementKind,
|
||||
dictionary: SourceKittenDictionary) -> [NSRange] {
|
||||
guard type(of: self).kinds.contains(kind),
|
||||
let offset = dictionary.offset, let length = dictionary.length,
|
||||
case let byteRange = NSRange(location: offset, length: length),
|
||||
let byteRange = dictionary.byteRange,
|
||||
case let tokens = file.syntaxMap.tokens(inByteRange: byteRange),
|
||||
let firstToken = tokens.first,
|
||||
firstToken.kind == .identifier,
|
||||
let tokenContent = file.contents(for: firstToken),
|
||||
case let contents = file.stringView,
|
||||
let range = contents.byteRangeToNSRange(start: offset, length: length) else {
|
||||
return []
|
||||
}
|
||||
|
||||
let pattern = "(?:break|continue)\\s+\(tokenContent)\\b"
|
||||
guard file.match(pattern: pattern, with: [.keyword, .identifier], range: range).isEmpty,
|
||||
let violationRange = contents.byteRangeToNSRange(start: firstToken.offset,
|
||||
length: firstToken.length) else {
|
||||
return []
|
||||
let range = contents.byteRangeToNSRange(byteRange),
|
||||
case let pattern = "(?:break|continue)\\s+\(tokenContent)\\b",
|
||||
file.match(pattern: pattern, with: [.keyword, .identifier], range: range).isEmpty,
|
||||
let violationRange = contents.byteRangeToNSRange(firstToken.range)
|
||||
else {
|
||||
return []
|
||||
}
|
||||
|
||||
return [violationRange]
|
||||
|
|
|
@ -4,7 +4,7 @@ import SourceKittenFramework
|
|||
public struct UnusedDeclarationRule: AutomaticTestableRule, ConfigurationProviderRule, AnalyzerRule, CollectingRule {
|
||||
public struct FileUSRs {
|
||||
var referenced: Set<String>
|
||||
var declared: [(usr: String, nameOffset: Int)]
|
||||
var declared: [(usr: String, nameOffset: ByteCount)]
|
||||
var testCaseUSRs: Set<String>
|
||||
}
|
||||
|
||||
|
@ -121,9 +121,9 @@ public struct UnusedDeclarationRule: AutomaticTestableRule, ConfigurationProvide
|
|||
}
|
||||
|
||||
private func violationOffsets(in file: SwiftLintFile, compilerArguments: [String],
|
||||
declaredUSRs: [(usr: String, nameOffset: Int)],
|
||||
declaredUSRs: [(usr: String, nameOffset: ByteCount)],
|
||||
allReferencedUSRs: Set<String>,
|
||||
allTestCaseUSRs: Set<String>) -> [Int] {
|
||||
allTestCaseUSRs: Set<String>) -> [ByteCount] {
|
||||
// Unused declarations are:
|
||||
// 1. all declarations
|
||||
// 2. minus all references
|
||||
|
@ -160,7 +160,7 @@ private extension SwiftLintFile {
|
|||
return nil
|
||||
}
|
||||
|
||||
let offset = Int64(token.offset)
|
||||
let offset = token.offset
|
||||
let request = Request.cursorInfo(file: path, offset: offset, arguments: compilerArguments)
|
||||
guard var cursorInfo = try? request.sendIfNotDisabled() else {
|
||||
return nil
|
||||
|
@ -169,14 +169,14 @@ private extension SwiftLintFile {
|
|||
if let acl = editorOpen.aclAtOffset(offset) {
|
||||
cursorInfo["key.accessibility"] = acl.rawValue
|
||||
}
|
||||
cursorInfo["swiftlint.offset"] = offset
|
||||
cursorInfo["swiftlint.offset"] = Int64(offset.value)
|
||||
return cursorInfo
|
||||
}
|
||||
.map(SourceKittenDictionary.init)
|
||||
}
|
||||
|
||||
static func declaredUSRs(allCursorInfo: [SourceKittenDictionary], includePublicAndOpen: Bool)
|
||||
-> [(usr: String, nameOffset: Int)] {
|
||||
-> [(usr: String, nameOffset: ByteCount)] {
|
||||
return allCursorInfo.compactMap { cursorInfo in
|
||||
return declaredUSRAndOffset(cursorInfo: cursorInfo, includePublicAndOpen: includePublicAndOpen)
|
||||
}
|
||||
|
@ -191,7 +191,7 @@ private extension SwiftLintFile {
|
|||
}
|
||||
|
||||
private static func declaredUSRAndOffset(cursorInfo: SourceKittenDictionary, includePublicAndOpen: Bool)
|
||||
-> (usr: String, nameOffset: Int)? {
|
||||
-> (usr: String, nameOffset: ByteCount)? {
|
||||
if let offset = cursorInfo.swiftlintOffset,
|
||||
let usr = cursorInfo.usr,
|
||||
let kind = cursorInfo.declarationKind,
|
||||
|
@ -231,7 +231,7 @@ private extension SwiftLintFile {
|
|||
return nil
|
||||
}
|
||||
|
||||
return (usr, Int(offset))
|
||||
return (usr, ByteCount(offset))
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -276,7 +276,7 @@ private extension SourceKittenDictionary {
|
|||
return value["key.annotated_decl"] as? String
|
||||
}
|
||||
|
||||
func aclAtOffset(_ offset: Int64) -> AccessControlLevel? {
|
||||
func aclAtOffset(_ offset: ByteCount) -> AccessControlLevel? {
|
||||
if let nameOffset = nameOffset,
|
||||
nameOffset == offset,
|
||||
let acl = accessibility {
|
||||
|
|
|
@ -203,7 +203,7 @@ private extension SwiftLintFile {
|
|||
if syntaxKindsToSkip.contains(tokenKind) {
|
||||
continue
|
||||
}
|
||||
let cursorInfoRequest = Request.cursorInfo(file: path!, offset: Int64(token.offset),
|
||||
let cursorInfoRequest = Request.cursorInfo(file: path!, offset: token.offset,
|
||||
arguments: compilerArguments)
|
||||
guard let cursorInfo = (try? cursorInfoRequest.sendIfNotDisabled()).map(SourceKittenDictionary.init) else {
|
||||
queuedPrintError("Could not get cursor info")
|
||||
|
@ -252,7 +252,7 @@ private extension SwiftLintFile {
|
|||
}
|
||||
|
||||
// Operators are omitted in the editor.open request and thus have to be looked up by the indexsource request
|
||||
func operatorImports(arguments: [String], processedTokenOffsets: Set<Int>) -> Set<String> {
|
||||
func operatorImports(arguments: [String], processedTokenOffsets: Set<ByteCount>) -> Set<String> {
|
||||
guard let index = (try? Request.index(file: path!, arguments: arguments).sendIfNotDisabled())
|
||||
.map(SourceKittenDictionary.init) else {
|
||||
queuedPrintError("Could not get index")
|
||||
|
@ -271,9 +271,9 @@ private extension SwiftLintFile {
|
|||
let offset = lineOffset + column - 1
|
||||
|
||||
// Filter already processed tokens such as static methods that are not operators
|
||||
guard !processedTokenOffsets.contains(Int(offset)) else { continue }
|
||||
guard !processedTokenOffsets.contains(ByteCount(offset)) else { continue }
|
||||
|
||||
let cursorInfoRequest = Request.cursorInfo(file: path!, offset: offset, arguments: arguments)
|
||||
let cursorInfoRequest = Request.cursorInfo(file: path!, offset: ByteCount(offset), arguments: arguments)
|
||||
guard let cursorInfo = (try? cursorInfoRequest.sendIfNotDisabled())
|
||||
.map(SourceKittenDictionary.init) else {
|
||||
queuedPrintError("Could not get cursor info")
|
||||
|
|
|
@ -101,43 +101,43 @@ public struct UnusedSetterValueRule: ConfigurationProviderRule, AutomaticTestabl
|
|||
public func validate(file: SwiftLintFile) -> [StyleViolation] {
|
||||
let setTokens = file.rangesAndTokens(matching: "\\bset\\b").keywordTokens()
|
||||
|
||||
let violatingLocations = setTokens.compactMap { setToken -> Int? in
|
||||
let violatingLocations = setTokens.compactMap { setToken -> ByteCount? in
|
||||
// the last element is the deepest structure
|
||||
guard let dict = declarations(forByteOffset: setToken.offset,
|
||||
structureDictionary: file.structureDictionary).last,
|
||||
let bodyOffset = dict.bodyOffset, let bodyLength = dict.bodyLength,
|
||||
let bodyByteRange = dict.bodyByteRange,
|
||||
case let contents = file.stringView,
|
||||
let propertyRange = contents.byteRangeToNSRange(start: bodyOffset, length: bodyLength),
|
||||
let getToken = findGetToken(in: propertyRange, file: file, propertyStructure: dict) else {
|
||||
return nil
|
||||
let propertyRange = contents.byteRangeToNSRange(bodyByteRange),
|
||||
let getToken = findGetToken(in: propertyRange, file: file, propertyStructure: dict)
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let argument = findNamedArgument(after: setToken, file: file)
|
||||
|
||||
let propertyEndOffset = bodyOffset + bodyLength
|
||||
let setterByteRange: NSRange
|
||||
let propertyEndOffset = bodyByteRange.upperBound
|
||||
let setterByteRange: ByteRange
|
||||
if setToken.offset > getToken.offset { // get {} set {}
|
||||
let startOfBody: Int
|
||||
let startOfBody: ByteCount
|
||||
if let argumentToken = argument?.token {
|
||||
startOfBody = argumentToken.offset + argumentToken.length
|
||||
} else {
|
||||
startOfBody = setToken.offset
|
||||
}
|
||||
setterByteRange = NSRange(location: startOfBody,
|
||||
length: propertyEndOffset - startOfBody)
|
||||
setterByteRange = ByteRange(location: startOfBody,
|
||||
length: propertyEndOffset - startOfBody)
|
||||
} else { // set {} get {}
|
||||
let startOfBody: Int
|
||||
let startOfBody: ByteCount
|
||||
if let argumentToken = argument?.token {
|
||||
startOfBody = argumentToken.offset + argumentToken.length
|
||||
} else {
|
||||
startOfBody = setToken.offset
|
||||
}
|
||||
setterByteRange = NSRange(location: startOfBody,
|
||||
length: getToken.offset - startOfBody)
|
||||
setterByteRange = ByteRange(location: startOfBody,
|
||||
length: getToken.offset - startOfBody)
|
||||
}
|
||||
|
||||
guard let setterRange = contents.byteRangeToNSRange(start: setterByteRange.location,
|
||||
length: setterByteRange.length) else {
|
||||
guard let setterRange = contents.byteRangeToNSRange(setterByteRange) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -188,7 +188,7 @@ public struct UnusedSetterValueRule: ConfigurationProviderRule, AutomaticTestabl
|
|||
})
|
||||
}
|
||||
|
||||
private func declarations(forByteOffset byteOffset: Int,
|
||||
private func declarations(forByteOffset byteOffset: ByteCount,
|
||||
structureDictionary: SourceKittenDictionary) -> [SourceKittenDictionary] {
|
||||
var results = [SourceKittenDictionary]()
|
||||
let allowedKinds = SwiftDeclarationKind.variableKinds.subtracting([.varParameter])
|
||||
|
@ -197,11 +197,10 @@ public struct UnusedSetterValueRule: ConfigurationProviderRule, AutomaticTestabl
|
|||
// Only accepts declarations which contains a body and contains the
|
||||
// searched byteOffset
|
||||
guard let kind = dictionary.declarationKind,
|
||||
let bodyOffset = dictionary.bodyOffset,
|
||||
let bodyLength = dictionary.bodyLength,
|
||||
case let byteRange = NSRange(location: bodyOffset, length: bodyLength),
|
||||
NSLocationInRange(byteOffset, byteRange) else {
|
||||
return
|
||||
let byteRange = dictionary.bodyByteRange,
|
||||
byteRange.contains(byteOffset)
|
||||
else {
|
||||
return
|
||||
}
|
||||
|
||||
if parentKind != .protocol && allowedKinds.contains(kind) {
|
||||
|
|
|
@ -74,7 +74,10 @@ public struct WeakDelegateRule: ASTRule, SubstitutionCorrectableASTRule, Configu
|
|||
guard !isComputed else { return [] }
|
||||
|
||||
guard let offset = dictionary.offset,
|
||||
let range = file.stringView.byteRangeToNSRange(start: offset, length: 3) else { return [] }
|
||||
let range = file.stringView.byteRangeToNSRange(ByteRange(location: offset, length: 3))
|
||||
else {
|
||||
return []
|
||||
}
|
||||
|
||||
return [range]
|
||||
}
|
||||
|
@ -83,13 +86,14 @@ public struct WeakDelegateRule: ASTRule, SubstitutionCorrectableASTRule, Configu
|
|||
return (violationRange, "weak var")
|
||||
}
|
||||
|
||||
private func protocolDeclarations(forByteOffset byteOffset: Int,
|
||||
private func protocolDeclarations(forByteOffset byteOffset: ByteCount,
|
||||
structureDictionary: SourceKittenDictionary) -> [SourceKittenDictionary] {
|
||||
return structureDictionary.traverseBreadthFirst { dictionary in
|
||||
guard dictionary.declarationKind == .protocol,
|
||||
let byteRange = dictionary.byteRange,
|
||||
NSLocationInRange(byteOffset, byteRange) else {
|
||||
return nil
|
||||
byteRange.contains(byteOffset)
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
return [dictionary]
|
||||
}
|
||||
|
|
|
@ -61,11 +61,8 @@ public struct YodaConditionRule: ASTRule, OptInRule, ConfigurationProviderRule,
|
|||
public func validate(file: SwiftLintFile,
|
||||
kind: StatementKind,
|
||||
dictionary: SourceKittenDictionary) -> [StyleViolation] {
|
||||
guard observedStatements.contains(kind),
|
||||
let offset = dictionary.offset,
|
||||
let length = dictionary.length
|
||||
else {
|
||||
return []
|
||||
guard observedStatements.contains(kind), let offset = dictionary.offset else {
|
||||
return []
|
||||
}
|
||||
|
||||
let matches = file.lines.filter({ $0.byteRange.contains(offset) }).reduce(into: []) { matches, line in
|
||||
|
@ -75,15 +72,8 @@ public struct YodaConditionRule: ASTRule, OptInRule, ConfigurationProviderRule,
|
|||
}
|
||||
|
||||
return matches.map { _ -> StyleViolation in
|
||||
let characterOffset = startOffset(of: offset, with: length, in: file)
|
||||
let location = Location(file: file, characterOffset: characterOffset)
|
||||
return StyleViolation(ruleDescription: type(of: self).description, severity: configuration.severity,
|
||||
location: location)
|
||||
location: Location(file: file, byteOffset: offset))
|
||||
}
|
||||
}
|
||||
|
||||
private func startOffset(of offset: Int, with length: Int, in file: SwiftLintFile) -> Int {
|
||||
let range = file.stringView.byteRangeToNSRange(start: offset, length: length)
|
||||
return range?.location ?? offset
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,10 +89,9 @@ public struct CyclomaticComplexityRule: ASTRule, ConfigurationProviderRule {
|
|||
|
||||
private func reduceSwitchComplexity(initialComplexity complexity: Int, file: SwiftLintFile,
|
||||
dictionary: SourceKittenDictionary) -> Int {
|
||||
let bodyOffset = dictionary.bodyOffset ?? 0
|
||||
let bodyLength = dictionary.bodyLength ?? 0
|
||||
let bodyRange = dictionary.bodyByteRange ?? ByteRange(location: 0, length: 0)
|
||||
|
||||
let contents = file.stringView.substringWithByteRange(start: bodyOffset, length: bodyLength) ?? ""
|
||||
let contents = file.stringView.substringWithByteRange(bodyRange) ?? ""
|
||||
|
||||
let fallthroughCount = contents.components(separatedBy: "fallthrough").count - 1
|
||||
return complexity - fallthroughCount
|
||||
|
|
|
@ -40,10 +40,8 @@ public struct FunctionParameterCountRule: ASTRule, ConfigurationProviderRule {
|
|||
return []
|
||||
}
|
||||
|
||||
let nameOffset = dictionary.nameOffset ?? 0
|
||||
let length = dictionary.nameLength ?? 0
|
||||
|
||||
if functionIsInitializer(file: file, byteOffset: nameOffset, byteLength: length) {
|
||||
let nameRange = ByteRange(location: dictionary.nameOffset ?? 0, length: dictionary.nameLength ?? 0)
|
||||
if functionIsInitializer(file: file, byteRange: nameRange) {
|
||||
return []
|
||||
}
|
||||
|
||||
|
@ -53,8 +51,7 @@ public struct FunctionParameterCountRule: ASTRule, ConfigurationProviderRule {
|
|||
|
||||
let minThreshold = configuration.severityConfiguration.params.map({ $0.value }).min(by: <)
|
||||
|
||||
let allParameterCount = allFunctionParameterCount(structure: dictionary.substructure, offset: nameOffset,
|
||||
length: length)
|
||||
let allParameterCount = allFunctionParameterCount(structure: dictionary.substructure, range: nameRange)
|
||||
if allParameterCount < minThreshold! {
|
||||
return []
|
||||
}
|
||||
|
@ -62,7 +59,7 @@ public struct FunctionParameterCountRule: ASTRule, ConfigurationProviderRule {
|
|||
var parameterCount = allParameterCount
|
||||
|
||||
if configuration.ignoresDefaultParameters {
|
||||
parameterCount -= defaultFunctionParameterCount(file: file, byteOffset: nameOffset, byteLength: length)
|
||||
parameterCount -= defaultFunctionParameterCount(file: file, byteRange: nameRange)
|
||||
}
|
||||
|
||||
for parameter in configuration.severityConfiguration.params where parameterCount > parameter.value {
|
||||
|
@ -78,16 +75,14 @@ public struct FunctionParameterCountRule: ASTRule, ConfigurationProviderRule {
|
|||
return []
|
||||
}
|
||||
|
||||
private func allFunctionParameterCount(structure: [SourceKittenDictionary],
|
||||
offset: Int, length: Int) -> Int {
|
||||
private func allFunctionParameterCount(structure: [SourceKittenDictionary], range: ByteRange) -> Int {
|
||||
var parameterCount = 0
|
||||
for subDict in structure {
|
||||
guard subDict.kind != nil,
|
||||
let parameterOffset = subDict.offset else {
|
||||
continue
|
||||
guard subDict.kind != nil, let parameterOffset = subDict.offset else {
|
||||
continue
|
||||
}
|
||||
|
||||
guard offset..<(offset + length) ~= parameterOffset else {
|
||||
guard range.contains(parameterOffset) else {
|
||||
return parameterCount
|
||||
}
|
||||
|
||||
|
@ -98,15 +93,15 @@ public struct FunctionParameterCountRule: ASTRule, ConfigurationProviderRule {
|
|||
return parameterCount
|
||||
}
|
||||
|
||||
private func defaultFunctionParameterCount(file: SwiftLintFile, byteOffset: Int, byteLength: Int) -> Int {
|
||||
let substring = file.stringView.substringWithByteRange(start: byteOffset, length: byteLength)!
|
||||
private func defaultFunctionParameterCount(file: SwiftLintFile, byteRange: ByteRange) -> Int {
|
||||
let substring = file.stringView.substringWithByteRange(byteRange)!
|
||||
let equals = substring.filter { $0 == "=" }
|
||||
return equals.count
|
||||
}
|
||||
|
||||
private func functionIsInitializer(file: SwiftLintFile, byteOffset: Int, byteLength: Int) -> Bool {
|
||||
private func functionIsInitializer(file: SwiftLintFile, byteRange: ByteRange) -> Bool {
|
||||
guard let name = file.stringView
|
||||
.substringWithByteRange(start: byteOffset, length: byteLength),
|
||||
.substringWithByteRange(byteRange),
|
||||
name.hasPrefix("init"),
|
||||
let funcName = name.components(separatedBy: CharacterSet(charactersIn: "<(")).first else {
|
||||
return false
|
||||
|
|
|
@ -73,7 +73,7 @@ public struct LargeTupleRule: ASTRule, ConfigurationProviderRule, AutomaticTesta
|
|||
}
|
||||
|
||||
private func violationOffsetsForTypes(in file: SwiftLintFile, dictionary: SourceKittenDictionary,
|
||||
kind: SwiftDeclarationKind) -> [(offset: Int, size: Int)] {
|
||||
kind: SwiftDeclarationKind) -> [(offset: ByteCount, size: Int)] {
|
||||
let kinds = SwiftDeclarationKind.variableKinds.subtracting([.varLocal])
|
||||
guard kinds.contains(kind),
|
||||
let type = dictionary.typeName,
|
||||
|
@ -86,12 +86,11 @@ public struct LargeTupleRule: ASTRule, ConfigurationProviderRule, AutomaticTesta
|
|||
}
|
||||
|
||||
private func violationOffsetsForFunctions(in file: SwiftLintFile, dictionary: SourceKittenDictionary,
|
||||
kind: SwiftDeclarationKind) -> [(offset: Int, size: Int)] {
|
||||
kind: SwiftDeclarationKind) -> [(offset: ByteCount, size: Int)] {
|
||||
let contents = file.stringView
|
||||
guard SwiftDeclarationKind.functionKinds.contains(kind),
|
||||
let returnRange = returnRangeForFunction(dictionary: dictionary),
|
||||
let returnSubstring = contents.substringWithByteRange(start: returnRange.location,
|
||||
length: returnRange.length) else {
|
||||
let returnSubstring = contents.substringWithByteRange(returnRange) else {
|
||||
return []
|
||||
}
|
||||
|
||||
|
@ -99,13 +98,13 @@ public struct LargeTupleRule: ASTRule, ConfigurationProviderRule, AutomaticTesta
|
|||
return offsets.sorted { $0.offset < $1.offset }
|
||||
}
|
||||
|
||||
private func violationOffsets(for text: String, initialOffset: Int = 0) -> [(offset: Int, size: Int)] {
|
||||
private func violationOffsets(for text: String, initialOffset: ByteCount = 0) -> [(offset: ByteCount, size: Int)] {
|
||||
guard let ranges = try? parenthesesRanges(in: text) else {
|
||||
return []
|
||||
}
|
||||
|
||||
var text = text.bridge()
|
||||
var offsets = [(offset: Int, size: Int)]()
|
||||
var offsets = [(offset: ByteCount, size: Int)]()
|
||||
|
||||
for (range, kind) in ranges {
|
||||
let substring = text.substring(with: range)
|
||||
|
@ -124,7 +123,7 @@ public struct LargeTupleRule: ASTRule, ConfigurationProviderRule, AutomaticTesta
|
|||
return offsets
|
||||
}
|
||||
|
||||
private func returnRangeForFunction(dictionary: SourceKittenDictionary) -> NSRange? {
|
||||
private func returnRangeForFunction(dictionary: SourceKittenDictionary) -> ByteRange? {
|
||||
guard let nameOffset = dictionary.nameOffset,
|
||||
let nameLength = dictionary.nameLength,
|
||||
let length = dictionary.length,
|
||||
|
@ -139,7 +138,7 @@ public struct LargeTupleRule: ASTRule, ConfigurationProviderRule, AutomaticTesta
|
|||
return nil
|
||||
}
|
||||
|
||||
return NSRange(location: start, length: end - start)
|
||||
return ByteRange(location: start, length: end - start)
|
||||
}
|
||||
|
||||
private func parenthesesRanges(in text: String) throws -> [(NSRange, RangeKind)] {
|
||||
|
|
|
@ -47,11 +47,11 @@ public struct FirstWhereRule: CallPairRule, OptInRule, ConfigurationProviderRule
|
|||
return true // has a substructure, like a closure
|
||||
}
|
||||
|
||||
guard let bodyOffset = dictionary.bodyOffset, let bodyLength = dictionary.bodyLength else {
|
||||
guard let bodyRange = dictionary.bodyByteRange else {
|
||||
return true
|
||||
}
|
||||
|
||||
let syntaxKinds = file.syntaxMap.kinds(inByteRange: NSRange(location: bodyOffset, length: bodyLength))
|
||||
let syntaxKinds = file.syntaxMap.kinds(inByteRange: bodyRange)
|
||||
return !syntaxKinds.contains(.string)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,11 +40,11 @@ public struct LastWhereRule: CallPairRule, OptInRule, ConfigurationProviderRule,
|
|||
return true // has a substructure, like a closure
|
||||
}
|
||||
|
||||
guard let bodyOffset = dictionary.bodyOffset, let bodyLength = dictionary.bodyLength else {
|
||||
guard let bodyRange = dictionary.bodyByteRange else {
|
||||
return true
|
||||
}
|
||||
|
||||
let syntaxKinds = file.syntaxMap.kinds(inByteRange: NSRange(location: bodyOffset, length: bodyLength))
|
||||
let syntaxKinds = file.syntaxMap.kinds(inByteRange: bodyRange)
|
||||
return !syntaxKinds.contains(.string)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -103,7 +103,8 @@ public struct ReduceIntoRule: ASTRule, ConfigurationProviderRule, OptInRule, Aut
|
|||
kind == .call,
|
||||
let nameOffset = dictionary.nameOffset,
|
||||
let nameLength = dictionary.nameLength,
|
||||
let nameRange = file.stringView.byteRangeToNSRange(start: nameOffset, length: nameLength),
|
||||
case let nameByteRange = ByteRange(location: nameOffset, length: nameLength),
|
||||
let nameRange = file.stringView.byteRangeToNSRange(nameByteRange),
|
||||
let match = reduceExpression.firstMatch(in: file.contents, options: [], range: nameRange),
|
||||
dictionary.enclosedArguments.count == 2,
|
||||
// would otherwise equal "into"
|
||||
|
@ -132,13 +133,11 @@ public struct ReduceIntoRule: ASTRule, ConfigurationProviderRule, OptInRule, Aut
|
|||
}
|
||||
|
||||
let contents = file.stringView
|
||||
guard let offset = argument.offset,
|
||||
let length = argument.length,
|
||||
let range = contents.byteRangeToNSRange(start: offset, length: length)
|
||||
guard let byteRange = argument.byteRange,
|
||||
let range = contents.byteRangeToNSRange(byteRange)
|
||||
else { return false }
|
||||
|
||||
// Check for string literal
|
||||
let byteRange = NSRange(location: offset, length: length)
|
||||
let kinds = file.syntaxMap.kinds(inByteRange: byteRange)
|
||||
if kinds == [.string] {
|
||||
return true
|
||||
|
|
|
@ -138,7 +138,7 @@ public struct AttributesRule: ASTRule, OptInRule, ConfigurationProviderRule {
|
|||
}
|
||||
|
||||
private func createAlwaysOnNewLineAttributes(previousAttributes: [(String, Bool)],
|
||||
attributesTokens: [(String, NSRange)],
|
||||
attributesTokens: [(String, ByteRange)],
|
||||
line: Line, file: SwiftLintFile) -> Set<String> {
|
||||
let attributesTokensWithParameters: [(String, Bool)] = attributesTokens.map {
|
||||
let hasParameter = attributeContainsParameter(attributeRange: $1,
|
||||
|
@ -241,16 +241,17 @@ public struct AttributesRule: ASTRule, OptInRule, ConfigurationProviderRule {
|
|||
return allTokens
|
||||
}
|
||||
|
||||
private func attributeContainsParameter(attributeRange: NSRange,
|
||||
private func attributeContainsParameter(attributeRange: ByteRange,
|
||||
line: Line, file: SwiftLintFile) -> Bool {
|
||||
let restOfLineOffset = attributeRange.location + attributeRange.length
|
||||
let restOfLineLength = line.byteRange.location + line.byteRange.length - restOfLineOffset
|
||||
let restOfLineOffset = attributeRange.upperBound
|
||||
let restOfLineLength = line.byteRange.upperBound - restOfLineOffset
|
||||
|
||||
let regex = AttributesRule.regularExpression
|
||||
let contents = file.stringView
|
||||
|
||||
// check if after the token is a `(` with only spaces allowed between the token and `(`
|
||||
guard let restOfLine = contents.substringWithByteRange(start: restOfLineOffset, length: restOfLineLength),
|
||||
let restOfLineByteRange = ByteRange(location: restOfLineOffset, length: restOfLineLength)
|
||||
guard let restOfLine = contents.substringWithByteRange(restOfLineByteRange),
|
||||
case let range = restOfLine.fullNSRange,
|
||||
regex.firstMatch(in: restOfLine, options: [], range: range) != nil else {
|
||||
return false
|
||||
|
@ -259,7 +260,7 @@ public struct AttributesRule: ASTRule, OptInRule, ConfigurationProviderRule {
|
|||
return true
|
||||
}
|
||||
|
||||
private func attributeName(token: SwiftLintSyntaxToken, file: SwiftLintFile) -> (String, NSRange)? {
|
||||
private func attributeName(token: SwiftLintSyntaxToken, file: SwiftLintFile) -> (String, ByteRange)? {
|
||||
guard token.kind == .attributeBuiltin else {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -38,8 +38,12 @@ public struct ClosureEndIndentationRule: Rule, OptInRule, ConfigurationProviderR
|
|||
|
||||
extension ClosureEndIndentationRule: CorrectableRule {
|
||||
public func correct(file: SwiftLintFile) -> [Correction] {
|
||||
let allViolations = violations(in: file).reversed().filter {
|
||||
!file.ruleEnabled(violatingRanges: [$0.range], for: self).isEmpty
|
||||
let allViolations = violations(in: file).reversed().filter { violation in
|
||||
guard let nsRange = file.stringView.byteRangeToNSRange(violation.range) else {
|
||||
return false
|
||||
}
|
||||
|
||||
return !file.ruleEnabled(violatingRanges: [nsRange], for: self).isEmpty
|
||||
}
|
||||
|
||||
guard !allViolations.isEmpty else {
|
||||
|
@ -107,8 +111,8 @@ extension ClosureEndIndentationRule: CorrectableRule {
|
|||
extension ClosureEndIndentationRule {
|
||||
fileprivate struct Violation {
|
||||
var indentationRanges: (expected: NSRange, actual: NSRange)
|
||||
var endOffset: Int
|
||||
var range: NSRange
|
||||
var endOffset: ByteCount
|
||||
var range: ByteRange
|
||||
}
|
||||
|
||||
fileprivate func violations(in file: SwiftLintFile) -> [Violation] {
|
||||
|
@ -136,11 +140,10 @@ extension ClosureEndIndentationRule {
|
|||
private func hasTrailingClosure(in file: SwiftLintFile,
|
||||
dictionary: SourceKittenDictionary) -> Bool {
|
||||
guard
|
||||
let offset = dictionary.offset,
|
||||
let length = dictionary.length,
|
||||
let text = file.stringView.substringWithByteRange(start: offset, length: length)
|
||||
else {
|
||||
return false
|
||||
let byteRange = dictionary.byteRange,
|
||||
let text = file.stringView.substringWithByteRange(byteRange)
|
||||
else {
|
||||
return false
|
||||
}
|
||||
|
||||
return !text.hasSuffix(")")
|
||||
|
@ -156,15 +159,17 @@ extension ClosureEndIndentationRule {
|
|||
let nameLength = dictionary.nameLength,
|
||||
bodyLength > 0,
|
||||
case let endOffset = offset + length - 1,
|
||||
contents.substringWithByteRange(start: endOffset, length: 1) == "}",
|
||||
case let closingBraceByteRange = ByteRange(location: endOffset, length: 1),
|
||||
contents.substringWithByteRange(closingBraceByteRange) == "}",
|
||||
let startOffset = startOffset(forDictionary: dictionary, file: file),
|
||||
let (startLine, _) = contents.lineAndCharacter(forByteOffset: startOffset),
|
||||
let (endLine, endPosition) = contents.lineAndCharacter(forByteOffset: endOffset),
|
||||
case let nameEndPosition = nameOffset + nameLength,
|
||||
let (bodyOffsetLine, _) = contents.lineAndCharacter(forByteOffset: nameEndPosition),
|
||||
startLine != endLine, bodyOffsetLine != endLine,
|
||||
!containsSingleLineClosure(dictionary: dictionary, endPosition: endOffset, file: file) else {
|
||||
return nil
|
||||
!containsSingleLineClosure(dictionary: dictionary, endPosition: endOffset, file: file)
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let range = file.lines[startLine - 1].range
|
||||
|
@ -172,8 +177,9 @@ extension ClosureEndIndentationRule {
|
|||
let actual = endPosition - 1
|
||||
guard let match = regex.firstMatch(in: file.contents, options: [], range: range)?.range,
|
||||
case let expected = match.location - range.location,
|
||||
expected != actual else {
|
||||
return nil
|
||||
expected != actual
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
|
||||
var expectedRange = range
|
||||
|
@ -184,7 +190,7 @@ extension ClosureEndIndentationRule {
|
|||
|
||||
return Violation(indentationRanges: (expected: expectedRange, actual: actualRange),
|
||||
endOffset: endOffset,
|
||||
range: NSRange(location: offset, length: length))
|
||||
range: ByteRange(location: offset, length: length))
|
||||
}
|
||||
|
||||
private func validateArguments(in file: SwiftLintFile,
|
||||
|
@ -216,15 +222,17 @@ extension ClosureEndIndentationRule {
|
|||
let nameLength = dictionary.nameLength,
|
||||
bodyLength > 0,
|
||||
case let endOffset = offset + length - 1,
|
||||
contents.substringWithByteRange(start: endOffset, length: 1) == "}",
|
||||
case let closingBraceByteRange = ByteRange(location: endOffset, length: 1),
|
||||
contents.substringWithByteRange(closingBraceByteRange) == "}",
|
||||
let startOffset = dictionary.offset,
|
||||
let (startLine, _) = contents.lineAndCharacter(forByteOffset: startOffset),
|
||||
let (endLine, endPosition) = contents.lineAndCharacter(forByteOffset: endOffset),
|
||||
case let nameEndPosition = nameOffset + nameLength,
|
||||
let (bodyOffsetLine, _) = contents.lineAndCharacter(forByteOffset: nameEndPosition),
|
||||
startLine != endLine, bodyOffsetLine != endLine,
|
||||
!isSingleLineClosure(dictionary: dictionary, endPosition: endOffset, file: file) else {
|
||||
return nil
|
||||
!isSingleLineClosure(dictionary: dictionary, endPosition: endOffset, file: file)
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let range = file.lines[startLine - 1].range
|
||||
|
@ -232,8 +240,9 @@ extension ClosureEndIndentationRule {
|
|||
let actual = endPosition - 1
|
||||
guard let match = regex.firstMatch(in: file.contents, options: [], range: range)?.range,
|
||||
case let expected = match.location - range.location,
|
||||
expected != actual else {
|
||||
return nil
|
||||
expected != actual
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
|
||||
var expectedRange = range
|
||||
|
@ -244,30 +253,28 @@ extension ClosureEndIndentationRule {
|
|||
|
||||
return Violation(indentationRanges: (expected: expectedRange, actual: actualRange),
|
||||
endOffset: endOffset,
|
||||
range: NSRange(location: offset, length: length))
|
||||
range: ByteRange(location: offset, length: length))
|
||||
}
|
||||
|
||||
private func startOffset(forDictionary dictionary: SourceKittenDictionary, file: SwiftLintFile) -> Int? {
|
||||
guard let nameOffset = dictionary.nameOffset,
|
||||
let nameLength = dictionary.nameLength else {
|
||||
private func startOffset(forDictionary dictionary: SourceKittenDictionary, file: SwiftLintFile) -> ByteCount? {
|
||||
guard let nameByteRange = dictionary.nameByteRange else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let newLineRegex = regex("\n(\\s*\\}?\\.)")
|
||||
let contents = file.stringView
|
||||
guard let range = contents.byteRangeToNSRange(start: nameOffset, length: nameLength),
|
||||
let match = newLineRegex.matches(in: file.contents, options: [],
|
||||
range: range).last?.range(at: 1),
|
||||
let methodByteRange = contents.NSRangeToByteRange(start: match.location,
|
||||
length: match.length) else {
|
||||
return nameOffset
|
||||
guard let range = contents.byteRangeToNSRange(nameByteRange),
|
||||
let match = newLineRegex.matches(in: file.contents, options: [], range: range).last?.range(at: 1),
|
||||
let methodByteRange = contents.NSRangeToByteRange(start: match.location, length: match.length)
|
||||
else {
|
||||
return nameByteRange.location
|
||||
}
|
||||
|
||||
return methodByteRange.location
|
||||
}
|
||||
|
||||
private func isSingleLineClosure(dictionary: SourceKittenDictionary,
|
||||
endPosition: Int, file: SwiftLintFile) -> Bool {
|
||||
endPosition: ByteCount, file: SwiftLintFile) -> Bool {
|
||||
let contents = file.stringView
|
||||
|
||||
guard let start = dictionary.bodyOffset,
|
||||
|
@ -280,7 +287,7 @@ extension ClosureEndIndentationRule {
|
|||
}
|
||||
|
||||
private func containsSingleLineClosure(dictionary: SourceKittenDictionary,
|
||||
endPosition: Int, file: SwiftLintFile) -> Bool {
|
||||
endPosition: ByteCount, file: SwiftLintFile) -> Bool {
|
||||
let contents = file.stringView
|
||||
|
||||
guard let closure = trailingClosure(dictionary: dictionary, file: file),
|
||||
|
@ -309,12 +316,12 @@ extension ClosureEndIndentationRule {
|
|||
private func filterClosureArguments(_ arguments: [SourceKittenDictionary],
|
||||
file: SwiftLintFile) -> [SourceKittenDictionary] {
|
||||
return arguments.filter { argument in
|
||||
guard let offset = argument.bodyOffset,
|
||||
let length = argument.bodyLength,
|
||||
let range = file.stringView.byteRangeToNSRange(start: offset, length: length),
|
||||
guard let bodyByteRange = argument.bodyByteRange,
|
||||
let range = file.stringView.byteRangeToNSRange(bodyByteRange),
|
||||
let match = regex("\\s*\\{").firstMatch(in: file.contents, options: [], range: range)?.range,
|
||||
match.location == range.location else {
|
||||
return false
|
||||
match.location == range.location
|
||||
else {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
|
@ -330,10 +337,12 @@ extension ClosureEndIndentationRule {
|
|||
let firstArgumentOffset = firstArgument.offset,
|
||||
case let offset = nameOffset + nameLength,
|
||||
case let length = firstArgumentOffset - offset,
|
||||
let range = file.stringView.byteRangeToNSRange(start: offset, length: length),
|
||||
case let byteRange = ByteRange(location: offset, length: length),
|
||||
let range = file.stringView.byteRangeToNSRange(byteRange),
|
||||
let match = regex("\\(\\s*\\n\\s*").firstMatch(in: file.contents, options: [], range: range)?.range,
|
||||
match.location == range.location else {
|
||||
return false
|
||||
match.location == range.location
|
||||
else {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
|
|
|
@ -52,8 +52,9 @@ public struct ClosureParameterPositionRule: ASTRule, ConfigurationProviderRule,
|
|||
guard let nameOffset = dictionary.nameOffset,
|
||||
let nameLength = dictionary.nameLength,
|
||||
let bodyLength = dictionary.bodyLength,
|
||||
bodyLength > 0 else {
|
||||
return []
|
||||
bodyLength > 0
|
||||
else {
|
||||
return []
|
||||
}
|
||||
|
||||
let parameters = dictionary.enclosedVarParameters
|
||||
|
@ -70,14 +71,16 @@ public struct ClosureParameterPositionRule: ASTRule, ConfigurationProviderRule,
|
|||
let rangeLength = paramOffset - rangeStart
|
||||
let contents = file.stringView
|
||||
|
||||
guard let range = contents.byteRangeToNSRange(start: rangeStart, length: rangeLength),
|
||||
let byteRange = ByteRange(location: rangeStart, length: rangeLength)
|
||||
guard let range = contents.byteRangeToNSRange(byteRange),
|
||||
let match = regex.matches(in: file.contents, options: [], range: range).last?.range,
|
||||
match.location != NSNotFound,
|
||||
let braceOffset = contents.NSRangeToByteRange(start: match.location, length: match.length)?.location,
|
||||
let (braceLine, _) = contents.lineAndCharacter(forByteOffset: braceOffset),
|
||||
let (paramLine, _) = contents.lineAndCharacter(forByteOffset: paramOffset),
|
||||
braceLine != paramLine else {
|
||||
return nil
|
||||
braceLine != paramLine
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return StyleViolation(ruleDescription: type(of: self).description,
|
||||
|
|
|
@ -90,7 +90,7 @@ public struct ClosureSpacingRule: CorrectableRule, ConfigurationProviderRule, Op
|
|||
return kindsToExclude.contains(tokenKind)
|
||||
}
|
||||
let tokenRanges = tokens.compactMap {
|
||||
file.stringView.byteRangeToNSRange(start: $0.offset, length: $0.length)
|
||||
file.stringView.byteRangeToNSRange($0.range)
|
||||
}
|
||||
linesWithBraces.append(braces.filter({ !$0.intersects(tokenRanges) }))
|
||||
}
|
||||
|
|
|
@ -86,12 +86,13 @@ public struct CollectionAlignmentRule: ASTRule, ConfigurationProviderRule, OptIn
|
|||
}
|
||||
}
|
||||
|
||||
private func colonLocation(with file: SwiftLintFile, keyOffset: Int, keyLength: Int,
|
||||
valueOffset: Int) -> Location? {
|
||||
private func colonLocation(with file: SwiftLintFile, keyOffset: ByteCount, keyLength: ByteCount,
|
||||
valueOffset: ByteCount) -> Location? {
|
||||
let contents = file.stringView
|
||||
let matchStart = keyOffset + keyLength
|
||||
let matchLength = valueOffset - matchStart
|
||||
let range = contents.byteRangeToNSRange(start: matchStart, length: matchLength)
|
||||
let byteRange = ByteRange(location: matchStart, length: matchLength)
|
||||
let range = contents.byteRangeToNSRange(byteRange)
|
||||
|
||||
let matches = file.match(pattern: ":", excludingSyntaxKinds: [.comment], range: range)
|
||||
return matches.first.map { Location(file: file, characterOffset: $0.location) }
|
||||
|
|
|
@ -3,12 +3,12 @@ import SourceKittenFramework
|
|||
|
||||
extension ColonRule {
|
||||
internal func dictionaryColonViolationRanges(in file: SwiftLintFile,
|
||||
dictionary: SourceKittenDictionary) -> [NSRange] {
|
||||
dictionary: SourceKittenDictionary) -> [ByteRange] {
|
||||
guard configuration.applyToDictionaries else {
|
||||
return []
|
||||
}
|
||||
|
||||
let ranges: [NSRange] = dictionary.traverseDepthFirst { subDict in
|
||||
let ranges: [ByteRange] = dictionary.traverseDepthFirst { subDict in
|
||||
guard let kind = subDict.expressionKind else { return nil }
|
||||
return dictionaryColonViolationRanges(in: file, kind: kind, dictionary: subDict)
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ extension ColonRule {
|
|||
}
|
||||
|
||||
internal func dictionaryColonViolationRanges(in file: SwiftLintFile, kind: SwiftExpressionKind,
|
||||
dictionary: SourceKittenDictionary) -> [NSRange] {
|
||||
dictionary: SourceKittenDictionary) -> [ByteRange] {
|
||||
guard kind == .dictionary,
|
||||
let ranges = dictionaryColonRanges(dictionary: dictionary) else {
|
||||
return []
|
||||
|
@ -25,7 +25,7 @@ extension ColonRule {
|
|||
|
||||
let contents = file.stringView
|
||||
return ranges.filter {
|
||||
guard let colon = contents.substringWithByteRange(start: $0.location, length: $0.length) else {
|
||||
guard let colon = contents.substringWithByteRange($0) else {
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -38,31 +38,28 @@ extension ColonRule {
|
|||
}
|
||||
}
|
||||
|
||||
private func dictionaryColonRanges(dictionary: SourceKittenDictionary) -> [NSRange]? {
|
||||
private func dictionaryColonRanges(dictionary: SourceKittenDictionary) -> [ByteRange]? {
|
||||
let elements = dictionary.elements
|
||||
guard elements.count % 2 == 0 else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let expectedKind = "source.lang.swift.structure.elem.expr"
|
||||
let ranges: [NSRange] = elements.compactMap { subDict in
|
||||
guard subDict.kind == expectedKind,
|
||||
let offset = subDict.offset,
|
||||
let length = subDict.length else {
|
||||
return nil
|
||||
let ranges: [ByteRange] = elements.compactMap { subDict in
|
||||
guard subDict.kind == expectedKind else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return NSRange(location: offset, length: length)
|
||||
return subDict.byteRange
|
||||
}
|
||||
|
||||
let even = ranges.enumerated().compactMap { $0 % 2 == 0 ? $1 : nil }
|
||||
let odd = ranges.enumerated().compactMap { $0 % 2 != 0 ? $1 : nil }
|
||||
|
||||
return zip(even, odd).map { evenRange, oddRange -> NSRange in
|
||||
let location = NSMaxRange(evenRange)
|
||||
return zip(even, odd).map { evenRange, oddRange -> ByteRange in
|
||||
let location = evenRange.upperBound
|
||||
let length = oddRange.location - location
|
||||
|
||||
return NSRange(location: location, length: length)
|
||||
return ByteRange(location: location, length: length)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ import SourceKittenFramework
|
|||
|
||||
extension ColonRule {
|
||||
internal func functionCallColonViolationRanges(in file: SwiftLintFile,
|
||||
dictionary: SourceKittenDictionary) -> [NSRange] {
|
||||
dictionary: SourceKittenDictionary) -> [ByteRange] {
|
||||
return dictionary.traverseDepthFirst { subDict in
|
||||
guard let kind = subDict.expressionKind else { return nil }
|
||||
return functionCallColonViolationRanges(in: file, kind: kind, dictionary: subDict)
|
||||
|
@ -11,15 +11,16 @@ extension ColonRule {
|
|||
}
|
||||
|
||||
internal func functionCallColonViolationRanges(in file: SwiftLintFile, kind: SwiftExpressionKind,
|
||||
dictionary: SourceKittenDictionary) -> [NSRange] {
|
||||
dictionary: SourceKittenDictionary) -> [ByteRange] {
|
||||
guard kind == .argument,
|
||||
let ranges = functionCallColonRanges(dictionary: dictionary) else {
|
||||
return []
|
||||
let ranges = functionCallColonRanges(dictionary: dictionary)
|
||||
else {
|
||||
return []
|
||||
}
|
||||
|
||||
let contents = file.stringView
|
||||
return ranges.filter {
|
||||
guard let colon = contents.substringWithByteRange(start: $0.location, length: $0.length) else {
|
||||
guard let colon = contents.substringWithByteRange($0) else {
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -32,15 +33,16 @@ extension ColonRule {
|
|||
}
|
||||
}
|
||||
|
||||
private func functionCallColonRanges(dictionary: SourceKittenDictionary) -> [NSRange]? {
|
||||
private func functionCallColonRanges(dictionary: SourceKittenDictionary) -> [ByteRange]? {
|
||||
guard let nameOffset = dictionary.nameOffset,
|
||||
let nameLength = dictionary.nameLength, nameLength > 0,
|
||||
let bodyOffset = dictionary.bodyOffset,
|
||||
case let location = nameOffset + nameLength,
|
||||
bodyOffset > location else {
|
||||
return nil
|
||||
bodyOffset > location
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return [NSRange(location: location, length: bodyOffset - location)]
|
||||
return [ByteRange(location: location, length: bodyOffset - location)]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,8 +32,8 @@ internal extension ColonRule {
|
|||
|
||||
return isValidMatch(syntaxTokens: syntaxTokens, file: file)
|
||||
}.compactMap { match, syntaxTokens in
|
||||
let identifierRange = contents
|
||||
.byteRangeToNSRange(start: syntaxTokens[0].offset, length: 0)
|
||||
let firstSyntaxTokenByteRange = ByteRange(location: syntaxTokens[0].offset, length: 0)
|
||||
let identifierRange = contents.byteRangeToNSRange(firstSyntaxTokenByteRange)
|
||||
return identifierRange.map { NSUnionRange($0, match.range) }
|
||||
}
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ internal extension ColonRule {
|
|||
case (.identifier, .keyword),
|
||||
(.typeidentifier, .keyword):
|
||||
validKinds = file.isTypeLike(token: syntaxTokens[1])
|
||||
//Exclude explicit "Self" type because of static variables
|
||||
// Exclude explicit "Self" type because of static variables
|
||||
if syntaxKinds[0] == .identifier,
|
||||
file.contents(for: syntaxTokens[1]) == "Self" {
|
||||
validKinds = false
|
||||
|
|
|
@ -79,17 +79,11 @@ public struct ColonRule: CorrectableRule, ConfigurationProviderRule {
|
|||
let contents = file.stringView
|
||||
let dictViolations: [RangeWithKind] = dictionaryColonViolationRanges(in: file,
|
||||
dictionary: dictionary).compactMap {
|
||||
guard let range = contents.byteRangeToNSRange(start: $0.location, length: $0.length) else {
|
||||
return nil
|
||||
}
|
||||
return (range: range, kind: .dictionary)
|
||||
return contents.byteRangeToNSRange($0).map { (range: $0, kind: .dictionary) }
|
||||
}
|
||||
let functionViolations: [RangeWithKind] = functionCallColonViolationRanges(in: file,
|
||||
dictionary: dictionary).compactMap {
|
||||
guard let range = contents.byteRangeToNSRange(start: $0.location, length: $0.length) else {
|
||||
return nil
|
||||
}
|
||||
return (range: range, kind: .functionCall)
|
||||
return contents.byteRangeToNSRange($0).map { (range: $0, kind: .functionCall) }
|
||||
}
|
||||
|
||||
return (violations + dictViolations + functionViolations).sorted {
|
||||
|
|
|
@ -77,10 +77,10 @@ public struct EmptyEnumArgumentsRule: SubstitutionCorrectableASTRule, Configurat
|
|||
|
||||
let callsRanges = dictionary.substructure.compactMap { dict -> NSRange? in
|
||||
guard dict.expressionKind == .call,
|
||||
let offset = dict.offset,
|
||||
let length = dict.length,
|
||||
let range = contents.byteRangeToNSRange(start: offset, length: length) else {
|
||||
return nil
|
||||
let byteRange = dict.byteRange,
|
||||
let range = contents.byteRangeToNSRange(byteRange)
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return range
|
||||
|
@ -88,10 +88,10 @@ public struct EmptyEnumArgumentsRule: SubstitutionCorrectableASTRule, Configurat
|
|||
|
||||
return dictionary.elements.flatMap { subDictionary -> [NSRange] in
|
||||
guard subDictionary.kind == "source.lang.swift.structure.elem.pattern",
|
||||
let offset = subDictionary.offset,
|
||||
let length = subDictionary.length,
|
||||
let caseRange = contents.byteRangeToNSRange(start: offset, length: length) else {
|
||||
return []
|
||||
let byteRange = subDictionary.byteRange,
|
||||
let caseRange = contents.byteRangeToNSRange(byteRange)
|
||||
else {
|
||||
return []
|
||||
}
|
||||
|
||||
let emptyArgumentRegex = regex("\\.\\S+\\s*(\\([,\\s_]*\\))")
|
||||
|
@ -107,8 +107,8 @@ public struct EmptyEnumArgumentsRule: SubstitutionCorrectableASTRule, Configurat
|
|||
// avoid matches in "(_, _) where"
|
||||
if let whereByteRange = contents.NSRangeToByteRange(start: whereRange.location,
|
||||
length: whereRange.length),
|
||||
case let length = whereByteRange.location - offset,
|
||||
case let byteRange = NSRange(location: offset, length: length),
|
||||
case let length = whereByteRange.location - byteRange.location,
|
||||
case let byteRange = ByteRange(location: byteRange.location, length: length),
|
||||
Set(file.syntaxMap.kinds(inByteRange: byteRange)) == [.keyword] {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -82,12 +82,14 @@ public struct EmptyParenthesesWithTrailingClosureRule: SubstitutionCorrectableAS
|
|||
|
||||
let rangeStart = nameOffset + nameLength
|
||||
let rangeLength = (offset + length) - (nameOffset + nameLength)
|
||||
let byteRange = ByteRange(location: rangeStart, length: rangeLength)
|
||||
let regex = EmptyParenthesesWithTrailingClosureRule.emptyParenthesesRegex
|
||||
|
||||
guard let range = file.stringView.byteRangeToNSRange(start: rangeStart, length: rangeLength),
|
||||
guard let range = file.stringView.byteRangeToNSRange(byteRange),
|
||||
let match = regex.firstMatch(in: file.contents, options: [], range: range)?.range,
|
||||
match.location == range.location else {
|
||||
return []
|
||||
match.location == range.location
|
||||
else {
|
||||
return []
|
||||
}
|
||||
|
||||
return [match]
|
||||
|
|
|
@ -140,12 +140,12 @@ public struct ExplicitSelfRule: CorrectableRule, ConfigurationProviderRule, Anal
|
|||
let contents = file.stringView
|
||||
|
||||
return cursorsMissingExplicitSelf.compactMap { cursorInfo in
|
||||
guard let byteOffset = cursorInfo["swiftlint.offset"] as? Int64 else {
|
||||
guard let byteOffset = (cursorInfo["swiftlint.offset"] as? Int64).flatMap(ByteCount.init) else {
|
||||
queuedPrintError("couldn't convert offsets")
|
||||
return nil
|
||||
}
|
||||
|
||||
return contents.byteRangeToNSRange(start: Int(byteOffset), length: 0)
|
||||
return contents.byteRangeToNSRange(ByteRange(location: byteOffset, length: 0))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -156,29 +156,29 @@ private let kindsToFind: Set = [
|
|||
]
|
||||
|
||||
private extension SwiftLintFile {
|
||||
func allCursorInfo(compilerArguments: [String], atByteOffsets byteOffsets: [Int]) throws
|
||||
func allCursorInfo(compilerArguments: [String], atByteOffsets byteOffsets: [ByteCount]) throws
|
||||
-> [[String: SourceKitRepresentable]] {
|
||||
return try byteOffsets.compactMap { offset in
|
||||
if stringView.substringWithByteRange(start: offset - 1, length: 1)! == "." { return nil }
|
||||
var cursorInfo = try Request.cursorInfo(file: self.path!, offset: Int64(offset),
|
||||
if stringView.substringWithByteRange(ByteRange(location: offset - 1, length: 1))! == "." { return nil }
|
||||
var cursorInfo = try Request.cursorInfo(file: self.path!, offset: offset,
|
||||
arguments: compilerArguments).sendIfNotDisabled()
|
||||
cursorInfo["swiftlint.offset"] = Int64(offset)
|
||||
cursorInfo["swiftlint.offset"] = Int64(offset.value)
|
||||
return cursorInfo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension StringView {
|
||||
func byteOffset(forLine line: Int, column: Int) -> Int {
|
||||
var byteOffset = 0
|
||||
func byteOffset(forLine line: Int, column: Int) -> ByteCount {
|
||||
var byteOffset = ByteCount(0)
|
||||
for line in lines[..<(line - 1)] {
|
||||
byteOffset += line.byteRange.length
|
||||
}
|
||||
return byteOffset + column - 1
|
||||
return byteOffset + ByteCount(column - 1)
|
||||
}
|
||||
|
||||
func recursiveByteOffsets(_ dict: [String: Any]) -> [Int] {
|
||||
let cur: [Int]
|
||||
func recursiveByteOffsets(_ dict: [String: Any]) -> [ByteCount] {
|
||||
let cur: [ByteCount]
|
||||
if let line = dict["key.line"] as? Int64,
|
||||
let column = dict["key.column"] as? Int64,
|
||||
let kindString = dict["key.kind"] as? String,
|
||||
|
@ -194,7 +194,7 @@ private extension StringView {
|
|||
}
|
||||
}
|
||||
|
||||
private func binaryOffsets(file: SwiftLintFile, compilerArguments: [String]) throws -> [Int] {
|
||||
private func binaryOffsets(file: SwiftLintFile, compilerArguments: [String]) throws -> [ByteCount] {
|
||||
let absoluteFile = file.path!.bridge().absolutePathRepresentation()
|
||||
let index = try Request.index(file: absoluteFile, arguments: compilerArguments).sendIfNotDisabled()
|
||||
let binaryOffsets = file.stringView.recursiveByteOffsets(index)
|
||||
|
|
|
@ -63,7 +63,8 @@ public struct FileHeaderRule: ConfigurationProviderRule, OptInRule {
|
|||
if let firstToken = firstToken, let lastToken = lastToken {
|
||||
let start = firstToken.offset
|
||||
let length = lastToken.offset + lastToken.length - firstToken.offset
|
||||
guard let range = file.stringView.byteRangeToNSRange(start: start, length: length) else {
|
||||
let byteRange = ByteRange(location: start, length: length)
|
||||
guard let range = file.stringView.byteRangeToNSRange(byteRange) else {
|
||||
return []
|
||||
}
|
||||
|
||||
|
@ -75,36 +76,32 @@ public struct FileHeaderRule: ConfigurationProviderRule, OptInRule {
|
|||
if let regex = requiredRegex,
|
||||
case let matches = regex.matches(in: file.contents, options: [], range: range),
|
||||
matches.isEmpty {
|
||||
violationsOffsets.append(start)
|
||||
violationsOffsets.append(file.stringView.location(fromByteOffset: start))
|
||||
}
|
||||
} else if requiredRegex != nil {
|
||||
let location = firstNonCommentToken.map {
|
||||
Location(file: file, byteOffset: $0.offset)
|
||||
} ?? Location(file: file.path, line: 1)
|
||||
return [
|
||||
StyleViolation(ruleDescription: type(of: self).description,
|
||||
severity: configuration.severityConfiguration.severity,
|
||||
location: location,
|
||||
reason: type(of: self).reason)
|
||||
]
|
||||
return [makeViolation(at: location)]
|
||||
}
|
||||
|
||||
return violationsOffsets.map {
|
||||
StyleViolation(ruleDescription: type(of: self).description,
|
||||
severity: configuration.severityConfiguration.severity,
|
||||
location: Location(file: file, characterOffset: $0),
|
||||
reason: type(of: self).reason)
|
||||
}
|
||||
return violationsOffsets.map { makeViolation(at: Location(file: file, characterOffset: $0)) }
|
||||
}
|
||||
|
||||
private func isSwiftLintCommand(token: SwiftLintSyntaxToken, file: SwiftLintFile) -> Bool {
|
||||
guard let range = file.stringView.byteRangeToNSRange(start: token.offset,
|
||||
length: token.length) else {
|
||||
return false
|
||||
guard let range = file.stringView.byteRangeToNSRange(token.range) else {
|
||||
return false
|
||||
}
|
||||
|
||||
return !file.commands(in: range).isEmpty
|
||||
}
|
||||
|
||||
private func makeViolation(at location: Location) -> StyleViolation {
|
||||
return StyleViolation(ruleDescription: type(of: self).description,
|
||||
severity: configuration.severityConfiguration.severity,
|
||||
location: location,
|
||||
reason: type(of: self).reason)
|
||||
}
|
||||
}
|
||||
|
||||
private extension SyntaxKind {
|
||||
|
|
|
@ -2,7 +2,7 @@ import Foundation
|
|||
import SourceKittenFramework
|
||||
|
||||
public struct FileTypesOrderRule: ConfigurationProviderRule, OptInRule {
|
||||
private typealias FileTypeOffset = (fileType: FileType, offset: Int)
|
||||
private typealias FileTypeOffset = (fileType: FileType, offset: ByteCount)
|
||||
|
||||
public var configuration = FileTypesOrderConfiguration()
|
||||
|
||||
|
|
|
@ -80,7 +80,7 @@ public struct IdentifierNameRule: ASTRule, ConfigurationProviderRule {
|
|||
}
|
||||
|
||||
private func validateName(dictionary: SourceKittenDictionary,
|
||||
kind: SwiftDeclarationKind) -> (name: String, offset: Int)? {
|
||||
kind: SwiftDeclarationKind) -> (name: String, offset: ByteCount)? {
|
||||
guard var name = dictionary.name,
|
||||
let offset = dictionary.offset,
|
||||
kinds.contains(kind),
|
||||
|
|
|
@ -189,7 +189,7 @@ public struct ImplicitGetterRule: ConfigurationProviderRule, AutomaticTestableRu
|
|||
return token
|
||||
}
|
||||
|
||||
let violatingLocations = getTokens.compactMap { token -> (Int, SwiftDeclarationKind?)? in
|
||||
let violatingLocations = getTokens.compactMap { token -> (ByteCount, SwiftDeclarationKind?)? in
|
||||
// the last element is the deepest structure
|
||||
guard let dict = declarations(forByteOffset: token.offset,
|
||||
structureDictionary: file.structureDictionary).last else {
|
||||
|
@ -220,7 +220,7 @@ public struct ImplicitGetterRule: ConfigurationProviderRule, AutomaticTestableRu
|
|||
}
|
||||
|
||||
private extension ImplicitGetterRule {
|
||||
func declarations(forByteOffset byteOffset: Int,
|
||||
func declarations(forByteOffset byteOffset: ByteCount,
|
||||
structureDictionary: SourceKittenDictionary) -> [SourceKittenDictionary] {
|
||||
var results = [SourceKittenDictionary]()
|
||||
let allowedKinds = SwiftDeclarationKind.variableKinds.subtracting([.varParameter])
|
||||
|
@ -230,11 +230,10 @@ private extension ImplicitGetterRule {
|
|||
// Only accepts declarations which contains a body and contains the
|
||||
// searched byteOffset
|
||||
guard let kind = dictionary.declarationKind,
|
||||
let bodyOffset = dictionary.bodyOffset,
|
||||
let bodyLength = dictionary.bodyLength,
|
||||
case let byteRange = NSRange(location: bodyOffset, length: bodyLength),
|
||||
NSLocationInRange(byteOffset, byteRange) else {
|
||||
return
|
||||
let byteRange = dictionary.byteRange,
|
||||
byteRange.contains(byteOffset)
|
||||
else {
|
||||
return
|
||||
}
|
||||
|
||||
if parentKind != .protocol && allowedKinds.contains(kind) {
|
||||
|
|
|
@ -35,11 +35,10 @@ public struct ImplicitReturnRule: ConfigurationProviderRule, SubstitutionCorrect
|
|||
return file.matchesAndSyntaxKinds(matching: pattern).compactMap { result, kinds in
|
||||
let range = result.range
|
||||
guard kinds == [.keyword, .keyword] || kinds == [.keyword],
|
||||
let byteRange = contents.NSRangeToByteRange(start: range.location,
|
||||
length: range.length),
|
||||
let byteRange = contents.NSRangeToByteRange(start: range.location, length: range.length),
|
||||
let outerKindString = file.structureDictionary.kinds(forByteOffset: byteRange.location).last?.kind
|
||||
else {
|
||||
return nil
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
|
||||
func isKindIncluded(_ kind: ImplicitReturnConfiguration.ReturnKind) -> Bool {
|
||||
|
|
|
@ -119,7 +119,8 @@ public struct LetVarWhitespaceRule: ConfigurationProviderRule, OptInRule, Automa
|
|||
|
||||
private func lineOffsets(file: SwiftLintFile, statement: SourceKittenDictionary) -> (Int, Int)? {
|
||||
guard let offset = statement.offset,
|
||||
let length = statement.length else {
|
||||
let length = statement.length
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
let startLine = file.line(byteOffset: offset)
|
||||
|
@ -230,7 +231,7 @@ private extension SwiftDeclarationKind {
|
|||
|
||||
private extension SwiftLintFile {
|
||||
// Zero based line number for specified byte offset
|
||||
func line(byteOffset: Int) -> Int {
|
||||
func line(byteOffset: ByteCount) -> Int {
|
||||
let lineIndex = lines.firstIndexAssumingSorted { line in
|
||||
return line.byteRange.location > byteOffset
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue