From 09a9475cbcc413251a1f5c2b5ea5f217d37b418c Mon Sep 17 00:00:00 2001 From: Marcelo Fabri Date: Sun, 10 Feb 2019 21:49:51 -0800 Subject: [PATCH] Colon rule now catches violations on generic type declarations Fixes #2628 --- CHANGELOG.md | 5 +- Rules.md | 35 ++++ .../Rules/Style/ColonRule+Type.swift | 87 +++++----- .../Rules/Style/ColonRule.swift | 144 +--------------- .../Rules/Style/ColonRuleExamples.swift | 154 ++++++++++++++++++ SwiftLint.xcodeproj/project.pbxproj | 4 + 6 files changed, 249 insertions(+), 180 deletions(-) create mode 100644 Source/SwiftLintFramework/Rules/Style/ColonRuleExamples.swift diff --git a/CHANGELOG.md b/CHANGELOG.md index 953fbee9688..ff7d4617267 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,10 @@ #### Bug Fixes -* None. +* `colon` rule now catches violations when declaring generic types with + inheritance or protocol conformance. + [Marcelo Fabri](https://github.com/marcelofabri) + [#2628](https://github.com/realm/SwiftLint/issues/2628) ## 0.31.0: Busy Laundromat diff --git a/Rules.md b/Rules.md index cb7c0b4534c..c630e787ccf 100644 --- a/Rules.md +++ b/Rules.md @@ -1987,6 +1987,21 @@ class Foo: Bar {} ``` +```swift +class Foo: Bar {} + +``` + +```swift +class Foo: Bar {} + +``` + +```swift +class Foo: Bar {} + +``` + ```swift class Foo {} @@ -2230,6 +2245,26 @@ class ↓Foo:Bar {} ``` +```swift +class ↓Foo : Bar {} + +``` + +```swift +class ↓Foo:Bar {} + +``` + +```swift +class ↓Foo:Bar {} + +``` + +```swift +class ↓Foo:Bar {} + +``` + ```swift class Foo<↓T:Equatable> {} diff --git a/Source/SwiftLintFramework/Rules/Style/ColonRule+Type.swift b/Source/SwiftLintFramework/Rules/Style/ColonRule+Type.swift index aba1c133efa..890e03204b7 100644 --- a/Source/SwiftLintFramework/Rules/Style/ColonRule+Type.swift +++ b/Source/SwiftLintFramework/Rules/Style/ColonRule+Type.swift @@ -7,54 +7,63 @@ internal extension ColonRule { // If flexible_right_spacing is false or omitted, match 0 or 2+ whitespaces. let spacingRegex = configuration.flexibleRightSpacing ? "(?:\\s{0})" : "(?:\\s{0}|\\s{2,})" - return "(\\w)" + // Capture an identifier - "(?:" + // start group - "\\s+" + // followed by whitespace - ":" + // to the left of a colon - "\\s*" + // followed by any amount of whitespace. - "|" + // or - ":" + // immediately followed by a colon - spacingRegex + // followed by right spacing regex - ")" + // end group - "(" + // Capture a type identifier - "[\\[|\\(]*" + // which may begin with a series of nested parenthesis or brackets - "\\S)" // lazily to the first non-whitespace character. + return "(\\w)" + // Capture an identifier. + "(<[\\w\\s:\\.,]+>)?" + // Capture a generic parameter clause (optional). + "(?:" + // Start group + "\\s+" + // followed by whitespace + ":" + // to the left of a colon + "\\s*" + // followed by any amount of whitespace. + "|" + // or + ":" + // immediately followed by a colon + spacingRegex + // followed by right spacing regex + ")" + // end group + "(" + // Capture a type identifier + "[\\[|\\(]*" + // which may begin with a series of nested parenthesis or brackets + "\\S)" // lazily to the first non-whitespace character. } func typeColonViolationRanges(in file: File, matching pattern: String) -> [NSRange] { let nsstring = file.contents.bridge() - let commentAndStringKindsSet = SyntaxKind.commentAndStringKinds - return file.rangesAndTokens(matching: pattern).filter { _, syntaxTokens in - let syntaxKinds = syntaxTokens.kinds - - guard syntaxKinds.count == 2 else { - return false - } - - let validKinds: Bool - switch (syntaxKinds[0], syntaxKinds[1]) { - case (.identifier, .typeidentifier), - (.typeidentifier, .typeidentifier): - validKinds = true - case (.identifier, .keyword), - (.typeidentifier, .keyword): - validKinds = file.isTypeLike(token: syntaxTokens[1]) - case (.keyword, .typeidentifier): - validKinds = file.isTypeLike(token: syntaxTokens[0]) - default: - validKinds = false + return file.matchesAndTokens(matching: pattern).filter { match, syntaxTokens in + if match.range(at: 2).length > 0 && syntaxTokens.count > 2 { // captured a generic definition + let tokens = [syntaxTokens.first, syntaxTokens.last].compactMap { $0 } + return isValidMatch(syntaxTokens: tokens, file: file) } - guard validKinds else { - return false - } - - return Set(syntaxKinds).isDisjoint(with: commentAndStringKindsSet) - }.compactMap { range, syntaxTokens in + return isValidMatch(syntaxTokens: syntaxTokens, file: file) + }.compactMap { match, syntaxTokens in let identifierRange = nsstring .byteRangeToNSRange(start: syntaxTokens[0].offset, length: 0) - return identifierRange.map { NSUnionRange($0, range) } + return identifierRange.map { NSUnionRange($0, match.range) } + } + } + + private func isValidMatch(syntaxTokens: [SyntaxToken], file: File) -> Bool { + let syntaxKinds = syntaxTokens.kinds + + guard syntaxKinds.count == 2 else { + return false + } + + let validKinds: Bool + switch (syntaxKinds[0], syntaxKinds[1]) { + case (.identifier, .typeidentifier), + (.typeidentifier, .typeidentifier): + validKinds = true + case (.identifier, .keyword), + (.typeidentifier, .keyword): + validKinds = file.isTypeLike(token: syntaxTokens[1]) + case (.keyword, .typeidentifier): + validKinds = file.isTypeLike(token: syntaxTokens[0]) + default: + validKinds = false + } + + guard validKinds else { + return false } + + return Set(syntaxKinds).isDisjoint(with: SyntaxKind.commentAndStringKinds) } } diff --git a/Source/SwiftLintFramework/Rules/Style/ColonRule.swift b/Source/SwiftLintFramework/Rules/Style/ColonRule.swift index 5e0a5d711fb..8ce8335d3da 100644 --- a/Source/SwiftLintFramework/Rules/Style/ColonRule.swift +++ b/Source/SwiftLintFramework/Rules/Style/ColonRule.swift @@ -18,145 +18,9 @@ public struct ColonRule: CorrectableRule, ConfigurationProviderRule { description: "Colons should be next to the identifier when specifying a type " + "and next to the key in dictionary literals.", kind: .style, - nonTriggeringExamples: [ - "let abc: Void\n", - "let abc: [Void: Void]\n", - "let abc: (Void, Void)\n", - "let abc: ([Void], String, Int)\n", - "let abc: [([Void], String, Int)]\n", - "let abc: String=\"def\"\n", - "let abc: Int=0\n", - "let abc: Enum=Enum.Value\n", - "func abc(def: Void) {}\n", - "func abc(def: Void, ghi: Void) {}\n", - "let abc: String = \"abc:\"", - "let abc = [Void: Void]()\n", - "let abc = [1: [3: 2], 3: 4]\n", - "let abc = [\"string\": \"string\"]\n", - "let abc = [\"string:string\": \"string\"]\n", - "let abc: [String: Int]\n", - "func foo(bar: [String: Int]) {}\n", - "func foo() -> [String: Int] { return [:] }\n", - "let abc: Any\n", - "let abc: [Any: Int]\n", - "let abc: [String: Any]\n", - "class Foo: Bar {}\n", - "class Foo {}\n", - "switch foo {\n" + - "case .bar:\n" + - " _ = something()\n" + - "}\n", - "object.method(x: 5, y: \"string\")\n", - "object.method(x: 5, y:\n" + - " \"string\")", - "object.method(5, y: \"string\")\n", - "func abc() { def(ghi: jkl) }", - "func abc(def: Void) { ghi(jkl: mno) }", - "class ABC { let def = ghi(jkl: mno) } }", - "func foo() { let dict = [1: 1] }" - ], - triggeringExamples: [ - "let ↓abc:Void\n", - "let ↓abc: Void\n", - "let ↓abc :Void\n", - "let ↓abc : Void\n", - "let ↓abc : [Void: Void]\n", - "let ↓abc : (Void, String, Int)\n", - "let ↓abc : ([Void], String, Int)\n", - "let ↓abc : [([Void], String, Int)]\n", - "let ↓abc: (Void, String, Int)\n", - "let ↓abc: ([Void], String, Int)\n", - "let ↓abc: [([Void], String, Int)]\n", - "let ↓abc :String=\"def\"\n", - "let ↓abc :Int=0\n", - "let ↓abc :Int = 0\n", - "let ↓abc:Int=0\n", - "let ↓abc:Int = 0\n", - "let ↓abc:Enum=Enum.Value\n", - "func abc(↓def:Void) {}\n", - "func abc(↓def: Void) {}\n", - "func abc(↓def :Void) {}\n", - "func abc(↓def : Void) {}\n", - "func abc(def: Void, ↓ghi :Void) {}\n", - "let abc = [Void↓:Void]()\n", - "let abc = [Void↓ : Void]()\n", - "let abc = [Void↓: Void]()\n", - "let abc = [Void↓ : Void]()\n", - "let abc = [1: [3↓ : 2], 3: 4]\n", - "let abc = [1: [3↓ : 2], 3↓: 4]\n", - "let abc: [↓String : Int]\n", - "let abc: [↓String:Int]\n", - "func foo(bar: [↓String : Int]) {}\n", - "func foo(bar: [↓String:Int]) {}\n", - "func foo() -> [↓String : Int] { return [:] }\n", - "func foo() -> [↓String:Int] { return [:] }\n", - "let ↓abc : Any\n", - "let abc: [↓Any : Int]\n", - "let abc: [↓String : Any]\n", - "class ↓Foo : Bar {}\n", - "class ↓Foo:Bar {}\n", - "class Foo<↓T:Equatable> {}\n", - "class Foo<↓T : Equatable> {}\n", - "object.method(x: 5, y↓ : \"string\")\n", - "object.method(x↓:5, y: \"string\")\n", - "object.method(x↓: 5, y: \"string\")\n", - "func abc() { def(ghi↓:jkl) }", - "func abc(def: Void) { ghi(jkl↓:mno) }", - "class ABC { let def = ghi(jkl↓:mno) } }", - "func foo() { let dict = [1↓ : 1] }" - ], - corrections: [ - "let ↓abc:Void\n": "let abc: Void\n", - "let ↓abc: Void\n": "let abc: Void\n", - "let ↓abc :Void\n": "let abc: Void\n", - "let ↓abc : Void\n": "let abc: Void\n", - "let ↓abc : [Void: Void]\n": "let abc: [Void: Void]\n", - "let ↓abc : (Void, String, Int)\n": "let abc: (Void, String, Int)\n", - "let ↓abc : ([Void], String, Int)\n": "let abc: ([Void], String, Int)\n", - "let ↓abc : [([Void], String, Int)]\n": "let abc: [([Void], String, Int)]\n", - "let ↓abc: (Void, String, Int)\n": "let abc: (Void, String, Int)\n", - "let ↓abc: ([Void], String, Int)\n": "let abc: ([Void], String, Int)\n", - "let ↓abc: [([Void], String, Int)]\n": "let abc: [([Void], String, Int)]\n", - "let ↓abc :String=\"def\"\n": "let abc: String=\"def\"\n", - "let ↓abc :Int=0\n": "let abc: Int=0\n", - "let ↓abc :Int = 0\n": "let abc: Int = 0\n", - "let ↓abc:Int=0\n": "let abc: Int=0\n", - "let ↓abc:Int = 0\n": "let abc: Int = 0\n", - "let ↓abc:Enum=Enum.Value\n": "let abc: Enum=Enum.Value\n", - "func abc(↓def:Void) {}\n": "func abc(def: Void) {}\n", - "func abc(↓def: Void) {}\n": "func abc(def: Void) {}\n", - "func abc(↓def :Void) {}\n": "func abc(def: Void) {}\n", - "func abc(↓def : Void) {}\n": "func abc(def: Void) {}\n", - "func abc(def: Void, ↓ghi :Void) {}\n": "func abc(def: Void, ghi: Void) {}\n", - "let abc = [Void↓:Void]()\n": "let abc = [Void: Void]()\n", - "let abc = [Void↓ : Void]()\n": "let abc = [Void: Void]()\n", - "let abc = [Void↓: Void]()\n": "let abc = [Void: Void]()\n", - "let abc = [Void↓ : Void]()\n": "let abc = [Void: Void]()\n", - "let abc = [1: [3↓ : 2], 3: 4]\n": "let abc = [1: [3: 2], 3: 4]\n", - "let abc = [1: [3↓ : 2], 3↓: 4]\n": "let abc = [1: [3: 2], 3: 4]\n", - "let abc: [↓String : Int]\n": "let abc: [String: Int]\n", - "let abc: [↓String:Int]\n": "let abc: [String: Int]\n", - "func foo(bar: [↓String : Int]) {}\n": "func foo(bar: [String: Int]) {}\n", - "func foo(bar: [↓String:Int]) {}\n": "func foo(bar: [String: Int]) {}\n", - "func foo() -> [↓String : Int] { return [:] }\n": "func foo() -> [String: Int] { return [:] }\n", - "func foo() -> [↓String:Int] { return [:] }\n": "func foo() -> [String: Int] { return [:] }\n", - "let ↓abc : Any\n": "let abc: Any\n", - "let abc: [↓Any : Int]\n": "let abc: [Any: Int]\n", - "let abc: [↓String : Any]\n": "let abc: [String: Any]\n", - "class ↓Foo : Bar {}\n": "class Foo: Bar {}\n", - "class ↓Foo:Bar {}\n": "class Foo: Bar {}\n", - "class Foo<↓T:Equatable> {}\n": "class Foo {}\n", - "class Foo<↓T : Equatable> {}\n": "class Foo {}\n", - "object.method(x: 5, y↓ : \"string\")\n": "object.method(x: 5, y: \"string\")\n", - "object.method(x↓:5, y: \"string\")\n": "object.method(x: 5, y: \"string\")\n", - "object.method(x↓: 5, y: \"string\")\n": "object.method(x: 5, y: \"string\")\n", - "func abc() { def(ghi↓:jkl) }": "func abc() { def(ghi: jkl) }", - "func abc(def: Void) { ghi(jkl↓:mno) }": "func abc(def: Void) { ghi(jkl: mno) }", - "class ABC { let def = ghi(jkl↓:mno) } }": "class ABC { let def = ghi(jkl: mno) } }", - "func foo() { let dict = [1↓ : 1] }": "func foo() { let dict = [1: 1] }", - "class Foo {\n #if false\n #else\n let bar = [\"key\"↓ : \"value\"]\n #endif\n}": - "class Foo {\n #if false\n #else\n let bar = [\"key\": \"value\"]\n #endif\n}" - ] + nonTriggeringExamples: ColonRuleExamples.nonTriggeringExamples, + triggeringExamples: ColonRuleExamples.triggeringExamples, + corrections: ColonRuleExamples.corrections ) public func validate(file: File) -> [StyleViolation] { @@ -193,7 +57,7 @@ public struct ColonRule: CorrectableRule, ConfigurationProviderRule { contents = regularExpression.stringByReplacingMatches(in: contents, options: [], range: range, - withTemplate: "$1: $2") + withTemplate: "$1$2: $3") case .dictionary, .functionCall: contents = contents.bridge().replacingCharacters(in: range, with: ": ") } diff --git a/Source/SwiftLintFramework/Rules/Style/ColonRuleExamples.swift b/Source/SwiftLintFramework/Rules/Style/ColonRuleExamples.swift new file mode 100644 index 00000000000..c38e5bae454 --- /dev/null +++ b/Source/SwiftLintFramework/Rules/Style/ColonRuleExamples.swift @@ -0,0 +1,154 @@ +internal struct ColonRuleExamples { + static let nonTriggeringExamples = [ + "let abc: Void\n", + "let abc: [Void: Void]\n", + "let abc: (Void, Void)\n", + "let abc: ([Void], String, Int)\n", + "let abc: [([Void], String, Int)]\n", + "let abc: String=\"def\"\n", + "let abc: Int=0\n", + "let abc: Enum=Enum.Value\n", + "func abc(def: Void) {}\n", + "func abc(def: Void, ghi: Void) {}\n", + "let abc: String = \"abc:\"", + "let abc = [Void: Void]()\n", + "let abc = [1: [3: 2], 3: 4]\n", + "let abc = [\"string\": \"string\"]\n", + "let abc = [\"string:string\": \"string\"]\n", + "let abc: [String: Int]\n", + "func foo(bar: [String: Int]) {}\n", + "func foo() -> [String: Int] { return [:] }\n", + "let abc: Any\n", + "let abc: [Any: Int]\n", + "let abc: [String: Any]\n", + "class Foo: Bar {}\n", + "class Foo: Bar {}\n", + "class Foo: Bar {}\n", + "class Foo: Bar {}\n", + "class Foo {}\n", + "switch foo {\n" + + "case .bar:\n" + + " _ = something()\n" + + "}\n", + "object.method(x: 5, y: \"string\")\n", + "object.method(x: 5, y:\n" + + " \"string\")", + "object.method(5, y: \"string\")\n", + "func abc() { def(ghi: jkl) }", + "func abc(def: Void) { ghi(jkl: mno) }", + "class ABC { let def = ghi(jkl: mno) } }", + "func foo() { let dict = [1: 1] }" + ] + + static let triggeringExamples = [ + "let ↓abc:Void\n", + "let ↓abc: Void\n", + "let ↓abc :Void\n", + "let ↓abc : Void\n", + "let ↓abc : [Void: Void]\n", + "let ↓abc : (Void, String, Int)\n", + "let ↓abc : ([Void], String, Int)\n", + "let ↓abc : [([Void], String, Int)]\n", + "let ↓abc: (Void, String, Int)\n", + "let ↓abc: ([Void], String, Int)\n", + "let ↓abc: [([Void], String, Int)]\n", + "let ↓abc :String=\"def\"\n", + "let ↓abc :Int=0\n", + "let ↓abc :Int = 0\n", + "let ↓abc:Int=0\n", + "let ↓abc:Int = 0\n", + "let ↓abc:Enum=Enum.Value\n", + "func abc(↓def:Void) {}\n", + "func abc(↓def: Void) {}\n", + "func abc(↓def :Void) {}\n", + "func abc(↓def : Void) {}\n", + "func abc(def: Void, ↓ghi :Void) {}\n", + "let abc = [Void↓:Void]()\n", + "let abc = [Void↓ : Void]()\n", + "let abc = [Void↓: Void]()\n", + "let abc = [Void↓ : Void]()\n", + "let abc = [1: [3↓ : 2], 3: 4]\n", + "let abc = [1: [3↓ : 2], 3↓: 4]\n", + "let abc: [↓String : Int]\n", + "let abc: [↓String:Int]\n", + "func foo(bar: [↓String : Int]) {}\n", + "func foo(bar: [↓String:Int]) {}\n", + "func foo() -> [↓String : Int] { return [:] }\n", + "func foo() -> [↓String:Int] { return [:] }\n", + "let ↓abc : Any\n", + "let abc: [↓Any : Int]\n", + "let abc: [↓String : Any]\n", + "class ↓Foo : Bar {}\n", + "class ↓Foo:Bar {}\n", + "class ↓Foo : Bar {}\n", + "class ↓Foo:Bar {}\n", + "class ↓Foo:Bar {}\n", + "class ↓Foo:Bar {}\n", + "class Foo<↓T:Equatable> {}\n", + "class Foo<↓T : Equatable> {}\n", + "object.method(x: 5, y↓ : \"string\")\n", + "object.method(x↓:5, y: \"string\")\n", + "object.method(x↓: 5, y: \"string\")\n", + "func abc() { def(ghi↓:jkl) }", + "func abc(def: Void) { ghi(jkl↓:mno) }", + "class ABC { let def = ghi(jkl↓:mno) } }", + "func foo() { let dict = [1↓ : 1] }" + ] + + static let corrections = [ + "let ↓abc:Void\n": "let abc: Void\n", + "let ↓abc: Void\n": "let abc: Void\n", + "let ↓abc :Void\n": "let abc: Void\n", + "let ↓abc : Void\n": "let abc: Void\n", + "let ↓abc : [Void: Void]\n": "let abc: [Void: Void]\n", + "let ↓abc : (Void, String, Int)\n": "let abc: (Void, String, Int)\n", + "let ↓abc : ([Void], String, Int)\n": "let abc: ([Void], String, Int)\n", + "let ↓abc : [([Void], String, Int)]\n": "let abc: [([Void], String, Int)]\n", + "let ↓abc: (Void, String, Int)\n": "let abc: (Void, String, Int)\n", + "let ↓abc: ([Void], String, Int)\n": "let abc: ([Void], String, Int)\n", + "let ↓abc: [([Void], String, Int)]\n": "let abc: [([Void], String, Int)]\n", + "let ↓abc :String=\"def\"\n": "let abc: String=\"def\"\n", + "let ↓abc :Int=0\n": "let abc: Int=0\n", + "let ↓abc :Int = 0\n": "let abc: Int = 0\n", + "let ↓abc:Int=0\n": "let abc: Int=0\n", + "let ↓abc:Int = 0\n": "let abc: Int = 0\n", + "let ↓abc:Enum=Enum.Value\n": "let abc: Enum=Enum.Value\n", + "func abc(↓def:Void) {}\n": "func abc(def: Void) {}\n", + "func abc(↓def: Void) {}\n": "func abc(def: Void) {}\n", + "func abc(↓def :Void) {}\n": "func abc(def: Void) {}\n", + "func abc(↓def : Void) {}\n": "func abc(def: Void) {}\n", + "func abc(def: Void, ↓ghi :Void) {}\n": "func abc(def: Void, ghi: Void) {}\n", + "let abc = [Void↓:Void]()\n": "let abc = [Void: Void]()\n", + "let abc = [Void↓ : Void]()\n": "let abc = [Void: Void]()\n", + "let abc = [Void↓: Void]()\n": "let abc = [Void: Void]()\n", + "let abc = [Void↓ : Void]()\n": "let abc = [Void: Void]()\n", + "let abc = [1: [3↓ : 2], 3: 4]\n": "let abc = [1: [3: 2], 3: 4]\n", + "let abc = [1: [3↓ : 2], 3↓: 4]\n": "let abc = [1: [3: 2], 3: 4]\n", + "let abc: [↓String : Int]\n": "let abc: [String: Int]\n", + "let abc: [↓String:Int]\n": "let abc: [String: Int]\n", + "func foo(bar: [↓String : Int]) {}\n": "func foo(bar: [String: Int]) {}\n", + "func foo(bar: [↓String:Int]) {}\n": "func foo(bar: [String: Int]) {}\n", + "func foo() -> [↓String : Int] { return [:] }\n": "func foo() -> [String: Int] { return [:] }\n", + "func foo() -> [↓String:Int] { return [:] }\n": "func foo() -> [String: Int] { return [:] }\n", + "let ↓abc : Any\n": "let abc: Any\n", + "let abc: [↓Any : Int]\n": "let abc: [Any: Int]\n", + "let abc: [↓String : Any]\n": "let abc: [String: Any]\n", + "class ↓Foo : Bar {}\n": "class Foo: Bar {}\n", + "class ↓Foo:Bar {}\n": "class Foo: Bar {}\n", + "class ↓Foo : Bar {}\n": "class Foo: Bar {}\n", + "class ↓Foo:Bar {}\n": "class Foo: Bar {}\n", + "class ↓Foo:Bar {}\n": "class Foo: Bar {}\n", + "class ↓Foo:Bar {}\n": "class Foo: Bar {}\n", + "class Foo<↓T:Equatable> {}\n": "class Foo {}\n", + "class Foo<↓T : Equatable> {}\n": "class Foo {}\n", + "object.method(x: 5, y↓ : \"string\")\n": "object.method(x: 5, y: \"string\")\n", + "object.method(x↓:5, y: \"string\")\n": "object.method(x: 5, y: \"string\")\n", + "object.method(x↓: 5, y: \"string\")\n": "object.method(x: 5, y: \"string\")\n", + "func abc() { def(ghi↓:jkl) }": "func abc() { def(ghi: jkl) }", + "func abc(def: Void) { ghi(jkl↓:mno) }": "func abc(def: Void) { ghi(jkl: mno) }", + "class ABC { let def = ghi(jkl↓:mno) } }": "class ABC { let def = ghi(jkl: mno) } }", + "func foo() { let dict = [1↓ : 1] }": "func foo() { let dict = [1: 1] }", + "class Foo {\n #if false\n #else\n let bar = [\"key\"↓ : \"value\"]\n #endif\n}": + "class Foo {\n #if false\n #else\n let bar = [\"key\": \"value\"]\n #endif\n}" + ] +} diff --git a/SwiftLint.xcodeproj/project.pbxproj b/SwiftLint.xcodeproj/project.pbxproj index 5a9182f1429..cf4783ce4f3 100644 --- a/SwiftLint.xcodeproj/project.pbxproj +++ b/SwiftLint.xcodeproj/project.pbxproj @@ -306,6 +306,7 @@ D4C889711E385B7B00BAE88D /* RedundantDiscardableLetRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4C889701E385B7B00BAE88D /* RedundantDiscardableLetRule.swift */; }; D4CA758F1E2DEEA500A40E8A /* NumberSeparatorRuleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4CA758E1E2DEEA500A40E8A /* NumberSeparatorRuleTests.swift */; }; D4CFC5D2209EC95A00668488 /* FunctionDefaultParameterAtEndRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4CFC5D1209EC95A00668488 /* FunctionDefaultParameterAtEndRule.swift */; }; + D4D0B8F42211428D0053A116 /* ColonRuleExamples.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4D0B8F32211428D0053A116 /* ColonRuleExamples.swift */; }; D4D1B9BB1EAC2C910028BE6A /* AccessControlLevel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4D1B9B91EAC2C870028BE6A /* AccessControlLevel.swift */; }; D4D383852145F550000235BD /* StaticOperatorRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4D383842145F550000235BD /* StaticOperatorRule.swift */; }; D4D5A5FF1E1F3A1C00D15E0C /* ShorthandOperatorRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4D5A5FE1E1F3A1C00D15E0C /* ShorthandOperatorRule.swift */; }; @@ -777,6 +778,7 @@ D4C889701E385B7B00BAE88D /* RedundantDiscardableLetRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RedundantDiscardableLetRule.swift; sourceTree = ""; }; D4CA758E1E2DEEA500A40E8A /* NumberSeparatorRuleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NumberSeparatorRuleTests.swift; sourceTree = ""; }; D4CFC5D1209EC95A00668488 /* FunctionDefaultParameterAtEndRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FunctionDefaultParameterAtEndRule.swift; sourceTree = ""; }; + D4D0B8F32211428D0053A116 /* ColonRuleExamples.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColonRuleExamples.swift; sourceTree = ""; }; D4D1B9B91EAC2C870028BE6A /* AccessControlLevel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccessControlLevel.swift; sourceTree = ""; }; D4D383842145F550000235BD /* StaticOperatorRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StaticOperatorRule.swift; sourceTree = ""; }; D4D5A5FE1E1F3A1C00D15E0C /* ShorthandOperatorRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShorthandOperatorRule.swift; sourceTree = ""; }; @@ -1101,6 +1103,7 @@ 1E82D5581D7775C7009553D7 /* ClosureSpacingRule.swift */, 756B585C2138ECD300D1A4E9 /* CollectionAlignmentRule.swift */, E88DEA831B0990F500A66CB0 /* ColonRule.swift */, + D4D0B8F32211428D0053A116 /* ColonRuleExamples.swift */, D47EF4811F69E34D0012C4CA /* ColonRule+Dictionary.swift */, D47EF47F1F69E3100012C4CA /* ColonRule+FunctionCall.swift */, D47EF4831F69E3D60012C4CA /* ColonRule+Type.swift */, @@ -2027,6 +2030,7 @@ D48AE2CC1DFB58C5001C6A4A /* AttributesRuleExamples.swift in Sources */, C28B2B3D2106DF730009A0FE /* PrefixedConstantRuleConfiguration.swift in Sources */, 62A7127520F1178F00E604A6 /* AnyObjectProtocolRule.swift in Sources */, + D4D0B8F42211428D0053A116 /* ColonRuleExamples.swift in Sources */, E88DEA6F1B09843F00A66CB0 /* Location.swift in Sources */, D43B046B1E075905004016AF /* ClosureEndIndentationRule.swift in Sources */, D47EF4821F69E34D0012C4CA /* ColonRule+Dictionary.swift in Sources */,