diff --git a/CHANGELOG.md b/CHANGELOG.md index 48981da19..01be0d416 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,11 @@ [Scott Berrevoets](https://github.com/sberrevoets) [#900](https://github.com/realm/SwiftLint/issues/900) +* `type_name` rule forces enum values to be UpperCamelCase again + when used with Swift 2.3. + [Marcelo Fabri](https://github.com/marcelofabri) + [#1090](https://github.com/realm/SwiftLint/issues/1090) + * Make `weak_delegate` rule ignore computed properties. [Rafael Machado](https://github.com/rakaramos/) [#1089](https://github.com/realm/SwiftLint/issues/1089) diff --git a/Source/SwiftLintFramework/Rules/TypeNameRule.swift b/Source/SwiftLintFramework/Rules/TypeNameRule.swift index ac8c0f535..370df59d0 100644 --- a/Source/SwiftLintFramework/Rules/TypeNameRule.swift +++ b/Source/SwiftLintFramework/Rules/TypeNameRule.swift @@ -18,59 +18,25 @@ public struct TypeNameRule: ASTRule, ConfigurationProviderRule { public init() {} - private static func nonTriggeringExamples() -> [String] { - let types = ["class", "struct", "enum"] - let typeExamples: [String] = types.flatMap { (type: String) -> [String] in - [ - "\(type) MyType {}", - "private \(type) _MyType {}", - "enum MyType {\ncase value\n}", - "\(type) \(repeatElement("A", count: 40).joined()) {}" - ] - } - let typeAliasAndAssociatedTypeExamples = [ - "typealias Foo = Void", - "private typealias Foo = Void", - "protocol Foo {\n associatedtype Bar\n }", - "protocol Foo {\n associatedtype Bar: Equatable\n }" - ] - - return typeExamples + typeAliasAndAssociatedTypeExamples - } - - private static func triggeringExamples() -> [String] { - let types = ["class", "struct", "enum"] - let typeExamples: [String] = types.flatMap { (type: String) -> [String] in - [ - "↓\(type) myType {}", - "↓\(type) _MyType {}", - "private ↓\(type) MyType_ {}", - "↓\(type) My {}", - "↓\(type) \(repeatElement("A", count: 41).joined()) {}" - ] - } - let typeAliasAndAssociatedTypeExamples: [String] = [ - "typealias ↓X = Void", - "private typealias ↓Foo_Bar = Void", - "private typealias ↓foo = Void", - "typealias ↓\(repeatElement("A", count: 41).joined()) = Void", - "protocol Foo {\n associatedtype ↓X\n }", - "protocol Foo {\n associatedtype ↓Foo_Bar: Equatable\n }", - "protocol Foo {\n associatedtype ↓\(repeatElement("A", count: 41).joined())\n }" - ] - - return typeExamples + typeAliasAndAssociatedTypeExamples - } - public static let description = RuleDescription( identifier: "type_name", name: "Type Name", description: "Type name should only contain alphanumeric characters, start with an " + "uppercase character and span between 3 and 40 characters in length.", - nonTriggeringExamples: TypeNameRule.nonTriggeringExamples(), - triggeringExamples: TypeNameRule.triggeringExamples() + nonTriggeringExamples: TypeNameRuleExamples.swift3NonTriggeringExamples, + triggeringExamples: TypeNameRuleExamples.swift3TriggeringExamples ) + private let typeKinds: [SwiftDeclarationKind] = { + let common = SwiftDeclarationKind.typeKinds() + switch SwiftVersion.current { + case .two: + return common + [.enumelement] + case .three: + return common + } + }() + public func validateFile(_ file: File) -> [StyleViolation] { return validateTypeAliasesAndAssociatedTypes(file) + validateFile(file, dictionary: file.structure.dictionary) @@ -80,7 +46,7 @@ public struct TypeNameRule: ASTRule, ConfigurationProviderRule { kind: SwiftDeclarationKind, dictionary: [String: SourceKitRepresentable]) -> [StyleViolation] { - guard SwiftDeclarationKind.typeKinds().contains(kind), + guard typeKinds.contains(kind), let name = dictionary["key.name"] as? String, let offset = (dictionary["key.offset"] as? Int64).flatMap({ Int($0) }) else { return [] diff --git a/Source/SwiftLintFramework/Rules/TypeNameRuleExamples.swift b/Source/SwiftLintFramework/Rules/TypeNameRuleExamples.swift new file mode 100644 index 000000000..dd41a7229 --- /dev/null +++ b/Source/SwiftLintFramework/Rules/TypeNameRuleExamples.swift @@ -0,0 +1,63 @@ +// +// TypeNameRuleExamples.swift +// SwiftLint +// +// Created by Marcelo Fabri on 30/12/16. +// Copyright © 2016 Realm. All rights reserved. +// + +import Foundation + +internal struct TypeNameRuleExamples { + + static let swift2NonTriggeringExamples = commonNonTriggeringExamples + ["enum MyType {\ncase Value\n}"] + + static let swift3NonTriggeringExamples = commonNonTriggeringExamples + ["enum MyType {\ncase value\n}"] + + static let swift2TriggeringExamples = commonTriggeringExamples + ["enum MyType {\ncase ↓value\n}"] + + static let swift3TriggeringExamples = commonTriggeringExamples + + private static let types = ["class", "struct", "enum"] + + private static let commonNonTriggeringExamples: [String] = { + let typeExamples: [String] = types.flatMap { (type: String) -> [String] in + [ + "\(type) MyType {}", + "private \(type) _MyType {}", + "\(type) \(repeatElement("A", count: 40).joined()) {}" + ] + } + let typeAliasAndAssociatedTypeExamples = [ + "typealias Foo = Void", + "private typealias Foo = Void", + "protocol Foo {\n associatedtype Bar\n }", + "protocol Foo {\n associatedtype Bar: Equatable\n }" + ] + + return typeExamples + typeAliasAndAssociatedTypeExamples + }() + + private static let commonTriggeringExamples: [String] = { + let typeExamples: [String] = types.flatMap { (type: String) -> [String] in + [ + "↓\(type) myType {}", + "↓\(type) _MyType {}", + "private ↓\(type) MyType_ {}", + "↓\(type) My {}", + "↓\(type) \(repeatElement("A", count: 41).joined()) {}" + ] + } + let typeAliasAndAssociatedTypeExamples: [String] = [ + "typealias ↓X = Void", + "private typealias ↓Foo_Bar = Void", + "private typealias ↓foo = Void", + "typealias ↓\(repeatElement("A", count: 41).joined()) = Void", + "protocol Foo {\n associatedtype ↓X\n }", + "protocol Foo {\n associatedtype ↓Foo_Bar: Equatable\n }", + "protocol Foo {\n associatedtype ↓\(repeatElement("A", count: 41).joined())\n }" + ] + + return typeExamples + typeAliasAndAssociatedTypeExamples + }() +} diff --git a/SwiftLint.xcodeproj/project.pbxproj b/SwiftLint.xcodeproj/project.pbxproj index 141fa53c0..4ab4d43da 100644 --- a/SwiftLint.xcodeproj/project.pbxproj +++ b/SwiftLint.xcodeproj/project.pbxproj @@ -87,6 +87,7 @@ D286EC021E02DF6F0003CF72 /* SortedImportsRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D286EC001E02DA190003CF72 /* SortedImportsRule.swift */; }; D40AD08A1E032F9700F48C30 /* UnusedClosureParameterRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D40AD0891E032F9700F48C30 /* UnusedClosureParameterRule.swift */; }; D40F83881DE9179200524C62 /* TrailingCommaConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D40F83871DE9179200524C62 /* TrailingCommaConfiguration.swift */; }; + D4130D991E16CC1300242361 /* TypeNameRuleExamples.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4130D981E16CC1300242361 /* TypeNameRuleExamples.swift */; }; D41E7E0B1DF9DABB0065259A /* RedundantStringEnumValueRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D41E7E0A1DF9DABB0065259A /* RedundantStringEnumValueRule.swift */; }; D42D2B381E09CC0D00CD7A2E /* FirstWhereRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D42D2B371E09CC0D00CD7A2E /* FirstWhereRule.swift */; }; D4348EEA1C46122C007707FB /* FunctionBodyLengthRuleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4348EE91C46122C007707FB /* FunctionBodyLengthRuleTests.swift */; }; @@ -335,6 +336,7 @@ D286EC001E02DA190003CF72 /* SortedImportsRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SortedImportsRule.swift; sourceTree = ""; }; D40AD0891E032F9700F48C30 /* UnusedClosureParameterRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnusedClosureParameterRule.swift; sourceTree = ""; }; D40F83871DE9179200524C62 /* TrailingCommaConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TrailingCommaConfiguration.swift; sourceTree = ""; }; + D4130D981E16CC1300242361 /* TypeNameRuleExamples.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypeNameRuleExamples.swift; sourceTree = ""; }; D41E7E0A1DF9DABB0065259A /* RedundantStringEnumValueRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RedundantStringEnumValueRule.swift; sourceTree = ""; }; D42D2B371E09CC0D00CD7A2E /* FirstWhereRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FirstWhereRule.swift; sourceTree = ""; }; D4348EE91C46122C007707FB /* FunctionBodyLengthRuleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FunctionBodyLengthRuleTests.swift; sourceTree = ""; }; @@ -797,6 +799,7 @@ E88DEA851B0991BF00A66CB0 /* TrailingWhitespaceRule.swift */, E88DEA8D1B0999CD00A66CB0 /* TypeBodyLengthRule.swift */, E88DEA911B099B1F00A66CB0 /* TypeNameRule.swift */, + D4130D981E16CC1300242361 /* TypeNameRuleExamples.swift */, D40AD0891E032F9700F48C30 /* UnusedClosureParameterRule.swift */, D43B04631E0620AB004016AF /* UnusedEnumeratedRule.swift */, E81CDE701C00FEAA00B430F6 /* ValidDocsRule.swift */, @@ -1136,6 +1139,7 @@ 1EC163521D5992D900DD2928 /* VerticalWhitespaceRule.swift in Sources */, 57ED827B1CF656E3002B3513 /* JUnitReporter.swift in Sources */, D43B04691E072291004016AF /* ColonConfiguration.swift in Sources */, + D4130D991E16CC1300242361 /* TypeNameRuleExamples.swift in Sources */, 24E17F721B14BB3F008195BE /* File+Cache.swift in Sources */, 009E09281DFEE4C200B588A7 /* ProhibitedSuperRule.swift in Sources */, E80E018F1B92C1350078EB70 /* Region.swift in Sources */, diff --git a/SwiftLint.xcodeproj/xcshareddata/xcschemes/swiftlint with Swift 2.3.xcscheme b/SwiftLint.xcodeproj/xcshareddata/xcschemes/swiftlint with Swift 2.3.xcscheme index 2dadcaa6d..fa8156d38 100644 --- a/SwiftLint.xcodeproj/xcshareddata/xcschemes/swiftlint with Swift 2.3.xcscheme +++ b/SwiftLint.xcodeproj/xcshareddata/xcschemes/swiftlint with Swift 2.3.xcscheme @@ -48,6 +48,9 @@ + + diff --git a/Tests/SwiftLintFrameworkTests/Swift2RulesTests.swift b/Tests/SwiftLintFrameworkTests/Swift2RulesTests.swift index c4f8ee364..e5e5eb939 100644 --- a/Tests/SwiftLintFrameworkTests/Swift2RulesTests.swift +++ b/Tests/SwiftLintFrameworkTests/Swift2RulesTests.swift @@ -12,6 +12,18 @@ import XCTest #if !SWIFT_PACKAGE class Swift2RulesTests: XCTestCase { + func testAttributes() { + let description = RuleDescription( + identifier: AttributesRule.description.identifier, + name: AttributesRule.description.name, + description: AttributesRule.description.description, + nonTriggeringExamples: AttributesRuleExamples.swift2NonTriggeringExamples, + triggeringExamples: AttributesRuleExamples.swift2TriggeringExamples + ) + + verifyRule(description) + } + func testNumberSeparator() { let description = RuleDescription( identifier: NumberSeparatorRule.description.identifier, @@ -25,13 +37,13 @@ class Swift2RulesTests: XCTestCase { verifyRule(description) } - func testAttributes() { + func testTypeName() { let description = RuleDescription( - identifier: AttributesRule.description.identifier, - name: AttributesRule.description.name, - description: AttributesRule.description.description, - nonTriggeringExamples: AttributesRuleExamples.swift2NonTriggeringExamples, - triggeringExamples: AttributesRuleExamples.swift2TriggeringExamples + identifier: TypeNameRule.description.identifier, + name: TypeNameRule.description.name, + description: TypeNameRule.description.description, + nonTriggeringExamples: TypeNameRuleExamples.swift2NonTriggeringExamples, + triggeringExamples: TypeNameRuleExamples.swift2TriggeringExamples ) verifyRule(description)