Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@
[SimplyDanny](https://github.com/SimplyDanny)
[#6466](https://github.com/realm/SwiftLint/issues/6466)

* Avoid false positives in `prefer_self_in_static_references` when a nested type
shadows its enclosing type name.
[theamodhshetty](https://github.com/theamodhshetty)
[#5917](https://github.com/realm/SwiftLint/issues/5917)

## 0.63.2: High-Speed Extraction

### Breaking
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,16 @@ private extension PreferSelfInStaticReferencesRule {

final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
private var parentDeclScopes = Stack<ParentDeclBehavior>()
private var shadowingNestedTypeScopes = Stack<Bool>()
private var variableDeclScopes = Stack<VariableDeclBehavior>()

override func visit(_ node: ActorDeclSyntax) -> SyntaxVisitorContinueKind {
parentDeclScopes.push(.likeClass(name: node.name.text))
pushParentDeclScope(.likeClass(name: node.name.text), for: node.name.text, memberBlock: node.memberBlock)
return .skipChildren
}

override func visitPost(_: ActorDeclSyntax) {
parentDeclScopes.pop()
popParentDeclScope()
}

override func visit(_: AttributeSyntax) -> SyntaxVisitorContinueKind {
Expand All @@ -56,12 +57,12 @@ private extension PreferSelfInStaticReferencesRule {
}

override func visit(_ node: ClassDeclSyntax) -> SyntaxVisitorContinueKind {
parentDeclScopes.push(.likeClass(name: node.name.text))
pushParentDeclScope(.likeClass(name: node.name.text), for: node.name.text, memberBlock: node.memberBlock)
return .visitChildren
}

override func visitPost(_: ClassDeclSyntax) {
parentDeclScopes.pop()
popParentDeclScope()
}

override func visit(_: CodeBlockItemListSyntax) -> SyntaxVisitorContinueKind {
Expand All @@ -74,21 +75,21 @@ private extension PreferSelfInStaticReferencesRule {
}

override func visit(_ node: EnumDeclSyntax) -> SyntaxVisitorContinueKind {
parentDeclScopes.push(.likeStruct(node.name.text))
pushParentDeclScope(.likeStruct(node.name.text), for: node.name.text, memberBlock: node.memberBlock)
return .visitChildren
}

override func visitPost(_: EnumDeclSyntax) {
parentDeclScopes.pop()
popParentDeclScope()
}

override func visit(_: ExtensionDeclSyntax) -> SyntaxVisitorContinueKind {
parentDeclScopes.push(.skipReferences)
pushParentDeclScope(.skipReferences)
return .visitChildren
}

override func visitPost(_: ExtensionDeclSyntax) {
parentDeclScopes.pop()
popParentDeclScope()
}

override func visit(_ node: MemberAccessExprSyntax) -> SyntaxVisitorContinueKind {
Expand Down Expand Up @@ -146,12 +147,12 @@ private extension PreferSelfInStaticReferencesRule {
}

override func visit(_: ProtocolDeclSyntax) -> SyntaxVisitorContinueKind {
parentDeclScopes.push(.skipReferences)
pushParentDeclScope(.skipReferences)
return .skipChildren
}

override func visitPost(_: ProtocolDeclSyntax) {
parentDeclScopes.pop()
popParentDeclScope()
}

override func visit(_: ReturnClauseSyntax) -> SyntaxVisitorContinueKind {
Expand All @@ -162,12 +163,12 @@ private extension PreferSelfInStaticReferencesRule {
}

override func visit(_ node: StructDeclSyntax) -> SyntaxVisitorContinueKind {
parentDeclScopes.push(.likeStruct(node.name.text))
pushParentDeclScope(.likeStruct(node.name.text), for: node.name.text, memberBlock: node.memberBlock)
return .visitChildren
}

override func visitPost(_: StructDeclSyntax) {
parentDeclScopes.pop()
popParentDeclScope()
}

override func visit(_: GenericArgumentListSyntax) -> SyntaxVisitorContinueKind {
Expand Down Expand Up @@ -213,7 +214,9 @@ private extension PreferSelfInStaticReferencesRule {
}

private func addViolation(on node: TokenSyntax) {
if let parentName = parentDeclScopes.peek()?.parentName, node.tokenKind == .identifier(parentName) {
if shadowingNestedTypeScopes.peek() != true,
let parentName = parentDeclScopes.peek()?.parentName,
node.tokenKind == .identifier(parentName) {
violations.append(
at: node.positionAfterSkippingLeadingTrivia,
correction: .init(
Expand All @@ -224,5 +227,44 @@ private extension PreferSelfInStaticReferencesRule {
)
}
}

private func pushParentDeclScope(
_ behavior: ParentDeclBehavior,
for name: String? = nil,
memberBlock: MemberBlockSyntax? = nil
) {
parentDeclScopes.push(behavior)
let hasShadowingNestedType: Bool
if let name, let memberBlock {
hasShadowingNestedType = containsSameNamedNestedType(named: name, in: memberBlock)
} else {
hasShadowingNestedType = false
}
shadowingNestedTypeScopes.push(hasShadowingNestedType)
}

private func popParentDeclScope() {
parentDeclScopes.pop()
shadowingNestedTypeScopes.pop()
}

private func containsSameNamedNestedType(named name: String, in memberBlock: MemberBlockSyntax) -> Bool {
memberBlock.members.contains { member in
if let actor = member.decl.as(ActorDeclSyntax.self) {
return actor.name.text == name
}
if let classDecl = member.decl.as(ClassDeclSyntax.self) {
return classDecl.name.text == name
}
if let enumDecl = member.decl.as(EnumDeclSyntax.self) {
return enumDecl.name.text == name
}
if let structDecl = member.decl.as(StructDeclSyntax.self) {
return structDecl.name.text == name
}

return false
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,12 @@ enum PreferSelfInStaticReferencesRuleExamples {
}
}
""", excludeFromDocumentation: true),
Example("""
struct S1 {
struct S1 {}
var s = S1()
}
""", excludeFromDocumentation: true),
]

static let triggeringExamples = [
Expand Down
Loading