From 5bf50c8920c0eb0e44b8954f396f4486d1fc69f0 Mon Sep 17 00:00:00 2001 From: Timofey Solonin Date: Mon, 1 Oct 2018 12:32:43 +0300 Subject: [PATCH 1/6] #2422 - Specify which compiler protocol initialization rule was violated --- .../Rules/Lint/CompilerProtocolInitRule.swift | 51 +++++++++++-------- .../AutomaticRuleTests.generated.swift | 6 --- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/Source/SwiftLintFramework/Rules/Lint/CompilerProtocolInitRule.swift b/Source/SwiftLintFramework/Rules/Lint/CompilerProtocolInitRule.swift index 4e93b3d6c4..d4e5a06fa6 100644 --- a/Source/SwiftLintFramework/Rules/Lint/CompilerProtocolInitRule.swift +++ b/Source/SwiftLintFramework/Rules/Lint/CompilerProtocolInitRule.swift @@ -1,38 +1,45 @@ import Foundation import SourceKittenFramework -public struct CompilerProtocolInitRule: ASTRule, ConfigurationProviderRule, AutomaticTestableRule { +public struct CompilerProtocolInitRule: ASTRule, ConfigurationProviderRule { public var configuration = SeverityConfiguration(.warning) public init() {} - public static let description = RuleDescription( - identifier: "compiler_protocol_init", - name: "Compiler Protocol Init", - description: "The initializers declared in compiler protocols such as `ExpressibleByArrayLiteral` " + - "shouldn't be called directly.", - kind: .lint, - nonTriggeringExamples: [ - "let set: Set = [1, 2]\n", - "let set = Set(array)\n" - ], - triggeringExamples: [ - "let set = ↓Set(arrayLiteral: 1, 2)\n", - "let set = ↓Set.init(arrayLiteral: 1, 2)\n" - ] - ) + public static let description = specificDescription(for: "such as `ExpressibleByArrayLiteral`", isPlural: true) + + private static func specificDescription(for violation: String, isPlural: Bool) -> RuleDescription { + return RuleDescription( + identifier: "compiler_protocol_init", + name: "Compiler Protocol Init", + description: "The initializers declared in compiler protocol\(isPlural ? "s" : "") \(violation) " + + "shouldn't be called directly.", + kind: .lint, + nonTriggeringExamples: [ + "let set: Set = [1, 2]\n", + "let set = Set(array)\n" + ], + triggeringExamples: [ + "let set = ↓Set(arrayLiteral: 1, 2)\n", + "let set = ↓Set.init(arrayLiteral: 1, 2)\n" + ] + ) + } public func validate(file: File, kind: SwiftExpressionKind, dictionary: [String: SourceKitRepresentable]) -> [StyleViolation] { return violationRanges(in: file, kind: kind, dictionary: dictionary).map { - StyleViolation(ruleDescription: type(of: self).description, - severity: configuration.severity, - location: Location(file: file, characterOffset: $0.location)) + let (violation, range) = $0 + return StyleViolation( + ruleDescription: type(of: self).specificDescription(for: violation.protocolName, isPlural: false), + severity: configuration.severity, + location: Location(file: file, characterOffset: range.location) + ) } } private func violationRanges(in file: File, kind: SwiftExpressionKind, - dictionary: [String: SourceKitRepresentable]) -> [NSRange] { + dictionary: [String: SourceKitRepresentable]) -> [(ExpressibleByCompiler, NSRange)] { guard kind == .call, let name = dictionary.name else { return [] } @@ -47,7 +54,7 @@ public struct CompilerProtocolInitRule: ASTRule, ConfigurationProviderRule, Auto continue } - return [range] + return [(compilerProtocol, range)] } return [] @@ -55,7 +62,7 @@ public struct CompilerProtocolInitRule: ASTRule, ConfigurationProviderRule, Auto } private struct ExpressibleByCompiler { - private let protocolName: String + let protocolName: String let initCallNames: Set private let arguments: [[String]] diff --git a/Tests/SwiftLintFrameworkTests/AutomaticRuleTests.generated.swift b/Tests/SwiftLintFrameworkTests/AutomaticRuleTests.generated.swift index 6e9b91a395..8916c82b64 100644 --- a/Tests/SwiftLintFrameworkTests/AutomaticRuleTests.generated.swift +++ b/Tests/SwiftLintFrameworkTests/AutomaticRuleTests.generated.swift @@ -66,12 +66,6 @@ class CommaRuleTests: XCTestCase { } } -class CompilerProtocolInitRuleTests: XCTestCase { - func testWithDefaultConfiguration() { - verifyRule(CompilerProtocolInitRule.description) - } -} - class ContainsOverFirstNotNilRuleTests: XCTestCase { func testWithDefaultConfiguration() { verifyRule(ContainsOverFirstNotNilRule.description) From 2cc4dca379d7e1e590ebd74d1cfe22d39e2c1c50 Mon Sep 17 00:00:00 2001 From: Timofey Solonin Date: Mon, 1 Oct 2018 12:34:01 +0300 Subject: [PATCH 2/6] #2422 - Add CompilerProtocolInitRule violation unit test for ExpressibleByIntegerLiteral protocol --- SwiftLint.xcodeproj/project.pbxproj | 4 +++ .../CompilerProtocolInitRuleTests.swift | 30 +++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 Tests/SwiftLintFrameworkTests/CompilerProtocolInitRuleTests.swift diff --git a/SwiftLint.xcodeproj/project.pbxproj b/SwiftLint.xcodeproj/project.pbxproj index cad039852e..0aadb6af8c 100644 --- a/SwiftLint.xcodeproj/project.pbxproj +++ b/SwiftLint.xcodeproj/project.pbxproj @@ -181,6 +181,7 @@ B89F3BCE1FD5EE0200931E59 /* RequiredEnumCaseRuleTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = B89F3BCB1FD5EDA900931E59 /* RequiredEnumCaseRuleTestCase.swift */; }; B89F3BCF1FD5EE1400931E59 /* RequiredEnumCaseRuleConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = B89F3BC71FD5ED7D00931E59 /* RequiredEnumCaseRuleConfiguration.swift */; }; BB00B4E91F5216090079869F /* MultipleClosuresWithTrailingClosureRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB00B4E71F5216070079869F /* MultipleClosuresWithTrailingClosureRule.swift */; }; + BCB68283216213130078E4C3 /* CompilerProtocolInitRuleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCB68282216213130078E4C3 /* CompilerProtocolInitRuleTests.swift */; }; BFF028AE1CBCF8A500B38A9D /* TrailingWhitespaceConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF48D2D61CBCCA5F0080BDAE /* TrailingWhitespaceConfiguration.swift */; }; C25EBBDF2107884200E27603 /* PrefixedTopLevelConstantRuleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C25EBBDD210787B200E27603 /* PrefixedTopLevelConstantRuleTests.swift */; }; C25EBBE221078D5F00E27603 /* GlobTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C25EBBE021078D5B00E27603 /* GlobTests.swift */; }; @@ -599,6 +600,7 @@ B89F3BC91FD5ED9000931E59 /* RequiredEnumCaseRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RequiredEnumCaseRule.swift; sourceTree = ""; }; B89F3BCB1FD5EDA900931E59 /* RequiredEnumCaseRuleTestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RequiredEnumCaseRuleTestCase.swift; sourceTree = ""; }; BB00B4E71F5216070079869F /* MultipleClosuresWithTrailingClosureRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultipleClosuresWithTrailingClosureRule.swift; sourceTree = ""; }; + BCB68282216213130078E4C3 /* CompilerProtocolInitRuleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompilerProtocolInitRuleTests.swift; sourceTree = ""; }; BF48D2D61CBCCA5F0080BDAE /* TrailingWhitespaceConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TrailingWhitespaceConfiguration.swift; sourceTree = ""; }; C25EBBDD210787B200E27603 /* PrefixedTopLevelConstantRuleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrefixedTopLevelConstantRuleTests.swift; sourceTree = ""; }; C25EBBE021078D5B00E27603 /* GlobTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlobTests.swift; sourceTree = ""; }; @@ -1338,6 +1340,7 @@ F480DC801F2609AB00099465 /* XCTestCase+BundlePath.swift */, 3B30C4A01C3785B300E04027 /* YamlParserTests.swift */, 3B12C9C21C320A53000B423F /* YamlSwiftLintTests.swift */, + BCB68282216213130078E4C3 /* CompilerProtocolInitRuleTests.swift */, ); name = SwiftLintFrameworkTests; path = Tests/SwiftLintFrameworkTests; @@ -2050,6 +2053,7 @@ 62329C2B1F30B2310035737E /* DiscouragedDirectInitRuleTests.swift in Sources */, C25EBBE221078D5F00E27603 /* GlobTests.swift in Sources */, E86396C71BADAFE6002C9E88 /* ReporterTests.swift in Sources */, + BCB68283216213130078E4C3 /* CompilerProtocolInitRuleTests.swift in Sources */, D43B04661E071ED3004016AF /* ColonRuleTests.swift in Sources */, D4F5851920E99B5A0085C6D8 /* PrivateOutletRuleTests.swift in Sources */, 3B12C9C71C3361CB000B423F /* RuleTests.swift in Sources */, diff --git a/Tests/SwiftLintFrameworkTests/CompilerProtocolInitRuleTests.swift b/Tests/SwiftLintFrameworkTests/CompilerProtocolInitRuleTests.swift new file mode 100644 index 0000000000..c4a6b28b5b --- /dev/null +++ b/Tests/SwiftLintFrameworkTests/CompilerProtocolInitRuleTests.swift @@ -0,0 +1,30 @@ +@testable import SwiftLintFramework +import XCTest + +class CompilerProtocolInitRuleTests: XCTestCase { + + private let ruleID = CompilerProtocolInitRule.description.identifier + + func testDefaultConfiguration() { + verifyRule(CompilerProtocolInitRule.description) + } + + func testViolationMessageForExpressibleByIntegerLiteral() { + guard let config = makeConfig(nil, ruleID) else { + XCTFail("Failed to create configuration") + return + } + let allViolations = violations("let a = NSNumber(integerLiteral: 1)", config: config) + + let compilerProtocolInitViolation = allViolations.first { $0.ruleDescription.identifier == ruleID } + if let violation = compilerProtocolInitViolation { + XCTAssertEqual( + violation.reason, + "The initializers declared in compiler protocol ExpressibleByIntegerLiteral " + + "shouldn't be called directly." + ) + } else { + XCTFail("A compiler protocol init violation should have been triggered!") + } + } +} From 3189d171c7d4fcb41699dc62743b71544a9c5ed8 Mon Sep 17 00:00:00 2001 From: Timofey Solonin Date: Mon, 1 Oct 2018 13:37:18 +0300 Subject: [PATCH 3/6] #2422 - Fix CI --- Tests/LinuxMain.swift | 3 ++- .../CompilerProtocolInitRuleTests.swift | 9 ++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift index d67f614807..b086fa7bb1 100644 --- a/Tests/LinuxMain.swift +++ b/Tests/LinuxMain.swift @@ -116,7 +116,8 @@ extension CommandTests { extension CompilerProtocolInitRuleTests { static var allTests: [(String, (CompilerProtocolInitRuleTests) -> () throws -> Void)] = [ - ("testWithDefaultConfiguration", testWithDefaultConfiguration) + ("testWithDefaultConfiguration", testWithDefaultConfiguration), + ("testViolationMessageForExpressibleByIntegerLiteral", testViolationMessageForExpressibleByIntegerLiteral) ] } diff --git a/Tests/SwiftLintFrameworkTests/CompilerProtocolInitRuleTests.swift b/Tests/SwiftLintFrameworkTests/CompilerProtocolInitRuleTests.swift index c4a6b28b5b..8c0c84fd14 100644 --- a/Tests/SwiftLintFrameworkTests/CompilerProtocolInitRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/CompilerProtocolInitRuleTests.swift @@ -2,20 +2,19 @@ import XCTest class CompilerProtocolInitRuleTests: XCTestCase { - private let ruleID = CompilerProtocolInitRule.description.identifier - - func testDefaultConfiguration() { + + func testWithDefaultConfiguration() { verifyRule(CompilerProtocolInitRule.description) } - + func testViolationMessageForExpressibleByIntegerLiteral() { guard let config = makeConfig(nil, ruleID) else { XCTFail("Failed to create configuration") return } let allViolations = violations("let a = NSNumber(integerLiteral: 1)", config: config) - + let compilerProtocolInitViolation = allViolations.first { $0.ruleDescription.identifier == ruleID } if let violation = compilerProtocolInitViolation { XCTAssertEqual( From 22be71e6773b45d14c42d4c1b736f31dd9c6cb3a Mon Sep 17 00:00:00 2001 From: Timofey Solonin Date: Mon, 1 Oct 2018 18:28:52 +0300 Subject: [PATCH 4/6] #2422 - Replace ruleDescription change with a StyleViolation reason field in CompilerProtocolInitRule --- .../Rules/Lint/CompilerProtocolInitRule.swift | 44 ++++++++++--------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/Source/SwiftLintFramework/Rules/Lint/CompilerProtocolInitRule.swift b/Source/SwiftLintFramework/Rules/Lint/CompilerProtocolInitRule.swift index d4e5a06fa6..4996a4cfdd 100644 --- a/Source/SwiftLintFramework/Rules/Lint/CompilerProtocolInitRule.swift +++ b/Source/SwiftLintFramework/Rules/Lint/CompilerProtocolInitRule.swift @@ -6,24 +6,27 @@ public struct CompilerProtocolInitRule: ASTRule, ConfigurationProviderRule { public init() {} - public static let description = specificDescription(for: "such as `ExpressibleByArrayLiteral`", isPlural: true) - - private static func specificDescription(for violation: String, isPlural: Bool) -> RuleDescription { - return RuleDescription( - identifier: "compiler_protocol_init", - name: "Compiler Protocol Init", - description: "The initializers declared in compiler protocol\(isPlural ? "s" : "") \(violation) " + - "shouldn't be called directly.", - kind: .lint, - nonTriggeringExamples: [ - "let set: Set = [1, 2]\n", - "let set = Set(array)\n" - ], - triggeringExamples: [ - "let set = ↓Set(arrayLiteral: 1, 2)\n", - "let set = ↓Set.init(arrayLiteral: 1, 2)\n" - ] - ) + public static let description = RuleDescription( + identifier: "compiler_protocol_init", + name: "Compiler Protocol Init", + description: CompilerProtocolInitRule.violationReason( + protocolName: "such as `ExpressibleByArrayLiteral`", + isPlural: true + ), + kind: .lint, + nonTriggeringExamples: [ + "let set: Set = [1, 2]\n", + "let set = Set(array)\n" + ], + triggeringExamples: [ + "let set = ↓Set(arrayLiteral: 1, 2)\n", + "let set = ↓Set.init(arrayLiteral: 1, 2)\n" + ] + ) + + private static func violationReason(protocolName: String, isPlural: Bool) -> String { + return "The initializers declared in compiler protocol\(isPlural ? "s" : "") \(protocolName) " + + "shouldn't be called directly." } public func validate(file: File, kind: SwiftExpressionKind, @@ -31,9 +34,10 @@ public struct CompilerProtocolInitRule: ASTRule, ConfigurationProviderRule { return violationRanges(in: file, kind: kind, dictionary: dictionary).map { let (violation, range) = $0 return StyleViolation( - ruleDescription: type(of: self).specificDescription(for: violation.protocolName, isPlural: false), + ruleDescription: type(of: self).description, severity: configuration.severity, - location: Location(file: file, characterOffset: range.location) + location: Location(file: file, characterOffset: range.location), + reason: type(of: self).violationReason(protocolName: violation.protocolName, isPlural: false) ) } } From 78ebad7fd45437e7893ea1c5c5f1fef4c94211f1 Mon Sep 17 00:00:00 2001 From: Timofey Solonin Date: Mon, 1 Oct 2018 19:39:28 +0300 Subject: [PATCH 5/6] #2422 - Add changelog entry --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 358b0a91b7..035b6e66ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -75,6 +75,11 @@ [Marcelo Fabri](https://github.com/marcelofabri) [#2395](https://github.com/realm/SwiftLint/issues/2395) +* Specify what type of compiler protocol initializer violated the + `compiler_protocol_init` rule. + [Timofey Solonin](https://github.com/biboran) + [#2422](https://github.com/realm/SwiftLint/issues/2422) + #### Bug Fixes * Fix `comma` rule false positives on object literals (for example, images). From 1b71ae72c63bfee0b9065f2258de493317fc68ac Mon Sep 17 00:00:00 2001 From: Timofey Solonin Date: Mon, 1 Oct 2018 19:41:50 +0300 Subject: [PATCH 6/6] #2422 - Fix changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 035b6e66ce..9269ec29af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -76,7 +76,7 @@ [#2395](https://github.com/realm/SwiftLint/issues/2395) * Specify what type of compiler protocol initializer violated the - `compiler_protocol_init` rule. + `compiler_protocol_init` rule. [Timofey Solonin](https://github.com/biboran) [#2422](https://github.com/realm/SwiftLint/issues/2422)