From d269bde1fa17e7456d6229e7bcfe2c433a19f784 Mon Sep 17 00:00:00 2001 From: JP Simard Date: Tue, 17 Nov 2015 11:41:02 -0800 Subject: [PATCH] allow trailing semicolons in comments --- .../Extensions/File+SwiftLint.swift | 4 ++-- Source/SwiftLintFramework/Models/Linter.swift | 10 +++------- Source/SwiftLintFramework/Models/Region.swift | 12 ++++++++++++ .../Rules/TrailingSemicolonRule.swift | 11 +++++++---- .../StringRuleTests.swift | 2 +- Source/SwiftLintFrameworkTests/TestHelpers.swift | 16 +++++++--------- 6 files changed, 32 insertions(+), 23 deletions(-) diff --git a/Source/SwiftLintFramework/Extensions/File+SwiftLint.swift b/Source/SwiftLintFramework/Extensions/File+SwiftLint.swift index 526b13688..9ec0f82ee 100644 --- a/Source/SwiftLintFramework/Extensions/File+SwiftLint.swift +++ b/Source/SwiftLintFramework/Extensions/File+SwiftLint.swift @@ -47,7 +47,7 @@ extension File { } public func matchPattern(pattern: String) -> [(NSRange, [SyntaxKind])] { - let regex = try! NSRegularExpression(pattern: pattern, options: []) + let regex = try! NSRegularExpression(pattern: pattern, options: [.AnchorsMatchLines]) let range = NSRange(location: 0, length: contents.utf16.count) let syntax = syntaxMap let matches = regex.matchesInString(contents, options: [], range: range) @@ -78,7 +78,7 @@ extension File { */ public func matchPattern(pattern: String, excludingSyntaxKinds syntaxKinds: [SyntaxKind]) -> [NSRange] { - let regex = try! NSRegularExpression(pattern: pattern, options: []) + let regex = try! NSRegularExpression(pattern: pattern, options: [.AnchorsMatchLines]) let range = NSRange(location: 0, length: contents.utf16.count) let syntax = syntaxMap let matches = regex.matchesInString(contents, options: [], range: range) diff --git a/Source/SwiftLintFramework/Models/Linter.swift b/Source/SwiftLintFramework/Models/Linter.swift index 104b79fbc..943205a4d 100644 --- a/Source/SwiftLintFramework/Models/Linter.swift +++ b/Source/SwiftLintFramework/Models/Linter.swift @@ -18,15 +18,11 @@ public struct Linter { public var styleViolations: [StyleViolation] { let regions = file.regions() return rules.flatMap { rule in - return rule.validateFile(self.file).filter { styleViolation in - guard let violationRegion = regions.filter({ - $0.start <= styleViolation.location && $0.end >= styleViolation.location - }).first else { + return rule.validateFile(self.file).filter { violation in + guard let violationRegion = regions.filter({ $0.contains(violation) }).first else { return true } - return !violationRegion.disabledRuleIdentifiers.contains( - rule.dynamicType.description.identifier - ) + return violationRegion.isRuleEnabled(rule) } } } diff --git a/Source/SwiftLintFramework/Models/Region.swift b/Source/SwiftLintFramework/Models/Region.swift index 18fb264ee..b15949581 100644 --- a/Source/SwiftLintFramework/Models/Region.swift +++ b/Source/SwiftLintFramework/Models/Region.swift @@ -19,4 +19,16 @@ public struct Region { self.end = end self.disabledRuleIdentifiers = disabledRuleIdentifiers } + + public func contains(violation: StyleViolation) -> Bool { + return start <= violation.location && end >= violation.location + } + + public func isRuleEnabled(rule: Rule) -> Bool { + return !isRuleDisabled(rule) + } + + public func isRuleDisabled(rule: Rule) -> Bool { + return disabledRuleIdentifiers.contains(rule.dynamicType.description.identifier) + } } diff --git a/Source/SwiftLintFramework/Rules/TrailingSemicolonRule.swift b/Source/SwiftLintFramework/Rules/TrailingSemicolonRule.swift index 965b56d67..2a34cde94 100644 --- a/Source/SwiftLintFramework/Rules/TrailingSemicolonRule.swift +++ b/Source/SwiftLintFramework/Rules/TrailingSemicolonRule.swift @@ -16,14 +16,17 @@ public struct TrailingSemicolonRule: Rule { name: "Trailing Semicolon", description: "Lines should not have trailing semicolons.", nonTriggeringExamples: [ "let a = 0\n" ], - triggeringExamples: [ "let a = 0;\n" ] + triggeringExamples: [ + "let a = 0;\n", + "let a = 0;\nlet b = 1\n" + ] ) public func validateFile(file: File) -> [StyleViolation] { - return file.lines.filter { $0.content.hasSuffix(";") }.map { + let excludingKinds = SyntaxKind.commentAndStringKinds() + return file.matchPattern(";$", excludingSyntaxKinds: excludingKinds).flatMap { StyleViolation(ruleDescription: self.dynamicType.description, - location: Location(file: file.path, line: $0.index), - reason: "Line #\($0.index) should have no trailing semicolon") + location: Location(file: file, offset: $0.location)) } } } diff --git a/Source/SwiftLintFrameworkTests/StringRuleTests.swift b/Source/SwiftLintFrameworkTests/StringRuleTests.swift index 13d2732d8..d39ba28e9 100644 --- a/Source/SwiftLintFrameworkTests/StringRuleTests.swift +++ b/Source/SwiftLintFrameworkTests/StringRuleTests.swift @@ -90,6 +90,6 @@ class StringRuleTests: XCTestCase { } func testTrailingSemicolon() { - verifyRule(TrailingSemicolonRule.description, commentDoesntViolate: false) + verifyRule(TrailingSemicolonRule.description) } } diff --git a/Source/SwiftLintFrameworkTests/TestHelpers.swift b/Source/SwiftLintFrameworkTests/TestHelpers.swift index 51cbea776..b3129c911 100644 --- a/Source/SwiftLintFrameworkTests/TestHelpers.swift +++ b/Source/SwiftLintFrameworkTests/TestHelpers.swift @@ -19,8 +19,7 @@ private func violations(string: String, _ description: RuleDescription) -> [Styl } extension XCTestCase { - func verifyRule(ruleDescription: RuleDescription, - commentDoesntViolate: Bool = true) { + func verifyRule(ruleDescription: RuleDescription, commentDoesntViolate: Bool = true) { XCTAssertEqual( ruleDescription.nonTriggeringExamples.flatMap({violations($0, ruleDescription)}), [] @@ -29,15 +28,14 @@ extension XCTestCase { ruleDescription.triggeringExamples.flatMap({ violations($0, ruleDescription).map({$0.ruleDescription}) }), - Array(count: ruleDescription.triggeringExamples.count, repeatedValue: ruleDescription)) + Array(count: ruleDescription.triggeringExamples.count, repeatedValue: ruleDescription) + ) if commentDoesntViolate { - XCTAssertEqual( - ruleDescription.triggeringExamples.flatMap({ - violations("/** " + $0, ruleDescription) - }), - [] - ) + let commentedViolations = ruleDescription.triggeringExamples.flatMap { + violations("/** " + $0, ruleDescription) + } + XCTAssertEqual(commentedViolations, []) } let command = "// swiftlint:disable \(ruleDescription.identifier)\n"