From 0ad2488d7e5416a77e91229e5396257542e515ec Mon Sep 17 00:00:00 2001 From: Frederick Pietschmann Date: Sun, 11 Mar 2018 17:35:48 +0100 Subject: [PATCH] Add all keyword --- .../Extensions/File+SwiftLint.swift | 23 ++++++--- .../SwiftLintFramework/Models/Command.swift | 16 +++---- Source/SwiftLintFramework/Models/Linter.swift | 5 +- Source/SwiftLintFramework/Models/Region.swift | 12 ++--- .../Models/RuleIdentifier.swift | 48 +++++++++++++++++++ .../Rules/CustomRules.swift | 2 +- SwiftLint.xcodeproj/project.pbxproj | 4 ++ .../SwiftLintFrameworkTests/RegionTests.swift | 28 +++++------ 8 files changed, 100 insertions(+), 38 deletions(-) create mode 100644 Source/SwiftLintFramework/Models/RuleIdentifier.swift diff --git a/Source/SwiftLintFramework/Extensions/File+SwiftLint.swift b/Source/SwiftLintFramework/Extensions/File+SwiftLint.swift index cd5dd8fa70..6233124d53 100644 --- a/Source/SwiftLintFramework/Extensions/File+SwiftLint.swift +++ b/Source/SwiftLintFramework/Extensions/File+SwiftLint.swift @@ -20,9 +20,9 @@ internal func regex(_ pattern: String, } extension File { - internal func regions(restrictingRuleIdentifiers: [String]? = nil) -> [Region] { + internal func regions(restrictingRuleIdentifiers: Set? = nil) -> [Region] { var regions = [Region]() - var disabledRules = Set() + var disabledRules = Set() let commands: [Command] if let restrictingRuleIdentifiers = restrictingRuleIdentifiers { commands = self.commands().filter { command in @@ -34,20 +34,29 @@ extension File { let commandPairs = zip(commands, Array(commands.dropFirst().map(Optional.init)) + [nil]) for (command, nextCommand) in commandPairs { switch command.action { - case .disable: disabledRules.formUnion(command.ruleIdentifiers) - case .enable: disabledRules.subtract(command.ruleIdentifiers) + case .disable: + disabledRules.formUnion(command.ruleIdentifiers) + + case .enable: + disabledRules.subtract(command.ruleIdentifiers) } + let start = Location(file: path, line: command.line, character: command.character) let end = endOf(next: nextCommand) guard start < end else { continue } var didSetRegion = false for (index, region) in zip(regions.indices, regions) where region.start == start && region.end == end { - regions[index] = Region(start: start, end: end, - disabledRuleIdentifiers: disabledRules.union(region.disabledRuleIdentifiers)) + regions[index] = Region( + start: start, + end: end, + disabledRules: disabledRules.union(region.disabledRuleIdentifiers) + ) didSetRegion = true } if !didSetRegion { - regions.append(Region(start: start, end: end, disabledRuleIdentifiers: disabledRules)) + regions.append( + Region(start: start, end: end, disabledRules: disabledRules) + ) } } return regions diff --git a/Source/SwiftLintFramework/Models/Command.swift b/Source/SwiftLintFramework/Models/Command.swift index 9e06580627..1f00d5737d 100644 --- a/Source/SwiftLintFramework/Models/Command.swift +++ b/Source/SwiftLintFramework/Models/Command.swift @@ -56,12 +56,12 @@ public struct Command: Equatable { } internal let action: Action - internal let ruleIdentifiers: [String] + internal let ruleIdentifiers: Set internal let line: Int internal let character: Int? internal let modifier: Modifier? - public init(action: Action, ruleIdentifiers: [String], line: Int = 0, + public init(action: Action, ruleIdentifiers: Set, line: Int = 0, character: Int? = nil, modifier: Modifier? = nil) { self.action = action self.ruleIdentifiers = ruleIdentifiers @@ -84,15 +84,16 @@ public struct Command: Equatable { return nil } self.action = action - ruleIdentifiers = scanner.string.bridge() - .substring(from: scanner.scanLocation + 1) - .components(separatedBy: .whitespaces) line = lineAndCharacter.line character = lineAndCharacter.character - let hasModifier = actionAndModifierScanner.scanString(string: ":") != nil + let ruleTexts = scanner.string.bridge().substring( + from: scanner.scanLocation + 1 + ).components(separatedBy: .whitespaces) + ruleIdentifiers = Set(ruleTexts.map { RuleIdentifier($0) }) // Modifier + let hasModifier = actionAndModifierScanner.scanString(string: ":") != nil if hasModifier { let modifierString = actionAndModifierScanner.string.bridge() .substring(from: actionAndModifierScanner.scanLocation) @@ -122,8 +123,7 @@ public struct Command: Equatable { case .next: return [ Command(action: action, ruleIdentifiers: ruleIdentifiers, line: line + 1), - Command(action: action.inverse(), ruleIdentifiers: ruleIdentifiers, line: line + 1, - character: Int.max) + Command(action: action.inverse(), ruleIdentifiers: ruleIdentifiers, line: line + 1, character: Int.max) ] } } diff --git a/Source/SwiftLintFramework/Models/Linter.swift b/Source/SwiftLintFramework/Models/Linter.swift index 7498f95f94..628efeeece 100644 --- a/Source/SwiftLintFramework/Models/Linter.swift +++ b/Source/SwiftLintFramework/Models/Linter.swift @@ -78,11 +78,12 @@ private extension Rule { return region?.isRuleEnabled(self) ?? true } - let ruleIDs = Self.description.allIdentifiers + + let ruleIds = Self.description.allIdentifiers + (superfluousDisableCommandRule.map({ type(of: $0) })?.description.allIdentifiers ?? []) + let ruleIdentifiers = Set(ruleIds.map { RuleIdentifier($0) }) let superfluousDisableCommandViolations = Self.superfluousDisableCommandViolations( - regions: regions.count > 1 ? file.regions(restrictingRuleIdentifiers: ruleIDs) : regions, + regions: regions.count > 1 ? file.regions(restrictingRuleIdentifiers: ruleIdentifiers) : regions, superfluousDisableCommandRule: superfluousDisableCommandRule, allViolations: violations ) diff --git a/Source/SwiftLintFramework/Models/Region.swift b/Source/SwiftLintFramework/Models/Region.swift index 9c518a276d..3afd68f4b2 100644 --- a/Source/SwiftLintFramework/Models/Region.swift +++ b/Source/SwiftLintFramework/Models/Region.swift @@ -12,12 +12,12 @@ import SourceKittenFramework public struct Region: Equatable { public let start: Location public let end: Location - public let disabledRuleIdentifiers: Set + public let disabledRuleIdentifiers: Set - public init(start: Location, end: Location, disabledRuleIdentifiers: Set) { + public init(start: Location, end: Location, disabledRules: Set) { self.start = start self.end = end - self.disabledRuleIdentifiers = disabledRuleIdentifiers + self.disabledRuleIdentifiers = disabledRules } public func contains(_ location: Location) -> Bool { @@ -30,17 +30,17 @@ public struct Region: Equatable { public func isRuleDisabled(_ rule: Rule) -> Bool { let identifiers = type(of: rule).description.allIdentifiers - return !disabledRuleIdentifiers.isDisjoint(with: identifiers) + return disabledRuleIdentifiers.contains(.all) || + identifiers.reduce(false) { $0 || disabledRuleIdentifiers.contains(RuleIdentifier($1)) } } public func deprecatedAliasesDisabling(rule: Rule) -> Set { let identifiers = type(of: rule).description.deprecatedAliases - return disabledRuleIdentifiers.intersection(identifiers) + return Set(disabledRuleIdentifiers.map { $0.stringRepresentation }).intersection(identifiers) } } // MARK: Equatable - public func == (lhs: Region, rhs: Region) -> Bool { return lhs.start == rhs.start && lhs.end == rhs.end && diff --git a/Source/SwiftLintFramework/Models/RuleIdentifier.swift b/Source/SwiftLintFramework/Models/RuleIdentifier.swift new file mode 100644 index 0000000000..6358454bf4 --- /dev/null +++ b/Source/SwiftLintFramework/Models/RuleIdentifier.swift @@ -0,0 +1,48 @@ +// +// RuleIdentifier.swift +// SwiftLint +// +// Created by Frederick Pietschmann on 3/5/18. +// Copyright © 2018 Realm. All rights reserved. +// + +import Foundation + +public enum RuleIdentifier: Hashable, ExpressibleByStringLiteral { + case all + case some(identifier: String) + + private static let allStringRepresentation = "all" + + public var hashValue: Int { + switch self { + case .all: + return -1 + + case .some(let identifier): + return identifier.hashValue + } + } + + public var stringRepresentation: String { + switch self { + case .all: + return RuleIdentifier.allStringRepresentation + + case .some(let identifier): + return identifier + } + } + + public init(_ value: String) { + self = value == RuleIdentifier.allStringRepresentation ? .all : .some(identifier: value) + } + + public init(stringLiteral value: String) { + self = RuleIdentifier(value) + } + + public static func == (lhs: RuleIdentifier, rhs: RuleIdentifier) -> Bool { + return lhs.hashValue == rhs.hashValue + } +} diff --git a/Source/SwiftLintFramework/Rules/CustomRules.swift b/Source/SwiftLintFramework/Rules/CustomRules.swift index 2ce380a67e..14b1a86e8c 100644 --- a/Source/SwiftLintFramework/Rules/CustomRules.swift +++ b/Source/SwiftLintFramework/Rules/CustomRules.swift @@ -11,7 +11,7 @@ import SourceKittenFramework private extension Region { func isRuleDisabled(customRuleIdentifier: String) -> Bool { - return disabledRuleIdentifiers.contains(customRuleIdentifier) + return disabledRuleIdentifiers.contains(RuleIdentifier(customRuleIdentifier)) } } diff --git a/SwiftLint.xcodeproj/project.pbxproj b/SwiftLint.xcodeproj/project.pbxproj index a22215348a..f519a721ef 100644 --- a/SwiftLint.xcodeproj/project.pbxproj +++ b/SwiftLint.xcodeproj/project.pbxproj @@ -149,6 +149,7 @@ C3DE5DAC1E7DF9CA00761483 /* FatalErrorMessageRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DE5DAA1E7DF99B00761483 /* FatalErrorMessageRule.swift */; }; C946FECB1EAE67EE007DD778 /* LetVarWhitespaceRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = C946FEC91EAE5E20007DD778 /* LetVarWhitespaceRule.swift */; }; C9802F2F1E0C8AEE008AB27F /* TrailingCommaRuleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9802F2E1E0C8AEE008AB27F /* TrailingCommaRuleTests.swift */; }; + CC26ED07204DEB510013BBBC /* RuleIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC26ED05204DE86E0013BBBC /* RuleIdentifier.swift */; }; CE8178ED1EAC039D0063186E /* UnusedOptionalBindingConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE8178EB1EAC02CD0063186E /* UnusedOptionalBindingConfiguration.swift */; }; D0AAAB5019FB0960007B24B3 /* SwiftLintFramework.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D0D1216D19E87B05005E4BAA /* SwiftLintFramework.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; D0D1217819E87B05005E4BAA /* SwiftLintFramework.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0D1216D19E87B05005E4BAA /* SwiftLintFramework.framework */; }; @@ -502,6 +503,7 @@ C3DE5DAA1E7DF99B00761483 /* FatalErrorMessageRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FatalErrorMessageRule.swift; sourceTree = ""; }; C946FEC91EAE5E20007DD778 /* LetVarWhitespaceRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LetVarWhitespaceRule.swift; sourceTree = ""; }; C9802F2E1E0C8AEE008AB27F /* TrailingCommaRuleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TrailingCommaRuleTests.swift; sourceTree = ""; }; + CC26ED05204DE86E0013BBBC /* RuleIdentifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleIdentifier.swift; sourceTree = ""; }; CE8178EB1EAC02CD0063186E /* UnusedOptionalBindingConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnusedOptionalBindingConfiguration.swift; sourceTree = ""; }; D0D1211B19E87861005E4BAA /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; usesTabs = 0; }; D0D1212419E878CC005E4BAA /* Common.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Common.xcconfig; sourceTree = ""; }; @@ -1201,6 +1203,7 @@ 3B12C9C41C322032000B423F /* MasterRuleList.swift */, E80E018E1B92C1350078EB70 /* Region.swift */, 83D71E261B131EB5000395DE /* RuleDescription.swift */, + CC26ED05204DE86E0013BBBC /* RuleIdentifier.swift */, E8BDE3FE1EDF91B6002EC12F /* RuleList.swift */, D48B51201F4F5DEF0068AB98 /* RuleList+Documentation.swift */, D401D9251ED85EF0005DA5D4 /* RuleKind.swift */, @@ -1629,6 +1632,7 @@ D43B046B1E075905004016AF /* ClosureEndIndentationRule.swift in Sources */, D47EF4821F69E34D0012C4CA /* ColonRule+Dictionary.swift in Sources */, D93DA3D11E699E6300809827 /* NestingConfiguration.swift in Sources */, + CC26ED07204DEB510013BBBC /* RuleIdentifier.swift in Sources */, C328A2F71E6759AE00A9E4D7 /* ExplicitTypeInterfaceRule.swift in Sources */, 93E0C3CE1D67BD7F007FA25D /* ConditionalReturnsOnNewlineRule.swift in Sources */, D43DB1081DC573DA00281215 /* ImplicitGetterRule.swift in Sources */, diff --git a/Tests/SwiftLintFrameworkTests/RegionTests.swift b/Tests/SwiftLintFrameworkTests/RegionTests.swift index 0d8cdb93c7..9c432434c7 100644 --- a/Tests/SwiftLintFrameworkTests/RegionTests.swift +++ b/Tests/SwiftLintFrameworkTests/RegionTests.swift @@ -31,14 +31,14 @@ class RegionTests: XCTestCase { let file = File(contents: "// swiftlint:disable rule_id\n") let start = Location(file: nil, line: 1, character: 29) let end = Location(file: nil, line: .max, character: .max) - XCTAssertEqual(file.regions(), [Region(start: start, end: end, disabledRuleIdentifiers: ["rule_id"])]) + XCTAssertEqual(file.regions(), [Region(start: start, end: end, disabledRules: ["rule_id"])]) } // enable do { let file = File(contents: "// swiftlint:enable rule_id\n") let start = Location(file: nil, line: 1, character: 28) let end = Location(file: nil, line: .max, character: .max) - XCTAssertEqual(file.regions(), [Region(start: start, end: end, disabledRuleIdentifiers: [])]) + XCTAssertEqual(file.regions(), [Region(start: start, end: end, disabledRules: [])]) } } @@ -49,10 +49,10 @@ class RegionTests: XCTestCase { XCTAssertEqual(file.regions(), [ Region(start: Location(file: nil, line: 1, character: 29), end: Location(file: nil, line: 2, character: 27), - disabledRuleIdentifiers: ["rule_id"]), + disabledRules: ["rule_id"]), Region(start: Location(file: nil, line: 2, character: 28), end: Location(file: nil, line: .max, character: .max), - disabledRuleIdentifiers: []) + disabledRules: []) ]) } // enable/disable @@ -61,10 +61,10 @@ class RegionTests: XCTestCase { XCTAssertEqual(file.regions(), [ Region(start: Location(file: nil, line: 1, character: 28), end: Location(file: nil, line: 2, character: 28), - disabledRuleIdentifiers: []), + disabledRules: []), Region(start: Location(file: nil, line: 2, character: 29), end: Location(file: nil, line: .max, character: .max), - disabledRuleIdentifiers: ["rule_id"]) + disabledRules: ["rule_id"]) ]) } } @@ -76,10 +76,10 @@ class RegionTests: XCTestCase { XCTAssertEqual(file.regions(), [ Region(start: Location(file: nil, line: 2, character: nil), end: Location(file: nil, line: 2, character: .max - 1), - disabledRuleIdentifiers: ["1", "2", "3"]), + disabledRules: ["1", "2", "3"]), Region(start: Location(file: nil, line: 2, character: .max), end: Location(file: nil, line: .max, character: .max), - disabledRuleIdentifiers: []) + disabledRules: []) ]) } @@ -93,22 +93,22 @@ class RegionTests: XCTestCase { XCTAssertEqual(file.regions(), [ Region(start: Location(file: nil, line: 1, character: 23), end: Location(file: nil, line: 2, character: 22), - disabledRuleIdentifiers: ["1"]), + disabledRules: ["1"]), Region(start: Location(file: nil, line: 2, character: 23), end: Location(file: nil, line: 3, character: 22), - disabledRuleIdentifiers: ["1", "2"]), + disabledRules: ["1", "2"]), Region(start: Location(file: nil, line: 3, character: 23), end: Location(file: nil, line: 4, character: 21), - disabledRuleIdentifiers: ["1", "2", "3"]), + disabledRules: ["1", "2", "3"]), Region(start: Location(file: nil, line: 4, character: 22), end: Location(file: nil, line: 5, character: 21), - disabledRuleIdentifiers: ["2", "3"]), + disabledRules: ["2", "3"]), Region(start: Location(file: nil, line: 5, character: 22), end: Location(file: nil, line: 6, character: 21), - disabledRuleIdentifiers: ["3"]), + disabledRules: ["3"]), Region(start: Location(file: nil, line: 6, character: 22), end: Location(file: nil, line: .max, character: .max), - disabledRuleIdentifiers: []) + disabledRules: []) ]) }