Add redundant_final_actor opt-in rule#6504
Add redundant_final_actor opt-in rule#6504william-laverty wants to merge 5 commits intorealm:mainfrom
redundant_final_actor opt-in rule#6504Conversation
Here's an example of your CHANGELOG entry: * Add `redundant_final_actor` opt-in rule.
[William-Laverty](https://github.com/William-Laverty)
[#issue_number](https://github.com/realm/SwiftLint/issues/issue_number)note: There are two invisible spaces after the entry's text. Generated by 🚫 Danger |
Actors in Swift cannot be subclassed (SE-0306), making the `final`
modifier redundant on actor declarations. This new opt-in rule detects
and auto-corrects `final actor` to just `actor`.
Examples:
- `final actor MyActor {}` → `actor MyActor {}`
- `public final actor DataStore {}` → `public actor DataStore {}`
Closes realm#6407
- Use @SwiftSyntaxRule(explicitRewriter: true, optIn: true) instead of directly conforming to OptInRule, which caused a type mismatch - Rebase on latest upstream main - Re-run rules and reporters register
2d01a01 to
f655ffa
Compare
SimplyDanny
left a comment
There was a problem hiding this comment.
Good idea!
Have in mind, however, that actors don't support inheritance now. That is open to change in the future. We should perhaps mention that in a rational. RuleDescription support a rational value we can use to explain that a little and consider it a caveat.
What about final methods and properties?
actor A {
final func f() {}
}
Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantFinalActorRule.swift
Outdated
Show resolved
Hide resolved
Address SimplyDanny's suggestion to use range-replace correction appended to the violation, removing the need for a separate Rewriter.
Add correctable: true to the @SwiftSyntaxRule macro so the rule properly conforms to SwiftSyntaxCorrectableRule. The correction was already implemented via ViolationCorrection but the macro parameter was missing.
|
What about |
|
Good callouts, thanks.
I'll push both changes shortly. |
- Add rationale explaining actors don't support inheritance (with caveat) - Detect redundant final on functions, properties, and subscripts inside actors - Skip nested class declarations where final is meaningful - Add non-triggering/triggering examples for member declarations
SimplyDanny
left a comment
There was a problem hiding this comment.
Sorry for the late reply ... here are a few more comments.
Please also add a changelog entry to credit yourself and let others know about the new rule.
| static let description = RuleDescription( | ||
| identifier: "redundant_final_actor", | ||
| name: "Redundant Final on Actor", | ||
| description: "`final` is redundant on an actor declaration and its members because actors cannot be subclassed", |
There was a problem hiding this comment.
Keep it short:
| description: "`final` is redundant on an actor declaration and its members because actors cannot be subclassed", | |
| description: "`final` is redundant on an actor declaration and its members", |
| } | ||
|
|
||
| override func visitPost(_ node: ActorDeclSyntax) { | ||
| if let finalModifier = node.modifiers.first(where: { $0.name.text == "final" }) { |
There was a problem hiding this comment.
We could have the keyword lookup in an extension on DeclModifierListSyntax. You might even add it to SwiftSyntax+SwiftLint.swift.
|
|
||
| private extension RedundantFinalActorRule { | ||
| final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> { | ||
| private var insideActor = false |
There was a problem hiding this comment.
This is not sufficient. You would need to have a stack to track "is actor" when entering a type declaration. Otherwise, you cannot correctly handle nested types, e.g.
struct S {
final actor A {}
}Another case that justifies a stack is
actor A {
final var x: Int { 1 } // Rule triggers here.
struct S {}
final var y: Int { 2 } // Would it trigger here as well?
}
Summary
Implements #6407.
Actors in Swift cannot be subclassed (SE-0306), so the
finalmodifier is always redundant on actor declarations. The compiler doesn't warn about this, but it's unnecessary noise similar to redundantinternalaccess control.New Rule:
redundant_final_actorfinalmodifierExamples
Changes
RedundantFinalActorRule.swiftwith visitor + rewriterBuiltInRules.swift