From d0954cbad476f1548508133ac71b556cce6971b0 Mon Sep 17 00:00:00 2001 From: Harlan Haskins Date: Tue, 9 Jul 2024 16:07:03 -0600 Subject: [PATCH 1/2] Add swift-format rule warning for retroactive conformances. This provides a lint rule whenever an `@retroactive` appears in a source file. I've marked the rule as opt-out, but I'm also wondering if we have a syntax for opting out of a rule in general. --- Documentation/RuleDocumentation.md | 9 +++++ .../Core/Pipelines+Generated.swift | 10 +++++ .../Core/RuleNameCache+Generated.swift | 1 + .../Core/RuleRegistry+Generated.swift | 1 + .../Rules/AvoidRetroactiveConformances.swift | 38 +++++++++++++++++++ .../AvoidRetroactiveConformancesTests.swift | 17 +++++++++ 6 files changed, 76 insertions(+) create mode 100644 Sources/SwiftFormat/Rules/AvoidRetroactiveConformances.swift create mode 100644 Tests/SwiftFormatTests/Rules/AvoidRetroactiveConformancesTests.swift diff --git a/Documentation/RuleDocumentation.md b/Documentation/RuleDocumentation.md index 654bc8b04..d9fa83760 100644 --- a/Documentation/RuleDocumentation.md +++ b/Documentation/RuleDocumentation.md @@ -14,6 +14,7 @@ Here's the list of available rules: - [AlwaysUseLiteralForEmptyCollectionInit](#AlwaysUseLiteralForEmptyCollectionInit) - [AlwaysUseLowerCamelCase](#AlwaysUseLowerCamelCase) - [AmbiguousTrailingClosureOverload](#AmbiguousTrailingClosureOverload) +- [AvoidRetroactiveConformances](#AvoidRetroactiveConformances) - [BeginDocumentationCommentWithOneLineSummary](#BeginDocumentationCommentWithOneLineSummary) - [DoNotUseSemicolons](#DoNotUseSemicolons) - [DontRepeatTypeInStaticProperties](#DontRepeatTypeInStaticProperties) @@ -93,6 +94,14 @@ Lint: If two overloaded functions with one closure parameter appear in the same `AmbiguousTrailingClosureOverload` is a linter-only rule. +### AvoidRetroactiveConformances + +`@retroactive` conformances are forbidden. + +Lint: Using `@retroactive` results in a lint error. + +`AvoidRetroactiveConformances` is a linter-only rule. + ### BeginDocumentationCommentWithOneLineSummary All documentation comments must begin with a one-line summary of the declaration. diff --git a/Sources/SwiftFormat/Core/Pipelines+Generated.swift b/Sources/SwiftFormat/Core/Pipelines+Generated.swift index 9707ee80f..c0af02e39 100644 --- a/Sources/SwiftFormat/Core/Pipelines+Generated.swift +++ b/Sources/SwiftFormat/Core/Pipelines+Generated.swift @@ -64,6 +64,14 @@ class LintPipeline: SyntaxVisitor { onVisitPost(rule: TypeNamesShouldBeCapitalized.self, for: node) } + override func visit(_ node: AttributeSyntax) -> SyntaxVisitorContinueKind { + visitIfEnabled(AvoidRetroactiveConformances.visit, for: node) + return .visitChildren + } + override func visitPost(_ node: AttributeSyntax) { + onVisitPost(rule: AvoidRetroactiveConformances.self, for: node) + } + override func visit(_ node: ClassDeclSyntax) -> SyntaxVisitorContinueKind { visitIfEnabled(AllPublicDeclarationsHaveDocumentation.visit, for: node) visitIfEnabled(AlwaysUseLowerCamelCase.visit, for: node) @@ -193,12 +201,14 @@ class LintPipeline: SyntaxVisitor { } override func visit(_ node: ExtensionDeclSyntax) -> SyntaxVisitorContinueKind { + visitIfEnabled(AvoidRetroactiveConformances.visit, for: node) visitIfEnabled(DontRepeatTypeInStaticProperties.visit, for: node) visitIfEnabled(NoAccessLevelOnExtensionDeclaration.visit, for: node) visitIfEnabled(UseTripleSlashForDocumentationComments.visit, for: node) return .visitChildren } override func visitPost(_ node: ExtensionDeclSyntax) { + onVisitPost(rule: AvoidRetroactiveConformances.self, for: node) onVisitPost(rule: DontRepeatTypeInStaticProperties.self, for: node) onVisitPost(rule: NoAccessLevelOnExtensionDeclaration.self, for: node) onVisitPost(rule: UseTripleSlashForDocumentationComments.self, for: node) diff --git a/Sources/SwiftFormat/Core/RuleNameCache+Generated.swift b/Sources/SwiftFormat/Core/RuleNameCache+Generated.swift index b19b88d6b..ac542c1d4 100644 --- a/Sources/SwiftFormat/Core/RuleNameCache+Generated.swift +++ b/Sources/SwiftFormat/Core/RuleNameCache+Generated.swift @@ -19,6 +19,7 @@ public let ruleNameCache: [ObjectIdentifier: String] = [ ObjectIdentifier(AlwaysUseLiteralForEmptyCollectionInit.self): "AlwaysUseLiteralForEmptyCollectionInit", ObjectIdentifier(AlwaysUseLowerCamelCase.self): "AlwaysUseLowerCamelCase", ObjectIdentifier(AmbiguousTrailingClosureOverload.self): "AmbiguousTrailingClosureOverload", + ObjectIdentifier(AvoidRetroactiveConformances.self): "AvoidRetroactiveConformances", ObjectIdentifier(BeginDocumentationCommentWithOneLineSummary.self): "BeginDocumentationCommentWithOneLineSummary", ObjectIdentifier(DoNotUseSemicolons.self): "DoNotUseSemicolons", ObjectIdentifier(DontRepeatTypeInStaticProperties.self): "DontRepeatTypeInStaticProperties", diff --git a/Sources/SwiftFormat/Core/RuleRegistry+Generated.swift b/Sources/SwiftFormat/Core/RuleRegistry+Generated.swift index 9fb96fcf0..a5aeeab1f 100644 --- a/Sources/SwiftFormat/Core/RuleRegistry+Generated.swift +++ b/Sources/SwiftFormat/Core/RuleRegistry+Generated.swift @@ -18,6 +18,7 @@ "AlwaysUseLiteralForEmptyCollectionInit": false, "AlwaysUseLowerCamelCase": true, "AmbiguousTrailingClosureOverload": true, + "AvoidRetroactiveConformances": true, "BeginDocumentationCommentWithOneLineSummary": false, "DoNotUseSemicolons": true, "DontRepeatTypeInStaticProperties": true, diff --git a/Sources/SwiftFormat/Rules/AvoidRetroactiveConformances.swift b/Sources/SwiftFormat/Rules/AvoidRetroactiveConformances.swift new file mode 100644 index 000000000..1573d3de2 --- /dev/null +++ b/Sources/SwiftFormat/Rules/AvoidRetroactiveConformances.swift @@ -0,0 +1,38 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +import SwiftSyntax + +/// `@retroactive` conformances are forbidden. +/// +/// Lint: Using `@retroactive` results in a lint error. +@_spi(Rules) +public final class AvoidRetroactiveConformances: SyntaxLintRule { + public override func visit(_ node: ExtensionDeclSyntax) -> SyntaxVisitorContinueKind { + if let inheritanceClause = node.inheritanceClause { + walk(inheritanceClause) + } + return .skipChildren + } + public override func visit(_ type: AttributeSyntax) -> SyntaxVisitorContinueKind { + if let identifier = type.attributeName.as(IdentifierTypeSyntax.self) { + if identifier.name.text == "retroactive" { + diagnose(.doNotUseRetroactive, on: type) + } + } + return .skipChildren + } +} + +extension Finding.Message { + fileprivate static let doNotUseRetroactive: Finding.Message = "do not declare retroactive conformances" +} diff --git a/Tests/SwiftFormatTests/Rules/AvoidRetroactiveConformancesTests.swift b/Tests/SwiftFormatTests/Rules/AvoidRetroactiveConformancesTests.swift new file mode 100644 index 000000000..2616d2581 --- /dev/null +++ b/Tests/SwiftFormatTests/Rules/AvoidRetroactiveConformancesTests.swift @@ -0,0 +1,17 @@ +import _SwiftFormatTestSupport + +@_spi(Rules) import SwiftFormat + +final class AvoidRetroactiveConformancesTests: LintOrFormatRuleTestCase { + func testRetroactiveConformanceIsDiagnosed() { + assertLint( + AvoidRetroactiveConformances.self, + """ + extension Int: 1️⃣@retroactive Identifiable {} + """, + findings: [ + FindingSpec("1️⃣", message: "do not declare retroactive conformances"), + ] + ) + } +} From e99495c4872a435b9440d7805a634bea7a839a88 Mon Sep 17 00:00:00 2001 From: Harlan Haskins Date: Thu, 11 Jul 2024 14:49:11 -0600 Subject: [PATCH 2/2] Add source file to CMakeLists --- Sources/SwiftFormat/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Sources/SwiftFormat/CMakeLists.txt b/Sources/SwiftFormat/CMakeLists.txt index 062e12dc7..7ea0c97f6 100644 --- a/Sources/SwiftFormat/CMakeLists.txt +++ b/Sources/SwiftFormat/CMakeLists.txt @@ -57,6 +57,7 @@ add_library(SwiftFormat Rules/AlwaysUseLiteralForEmptyCollectionInit.swift Rules/AlwaysUseLowerCamelCase.swift Rules/AmbiguousTrailingClosureOverload.swift + Rules/AvoidRetroactiveConformances.swift Rules/BeginDocumentationCommentWithOneLineSummary.swift Rules/DoNotUseSemicolons.swift Rules/DontRepeatTypeInStaticProperties.swift