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

Color literals count as single character towards line count #830

Merged
merged 9 commits into from
Oct 14, 2016
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
[Norio Nomura](https://github.com/norio-nomura)
[Syo Ikeda](https://github.com/ikesyo)

* Color literals count as single characters to avoid unintentional line length violations.
[Jonas](https://github.com/VFUC)
[#742](https://github.com/realm/SwiftLint/issues/742)

##### Bug Fixes

* Fixed whitespace being added to TODO messages.
Expand Down
48 changes: 45 additions & 3 deletions Source/SwiftLintFramework/Rules/LineLengthRule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,14 @@ public struct LineLengthRule: ConfigurationProviderRule, SourceKitFreeRule {
name: "Line Length",
description: "Lines should not span too many characters.",
nonTriggeringExamples: [
Repeat(count: 100, repeatedValue: "/").joinWithSeparator("") + "\n"
Repeat(count: 100, repeatedValue: "/").joinWithSeparator("") + "\n",
Repeat(count: 100, repeatedValue: "#colorLiteral(red: 0.9607843161, green: 0.7058823705, blue: 0.200000003, alpha: 1)").joinWithSeparator("") + "\n",
Repeat(count: 100, repeatedValue: "#imageLiteral(resourceName: \"image.jpg\")").joinWithSeparator("") + "\n"
],
triggeringExamples: [
Repeat(count: 101, repeatedValue: "/").joinWithSeparator("") + "\n"
Repeat(count: 101, repeatedValue: "/").joinWithSeparator("") + "\n",
Repeat(count: 101, repeatedValue: "#colorLiteral(red: 0.9607843161, green: 0.7058823705, blue: 0.200000003, alpha: 1)").joinWithSeparator("") + "\n",
Repeat(count: 101, repeatedValue: "#imageLiteral(resourceName: \"image.jpg\")").joinWithSeparator("") + "\n"
]
)

Expand All @@ -34,7 +38,15 @@ public struct LineLengthRule: ConfigurationProviderRule, SourceKitFreeRule {
if line.range.length < minValue {
return nil
}
let length = line.content.characters.count

var strippedString = line.content
strippedString = stripLiterals(fromSourceString: strippedString,
withDelimiter: "#colorLiteral")
strippedString = stripLiterals(fromSourceString: strippedString,
withDelimiter: "#imageLiteral")

let length = strippedString.characters.count

for param in configuration.params where length > param.value {
return StyleViolation(ruleDescription: self.dynamicType.description,
severity: param.severity,
Expand All @@ -45,4 +57,34 @@ public struct LineLengthRule: ConfigurationProviderRule, SourceKitFreeRule {
return nil
}
}

/// Takes a string and replaces any literals specified by the `delimiter` parameter with `#`
///
/// - parameter sourceString: Original string, possibly containing literals
/// - parameter delimiter: Delimiter of the literal
/// (characters before the parentheses, e.g. `#colorLiteral`)
///
/// - returns: sourceString with the given literals replaced by `#`
private func stripLiterals(fromSourceString sourceString: String,
withDelimiter delimiter: String) -> String {
var modifiedString = sourceString

// While copy of content contains literal, replace with a single character
while modifiedString.containsString("\(delimiter)(") {
if let rangeStart = modifiedString.rangeOfString("\(delimiter)("),
let rangeEnd = modifiedString.rangeOfString(")",
options: .LiteralSearch,
range:
rangeStart.startIndex..<modifiedString.endIndex,
locale: nil) {
modifiedString.replaceRange(rangeStart.startIndex..<rangeEnd.endIndex, with: "#")

} else { // Should never be the case, but break to avoid accidental infinity loop
break
}
}

return modifiedString
}

}