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,20 @@ private extension RedundantSelfInClosureRule {
6362 } else {
6463 selfCaptures. push ( . uncaptured)
6564 }
65+ if node. keyPathInParent == \FunctionCallExprSyntax . calledExpression {
66+ functionCalls. push ( . anonymousClosure)
67+ } else if [ . functionCallExpr, . multipleTrailingClosureElement] . contains ( node. parent? . kind) {
68+ functionCalls. push ( . function)
69+ }
6670 return . visitChildren
6771 }
6872
6973 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)
8474 selfCaptures. pop ( )
75+ if node. keyPathInParent == \FunctionCallExprSyntax . calledExpression
76+ || [ . functionCallExpr, . multipleTrailingClosureElement] . contains ( node. parent? . kind) {
77+ functionCalls. pop ( )
78+ }
8579 }
8680
8781 override func visit( _: EnumDeclSyntax ) -> SyntaxVisitorContinueKind {
@@ -93,17 +87,26 @@ private extension RedundantSelfInClosureRule {
9387 typeDeclarations. pop ( )
9488 }
9589
96- override func visit( _ node: FunctionCallExprSyntax ) -> SyntaxVisitorContinueKind {
97- if node. calledExpression. is ( ClosureExprSyntax . self) {
98- functionCalls. push ( . anonymousClosure)
99- } else {
100- functionCalls. push ( . function)
90+ override func visitPost( _ node: MemberAccessExprSyntax ) {
91+ if selfCaptures. isNotEmpty {
92+ // In closure ...
93+ guard typeDeclarations. isNotEmpty, functionCalls. isNotEmpty, isSelfRedundant else {
94+ return
95+ }
96+ }
97+ let declName = node. declName. baseName. text
98+ if !hasSeenDeclaration( for: declName) , node. isBaseSelf, declName != " init " {
99+ violations. append (
100+ at: node. positionAfterSkippingLeadingTrivia,
101+ correction: . init(
102+ start: node. positionAfterSkippingLeadingTrivia,
103+ end: node. endPositionBeforeTrailingTrivia,
104+ replacement: node. declName. baseName. needsEscaping
105+ ? " ` \( declName) ` "
106+ : declName
107+ )
108+ )
101109 }
102- return . visitChildren
103- }
104-
105- override func visitPost( _: FunctionCallExprSyntax ) {
106- functionCalls. pop ( )
107110 }
108111
109112 override func visit( _: StructDeclSyntax ) -> SyntaxVisitorContinueKind {
@@ -114,48 +117,23 @@ private extension RedundantSelfInClosureRule {
114117 override func visitPost( _: StructDeclSyntax ) {
115118 typeDeclarations. pop ( )
116119 }
117- }
118- }
119120
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- }
136-
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- )
121+ private var isSelfRedundant : Bool {
122+ typeDeclarations. peek ( ) == . likeStruct
123+ || functionCalls. peek ( ) == . anonymousClosure
124+ || selfCaptures. peek ( ) == . strong && SwiftVersion . current >= . fiveDotThree
125+ || selfCaptures. peek ( ) == . weak && SwiftVersion . current >= . fiveDotEight
147126 }
148127 }
128+ }
149129
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
130+ private extension TokenSyntax {
131+ var needsEscaping : Bool {
132+ [ UInt8] ( text. utf8) . withUnsafeBufferPointer {
133+ if let keyword = Keyword ( SyntaxText ( baseAddress: $0. baseAddress, count: text. count) ) {
134+ return TokenKind . keyword ( keyword) . isLexerClassifiedKeyword
135+ }
136+ return false
137+ }
160138 }
161139}
0 commit comments