Skip to content

Commit

Permalink
Merge pull request #195 from mmorier/master
Browse files Browse the repository at this point in the history
Improve ControlStatementRule for issues #187 and #189
  • Loading branch information
jpsim committed Nov 11, 2015
2 parents 8609636 + b6bb316 commit d50c2a2
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 5 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,25 @@
`OptionSetType` subclasses.
[Will Fleming](https://github.com/wfleming)

* Add `VariableNameMaxLengthRule` and `VariableNameMinLengthRule` parameter rules.
Remove length checks on `VariableNameRule`.
[Mickael Morier](https://github.com/mmorier)

##### Bug Fixes

* All rules now print their identifiers in reports.
[JP Simard](https://github.com/jpsim)
[#180](https://github.com/realm/SwiftLint/issues/180)

* `ControlStatementRule` now detects all violations.
[Mickael Morier](https://github.com/mmorier)
[#187](https://github.com/realm/SwiftLint/issues/187)

* `ControlStatementRule` no longer triggers a violation for acceptable use of
parentheses.
[Mickael Morier](https://github.com/mmorier)
[#189](https://github.com/realm/SwiftLint/issues/189)

* Nesting rule no longer triggers a violation for enums nested one level deep.
[JP Simard](https://github.com/jpsim)
[#190](https://github.com/realm/SwiftLint/issues/190)
Expand Down
41 changes: 36 additions & 5 deletions Source/SwiftLintFramework/Rules/ControlStatementRule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ public struct ControlStatementRule: Rule {
nonTriggeringExamples: [
"if condition {\n",
"if (a, b) == (0, 1) {\n",
"if (a || b) && (c || d) {\n",
"if (min...max).contains(value) {\n",
"if renderGif(data) {\n",
"renderGif(data)\n",
"for item in collection {\n",
Expand All @@ -28,11 +30,13 @@ public struct ControlStatementRule: Rule {
"while condition {\n",
"} while condition {\n",
"do { ; } while condition {\n",
"switch foo {\n",
"switch foo {\n"
],
triggeringExamples: [
"if (condition) {\n",
"if(condition) {\n",
"if ((a || b) && (c || d)) {\n",
"if ((min...max).contains(value)) {\n",
"for (item in collection) {\n",
"for (var index = 0; index < 42; index++) {\n",
"for(item in collection) {\n",
Expand All @@ -44,18 +48,19 @@ public struct ControlStatementRule: Rule {
"} while(condition) {\n",
"do { ; } while(condition) {\n",
"do { ; } while (condition) {\n",
"switch (foo) {\n",
"switch (foo) {\n"
]
)

public func validateFile(file: File) -> [StyleViolation] {
let statements = ["if", "for", "guard", "switch", "while"]
return statements.flatMap { statementKind -> [StyleViolation] in
let pattern = statementKind == "guard"
? "\(statementKind)\\s*\\([^,]*\\)\\s*else\\s*\\{"
: "\(statementKind)\\s*\\([^,]*\\)\\s*\\{"
? "\(statementKind)\\s*\\([^,{]*\\)\\s*else\\s*\\{"
: "\(statementKind)\\s*\\([^,{]*\\)\\s*\\{"
return file.matchPattern(pattern).flatMap { match, syntaxKinds in
if syntaxKinds.first != .Keyword {
let matchString = file.contents.substring(match.location, length: match.length)
if self.isFalsePositive(matchString, syntaxKind: syntaxKinds.first) {
return nil
}
return StyleViolation(ruleDescription: self.dynamicType.description,
Expand All @@ -64,5 +69,31 @@ public struct ControlStatementRule: Rule {
"parentheses.")
}
}

}

private func isFalsePositive(content: String, syntaxKind: SyntaxKind?) -> Bool {
if syntaxKind != .Keyword {
return true
}

guard let lastClosingParenthesePosition = content.lastIndexOf(")") else {
return false
}

var depth = 0
var index = 0
for char in content.characters {
if char == ")" {
if index != lastClosingParenthesePosition && depth == 1 {
return true
}
depth--
} else if char == "(" {
depth++
}
index++
}
return false
}
}
22 changes: 22 additions & 0 deletions Source/SwiftLintFramework/String+SwiftLint.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,28 @@ extension String {
}
return self
}

subscript (range: Range<Int>) -> String {
get {
let subStart = startIndex.advancedBy(range.startIndex, limit: endIndex)
let subEnd = subStart.advancedBy(range.endIndex - range.startIndex, limit: endIndex)
return substringWithRange(Range(start: subStart, end: subEnd))
}
}

func substring(from: Int, length: Int? = nil) -> String {
if let length = length {
return self[from..<from + length]
}
return substringFromIndex(startIndex.advancedBy(from, limit: endIndex))
}

public func lastIndexOf(search: String) -> Int? {
if let range = rangeOfString(search, options: [.LiteralSearch, .BackwardsSearch]) {
return startIndex.distanceTo(range.startIndex)
}
return nil
}
}

extension NSString {
Expand Down

0 comments on commit d50c2a2

Please sign in to comment.