diff --git a/CHANGELOG.md b/CHANGELOG.md index b17ceb3fe3..fba7d5101f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,8 +12,10 @@ ### Enhancements -* None. - +* Add `ignore_coding_keys` parameter to `nesting` rule. + [braker1nine](https://github.com/braker1nine) + [#5641](https://github.com/realm/SwiftLint/issues/5641) + ### Bug Fixes * None. diff --git a/Source/SwiftLintBuiltInRules/Rules/Metrics/NestingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Metrics/NestingRule.swift index 7eb1af8163..be6fd5d8ea 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Metrics/NestingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Metrics/NestingRule.swift @@ -64,7 +64,9 @@ private extension NestingRule { } override func visit(_ node: EnumDeclSyntax) -> SyntaxVisitorContinueKind { - validate(forFunction: false, triggeringToken: node.enumKeyword) + if !configuration.ignoreCodingKeys || !node.definesCodingKeys { + validate(forFunction: false, triggeringToken: node.enumKeyword) + } return .visitChildren } diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NestingConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NestingConfiguration.swift index 750b1793ef..2600c45ab6 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NestingConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NestingConfiguration.swift @@ -15,6 +15,8 @@ struct NestingConfiguration: RuleConfiguration { private(set) var alwaysAllowOneTypeInFunctions = false @ConfigurationElement(key: "ignore_typealiases_and_associatedtypes") private(set) var ignoreTypealiasesAndAssociatedtypes = false + @ConfigurationElement(key: "ignore_coding_keys") + private(set) var ignoreCodingKeys = false func severity(with config: Severity, for level: Int) -> ViolationSeverity? { if let error = config.error, level > error { diff --git a/Source/SwiftLintCore/Extensions/SwiftSyntax+SwiftLint.swift b/Source/SwiftLintCore/Extensions/SwiftSyntax+SwiftLint.swift index 521c6fcbc6..c6b9a716ba 100644 --- a/Source/SwiftLintCore/Extensions/SwiftSyntax+SwiftLint.swift +++ b/Source/SwiftLintCore/Extensions/SwiftSyntax+SwiftLint.swift @@ -184,6 +184,18 @@ public extension EnumDeclSyntax { return rawValueTypes.contains(identifier) } } + + /// True if this enum is a `CodingKey`. For that, it has to be named `CodingKeys` and must conform to the `CodingKey` protocol. + var definesCodingKeys: Bool { + guard let inheritedTypeCollection = inheritanceClause?.inheritedTypes, + name.text == "CodingKeys" else { + return false + } + + return inheritedTypeCollection.contains { element in + element.type.as(IdentifierTypeSyntax.self)?.name.text == "CodingKey" + } + } } public extension FunctionDeclSyntax { diff --git a/Tests/BuiltInRulesTests/NestingRuleTests.swift b/Tests/BuiltInRulesTests/NestingRuleTests.swift index b41082edb4..a6070795dd 100644 --- a/Tests/BuiltInRulesTests/NestingRuleTests.swift +++ b/Tests/BuiltInRulesTests/NestingRuleTests.swift @@ -555,4 +555,46 @@ final class NestingRuleTests: SwiftLintTestCase { verifyRule(description, ruleConfiguration: ["ignore_typealiases_and_associatedtypes": true]) } + + func testNestingWithoutCodingKeys() { + var nonTriggeringExamples = NestingRule.description.nonTriggeringExamples + nonTriggeringExamples.append(contentsOf: [ + .init(""" + struct Outer { + struct Inner { + enum CodingKeys: String, CodingKey { + case id + } + } + } + """ + ), + ]) + + var triggeringExamples = NestingRule.description.triggeringExamples + triggeringExamples.append(contentsOf: [ + .init(""" + struct Outer { + struct Inner { + ↓enum Example: String, CodingKey { + case id + } + } + } + """), + .init(""" + struct Outer { + enum CodingKeys: String, CodingKey { + case id + + ↓struct S {} + } + } + """) + ]) + + let description = NestingRule.description.with(nonTriggeringExamples: nonTriggeringExamples, triggeringExamples: triggeringExamples) + + verifyRule(description, ruleConfiguration: ["ignore_coding_keys": true ]) + } }