1+ @_spi ( Diagnostics)
2+ import SwiftParser
3+ @_spi ( RawSyntax)
14import SwiftSyntax
25
36@SwiftSyntaxRule ( correctable: true , optIn: true )
@@ -16,19 +19,15 @@ struct RedundantSelfInClosureRule: Rule {
1619}
1720
1821private enum TypeDeclarationKind {
19- case likeStruct
20- case likeClass
22+ case likeStruct, likeClass
2123}
2224
2325private enum FunctionCallType {
24- case anonymousClosure
25- case function
26+ case anonymousClosure, function
2627}
2728
2829private enum SelfCaptureKind {
29- case strong
30- case weak
31- case uncaptured
30+ case strong, weak, uncaptured
3231}
3332
3433private extension RedundantSelfInClosureRule {
@@ -63,25 +62,17 @@ private extension RedundantSelfInClosureRule {
6362 } else {
6463 selfCaptures. push ( . uncaptured)
6564 }
65+ if node. keyPathInParent == \FunctionCallExprSyntax . calledExpression {
66+ functionCalls. push ( . anonymousClosure)
67+ } else {
68+ functionCalls. push ( . function)
69+ }
6670 return . visitChildren
6771 }
6872
69- override func visitPost( _ node: ClosureExprSyntax ) {
70- guard let activeTypeDeclarationKind = typeDeclarations. peek ( ) ,
71- let activeFunctionCallType = functionCalls. peek ( ) ,
72- let activeSelfCaptureKind = selfCaptures. peek ( ) else {
73- return
74- }
75- let localViolationCorrections = ExplicitSelfVisitor (
76- configuration: configuration,
77- file: file,
78- typeDeclarationKind: activeTypeDeclarationKind,
79- functionCallType: activeFunctionCallType,
80- selfCaptureKind: activeSelfCaptureKind,
81- scope: scope
82- ) . walk ( tree: node. statements, handler: \. violations)
83- violations. append ( contentsOf: localViolationCorrections)
73+ override func visitPost( _: ClosureExprSyntax ) {
8474 selfCaptures. pop ( )
75+ functionCalls. pop ( )
8576 }
8677
8778 override func visit( _: EnumDeclSyntax ) -> SyntaxVisitorContinueKind {
@@ -93,17 +84,26 @@ private extension RedundantSelfInClosureRule {
9384 typeDeclarations. pop ( )
9485 }
9586
96- override func visit( _ node: FunctionCallExprSyntax ) -> SyntaxVisitorContinueKind {
97- if node. calledExpression. is ( ClosureExprSyntax . self) {
98- functionCalls. push ( . anonymousClosure)
99- } else {
100- functionCalls. push ( . function)
87+ override func visitPost( _ node: MemberAccessExprSyntax ) {
88+ if selfCaptures. isNotEmpty {
89+ // In closure ...
90+ guard typeDeclarations. isNotEmpty, functionCalls. isNotEmpty, isSelfRedundant else {
91+ return
92+ }
93+ }
94+ let declName = node. declName. baseName. text
95+ if !hasSeenDeclaration( for: declName) , node. isBaseSelf, declName != " init " {
96+ violations. append (
97+ at: node. positionAfterSkippingLeadingTrivia,
98+ correction: . init(
99+ start: node. positionAfterSkippingLeadingTrivia,
100+ end: node. endPositionBeforeTrailingTrivia,
101+ replacement: node. declName. baseName. needsEscaping
102+ ? " ` \( declName) ` "
103+ : declName
104+ )
105+ )
101106 }
102- return . visitChildren
103- }
104-
105- override func visitPost( _: FunctionCallExprSyntax ) {
106- functionCalls. pop ( )
107107 }
108108
109109 override func visit( _: StructDeclSyntax ) -> SyntaxVisitorContinueKind {
@@ -114,48 +114,23 @@ private extension RedundantSelfInClosureRule {
114114 override func visitPost( _: StructDeclSyntax ) {
115115 typeDeclarations. pop ( )
116116 }
117- }
118- }
119-
120- private class ExplicitSelfVisitor < Configuration: RuleConfiguration > : DeclaredIdentifiersTrackingVisitor < Configuration > {
121- private let typeDeclKind : TypeDeclarationKind
122- private let functionCallType : FunctionCallType
123- private let selfCaptureKind : SelfCaptureKind
124-
125- init ( configuration: Configuration ,
126- file: SwiftLintFile ,
127- typeDeclarationKind: TypeDeclarationKind ,
128- functionCallType: FunctionCallType ,
129- selfCaptureKind: SelfCaptureKind ,
130- scope: Scope ) {
131- self . typeDeclKind = typeDeclarationKind
132- self . functionCallType = functionCallType
133- self . selfCaptureKind = selfCaptureKind
134- super. init ( configuration: configuration, file: file, scope: scope)
135- }
136117
137- override func visitPost( _ node: MemberAccessExprSyntax ) {
138- if !hasSeenDeclaration( for: node. declName. baseName. text) , node. isBaseSelf, isSelfRedundant {
139- violations. append (
140- at: node. positionAfterSkippingLeadingTrivia,
141- correction: . init(
142- start: node. positionAfterSkippingLeadingTrivia,
143- end: node. period. endPositionBeforeTrailingTrivia,
144- replacement: " "
145- )
146- )
118+ private var isSelfRedundant : Bool {
119+ typeDeclarations. peek ( ) == . likeStruct
120+ || functionCalls. peek ( ) == . anonymousClosure
121+ || selfCaptures. peek ( ) == . strong && SwiftVersion . current >= . fiveDotThree
122+ || selfCaptures. peek ( ) == . weak && SwiftVersion . current >= . fiveDotEight
147123 }
148124 }
125+ }
149126
150- override func visit( _: ClosureExprSyntax ) -> SyntaxVisitorContinueKind {
151- // Will be handled separately by the parent visitor.
152- . skipChildren
153- }
154-
155- var isSelfRedundant : Bool {
156- typeDeclKind == . likeStruct
157- || functionCallType == . anonymousClosure
158- || selfCaptureKind == . strong && SwiftVersion . current >= . fiveDotThree
159- || selfCaptureKind == . weak && SwiftVersion . current >= . fiveDotEight
127+ private extension TokenSyntax {
128+ var needsEscaping : Bool {
129+ [ UInt8] ( text. utf8) . withUnsafeBufferPointer {
130+ if let keyword = Keyword ( SyntaxText ( baseAddress: $0. baseAddress, count: text. count) ) {
131+ return TokenKind . keyword ( keyword) . isLexerClassifiedKeyword
132+ }
133+ return false
134+ }
160135 }
161136}
0 commit comments