Merge pull request #985 from realm/jp-correctable-void-return

make VoidReturnRule correctable
This commit is contained in:
Marcelo Fabri
2016-12-15 10:40:15 -02:00
committed by GitHub
2 changed files with 46 additions and 10 deletions
+3 -1
View File
@@ -82,8 +82,10 @@
[Aaron McTavish](https://github.com/aamctustwo)
[#970](https://github.com/realm/SwiftLint/issues/970)
* Add `void_return` rule to validate usage of `-> Void` over `-> ()`.
* Add correctable `void_return` rule to validate usage of `-> Void`
over `-> ()`.
[Marcelo Fabri](https://github.com/marcelofabri)
[JP Simard](https://github.com/jpsim)
[#964](https://github.com/realm/SwiftLint/issues/964)
* Add `empty_parameters` rule to validate usage of `() -> ` over `Void -> `.
@@ -9,7 +9,7 @@
import Foundation
import SourceKittenFramework
public struct VoidReturnRule: Rule, ConfigurationProviderRule {
public struct VoidReturnRule: ConfigurationProviderRule, CorrectableRule {
public var configuration = SeverityConfiguration(.warning)
public init() {}
@@ -31,26 +31,60 @@ public struct VoidReturnRule: Rule, ConfigurationProviderRule {
"func foo(completion: () -> ↓())\n",
"func foo(completion: () -> ↓( ))\n",
"let foo: (ConfigurationTests) -> () throws -> ↓())\n"
],
corrections: [
"let abc: () -> () = {}\n": "let abc: () -> Void = {}\n",
"func foo(completion: () -> ())\n": "func foo(completion: () -> Void)\n",
"func foo(completion: () -> ( ))\n": "func foo(completion: () -> Void)\n",
"let foo: (ConfigurationTests) -> () throws -> ())\n":
"let foo: (ConfigurationTests) -> () throws -> Void)\n"
]
)
public func validateFile(_ file: File) -> [StyleViolation] {
return violationRanges(file: file).map {
StyleViolation(ruleDescription: type(of: self).description,
severity: configuration.severity,
location: Location(file: file, characterOffset: $0.location))
}
}
private func violationRanges(file: File) -> [NSRange] {
let kinds = SyntaxKind.commentAndStringKinds()
let pattern = "->\\s*\\(\\s*\\)\\s*(?!->)"
let parensPattern = "\\(\\s*\\)"
let pattern = "->\\s*\(parensPattern)\\s*(?!->)"
let excludingPattern = "(\(pattern))\\s*(throws\\s+)?->"
return file.matchPattern(pattern, excludingSyntaxKinds: kinds,
excludingPattern: excludingPattern) { $0.rangeAt(1) }.flatMap {
let parensRegex = NSRegularExpression.forcePattern(parensPattern)
return parensRegex.firstMatch(in: file.contents, options: [], range: $0)?.range
}
}
let range = file.contents.bridge().substring(with: $0).bridge().range(of: "(")
guard range.location != NSNotFound else {
return nil
public func correctFile(_ file: File) -> [Correction] {
let violatingRanges = file.ruleEnabledViolatingRanges(violationRanges(file: file),
forRule: self)
return writeToFile(file, violatingRanges: violatingRanges)
}
private func writeToFile(_ file: File, violatingRanges: [NSRange]) -> [Correction] {
var correctedContents = file.contents
var adjustedLocations = [Int]()
for violatingRange in violatingRanges.reversed() {
if let indexRange = correctedContents.nsrangeToIndexRange(violatingRange) {
correctedContents = correctedContents
.replacingCharacters(in: indexRange, with: "Void")
adjustedLocations.insert(violatingRange.location, at: 0)
}
}
let offset = range.location + $0.location
return StyleViolation(ruleDescription: type(of: self).description,
severity: configuration.severity,
location: Location(file: file, characterOffset: offset))
file.write(correctedContents)
return adjustedLocations.map {
Correction(ruleDescription: type(of: self).description,
location: Location(file: file, characterOffset: $0))
}
}
}