From 83c54b9e3966c4d091269649ded7e2c4ff02b435 Mon Sep 17 00:00:00 2001 From: Muhammad Zeeshan Date: Mon, 18 Dec 2023 13:21:46 +0500 Subject: [PATCH 1/2] - rule added i.e. redundant_extension --- .swiftlint.yml | 1 + CHANGELOG.md | 6 +++ .../Models/BuiltInRules.swift | 1 + .../Idiomatic/RedundantExtensionRule.swift | 50 +++++++++++++++++++ Tests/GeneratedTests/GeneratedTests.swift | 6 +++ 5 files changed, 64 insertions(+) create mode 100644 Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantExtensionRule.swift diff --git a/.swiftlint.yml b/.swiftlint.yml index d58e739045..dfab57497c 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -42,6 +42,7 @@ disabled_rules: - prefer_nimble - prefer_self_in_static_references - prefixed_toplevel_constant + - redundant_extension - redundant_self_in_closure - required_deinit - self_binding diff --git a/CHANGELOG.md b/CHANGELOG.md index 6502094eb5..66b9e19316 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,12 @@ #### Enhancements +* Add new `redundant_extension` rule that detects redundant extensions. + An extension is considered redundant if it does not define any + members, but only conformances. + [Muhammad Zeeshan](https://github.com/mzeeshanid) + [#5359](https://github.com/realm/SwiftLint/issues/5359) + * Add new `one_declaration_per_file` rule that allows only a single class/struct/enum/protocol declaration per file. Extensions are an exception; more than one is allowed. diff --git a/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift b/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift index 4615c17caf..301211a247 100644 --- a/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift +++ b/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift @@ -166,6 +166,7 @@ public let builtInRules: [any Rule.Type] = [ ReduceBooleanRule.self, ReduceIntoRule.self, RedundantDiscardableLetRule.self, + RedundantExtensionRule.self, RedundantNilCoalescingRule.self, RedundantObjcAttributeRule.self, RedundantOptionalInitializationRule.self, diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantExtensionRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantExtensionRule.swift new file mode 100644 index 0000000000..81c5bb64e7 --- /dev/null +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantExtensionRule.swift @@ -0,0 +1,50 @@ +import SwiftSyntax + +@SwiftSyntaxRule +struct RedundantExtensionRule: OptInRule { + var configuration = SeverityConfiguration(.warning) + + static let description = RuleDescription( + identifier: "redundant_extension", + name: "Redundant Extension", + description: "Avoid redundant extensions", + kind: .idiomatic, + nonTriggeringExamples: [ + Example(""" + extension Foo { + func something() {} + } + """), + Example(""" + extension Foo { + var a: Int { 1 } + } + """), + Example(""" + extension Foo { + final class Bar {} + } + """), + Example(""" + extension Foo { + struct Bar {} + } + """) + ], + triggeringExamples: [ + Example(""" + ↓extension Bar {} + """) + ] + ) +} + +private extension RedundantExtensionRule { + final class Visitor: ViolationsSyntaxVisitor { + override func visitPost(_ node: ExtensionDeclSyntax) { + if node.memberBlock.members.isEmpty { + violations.append(node.extensionKeyword.positionAfterSkippingLeadingTrivia) + } + } + } +} diff --git a/Tests/GeneratedTests/GeneratedTests.swift b/Tests/GeneratedTests/GeneratedTests.swift index 078c6f614e..2f919c2d73 100644 --- a/Tests/GeneratedTests/GeneratedTests.swift +++ b/Tests/GeneratedTests/GeneratedTests.swift @@ -986,6 +986,12 @@ class RedundantDiscardableLetRuleGeneratedTests: SwiftLintTestCase { } } +class RedundantExtensionRuleGeneratedTests: SwiftLintTestCase { + func testWithDefaultConfiguration() { + verifyRule(RedundantExtensionRule.description) + } +} + class RedundantNilCoalescingRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(RedundantNilCoalescingRule.description) From a44aa8202a316253662527a78a337321ab2f051f Mon Sep 17 00:00:00 2001 From: Muhammad Zeeshan Date: Mon, 18 Dec 2023 13:21:46 +0500 Subject: [PATCH 2/2] - rule added i.e. redundant_extension --- .swiftlint.yml | 1 + CHANGELOG.md | 5 ++ .../Models/BuiltInRules.swift | 1 + .../Idiomatic/RedundantExtensionRule.swift | 50 +++++++++++++++++++ Tests/GeneratedTests/GeneratedTests.swift | 6 +++ 5 files changed, 63 insertions(+) create mode 100644 Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantExtensionRule.swift diff --git a/.swiftlint.yml b/.swiftlint.yml index 115c0f7115..93d6ba5998 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -43,6 +43,7 @@ disabled_rules: - prefer_nimble - prefer_self_in_static_references - prefixed_toplevel_constant + - redundant_extension - redundant_self_in_closure - required_deinit - self_binding diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c1c654055..1d3f77c176 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,11 @@ rule to ignore switch statements written in a single line. [tonell-m](https://github.com/tonell-m) [#5373](https://github.com/realm/SwiftLint/issues/5373) +* Add new `redundant_extension` rule that detects redundant extensions. + An extension is considered redundant if it does not define any + members, but only conformances. + [Muhammad Zeeshan](https://github.com/mzeeshanid) + [#5359](https://github.com/realm/SwiftLint/issues/5359) * Add new `one_declaration_per_file` rule that allows only a single class/struct/enum/protocol declaration per file. diff --git a/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift b/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift index 8788d3c056..fe93a776fb 100644 --- a/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift +++ b/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift @@ -167,6 +167,7 @@ public let builtInRules: [any Rule.Type] = [ ReduceBooleanRule.self, ReduceIntoRule.self, RedundantDiscardableLetRule.self, + RedundantExtensionRule.self, RedundantNilCoalescingRule.self, RedundantObjcAttributeRule.self, RedundantOptionalInitializationRule.self, diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantExtensionRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantExtensionRule.swift new file mode 100644 index 0000000000..81c5bb64e7 --- /dev/null +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantExtensionRule.swift @@ -0,0 +1,50 @@ +import SwiftSyntax + +@SwiftSyntaxRule +struct RedundantExtensionRule: OptInRule { + var configuration = SeverityConfiguration(.warning) + + static let description = RuleDescription( + identifier: "redundant_extension", + name: "Redundant Extension", + description: "Avoid redundant extensions", + kind: .idiomatic, + nonTriggeringExamples: [ + Example(""" + extension Foo { + func something() {} + } + """), + Example(""" + extension Foo { + var a: Int { 1 } + } + """), + Example(""" + extension Foo { + final class Bar {} + } + """), + Example(""" + extension Foo { + struct Bar {} + } + """) + ], + triggeringExamples: [ + Example(""" + ↓extension Bar {} + """) + ] + ) +} + +private extension RedundantExtensionRule { + final class Visitor: ViolationsSyntaxVisitor { + override func visitPost(_ node: ExtensionDeclSyntax) { + if node.memberBlock.members.isEmpty { + violations.append(node.extensionKeyword.positionAfterSkippingLeadingTrivia) + } + } + } +} diff --git a/Tests/GeneratedTests/GeneratedTests.swift b/Tests/GeneratedTests/GeneratedTests.swift index 78003f5f18..256d8877cd 100644 --- a/Tests/GeneratedTests/GeneratedTests.swift +++ b/Tests/GeneratedTests/GeneratedTests.swift @@ -992,6 +992,12 @@ class RedundantDiscardableLetRuleGeneratedTests: SwiftLintTestCase { } } +class RedundantExtensionRuleGeneratedTests: SwiftLintTestCase { + func testWithDefaultConfiguration() { + verifyRule(RedundantExtensionRule.description) + } +} + class RedundantNilCoalescingRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(RedundantNilCoalescingRule.description)