12
12
13
13
import SwiftSyntax
14
14
15
+ /// An entity that is implicitly declared based on the syntactic structure of the program.
16
+ @_spi ( Experimental) public enum ImplicitDecl {
17
+ /// `self` keyword representing object instance.
18
+ /// Could be associated with type declaration, extension,
19
+ /// or closure captures.
20
+ case `self`( DeclSyntaxProtocol )
21
+ /// `Self` keyword representing object type.
22
+ /// Could be associated with type declaration or extension.
23
+ case `Self`( DeclSyntaxProtocol )
24
+ /// `error` value caught by a `catch`
25
+ /// block that does not specify a catch pattern.
26
+ case error( CatchClauseSyntax )
27
+ /// `newValue` available by default inside `set` and `willSet`.
28
+ case newValue( AccessorDeclSyntax )
29
+ /// `oldValue` available by default inside `didSet`.
30
+ case oldValue( AccessorDeclSyntax )
31
+
32
+ /// Syntax associated with this name.
33
+ @_spi ( Experimental) public var syntax : SyntaxProtocol {
34
+ switch self {
35
+ case . self ( let syntax) :
36
+ return syntax
37
+ case . Self( let syntax) :
38
+ return syntax
39
+ case . error( let syntax) :
40
+ return syntax
41
+ case . newValue( let syntax) :
42
+ return syntax
43
+ case . oldValue( let syntax) :
44
+ return syntax
45
+ }
46
+ }
47
+
48
+ /// The name of the implicit declaration.
49
+ private var name : String {
50
+ switch self {
51
+ case . self :
52
+ return " self "
53
+ case . Self:
54
+ return " Self "
55
+ case . error:
56
+ return " error "
57
+ case . newValue:
58
+ return " newValue "
59
+ case . oldValue:
60
+ return " oldValue "
61
+ }
62
+ }
63
+
64
+ /// Identifier used for name comparison.
65
+ ///
66
+ /// Note that `self` and `Self` are treated as identifiers for name lookup purposes
67
+ /// and that a variable named `self` can shadow the `self` keyword. For example.
68
+ /// ```swift
69
+ /// class Foo {
70
+ /// func test() {
71
+ /// let `Self` = "abc"
72
+ /// print(Self.self)
73
+ ///
74
+ /// let `self` = "def"
75
+ /// print(self)
76
+ /// }
77
+ /// }
78
+ ///
79
+ /// Foo().test()
80
+ /// ```
81
+ /// prints:
82
+ /// ```
83
+ /// abc
84
+ /// def
85
+ /// ```
86
+ /// `self` and `Self` identifers override implicit `self` and `Self` introduced by
87
+ /// the `Foo` class declaration.
88
+ var identifier : Identifier {
89
+ switch self {
90
+ case . self :
91
+ return Identifier ( " self " )
92
+ case . Self:
93
+ return Identifier ( " Self " )
94
+ case . error:
95
+ return Identifier ( " error " )
96
+ case . newValue:
97
+ return Identifier ( " newValue " )
98
+ case . oldValue:
99
+ return Identifier ( " oldValue " )
100
+ }
101
+ }
102
+ }
103
+
15
104
@_spi ( Experimental) public enum LookupName {
16
105
/// Identifier associated with the name.
17
106
/// Could be an identifier of a variable, function or closure parameter and more.
18
107
case identifier( IdentifiableSyntax , accessibleAfter: AbsolutePosition ? )
19
108
/// Declaration associated with the name.
20
109
/// Could be class, struct, actor, protocol, function and more.
21
110
case declaration( NamedDeclSyntax )
111
+ /// Name introduced implicitly by certain syntax nodes.
112
+ case implicit( ImplicitDecl )
113
+ /// Explicit `self` keyword.
114
+ case `self`( IdentifiableSyntax , accessibleAfter: AbsolutePosition ? )
115
+ /// Explicit `Self` keyword.
116
+ case `Self`( IdentifiableSyntax , accessibleAfter: AbsolutePosition ? )
22
117
23
118
/// Syntax associated with this name.
24
119
@_spi ( Experimental) public var syntax : SyntaxProtocol {
@@ -27,40 +122,52 @@ import SwiftSyntax
27
122
return syntax
28
123
case . declaration( let syntax) :
29
124
return syntax
125
+ case . implicit( let implicitName) :
126
+ return implicitName. syntax
127
+ case . self ( let syntax, _) , . Self( let syntax, _) :
128
+ return syntax
30
129
}
31
130
}
32
131
33
- /// Introduced name.
132
+ /// Identifier used for name comparison .
34
133
@_spi ( Experimental) public var identifier : Identifier ? {
35
134
switch self {
36
135
case . identifier( let syntax, _) :
37
136
return Identifier ( syntax. identifier)
38
137
case . declaration( let syntax) :
39
138
return Identifier ( syntax. name)
139
+ case . implicit( let kind) :
140
+ return kind. identifier
141
+ case . self :
142
+ return Identifier ( " self " )
143
+ case . Self:
144
+ return Identifier ( " Self " )
40
145
}
41
146
}
42
147
43
148
/// Point, after which the name is available in scope.
44
149
/// If set to `nil`, the name is available at any point in scope.
45
150
var accessibleAfter : AbsolutePosition ? {
46
151
switch self {
47
- case . identifier( _, let absolutePosition) :
152
+ case . identifier( _, let absolutePosition) ,
153
+ . self ( _, let absolutePosition) ,
154
+ . Self( _, let absolutePosition) :
48
155
return absolutePosition
49
156
default :
50
157
return nil
51
158
}
52
159
}
53
160
54
161
/// Checks if this name was introduced before the syntax used for lookup.
55
- func isAccessible( at lookedUpSyntax : SyntaxProtocol ) -> Bool {
162
+ func isAccessible( at origin : AbsolutePosition ) -> Bool {
56
163
guard let accessibleAfter else { return true }
57
- return accessibleAfter <= lookedUpSyntax . position
164
+ return accessibleAfter <= origin
58
165
}
59
166
60
167
/// Checks if this name refers to the looked up phrase.
61
- func refersTo( _ lookedUpName : String ) -> Bool {
62
- guard let name = identifier? . name else { return false }
63
- return name == lookedUpName
168
+ func refersTo( _ lookedUpIdentifier : Identifier ) -> Bool {
169
+ guard let identifier else { return false }
170
+ return identifier == lookedUpIdentifier
64
171
}
65
172
66
173
/// Extracts names introduced by the given `syntax` structure.
@@ -105,10 +212,6 @@ import SwiftSyntax
105
212
return functionCallExpr. arguments. flatMap { argument in
106
213
getNames ( from: argument. expression, accessibleAfter: accessibleAfter)
107
214
}
108
- case . guardStmt( let guardStmt) :
109
- return guardStmt. conditions. flatMap { cond in
110
- getNames ( from: cond. condition, accessibleAfter: cond. endPosition)
111
- }
112
215
default :
113
216
if let namedDecl = Syntax ( syntax) . asProtocol ( SyntaxProtocol . self) as? NamedDeclSyntax {
114
217
return handle ( namedDecl: namedDecl, accessibleAfter: accessibleAfter)
@@ -121,12 +224,21 @@ import SwiftSyntax
121
224
}
122
225
123
226
/// Extracts name introduced by `IdentifiableSyntax` node.
124
- private static func handle( identifiable: IdentifiableSyntax , accessibleAfter: AbsolutePosition ? = nil ) -> [ LookupName ]
125
- {
126
- if identifiable. identifier. tokenKind != . wildcard {
127
- return [ . identifier( identifiable, accessibleAfter: accessibleAfter) ]
128
- } else {
129
- return [ ]
227
+ private static func handle(
228
+ identifiable: IdentifiableSyntax ,
229
+ accessibleAfter: AbsolutePosition ? = nil
230
+ ) -> [ LookupName ] {
231
+ switch identifiable. identifier. tokenKind {
232
+ case . keyword( . self ) :
233
+ return [ . self ( identifiable, accessibleAfter: accessibleAfter) ]
234
+ case . keyword( . Self) :
235
+ return [ . Self( identifiable, accessibleAfter: accessibleAfter) ]
236
+ default :
237
+ if identifiable. identifier. tokenKind != . wildcard {
238
+ return [ . identifier( identifiable, accessibleAfter: accessibleAfter) ]
239
+ } else {
240
+ return [ ]
241
+ }
130
242
}
131
243
}
132
244
0 commit comments