mirror of
https://github.com/realm/SwiftLint.git
synced 2026-06-06 20:18:40 +00:00
Add options to generic_type_name and type_name rules
This commit is contained in:
+3
-2
@@ -13,8 +13,9 @@
|
||||
|
||||
##### Enhancements
|
||||
|
||||
* Add opt-in options to `identifier_name` rule to exclude non-alphanumeric
|
||||
characters and to allow names that start with uppercase.
|
||||
* Add opt-in configurations to `generic_type_name`, `identifier_name` and
|
||||
`type_name` rules to allow excluding non-alphanumeric characters and names
|
||||
that start with uppercase.
|
||||
[Javier Hernández](https://github.com/jaherhi)
|
||||
[#541](https://github.com/realm/SwiftLint/issues/541)
|
||||
|
||||
|
||||
@@ -166,14 +166,16 @@ public struct GenericTypeNameRule: ASTRule, ConfigurationProviderRule {
|
||||
return []
|
||||
}
|
||||
|
||||
if !CharacterSet.alphanumerics.isSuperset(ofCharactersIn: name) {
|
||||
let containsAllowedSymbol = configuration.allowedSymbols.first(where: { name.contains($0) }) != nil
|
||||
if !containsAllowedSymbol && !CharacterSet.alphanumerics.isSuperset(ofCharactersIn: name) {
|
||||
return [
|
||||
StyleViolation(ruleDescription: type(of: self).description,
|
||||
severity: .error,
|
||||
location: Location(file: file, byteOffset: offset),
|
||||
reason: "Generic type name should only contain alphanumeric characters: '\(name)'")
|
||||
]
|
||||
} else if !name.substring(to: name.index(after: name.startIndex)).isUppercase() {
|
||||
} else if configuration.validatesStartWithLowercase &&
|
||||
!name.substring(to: name.index(after: name.startIndex)).isUppercase() {
|
||||
return [
|
||||
StyleViolation(ruleDescription: type(of: self).description,
|
||||
severity: .error,
|
||||
|
||||
@@ -74,12 +74,14 @@ public struct TypeNameRule: ASTRule, ConfigurationProviderRule {
|
||||
}
|
||||
|
||||
let name = name.nameStrippingLeadingUnderscoreIfPrivate(dictionary)
|
||||
if !CharacterSet.alphanumerics.isSuperset(ofCharactersIn: name) {
|
||||
let containsAllowedSymbol = configuration.allowedSymbols.first(where: { name.contains($0) }) != nil
|
||||
if !containsAllowedSymbol && !CharacterSet.alphanumerics.isSuperset(ofCharactersIn: name) {
|
||||
return [StyleViolation(ruleDescription: type(of: self).description,
|
||||
severity: .error,
|
||||
location: Location(file: file, byteOffset: offset),
|
||||
reason: "Type name should only contain alphanumeric characters: '\(name)'")]
|
||||
} else if !name.substring(to: name.index(after: name.startIndex)).isUppercase() {
|
||||
} else if configuration.validatesStartWithLowercase &&
|
||||
!name.substring(to: name.index(after: name.startIndex)).isUppercase() {
|
||||
return [StyleViolation(ruleDescription: type(of: self).description,
|
||||
severity: .error,
|
||||
location: Location(file: file, byteOffset: offset),
|
||||
|
||||
@@ -33,6 +33,8 @@
|
||||
3B12C9C51C322032000B423F /* MasterRuleList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B12C9C41C322032000B423F /* MasterRuleList.swift */; };
|
||||
3B12C9C71C3361CB000B423F /* RuleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B12C9C61C3361CB000B423F /* RuleTests.swift */; };
|
||||
3B1DF0121C5148140011BCED /* CustomRules.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B1DF0111C5148140011BCED /* CustomRules.swift */; };
|
||||
3B20CD0A1EB699380069EF2E /* GenericTypeNameRuleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B20CD091EB699380069EF2E /* GenericTypeNameRuleTests.swift */; };
|
||||
3B20CD0C1EB699C20069EF2E /* TypeNameRuleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B20CD0B1EB699C20069EF2E /* TypeNameRuleTests.swift */; };
|
||||
3B30C4A11C3785B300E04027 /* YamlParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B30C4A01C3785B300E04027 /* YamlParserTests.swift */; };
|
||||
3B3A9A331EA3DFD90075B121 /* IdentifierNameRuleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B3A9A321EA3DFD90075B121 /* IdentifierNameRuleTests.swift */; };
|
||||
3B5B9FE11C444DA20009AD27 /* Array+SwiftLint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B5B9FE01C444DA20009AD27 /* Array+SwiftLint.swift */; };
|
||||
@@ -301,6 +303,8 @@
|
||||
3B12C9C41C322032000B423F /* MasterRuleList.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MasterRuleList.swift; sourceTree = "<group>"; };
|
||||
3B12C9C61C3361CB000B423F /* RuleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RuleTests.swift; sourceTree = "<group>"; };
|
||||
3B1DF0111C5148140011BCED /* CustomRules.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomRules.swift; sourceTree = "<group>"; };
|
||||
3B20CD091EB699380069EF2E /* GenericTypeNameRuleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GenericTypeNameRuleTests.swift; sourceTree = "<group>"; };
|
||||
3B20CD0B1EB699C20069EF2E /* TypeNameRuleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypeNameRuleTests.swift; sourceTree = "<group>"; };
|
||||
3B30C4A01C3785B300E04027 /* YamlParserTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = YamlParserTests.swift; sourceTree = "<group>"; };
|
||||
3B3A9A321EA3DFD90075B121 /* IdentifierNameRuleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IdentifierNameRuleTests.swift; sourceTree = "<group>"; };
|
||||
3B5B9FE01C444DA20009AD27 /* Array+SwiftLint.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Array+SwiftLint.swift"; sourceTree = "<group>"; };
|
||||
@@ -759,6 +763,7 @@
|
||||
02FD8AEE1BFC18D60014BFFB /* ExtendedNSStringTests.swift */,
|
||||
D4998DE81DF194F20006E05D /* FileHeaderRuleTests.swift */,
|
||||
D4348EE91C46122C007707FB /* FunctionBodyLengthRuleTests.swift */,
|
||||
3B20CD091EB699380069EF2E /* GenericTypeNameRuleTests.swift */,
|
||||
3B3A9A321EA3DFD90075B121 /* IdentifierNameRuleTests.swift */,
|
||||
47ACC8991E7DCCAD0088EEB2 /* ImplicitlyUnwrappedOptionalConfigurationTests.swift */,
|
||||
47ACC89B1E7DCFA00088EEB2 /* ImplicitlyUnwrappedOptionalRuleTests.swift */,
|
||||
@@ -775,6 +780,7 @@
|
||||
E81224991B04F85B001783D2 /* TestHelpers.swift */,
|
||||
D4DB92241E628898005DE9C1 /* TodoRuleTests.swift */,
|
||||
C9802F2E1E0C8AEE008AB27F /* TrailingCommaRuleTests.swift */,
|
||||
3B20CD0B1EB699C20069EF2E /* TypeNameRuleTests.swift */,
|
||||
D4470D5A1EB76F44008A1B2E /* UnusedOptionalBindingRuleTests.swift */,
|
||||
006204DD1E1E4E0A00FFFBE1 /* VerticalWhitespaceRuleTests.swift */,
|
||||
3B12C9C21C320A53000B423F /* Yaml+SwiftLintTests.swift */,
|
||||
@@ -1368,12 +1374,14 @@
|
||||
6C7045441C6ADA450003F15A /* SourceKitCrashTests.swift in Sources */,
|
||||
3BB47D871C51DE6E00AE6A10 /* CustomRulesTests.swift in Sources */,
|
||||
E812249A1B04F85B001783D2 /* TestHelpers.swift in Sources */,
|
||||
3B20CD0C1EB699C20069EF2E /* TypeNameRuleTests.swift in Sources */,
|
||||
3B3A9A331EA3DFD90075B121 /* IdentifierNameRuleTests.swift in Sources */,
|
||||
E86396C71BADAFE6002C9E88 /* ReporterTests.swift in Sources */,
|
||||
D43B04661E071ED3004016AF /* ColonRuleTests.swift in Sources */,
|
||||
3B12C9C71C3361CB000B423F /* RuleTests.swift in Sources */,
|
||||
67EB4DFC1E4CD7F5004E9ACD /* CyclomaticComplexityRuleTests.swift in Sources */,
|
||||
3B30C4A11C3785B300E04027 /* YamlParserTests.swift in Sources */,
|
||||
3B20CD0A1EB699380069EF2E /* GenericTypeNameRuleTests.swift in Sources */,
|
||||
D4998DE71DF191380006E05D /* AttributesRuleTests.swift in Sources */,
|
||||
E88198631BEA9A5400333A11 /* RulesTests.swift in Sources */,
|
||||
47ACC89A1E7DCCAD0088EEB2 /* ImplicitlyUnwrappedOptionalConfigurationTests.swift in Sources */,
|
||||
|
||||
@@ -19,6 +19,7 @@ XCTMain([
|
||||
testCase(ExtendedNSStringTests.allTests),
|
||||
testCase(FileHeaderRuleTests.allTests),
|
||||
testCase(FunctionBodyLengthRuleTests.allTests),
|
||||
testCase(GenericTypeNameRuleTests.allTests),
|
||||
testCase(IdentifierNameRuleTests.allTests),
|
||||
testCase(ImplicitlyUnwrappedOptionalConfigurationTests.allTests),
|
||||
testCase(ImplicitlyUnwrappedOptionalRuleTests.allTests),
|
||||
@@ -33,6 +34,7 @@ XCTMain([
|
||||
testCase(RuleTests.allTests),
|
||||
testCase(SourceKitCrashTests.allTests),
|
||||
testCase(TrailingCommaRuleTests.allTests),
|
||||
testCase(TypeNameRuleTests.allTests),
|
||||
testCase(TodoRuleTests.allTests),
|
||||
testCase(UnusedOptionalBindingRuleTests.allTests),
|
||||
testCase(VerticalWhitespaceRuleTests.allTests),
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
//
|
||||
// GenericTypeNameRuleTests.swift
|
||||
// SwiftLint
|
||||
//
|
||||
// Created by Javier Hernandez on 30/04/17.
|
||||
// Copyright © 2017 Realm. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftLintFramework
|
||||
import XCTest
|
||||
|
||||
class GenericTypeNameRuleTests: XCTestCase {
|
||||
|
||||
func testGenericTypeName() {
|
||||
verifyRule(GenericTypeNameRule.description)
|
||||
}
|
||||
|
||||
func testGenericTypeNameWithAllowedSymbols() {
|
||||
let baseDescription = GenericTypeNameRule.description
|
||||
let nonTriggeringExamples = baseDescription.nonTriggeringExamples + [
|
||||
"func foo<T$>() {}\n",
|
||||
"func foo<T$, U%>(param: U%) -> T$ {}\n",
|
||||
"typealias StringDictionary<T$> = Dictionary<String, T$>\n",
|
||||
"class Foo<T$%> {}\n",
|
||||
"struct Foo<T$%> {}\n",
|
||||
"enum Foo<T$%> {}\n"
|
||||
]
|
||||
|
||||
let description = RuleDescription(identifier: baseDescription.identifier,
|
||||
name: baseDescription.name,
|
||||
description: baseDescription.description,
|
||||
nonTriggeringExamples: nonTriggeringExamples,
|
||||
triggeringExamples: baseDescription.triggeringExamples,
|
||||
corrections: baseDescription.corrections,
|
||||
deprecatedAliases: baseDescription.deprecatedAliases)
|
||||
|
||||
verifyRule(description, ruleConfiguration: ["allowed_symbols": ["$", "%"]])
|
||||
}
|
||||
|
||||
func testGenericTypeNameWithIgnoreStartWithLowercase() {
|
||||
let baseDescription = GenericTypeNameRule.description
|
||||
let triggeringExamplesToRemove = [
|
||||
"func foo<↓type>() {}\n",
|
||||
"class Foo<↓type> {}\n",
|
||||
"struct Foo<↓type> {}\n",
|
||||
"enum Foo<↓type> {}\n"
|
||||
]
|
||||
let nonTriggeringExamples = baseDescription.nonTriggeringExamples +
|
||||
triggeringExamplesToRemove.map { $0.replacingOccurrences(of: "↓", with: "") }
|
||||
let triggeringExamples = baseDescription.triggeringExamples
|
||||
.filter { !triggeringExamplesToRemove.contains($0) }
|
||||
|
||||
let description = RuleDescription(identifier: baseDescription.identifier,
|
||||
name: baseDescription.name,
|
||||
description: baseDescription.description,
|
||||
nonTriggeringExamples: nonTriggeringExamples,
|
||||
triggeringExamples: triggeringExamples,
|
||||
corrections: baseDescription.corrections,
|
||||
deprecatedAliases: baseDescription.deprecatedAliases)
|
||||
|
||||
verifyRule(description, ruleConfiguration: ["validates_start_lowercase": false])
|
||||
}
|
||||
}
|
||||
|
||||
extension GenericTypeNameRuleTests {
|
||||
static var allTests: [(String, (GenericTypeNameRuleTests) -> () throws -> Void)] {
|
||||
return [
|
||||
("testGenericTypeName", testGenericTypeName),
|
||||
("testGenericTypeNameWithAllowedSymbols", testGenericTypeNameWithAllowedSymbols),
|
||||
("testGenericTypeNameWithIgnoreStartWithLowercase", testGenericTypeNameWithIgnoreStartWithLowercase)
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -36,12 +36,14 @@ class IdentifierNameRuleTests: XCTestCase {
|
||||
|
||||
func testIdentifierNameWithIgnoreStartWithLowercase() {
|
||||
let baseDescription = IdentifierNameRule.description
|
||||
let nonTriggeringExamples = baseDescription.nonTriggeringExamples + [
|
||||
"let MyLet = 0",
|
||||
"enum Foo { case MyEnum }"
|
||||
let triggeringExamplesToRemove = [
|
||||
"↓let MyLet = 0",
|
||||
"enum Foo { case ↓MyEnum }"
|
||||
]
|
||||
let nonTriggeringExamples = baseDescription.nonTriggeringExamples +
|
||||
triggeringExamplesToRemove.map { $0.replacingOccurrences(of: "↓", with: "") }
|
||||
let triggeringExamples = baseDescription.triggeringExamples
|
||||
.filter { !$0.contains("MyLet") && !$0.contains("MyEnum") }
|
||||
.filter { !triggeringExamplesToRemove.contains($0) }
|
||||
|
||||
let description = RuleDescription(identifier: baseDescription.identifier,
|
||||
name: baseDescription.name,
|
||||
|
||||
@@ -121,10 +121,6 @@ class RulesTests: XCTestCase {
|
||||
verifyRule(FunctionParameterCountRule.description)
|
||||
}
|
||||
|
||||
func testGenericTypeName() {
|
||||
verifyRule(GenericTypeNameRule.description)
|
||||
}
|
||||
|
||||
func testImplicitGetter() {
|
||||
verifyRule(ImplicitGetterRule.description)
|
||||
}
|
||||
@@ -314,10 +310,6 @@ class RulesTests: XCTestCase {
|
||||
verifyRule(TypeBodyLengthRule.description)
|
||||
}
|
||||
|
||||
func testTypeName() {
|
||||
verifyRule(TypeNameRule.description)
|
||||
}
|
||||
|
||||
func testUnusedClosureParameter() {
|
||||
verifyRule(UnusedClosureParameterRule.description)
|
||||
}
|
||||
@@ -377,7 +369,6 @@ extension RulesTests {
|
||||
("testForWhere", testForWhere),
|
||||
("testFunctionBodyLength", testFunctionBodyLength),
|
||||
("testFunctionParameterCount", testFunctionParameterCount),
|
||||
("testGenericTypeName", testGenericTypeName),
|
||||
("testImplicitGetter", testImplicitGetter),
|
||||
("testImplicitlyUnwrappedOptional", testImplicitlyUnwrappedOptional),
|
||||
("testImplicitReturn", testImplicitReturn),
|
||||
@@ -414,7 +405,6 @@ extension RulesTests {
|
||||
("testTrailingSemicolon", testTrailingSemicolon),
|
||||
("testTrailingWhitespace", testTrailingWhitespace),
|
||||
("testTypeBodyLength", testTypeBodyLength),
|
||||
("testTypeName", testTypeName),
|
||||
("testUnusedClosureParameter", testUnusedClosureParameter),
|
||||
("testUnusedEnumerated", testUnusedEnumerated),
|
||||
("testValidIBInspectable", testValidIBInspectable),
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
//
|
||||
// TypeNameRuleTests.swift
|
||||
// SwiftLint
|
||||
//
|
||||
// Created by Javier Hernandez on 30/04/17.
|
||||
// Copyright © 2017 Realm. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftLintFramework
|
||||
import XCTest
|
||||
|
||||
class TypeNameRuleTests: XCTestCase {
|
||||
|
||||
func testTypeName() {
|
||||
verifyRule(TypeNameRule.description)
|
||||
}
|
||||
|
||||
func testTypeNameWithAllowedSymbols() {
|
||||
let baseDescription = TypeNameRule.description
|
||||
let nonTriggeringExamples = baseDescription.nonTriggeringExamples + [
|
||||
"class MyType$ {}",
|
||||
"struct MyType$ {}",
|
||||
"enum MyType$ {}",
|
||||
"typealias Foo$ = Void",
|
||||
"protocol Foo {\n associatedtype Bar$\n }"
|
||||
]
|
||||
|
||||
let description = RuleDescription(identifier: baseDescription.identifier,
|
||||
name: baseDescription.name,
|
||||
description: baseDescription.description,
|
||||
nonTriggeringExamples: nonTriggeringExamples,
|
||||
triggeringExamples: baseDescription.triggeringExamples,
|
||||
corrections: baseDescription.corrections,
|
||||
deprecatedAliases: baseDescription.deprecatedAliases)
|
||||
|
||||
verifyRule(description, ruleConfiguration: ["allowed_symbols": ["$"]])
|
||||
}
|
||||
|
||||
func testTypeNameWithIgnoreStartWithLowercase() {
|
||||
let baseDescription = TypeNameRule.description
|
||||
let triggeringExamplesToRemove = [
|
||||
"private typealias ↓foo = Void",
|
||||
"↓class myType {}",
|
||||
"↓struct myType {}",
|
||||
"↓enum myType {}"
|
||||
]
|
||||
let nonTriggeringExamples = baseDescription.nonTriggeringExamples +
|
||||
triggeringExamplesToRemove.map { $0.replacingOccurrences(of: "↓", with: "") }
|
||||
let triggeringExamples = baseDescription.triggeringExamples
|
||||
.filter { !triggeringExamplesToRemove.contains($0) }
|
||||
|
||||
let description = RuleDescription(identifier: baseDescription.identifier,
|
||||
name: baseDescription.name,
|
||||
description: baseDescription.description,
|
||||
nonTriggeringExamples: nonTriggeringExamples,
|
||||
triggeringExamples: triggeringExamples,
|
||||
corrections: baseDescription.corrections,
|
||||
deprecatedAliases: baseDescription.deprecatedAliases)
|
||||
|
||||
verifyRule(description, ruleConfiguration: ["validates_start_lowercase": false])
|
||||
}
|
||||
}
|
||||
|
||||
extension TypeNameRuleTests {
|
||||
static var allTests: [(String, (TypeNameRuleTests) -> () throws -> Void)] {
|
||||
return [
|
||||
("testTypeName", testTypeName),
|
||||
("testTypeNameWithAllowedSymbols", testTypeNameWithAllowedSymbols),
|
||||
("testTypeNameWithIgnoreStartWithLowercase", testTypeNameWithIgnoreStartWithLowercase)
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user