diff --git a/CHANGELOG.md b/CHANGELOG.md index 42eb9805b72..c6f22324b99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,9 +7,13 @@ ##### Enhancements * Add `LegacyNSGeometryFunctionsRule` rule. Add `NSSize`, `NSPoint`, and - `NSRect` constants and constructors to existing rules. + `NSRect` constants and constructors to existing rules. [David Rönnqvist](https://github.com/d-ronnqvist) +* Removed ConditionalBindingCascadeRule. + [J. Cheyo Jimenez](https://github.com/masters3d) + [#701](https://github.com/realm/SwiftLint/issues/701) + * Allow setting `flexible_right_spacing` configuration for the `colon` rule. [Shai Mishali](https://github.com/freak4pc) [#730](https://github.com/realm/SwiftLint/issues/730) diff --git a/Source/SwiftLintFramework/Models/MasterRuleList.swift b/Source/SwiftLintFramework/Models/MasterRuleList.swift index d89b4b06def..2414c3e7a21 100644 --- a/Source/SwiftLintFramework/Models/MasterRuleList.swift +++ b/Source/SwiftLintFramework/Models/MasterRuleList.swift @@ -44,7 +44,6 @@ public let masterRuleList = RuleList(rules: ClosingBraceRule.self, ColonRule.self, CommaRule.self, - ConditionalBindingCascadeRule.self, ControlStatementRule.self, CustomRules.self, CyclomaticComplexityRule.self, diff --git a/Source/SwiftLintFramework/Rules/ConditionalBindingCascadeRule.swift b/Source/SwiftLintFramework/Rules/ConditionalBindingCascadeRule.swift deleted file mode 100644 index 670525a7f2f..00000000000 --- a/Source/SwiftLintFramework/Rules/ConditionalBindingCascadeRule.swift +++ /dev/null @@ -1,128 +0,0 @@ -// -// ConditionalBindingCascadeRule.swift -// SwiftLint -// -// Created by Aaron McTavish on 08/01/2016. -// Copyright © 2016 Realm. All rights reserved. -// - -import Foundation -import SourceKittenFramework - -public struct ConditionalBindingCascadeRule: ASTRule, ConfigurationProviderRule { - - public var configuration = SeverityConfiguration(.Warning) - - public init() {} - - public static let description = RuleDescription( - identifier: "conditional_binding_cascade", - name: "Conditional Binding Cascade", - description: "Repeated `let` statements in conditional binding cascade should be avoided.", - nonTriggeringExamples: [ - "if let a = b, c = d {", - "if case .ar(let ao) = a, case .ar(let bo) = b {}", - "if case .ar(let aa) = $0 {", - "if case .ar(let aa, let bb) = $0 {", - "if let a = b, \n c = d {", - "if let a = b, \n c = d \n {", - "if let a = b { if let c = d {", - "if let a = b { let c = d({ foo in ... })", - "guard let a = b, c = d else {", - "guard let a = b where a, let c = d else {", - "guard let foo = someOptional(), var bar = someMutableOptional(foo) else { return }", - ], - triggeringExamples: [ - "if let a = b, let c = d {", - "if let a = b, \n let c = d {", - "if let a = b, c = d, let e = f {", - "if let a = b, let c = d \n {", - "if \n let a = b, let c = d {", - "if let a = b, c = d.indexOf({$0 == e}), let f = g {", - "guard let a = b, let c = d else {", - "if let a = a, b = b {\ndebugPrint(\"\")\n}\nif let c = a, let d = b {\n}", - // This is a rather exotic case that we cannot correctly identify as - // having too many `let` keywords because of the confounding `case` - // "if case .ar(let aa, let bb) = $0, let c = d, let e = f {", - ] - ) - - private static let kinds = [StatementKind.Guard, .If].map { $0.rawValue } - public func validateFile(file: File, kind: String, - dictionary: [String: SourceKitRepresentable]) -> [StyleViolation] { - guard self.dynamicType.kinds.contains(kind), - let elements = dictionary["key.elements"] as? [SourceKitRepresentable] else { - return [] - } - let conditionByteRanges = elements - .filter { $0.kind == "source.lang.swift.structure.elem.condition_expr" } - .flatMap { return $0.byteRange } - let contents = file.contents as NSString - let resultsArray: [[StyleViolation]] = conditionByteRanges.map { conditionByteRange in - let substructureRanges = dictionary.substructure?.flatMap { $0.byteRange } - .filter { NSLocationInRange($0.location, conditionByteRange) } ?? [] - let keywordTokensInRange = file.syntaxMap.tokensIn(conditionByteRange) - .filter { token in - // exclude tokens in sub structures - substructureRanges.indexOf { NSLocationInRange(token.offset, $0) } == nil - } - .filter { $0.type == SyntaxKind.Keyword.rawValue } - let byteOffsetAndKeywords = keywordTokensInRange.map { - ($0.offset, contents.substringWithByteRange(start: $0.offset, length: $0.length)!) - } - - var results = [StyleViolation]() - var previousBindingKeyword = "" - for (byteOffset, keyword) in byteOffsetAndKeywords { - switch keyword { - case "let": fallthrough - case "var": - if previousBindingKeyword == keyword { - results.append(StyleViolation(ruleDescription: self.dynamicType.description, - severity: configuration.severity, - location: Location(file: file, byteOffset: byteOffset))) - } else { - previousBindingKeyword = keyword - } - case "where": - previousBindingKeyword = "" - case "case": - // We cannot correctly differentiate valid uses of more than - // one let when a the case keyword is involved, so if we have - // one then bail rather than emit an invalid warning. - return [] - default: - break - } - } - return results - } - - return Array(resultsArray.flatten()) - } -} - -extension SourceKitRepresentable { - var dictionary: [String: SourceKitRepresentable]? { - return self as? [String: SourceKitRepresentable] - } - - var substructure: [SourceKitRepresentable]? { - return dictionary?["key.substructure"] as? [SourceKitRepresentable] - } - - var int: Int? { - guard let int64 = self as? Int64 else { return nil } - return Int(int64) - } - - var kind: String? { - return dictionary?["key.kind"] as? String - } - - var byteRange: NSRange? { - guard let byteOffset = dictionary?["key.offset"]?.int, - byteLength = dictionary?["key.length"]?.int else { return nil } - return NSRange(location: byteOffset, length: byteLength) - } -} diff --git a/SwiftLint.xcodeproj/project.pbxproj b/SwiftLint.xcodeproj/project.pbxproj index 03c83fd348d..b89854b4719 100644 --- a/SwiftLint.xcodeproj/project.pbxproj +++ b/SwiftLint.xcodeproj/project.pbxproj @@ -8,7 +8,6 @@ /* Begin PBXBuildFile section */ 006ECFC41C44E99E00EF6364 /* LegacyConstantRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 006ECFC31C44E99E00EF6364 /* LegacyConstantRule.swift */; }; - 00970C751C3FC3A0007C4A83 /* ConditionalBindingCascadeRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00970C741C3FC3A0007C4A83 /* ConditionalBindingCascadeRule.swift */; }; 02FD8AEF1BFC18D60014BFFB /* ExtendedNSStringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02FD8AEE1BFC18D60014BFFB /* ExtendedNSStringTests.swift */; }; 1F11B3CF1C252F23002E8FA8 /* ClosingBraceRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F11B3CE1C252F23002E8FA8 /* ClosingBraceRule.swift */; }; 24E17F721B14BB3F008195BE /* File+Cache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24E17F701B1481FF008195BE /* File+Cache.swift */; }; @@ -173,7 +172,6 @@ /* Begin PBXFileReference section */ 006ECFC31C44E99E00EF6364 /* LegacyConstantRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LegacyConstantRule.swift; sourceTree = ""; }; - 00970C741C3FC3A0007C4A83 /* ConditionalBindingCascadeRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConditionalBindingCascadeRule.swift; sourceTree = ""; }; 02FD8AEE1BFC18D60014BFFB /* ExtendedNSStringTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExtendedNSStringTests.swift; sourceTree = ""; }; 1F11B3CE1C252F23002E8FA8 /* ClosingBraceRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClosingBraceRule.swift; sourceTree = ""; }; 24E17F701B1481FF008195BE /* File+Cache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "File+Cache.swift"; sourceTree = ""; }; @@ -581,7 +579,6 @@ 1F11B3CE1C252F23002E8FA8 /* ClosingBraceRule.swift */, E88DEA831B0990F500A66CB0 /* ColonRule.swift */, 695BE9CE1BDFD92B0071E985 /* CommaRule.swift */, - 00970C741C3FC3A0007C4A83 /* ConditionalBindingCascadeRule.swift */, 65454F451B14D73800319A6C /* ControlStatementRule.swift */, 3B1DF0111C5148140011BCED /* CustomRules.swift */, 2E02005E1C54BF680024D09D /* CyclomaticComplexityRule.swift */, @@ -892,7 +889,6 @@ E816194E1BFBFEAB00946723 /* ForceTryRule.swift in Sources */, E88198541BEA945100333A11 /* CommaRule.swift in Sources */, E88198601BEA98F000333A11 /* VariableNameRule.swift in Sources */, - 00970C751C3FC3A0007C4A83 /* ConditionalBindingCascadeRule.swift in Sources */, E88DEA791B098D4400A66CB0 /* RuleParameter.swift in Sources */, E86396CB1BADB519002C9E88 /* CSVReporter.swift in Sources */, E88198561BEA94D800333A11 /* FileLengthRule.swift in Sources */, diff --git a/Tests/SwiftLintFramework/RulesTests.swift b/Tests/SwiftLintFramework/RulesTests.swift index 84abb78e4a4..7933ac39350 100644 --- a/Tests/SwiftLintFramework/RulesTests.swift +++ b/Tests/SwiftLintFramework/RulesTests.swift @@ -93,10 +93,6 @@ class RulesTests: XCTestCase { verifyRule(CommaRule.description) } - func testConditionalBindingCascade() { - verifyRule(ConditionalBindingCascadeRule.description) - } - func testControlStatement() { verifyRule(ControlStatementRule.description) }