Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve performance of ColonRule #520

Merged
merged 2 commits into from
Feb 10, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@
* Improve performance of `FunctionParameterCountRule`.
[Norio Nomura](https://github.com/norio-nomura)

* Improve performance of `ColonRule`.
[Norio Nomura](https://github.com/norio-nomura)

##### Bug Fixes

* Fix case sensitivity of keywords for `valid_docs`.
Expand Down
26 changes: 18 additions & 8 deletions Source/SwiftLintFramework/Extensions/File+SwiftLint.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,23 +73,33 @@ extension File {
}.map { $0.0 }
}

public func matchPattern(pattern: String) -> [(NSRange, [SyntaxKind])] {
return matchPattern(regex(pattern))
internal func rangesAndTokensMatching(pattern: String) -> [(NSRange, [SyntaxToken])] {
return rangesAndTokensMatching(regex(pattern))
}

public func matchPattern(regex: NSRegularExpression) -> [(NSRange, [SyntaxKind])] {
internal func rangesAndTokensMatching(regex: NSRegularExpression) ->
[(NSRange, [SyntaxToken])] {
let contents = self.contents as NSString
let range = NSRange(location: 0, length: contents.length)
let syntax = syntaxMap
let matches = regex.matchesInString(self.contents, options: [], range: range)
return matches.map { match in
return regex.matchesInString(self.contents, options: [], range: range).map { match in
let matchByteRange = contents.NSRangeToByteRange(start: match.range.location,
length: match.range.length) ?? match.range
let kindsInRange = syntax.tokens.filter { token in
let tokensInRange = syntax.tokens.filter { token in
let tokenByteRange = NSRange(location: token.offset, length: token.length)
return NSIntersectionRange(matchByteRange, tokenByteRange).length > 0
}.map({ $0.type }).flatMap(SyntaxKind.init)
return (match.range, kindsInRange)
}.map({ $0 })
return (match.range, tokensInRange)
}
}

public func matchPattern(pattern: String) -> [(NSRange, [SyntaxKind])] {
return matchPattern(regex(pattern))
}

public func matchPattern(regex: NSRegularExpression) -> [(NSRange, [SyntaxKind])] {
return rangesAndTokensMatching(regex).map { range, tokens in
(range, tokens.map({ $0.type }).flatMap(SyntaxKind.init))
}
}

Expand Down
35 changes: 21 additions & 14 deletions Source/SwiftLintFramework/Rules/ColonRule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -111,25 +111,32 @@ public struct ColonRule: CorrectableRule, ConfigProviderRule {
// MARK: - Private

private let pattern =
"(\\w+)" + // Capture an identifier
"(?:" + // start group
"\\s+" + // followed by whitespace
":" + // to the left of a colon
"\\s*" + // followed by any amount of whitespace.
"|" + // or
":" + // immediately followed by a colon
"(\\w)" + // Capture an identifier
"(?:" + // start group
"\\s+" + // followed by whitespace
":" + // to the left of a colon
"\\s*" + // followed by any amount of whitespace.
"|" + // or
":" + // immediately followed by a colon
"(?:\\s{0}|\\s{2,})" + // followed by 0 or 2+ whitespace characters.
")" + // end group
"(" + // Capture a type identifier
"(?:\\[|\\()*" + // which may begin with a series of nested parenthesis or brackets
"\\S+?)" // lazily to the first non-whitespace character.
")" + // end group
"(" + // Capture a type identifier
"[\\[|\\(]*" + // which may begin with a series of nested parenthesis or brackets
"\\S)" // lazily to the first non-whitespace character.

private func violationRangesInFile(file: File, withPattern pattern: String) -> [NSRange] {
return file.matchPattern(pattern).filter { range, syntaxKinds in
let nsstring = file.contents as NSString
let commentAndStringKindsSet = Set(SyntaxKind.commentAndStringKinds())
return file.rangesAndTokensMatching(pattern).filter { range, syntaxTokens in
let syntaxKinds = syntaxTokens.map({ $0.type }).flatMap(SyntaxKind.init)
if !syntaxKinds.startsWith([.Identifier, .Typeidentifier]) {
return false
}
return Set(syntaxKinds).intersect(Set(SyntaxKind.commentAndStringKinds())).isEmpty
}.flatMap { $0.0 }
return Set(syntaxKinds).intersect(commentAndStringKindsSet).isEmpty
}.flatMap { range, syntaxTokens in
let identifierRange = nsstring // swiftlint:disable:next force_unwrapping
.byteRangeToNSRange(start: syntaxTokens.first!.offset, length: 0)
return identifierRange.map { NSUnionRange($0, range) }
}
}
}