From a41834db4a2c49a0dd60bf253ad0b1ec4b9057d9 Mon Sep 17 00:00:00 2001 From: Chris Brakebill Date: Mon, 1 Jul 2024 19:24:45 -0400 Subject: [PATCH 1/3] Add an isCodingKey Bool getter to EnumDeclSyntax This only returns true when the name of the enum is CodingKeys and it conforms to CodingKey --- .../Extensions/SwiftSyntax+SwiftLint.swift | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Source/SwiftLintCore/Extensions/SwiftSyntax+SwiftLint.swift b/Source/SwiftLintCore/Extensions/SwiftSyntax+SwiftLint.swift index 677faf7c0b..78b67c5e22 100644 --- a/Source/SwiftLintCore/Extensions/SwiftSyntax+SwiftLint.swift +++ b/Source/SwiftLintCore/Extensions/SwiftSyntax+SwiftLint.swift @@ -184,6 +184,25 @@ public extension EnumDeclSyntax { return rawValueTypes.contains(identifier) } } + + /// True if this enum is a `CodingKey` + var isCodingKey: Bool { + guard let inheritedTypeCollection = inheritanceClause?.inheritedTypes else { + return false + } + + guard self.name.text == "CodingKeys" else { + return false + } + + return inheritedTypeCollection.contains { element in + guard let identifier = element.type.as(IdentifierTypeSyntax.self)?.name.text else { + return false + } + + return identifier == "CodingKey" + } + } } public extension FunctionDeclSyntax { From 317448e6133f0520a83b42e608ce5290685b1d84 Mon Sep 17 00:00:00 2001 From: Chris Brakebill Date: Mon, 1 Jul 2024 19:43:04 -0400 Subject: [PATCH 2/3] Add ignore_codingkeys parameter to nesting This prevents nested CodingKeys (which may be necessary for functioning Codable conformance) from triggering nesting violations --- .../Rules/Metrics/NestingRule.swift | 4 ++- .../NestingConfiguration.swift | 2 ++ .../NestingRuleTests.swift | 34 +++++++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Metrics/NestingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Metrics/NestingRule.swift index 2e9b95662e..91a0ac080c 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.isCodingKey) { + 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 9fe2c155cd..4490f8ce0a 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_codingkeys") + private(set) var ignoreCodingKeys = false func severity(with config: Severity, for level: Int) -> ViolationSeverity? { if let error = config.error, level > error { diff --git a/Tests/SwiftLintFrameworkTests/NestingRuleTests.swift b/Tests/SwiftLintFrameworkTests/NestingRuleTests.swift index 2df7ba3901..e518580a31 100644 --- a/Tests/SwiftLintFrameworkTests/NestingRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/NestingRuleTests.swift @@ -551,4 +551,38 @@ 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 + } + } + } + """) + ]) + + let description = NestingRule.description.with(nonTriggeringExamples: nonTriggeringExamples, triggeringExamples: triggeringExamples) + + verifyRule(description, ruleConfiguration: ["ignore_codingkeys": true ]) + } + } From 0be58c7ba0023fd93c36d6682d41f5f2872d5567 Mon Sep 17 00:00:00 2001 From: Chris Brakebill Date: Tue, 2 Jul 2024 13:48:38 -0400 Subject: [PATCH 3/3] Add entry to CHANGELOG --- .vscode/launch.json | 28 ++++++++++++++++++++++++++++ CHANGELOG.md | 4 ++++ 2 files changed, 32 insertions(+) create mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000000..0e54c0c200 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,28 @@ +{ + "configurations": [ + { + "type": "lldb", + "request": "launch", + "sourceLanguages": [ + "swift" + ], + "args": [], + "cwd": "${workspaceFolder:SwiftLint}", + "name": "Debug swiftlint", + "program": "${workspaceFolder:SwiftLint}/.build/debug/swiftlint", + "preLaunchTask": "swift: Build Debug swiftlint" + }, + { + "type": "lldb", + "request": "launch", + "sourceLanguages": [ + "swift" + ], + "args": [], + "cwd": "${workspaceFolder:SwiftLint}", + "name": "Release swiftlint", + "program": "${workspaceFolder:SwiftLint}/.build/release/swiftlint", + "preLaunchTask": "swift: Build Release swiftlint" + } + ] +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 590831299b..4c54f88940 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,10 @@ improvements done in the [SwiftSyntax](https://github.com/apple/swift-syntax) library. +* Add `ignore_codingkeys` parameter to `nesting` rule. + [braker1nine](https://github.com/braker1nine) + [#5641](https://github.com/realm/SwiftLint/issues/5641) + #### Bug Fixes * Fix a few false positives and negatives by updating the parser to support