@@ -24,12 +24,34 @@ extension SyntaxProtocol {
24
24
}
25
25
26
26
@_spi ( Experimental) extension SourceFileSyntax : ScopeSyntax {
27
+ /// All names introduced in the file scope
28
+ /// according to the default strategy: `memberBlockUpToLastDecl`.
27
29
public var introducedNames : [ LookupName ] {
28
30
introducedNames ( using: . memberBlockUpToLastDecl)
29
31
}
30
32
31
- public func introducedNames( using nameIntroductionStrategy: FileScopeNameIntroductionStrategy ) -> [ LookupName ] {
32
- switch nameIntroductionStrategy {
33
+ /// All names introduced in the file scope
34
+ /// using the provided configuration.
35
+ ///
36
+ /// Example usage:
37
+ /// ```swift
38
+ /// class a {}
39
+ /// class b {
40
+ /// // <--
41
+ /// }
42
+ /// let c = 0
43
+ /// class d {}
44
+ /// if true {}
45
+ /// class e {}
46
+ /// let f = 0
47
+ /// ```
48
+ /// During lookup, according to different configurations,
49
+ /// names available at the marked place are:
50
+ /// - for `fileScopeNameIntroductionStrategy` - a, b, c, d
51
+ /// - for `memberBlock` - a, b, c, d, e, f
52
+ /// - for `codeBlock` - a
53
+ public func introducedNames( using fileScopeHandling: FileScopeHandlingConfig ) -> [ LookupName ] {
54
+ switch fileScopeHandling {
33
55
case . memberBlockUpToLastDecl:
34
56
var encounteredNonDeclaration = false
35
57
@@ -58,24 +80,43 @@ extension SyntaxProtocol {
58
80
}
59
81
}
60
82
83
+ /// Returns names matching lookup using provided file
84
+ /// scope handling configuration (by default: `memberBlockUpToLastDecl`).
85
+ ///
86
+ /// Example usage:
87
+ /// ```swift
88
+ /// class a {}
89
+ /// class b {
90
+ /// // <--
91
+ /// }
92
+ /// let c = 0
93
+ /// class d {}
94
+ /// if true {}
95
+ /// class e {}
96
+ /// let f = 0
97
+ /// ```
98
+ /// According to different configurations,
99
+ /// names available at the marked place are:
100
+ /// - for `fileScopeNameIntroductionStrategy` - a, b, c, d
101
+ /// - for `memberBlock` - a, b, c, d, e, f
102
+ /// - for `codeBlock` - a
61
103
public func lookup(
62
104
for name: String ? ,
63
105
at syntax: SyntaxProtocol ,
64
- with configDict : LookupConfigDictionary
106
+ with config : LookupConfig
65
107
) -> [ LookupResult ] {
66
- let nameIntroductionStrategy = configDict [ FileScopeNameIntroductionStrategy . self] ?? . memberBlockUpToLastDecl
67
-
68
- let names = introducedNames ( using: nameIntroductionStrategy)
108
+ let names = introducedNames ( using: config. fileScopeHandling)
69
109
. filter { introducedName in
70
110
does ( name: name, referTo: introducedName, at: syntax)
71
111
}
72
112
73
- return names. isEmpty
74
- ? [ ] : [ . fromFileScope( self , withNames: names, nameIntroductionStrategy: nameIntroductionStrategy) ]
113
+ return names. isEmpty ? [ ] : [ . fromFileScope( self , withNames: names) ]
75
114
}
76
115
}
77
116
78
117
@_spi ( Experimental) extension CodeBlockSyntax : ScopeSyntax {
118
+ /// Names introduced in the code block scope
119
+ /// accessible after their declaration.
79
120
public var introducedNames : [ LookupName ] {
80
121
statements. flatMap { codeBlockItem in
81
122
LookupName . getNames ( from: codeBlockItem. item, accessibleAfter: codeBlockItem. endPosition)
@@ -123,12 +164,24 @@ extension SyntaxProtocol {
123
164
}
124
165
125
166
@_spi ( Experimental) extension ForStmtSyntax : ScopeSyntax {
167
+ /// Names introduced in the `for` body.
126
168
public var introducedNames : [ LookupName ] {
127
169
LookupName . getNames ( from: pattern)
128
170
}
129
171
}
130
172
131
173
@_spi ( Experimental) extension ClosureExprSyntax : ScopeSyntax {
174
+ /// All names introduced by the closure signature.
175
+ /// Could be closure captures or (shorthand) parameters.
176
+ ///
177
+ /// Example:
178
+ /// ```swift
179
+ /// let x = { [weak self, a] b, _ in
180
+ /// // <--
181
+ /// }
182
+ /// ```
183
+ /// During lookup, names available at the marked place are:
184
+ /// `self`, a, b.
132
185
public var introducedNames : [ LookupName ] {
133
186
let captureNames =
134
187
signature? . capture? . children ( viewMode: . sourceAccurate) . flatMap { child in
@@ -157,6 +210,7 @@ extension SyntaxProtocol {
157
210
}
158
211
159
212
@_spi ( Experimental) extension WhileStmtSyntax : ScopeSyntax {
213
+ /// Names introduced by the `while` loop by its conditions.
160
214
public var introducedNames : [ LookupName ] {
161
215
conditions. flatMap { element in
162
216
LookupName . getNames ( from: element. condition)
@@ -165,11 +219,28 @@ extension SyntaxProtocol {
165
219
}
166
220
167
221
@_spi ( Experimental) extension IfExprSyntax : ScopeSyntax {
222
+ /// Parent scope, omitting ancestor `if` statements if part of their `else if` clause.
168
223
public var parentScope : ScopeSyntax ? {
169
224
getParent ( for: self . parent, previousIfElse: self . elseKeyword == nil )
170
225
}
171
226
172
- /// Finds the parent scope, omitting parent `if` statements if part of their `else if` clause.
227
+ /// Finds parent scope, omitting ancestor `if` statements if part of their `else if` clause.
228
+ ///
229
+ /// Example:
230
+ /// ```swift
231
+ /// func foo() {
232
+ /// if let a = x {
233
+ /// // <--
234
+ /// } else if let b {
235
+ /// // <--
236
+ /// } else if y == 1 {
237
+ /// // <--
238
+ /// }
239
+ /// }
240
+ /// ```
241
+ /// For each of the marked scopes, resulting parent
242
+ /// is the enclosing code block scope associated with
243
+ /// the function body.
173
244
private func getParent( for syntax: Syntax ? , previousIfElse: Bool ) -> ScopeSyntax ? {
174
245
guard let syntax else { return nil }
175
246
@@ -184,26 +255,40 @@ extension SyntaxProtocol {
184
255
}
185
256
}
186
257
258
+ /// Names introduced by the `if` optional binding conditions.
187
259
public var introducedNames : [ LookupName ] {
188
260
conditions. flatMap { element in
189
261
LookupName . getNames ( from: element. condition, accessibleAfter: element. endPosition)
190
262
}
191
263
}
192
264
265
+ /// Returns names matching lookup.
266
+ /// Lookup triggered from inside of `else`
267
+ /// clause is immediately forwarded to parent scope.
268
+ ///
269
+ /// Example:
270
+ /// ```swift
271
+ /// if let a = x {
272
+ /// // <-- a is visible here
273
+ /// } else {
274
+ /// // <-- a is not visible here
275
+ /// }
276
+ /// ```
193
277
public func lookup(
194
278
for name: String ? ,
195
279
at syntax: SyntaxProtocol ,
196
- with configDict : LookupConfigDictionary
280
+ with config : LookupConfig
197
281
) -> [ LookupResult ] {
198
282
if let elseBody, elseBody. position <= syntax. position, elseBody. endPosition >= syntax. position {
199
- lookupInParent ( for: name, at: syntax, with: configDict )
283
+ lookupInParent ( for: name, at: syntax, with: config )
200
284
} else {
201
- defaultLookupImplementation ( for: name, at: syntax, with: configDict )
285
+ defaultLookupImplementation ( for: name, at: syntax, with: config )
202
286
}
203
287
}
204
288
}
205
289
206
290
@_spi ( Experimental) extension MemberBlockSyntax : ScopeSyntax {
291
+ /// All names introduced by members of this member scope.
207
292
public var introducedNames : [ LookupName ] {
208
293
members. flatMap { member in
209
294
LookupName . getNames ( from: member. decl)
@@ -230,15 +315,26 @@ extension SyntaxProtocol {
230
315
[ ]
231
316
}
232
317
318
+ /// Returns names matching lookup.
319
+ /// Lookup triggered from inside of `else`
320
+ /// clause is immediately forwarded to parent scope.
321
+ ///
322
+ /// Example:
323
+ /// ```swift
324
+ /// guard let a = x else {
325
+ /// return // a is not visible here
326
+ /// }
327
+ /// // a is visible here
328
+ /// ```
233
329
public func lookup(
234
330
for name: String ? ,
235
331
at syntax: SyntaxProtocol ,
236
- with configDict : LookupConfigDictionary
332
+ with config : LookupConfig
237
333
) -> [ LookupResult ] {
238
334
if body. position <= syntax. position && body. endPosition >= syntax. position {
239
- lookupInParent ( for: name, at: self , with: configDict ) // Should we add a new config that will skip certain scopes in lookup? Could be more consistent.
335
+ lookupInParent ( for: name, at: self , with: config)
240
336
} else {
241
- defaultLookupImplementation ( for: name, at: syntax, with: configDict )
337
+ defaultLookupImplementation ( for: name, at: syntax, with: config )
242
338
}
243
339
}
244
340
}
0 commit comments