diff --git a/CHANGELOG.md b/CHANGELOG.md index 80150d62c..f0f7c2a60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -108,6 +108,11 @@ [Marcelo Fabri](https://github.com/marcelofabri) [#1029](https://github.com/realm/SwiftLint/issues/1029) +* Fix false positive in `empty_enum_arguments` rule when using wildcards and + `where` clauses. + [Marcelo Fabri](https://github.com/marcelofabri) + [#1722](https://github.com/realm/SwiftLint/issues/1722) + ## 0.20.1: More Liquid Fabric Softener ##### Breaking diff --git a/Rules.md b/Rules.md index 5469a670d..27fca03af 100644 --- a/Rules.md +++ b/Rules.md @@ -1738,31 +1738,37 @@ Arguments can be omitted when matching enums with associated types if they are n ```swift switch foo { - case .bar: break + case .bar: break } ``` ```swift switch foo { - case .bar(let x): break + .bar(let x): break } ``` ```swift switch foo { - case let .bar(x): break + case let .bar(x): break } ``` ```swift switch (foo, bar) { - case (_, _): break + case (_, _): break } ``` ```swift switch foo { - case "bar".uppercased(): break + case "bar".uppercased(): break +} +``` + +```swift +switch (foo, bar) { + case (_, _) where !something: break } ``` @@ -1772,25 +1778,25 @@ switch foo { ```swift switch foo { - case .bar↓(_): break + case .bar↓(_): break } ``` ```swift switch foo { - case .bar↓(): break + case .bar↓(): break } ``` ```swift switch foo { - case .bar↓(_), .bar2↓(_): break + case .bar↓(_), .bar2↓(_): break } ``` ```swift switch foo { - case .bar↓() where method() > 2: break + case .bar↓() where method() > 2: break } ``` @@ -9011,7 +9017,7 @@ Identifier | Enabled by default | Supports autocorrection | Kind --- | --- | --- | --- `trailing_closure` | Disabled | No | style -Trailing closure syntax should be used whenever possible +Trailing closure syntax should be used whenever possible. ### Examples diff --git a/Source/SwiftLintFramework/Rules/EmptyEnumArgumentsRule.swift b/Source/SwiftLintFramework/Rules/EmptyEnumArgumentsRule.swift index cd9938c3b..b9e8af6ea 100644 --- a/Source/SwiftLintFramework/Rules/EmptyEnumArgumentsRule.swift +++ b/Source/SwiftLintFramework/Rules/EmptyEnumArgumentsRule.swift @@ -9,6 +9,12 @@ import Foundation import SourceKittenFramework +private func wrapInSwitch(variable: String = "foo", _ str: String) -> String { + return "switch \(variable) {\n" + + " \(str): break\n" + + "}" +} + public struct EmptyEnumArgumentsRule: ASTRule, ConfigurationProviderRule, CorrectableRule { public var configuration = SeverityConfiguration(.warning) @@ -20,27 +26,24 @@ public struct EmptyEnumArgumentsRule: ASTRule, ConfigurationProviderRule, Correc description: "Arguments can be omitted when matching enums with associated types if they are not used.", kind: .style, nonTriggeringExamples: [ - "switch foo {\n case .bar: break\n}", - "switch foo {\n case .bar(let x): break\n}", - "switch foo {\n case let .bar(x): break\n}", - "switch (foo, bar) {\n case (_, _): break\n}", - "switch foo {\n case \"bar\".uppercased(): break\n}" + wrapInSwitch("case .bar"), + wrapInSwitch(".bar(let x)"), + wrapInSwitch("case let .bar(x)"), + wrapInSwitch(variable: "(foo, bar)", "case (_, _)"), + wrapInSwitch("case \"bar\".uppercased()"), + wrapInSwitch(variable: "(foo, bar)", "case (_, _) where !something") ], triggeringExamples: [ - "switch foo {\n case .bar↓(_): break\n}", - "switch foo {\n case .bar↓(): break\n}", - "switch foo {\n case .bar↓(_), .bar2↓(_): break\n}", - "switch foo {\n case .bar↓() where method() > 2: break\n}" + wrapInSwitch("case .bar↓(_)"), + wrapInSwitch("case .bar↓()"), + wrapInSwitch("case .bar↓(_), .bar2↓(_)"), + wrapInSwitch("case .bar↓() where method() > 2") ], corrections: [ - "switch foo {\n case .bar↓(_): break\n}": - "switch foo {\n case .bar: break\n}", - "switch foo {\n case .bar↓(): break\n}": - "switch foo {\n case .bar: break\n}", - "switch foo {\n case .bar↓(_), .bar2↓(_): break\n}": - "switch foo {\n case .bar, .bar2: break\n}", - "switch foo {\n case .bar↓() where method() > 2: break\n}": - "switch foo {\n case .bar where method() > 2: break\n}" + wrapInSwitch("case .bar↓(_)"): wrapInSwitch("case .bar"), + wrapInSwitch("case .bar↓()"): wrapInSwitch("case .bar"), + wrapInSwitch("case .bar↓(_), .bar2↓(_)"): wrapInSwitch("case .bar, .bar2"), + wrapInSwitch("case .bar↓() where method() > 2"): wrapInSwitch("case .bar where method() > 2") ] ) @@ -88,12 +91,22 @@ public struct EmptyEnumArgumentsRule: ASTRule, ConfigurationProviderRule, Correc } // avoid matches after `where` keyworkd - if let whereMatch = file.match(pattern: "where", with: [.keyword], range: caseRange).first, - whereMatch.location < range.location { - return nil + if let whereRange = file.match(pattern: "where", with: [.keyword], range: caseRange).first { + if whereRange.location < range.location { + return nil + } + + // avoid matches in "(_, _) where" + if let whereByteRange = contents.NSRangeToByteRange(start: whereRange.location, + length: whereRange.length), + case let length = whereByteRange.location - offset, + case let byteRange = NSRange(location: offset, length: length), + Set(file.syntaxMap.kinds(inByteRange: byteRange)) == [.keyword] { + return nil + } } - if callsRanges.first(where: range.intersects) != nil { + if callsRanges.contains(where: range.intersects) { return nil }