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

Add configuration for trailing_whitespace to ignore comments #854

Merged
merged 5 commits into from
Nov 4, 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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@

##### Enhancements

* Add `ignores_comment` configuration for `trailing_whitespace` rule.
[Javier Hernández](https://github.com/jaherhi)
[#576](https://github.com/realm/SwiftLint/issues/576)

* Added HTML reporter, identifier is `html`.
[Johnykutty Mathew](https://github.com/Johnykutty)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,17 @@ import Foundation
public struct TrailingWhitespaceConfiguration: RuleConfiguration, Equatable {
var severityConfiguration = SeverityConfiguration(.Warning)
var ignoresEmptyLines = false
var ignoresComments = true

public var consoleDescription: String {
return severityConfiguration.consoleDescription +
", ignores_empty_lines: \(ignoresEmptyLines)"
", ignores_empty_lines: \(ignoresEmptyLines)" +
", ignores_comments: \(ignoresComments)"
}

public init(ignoresEmptyLines: Bool) {
public init(ignoresEmptyLines: Bool, ignoresComments: Bool) {
self.ignoresEmptyLines = ignoresEmptyLines
self.ignoresComments = ignoresComments
}

public mutating func applyConfiguration(configuration: AnyObject) throws {
Expand All @@ -27,6 +30,7 @@ public struct TrailingWhitespaceConfiguration: RuleConfiguration, Equatable {
}

ignoresEmptyLines = (configuration["ignores_empty_lines"] as? Bool == true)
ignoresComments = (configuration["ignores_comments"] as? Bool == true)

if let severityString = configuration["severity"] as? String {
try severityConfiguration.applyConfiguration(severityString)
Expand All @@ -36,5 +40,6 @@ public struct TrailingWhitespaceConfiguration: RuleConfiguration, Equatable {

public func == (lhs: TrailingWhitespaceConfiguration,
rhs: TrailingWhitespaceConfiguration) -> Bool {
return lhs.ignoresEmptyLines == rhs.ignoresEmptyLines
return lhs.ignoresEmptyLines == rhs.ignoresEmptyLines &&
lhs.ignoresComments == rhs.ignoresComments
}
43 changes: 33 additions & 10 deletions Source/SwiftLintFramework/Rules/TrailingWhitespaceRule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,38 @@
import Foundation
import SourceKittenFramework

public struct TrailingWhitespaceRule: CorrectableRule, ConfigurationProviderRule,
SourceKitFreeRule {
public struct TrailingWhitespaceRule: CorrectableRule, ConfigurationProviderRule {

public var configuration = TrailingWhitespaceConfiguration(ignoresEmptyLines: false)
public var configuration = TrailingWhitespaceConfiguration(ignoresEmptyLines: false,
ignoresComments: true)

public init() {}

public static let description = RuleDescription(
identifier: "trailing_whitespace",
name: "Trailing Whitespace",
description: "Lines should not have trailing whitespace.",
nonTriggeringExamples: [ "//\n" ],
triggeringExamples: [ "// \n" ],
corrections: [ "// \n": "//\n" ]
nonTriggeringExamples: [ "let name: String\n", "//\n", "// \n",
"let name: String //\n", "let name: String // \n" ],
triggeringExamples: [ "let name: String \n", "/* */ let name: String \n" ],
corrections: [ "let name: String \n": "let name: String\n",
"/* */ let name: String \n": "/* */ let name: String\n"]
)

public func validateFile(file: File) -> [StyleViolation] {
let filteredLines = file.lines.filter {
$0.content.hasTrailingWhitespace() &&
(!configuration.ignoresEmptyLines ||
// If configured, ignore lines that contain nothing but whitespace (empty lines)
!$0.content.stringByTrimmingCharactersInSet(.whitespaceCharacterSet()).isEmpty)
guard $0.content.hasTrailingWhitespace() else { return false }

let commentKinds = SyntaxKind.commentKinds()
if configuration.ignoresComments,
let lastSyntaxKind = file.syntaxKindsByLines[$0.index].last
where commentKinds.contains(lastSyntaxKind) {
return false
}

return !configuration.ignoresEmptyLines ||
// If configured, ignore lines that contain nothing but whitespace (empty lines)
!$0.content.stringByTrimmingCharactersInSet(.whitespaceCharacterSet()).isEmpty
}

return filteredLines.map {
Expand All @@ -45,6 +55,19 @@ public struct TrailingWhitespaceRule: CorrectableRule, ConfigurationProviderRule
var correctedLines = [String]()
var corrections = [Correction]()
for line in file.lines {
guard line.content.hasTrailingWhitespace() else {
correctedLines.append(line.content)
continue
}

let commentKinds = SyntaxKind.commentKinds()
if configuration.ignoresComments,
let lastSyntaxKind = file.syntaxKindsByLines[line.index].last
where commentKinds.contains(lastSyntaxKind) {
correctedLines.append(line.content)
continue
}

let correctedLine = (line.content as NSString)
.stringByTrimmingTrailingCharactersInSet(whitespaceCharacterSet)

Expand Down
60 changes: 52 additions & 8 deletions Tests/SwiftLintFramework/RuleConfigurationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -132,22 +132,36 @@ class RuleConfigurationsTests: XCTestCase {

func testTrailingWhitespaceConfigurationThrowsOnBadConfig() {
let config = "unknown"
var configuration = TrailingWhitespaceConfiguration(ignoresEmptyLines: false)
var configuration = TrailingWhitespaceConfiguration(ignoresEmptyLines: false,
ignoresComments: true)
checkError(ConfigurationError.UnknownConfiguration) {
try configuration.applyConfiguration(config)
}
}

func testTrailingWhitespaceConfigurationInitializerSetsIgnoresEmptyLines() {
let configuration1 = TrailingWhitespaceConfiguration(ignoresEmptyLines: false)
let configuration1 = TrailingWhitespaceConfiguration(ignoresEmptyLines: false,
ignoresComments: true)
XCTAssertFalse(configuration1.ignoresEmptyLines)

let configuration2 = TrailingWhitespaceConfiguration(ignoresEmptyLines: true)
let configuration2 = TrailingWhitespaceConfiguration(ignoresEmptyLines: true,
ignoresComments: true)
XCTAssertTrue(configuration2.ignoresEmptyLines)
}

func testTrailingWhitespaceConfigurationInitializerSetsIgnoresComments() {
let configuration1 = TrailingWhitespaceConfiguration(ignoresEmptyLines: false,
ignoresComments: true)
XCTAssertTrue(configuration1.ignoresComments)

let configuration2 = TrailingWhitespaceConfiguration(ignoresEmptyLines: false,
ignoresComments: false)
XCTAssertFalse(configuration2.ignoresComments)
}

func testTrailingWhitespaceConfigurationApplyConfigurationSetsIgnoresEmptyLines() {
var configuration = TrailingWhitespaceConfiguration(ignoresEmptyLines: false)
var configuration = TrailingWhitespaceConfiguration(ignoresEmptyLines: false,
ignoresComments: true)
do {
let config1 = ["ignores_empty_lines": true]
try configuration.applyConfiguration(config1)
Expand All @@ -161,17 +175,47 @@ class RuleConfigurationsTests: XCTestCase {
}
}

func testTrailingWhitespaceConfigurationApplyConfigurationSetsIgnoresComments() {
var configuration = TrailingWhitespaceConfiguration(ignoresEmptyLines: false,
ignoresComments: true)
do {
let config1 = ["ignores_comments": true]
try configuration.applyConfiguration(config1)
XCTAssertTrue(configuration.ignoresComments)

let config2 = ["ignores_comments": false]
try configuration.applyConfiguration(config2)
XCTAssertFalse(configuration.ignoresComments)
} catch {
XCTFail()
}
}

func testTrailingWhitespaceConfigurationCompares() {
let configuration1 = TrailingWhitespaceConfiguration(ignoresEmptyLines: false)
let configuration2 = TrailingWhitespaceConfiguration(ignoresEmptyLines: true)
let configuration1 = TrailingWhitespaceConfiguration(ignoresEmptyLines: false,
ignoresComments: true)
let configuration2 = TrailingWhitespaceConfiguration(ignoresEmptyLines: true,
ignoresComments: true)
XCTAssertFalse(configuration1 == configuration2)

let configuration3 = TrailingWhitespaceConfiguration(ignoresEmptyLines: true)
let configuration3 = TrailingWhitespaceConfiguration(ignoresEmptyLines: true,
ignoresComments: true)
XCTAssertTrue(configuration2 == configuration3)

let configuration4 = TrailingWhitespaceConfiguration(ignoresEmptyLines: false,
ignoresComments: false)

XCTAssertFalse(configuration1 == configuration4)

let configuration5 = TrailingWhitespaceConfiguration(ignoresEmptyLines: true,
ignoresComments: false)

XCTAssertFalse(configuration1 == configuration5)
}

func testTrailingWhitespaceConfigurationApplyConfigurationUpdatesSeverityConfiguration() {
var configuration = TrailingWhitespaceConfiguration(ignoresEmptyLines: false)
var configuration = TrailingWhitespaceConfiguration(ignoresEmptyLines: false,
ignoresComments: true)
configuration.severityConfiguration.severity = .Warning

do {
Expand Down
20 changes: 18 additions & 2 deletions Tests/SwiftLintFramework/RulesTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ class RulesTests: XCTestCase {
}

func testTrailingWhitespace() {
verifyRule(TrailingWhitespaceRule.description, commentDoesntViolate: false)
verifyRule(TrailingWhitespaceRule.description)

// Perform additional tests with the ignores_empty_lines setting enabled.
// The set of non-triggering examples is extended by a whitespace-indented empty line
Expand All @@ -259,7 +259,23 @@ class RulesTests: XCTestCase {
nonTriggeringExamples: nonTriggeringExamples,
triggeringExamples: baseDescription.triggeringExamples,
corrections: baseDescription.corrections)
verifyRule(description, ruleConfiguration: ["ignores_empty_lines": true],
verifyRule(description,
ruleConfiguration: ["ignores_empty_lines": true, "ignores_comments": true])

// Perform additional tests with the ignores_comments settings disabled.
let triggeringComments = ["// \n", "let name: String // \n"]
let baseDescription2 = TrailingWhitespaceRule.description
let nonTriggeringExamples2 = baseDescription2.nonTriggeringExamples
.filter { !triggeringComments.contains($0) }
let triggeringExamples2 = baseDescription2.triggeringExamples + triggeringComments
let description2 = RuleDescription(identifier: baseDescription2.identifier,
name: baseDescription2.name,
description: baseDescription2.description,
nonTriggeringExamples: nonTriggeringExamples2,
triggeringExamples: triggeringExamples2,
corrections: baseDescription2.corrections)
verifyRule(description2,
ruleConfiguration: ["ignores_empty_lines": false, "ignores_comments": false],
commentDoesntViolate: false)
}

Expand Down