5
5
private import rust
6
6
private import codeql.rust.elements.internal.generated.ParentChild
7
7
8
+ private newtype TNamespace =
9
+ TTypeNamespace ( ) or
10
+ TValueNamespace ( )
11
+
12
+ /**
13
+ * A namespace.
14
+ *
15
+ * Either the _value_ namespace or the _type_ namespace, see
16
+ * https://doc.rust-lang.org/reference/names/namespaces.html.
17
+ */
18
+ final class Namespace extends TNamespace {
19
+ /** Holds if this is the value namespace. */
20
+ predicate isValue ( ) { this = TValueNamespace ( ) }
21
+
22
+ /** Holds if this is the type namespace. */
23
+ predicate isType ( ) { this = TTypeNamespace ( ) }
24
+
25
+ /** Gets a textual representation of this namespace. */
26
+ string toString ( ) {
27
+ this .isValue ( ) and result = "value"
28
+ or
29
+ this .isType ( ) and result = "type"
30
+ }
31
+ }
32
+
8
33
/**
9
34
* An item that may be referred to by a path, and which is a node in
10
35
* the _item graph_.
@@ -46,11 +71,15 @@ private import codeql.rust.elements.internal.generated.ParentChild
46
71
* - https://doc.rust-lang.org/reference/names/scopes.html
47
72
* - https://doc.rust-lang.org/reference/paths.html
48
73
* - https://doc.rust-lang.org/reference/visibility-and-privacy.html
74
+ * - https://doc.rust-lang.org/reference/names/namespaces.html
49
75
*/
50
76
abstract class ItemNode extends AstNode {
51
77
/** Gets the (original) name of this item. */
52
78
abstract string getName ( ) ;
53
79
80
+ /** Gets the namespace that this item belongs to, if any. */
81
+ abstract Namespace getNamespace ( ) ;
82
+
54
83
/** Gets the visibility of this item, if any. */
55
84
abstract Visibility getVisibility ( ) ;
56
85
@@ -143,30 +172,44 @@ abstract private class ModuleLikeNode extends ItemNode {
143
172
private class SourceFileItemNode extends ModuleLikeNode , SourceFile {
144
173
override string getName ( ) { result = "(source file)" }
145
174
175
+ override Namespace getNamespace ( ) {
176
+ result .isType ( ) // can be referenced with `super`
177
+ }
178
+
146
179
override Visibility getVisibility ( ) { none ( ) }
147
180
}
148
181
149
182
private class ConstItemNode extends ItemNode instanceof Const {
150
183
override string getName ( ) { result = Const .super .getName ( ) .getText ( ) }
151
184
185
+ override Namespace getNamespace ( ) { result .isValue ( ) }
186
+
152
187
override Visibility getVisibility ( ) { result = Const .super .getVisibility ( ) }
153
188
}
154
189
155
190
private class EnumItemNode extends ItemNode instanceof Enum {
156
191
override string getName ( ) { result = Enum .super .getName ( ) .getText ( ) }
157
192
193
+ override Namespace getNamespace ( ) { result .isType ( ) }
194
+
158
195
override Visibility getVisibility ( ) { result = Enum .super .getVisibility ( ) }
159
196
}
160
197
161
198
private class VariantItemNode extends ItemNode instanceof Variant {
162
199
override string getName ( ) { result = Variant .super .getName ( ) .getText ( ) }
163
200
201
+ override Namespace getNamespace ( ) {
202
+ if super .getFieldList ( ) instanceof RecordFieldList then result .isType ( ) else result .isValue ( )
203
+ }
204
+
164
205
override Visibility getVisibility ( ) { result = Variant .super .getVisibility ( ) }
165
206
}
166
207
167
208
private class FunctionItemNode extends ItemNode instanceof Function {
168
209
override string getName ( ) { result = Function .super .getName ( ) .getText ( ) }
169
210
211
+ override Namespace getNamespace ( ) { result .isValue ( ) }
212
+
170
213
override Visibility getVisibility ( ) { result = Function .super .getVisibility ( ) }
171
214
}
172
215
@@ -184,57 +227,92 @@ abstract private class ImplOrTraitItemNode extends ItemNode {
184
227
}
185
228
}
186
229
187
- private class ImplItemNode extends ImplOrTraitItemNode instanceof Impl {
230
+ class ImplItemNode extends ImplOrTraitItemNode instanceof Impl {
231
+ ItemNode resolveSelfTy ( ) { result = resolvePath ( super .getSelfTy ( ) .( PathTypeRepr ) .getPath ( ) ) }
232
+
188
233
override string getName ( ) { result = "(impl)" }
189
234
235
+ override Namespace getNamespace ( ) {
236
+ result .isType ( ) // can be referenced with `Self`
237
+ }
238
+
190
239
override Visibility getVisibility ( ) { result = Impl .super .getVisibility ( ) }
191
240
}
192
241
193
242
private class MacroCallItemNode extends ItemNode instanceof MacroCall {
194
243
override string getName ( ) { result = "(macro call)" }
195
244
245
+ override Namespace getNamespace ( ) { none ( ) }
246
+
196
247
override Visibility getVisibility ( ) { none ( ) }
197
248
}
198
249
199
250
private class ModuleItemNode extends ModuleLikeNode instanceof Module {
200
251
override string getName ( ) { result = Module .super .getName ( ) .getText ( ) }
201
252
253
+ override Namespace getNamespace ( ) { result .isType ( ) }
254
+
202
255
override Visibility getVisibility ( ) { result = Module .super .getVisibility ( ) }
203
256
}
204
257
205
258
private class StructItemNode extends ItemNode instanceof Struct {
206
259
override string getName ( ) { result = Struct .super .getName ( ) .getText ( ) }
207
260
261
+ override Namespace getNamespace ( ) {
262
+ result .isType ( ) // the struct itself
263
+ or
264
+ not super .getFieldList ( ) instanceof RecordFieldList and
265
+ result .isValue ( ) // the constructor
266
+ }
267
+
208
268
override Visibility getVisibility ( ) { result = Struct .super .getVisibility ( ) }
209
269
}
210
270
211
- private class TraitItemNode extends ImplOrTraitItemNode instanceof Trait {
271
+ class TraitItemNode extends ImplOrTraitItemNode instanceof Trait {
212
272
override string getName ( ) { result = Trait .super .getName ( ) .getText ( ) }
213
273
274
+ override Namespace getNamespace ( ) { result .isType ( ) }
275
+
214
276
override Visibility getVisibility ( ) { result = Trait .super .getVisibility ( ) }
215
277
}
216
278
279
+ class TypeAliasItemNode extends ItemNode instanceof TypeAlias {
280
+ override string getName ( ) { result = TypeAlias .super .getName ( ) .getText ( ) }
281
+
282
+ override Namespace getNamespace ( ) { result .isType ( ) }
283
+
284
+ override Visibility getVisibility ( ) { result = TypeAlias .super .getVisibility ( ) }
285
+ }
286
+
217
287
private class UnionItemNode extends ItemNode instanceof Union {
218
288
override string getName ( ) { result = Union .super .getName ( ) .getText ( ) }
219
289
290
+ override Namespace getNamespace ( ) { result .isType ( ) }
291
+
220
292
override Visibility getVisibility ( ) { result = Union .super .getVisibility ( ) }
221
293
}
222
294
223
295
private class UseItemNode extends ItemNode instanceof Use {
224
296
override string getName ( ) { result = "(use)" }
225
297
298
+ override Namespace getNamespace ( ) { none ( ) }
299
+
226
300
override Visibility getVisibility ( ) { none ( ) }
227
301
}
228
302
229
303
private class BlockExprItemNode extends ItemNode instanceof BlockExpr {
230
304
override string getName ( ) { result = "(block expr)" }
231
305
306
+ override Namespace getNamespace ( ) { none ( ) }
307
+
232
308
override Visibility getVisibility ( ) { none ( ) }
233
309
}
234
310
235
311
private class TypeParamItemNode extends ItemNode instanceof TypeParam {
236
312
override string getName ( ) { result = TypeParam .super .getName ( ) .getText ( ) }
237
313
314
+ override Namespace getNamespace ( ) { result .isType ( ) }
315
+
238
316
override Visibility getVisibility ( ) { none ( ) }
239
317
}
240
318
@@ -320,19 +398,22 @@ private predicate useTreeDeclares(UseTree tree, string name) {
320
398
}
321
399
322
400
/**
323
- * Holds if `item` explicitly declares a sub item named `name`. This includes
324
- * items declared by `use` statements, except for glob imports.
401
+ * Holds if `item` explicitly declares a sub item named `name` in the
402
+ * namespace `ns`. This includes items declared by `use` statements,
403
+ * except for glob imports.
325
404
*/
326
405
pragma [ nomagic]
327
- private predicate declares ( ItemNode item , string name ) {
406
+ private predicate declares ( ItemNode item , Namespace ns , string name ) {
328
407
exists ( ItemNode child | child .getImmediateParent ( ) = item |
329
- child .getName ( ) = name
408
+ child .getName ( ) = name and
409
+ child .getNamespace ( ) = ns
330
410
or
331
- useTreeDeclares ( child .( Use ) .getUseTree ( ) , name )
411
+ useTreeDeclares ( child .( Use ) .getUseTree ( ) , name ) and
412
+ exists ( ns ) // `use foo::bar` can refer to both a value and a type
332
413
)
333
414
or
334
415
exists ( MacroCallItemNode call |
335
- declares ( call , name ) and
416
+ declares ( call , ns , name ) and
336
417
call .getImmediateParent ( ) = item
337
418
)
338
419
}
@@ -351,19 +432,20 @@ private class RelevantPath extends Path {
351
432
352
433
/**
353
434
* Holds if the unqualified path `p` references an item named `name`, and `name`
354
- * may be looked up inside enclosing item `encl`.
435
+ * may be looked up in the `ns` namespace inside enclosing item `encl`.
355
436
*/
356
437
pragma [ nomagic]
357
- private predicate unqualifiedPathLookup ( RelevantPath p , string name , ItemNode encl ) {
438
+ private predicate unqualifiedPathLookup ( RelevantPath p , string name , Namespace ns , ItemNode encl ) {
358
439
exists ( ItemNode encl0 |
359
440
// lookup in the immediately enclosing item
360
441
p .isUnqualified ( name ) and
361
- encl0 .getADescendant ( ) = p
442
+ encl0 .getADescendant ( ) = p and
443
+ exists ( ns )
362
444
or
363
445
// lookup in an outer scope, but only if the item is not declared in inner scope
364
446
exists ( ItemNode mid |
365
- unqualifiedPathLookup ( p , name , mid ) and
366
- not declares ( mid , name )
447
+ unqualifiedPathLookup ( p , name , ns , mid ) and
448
+ not declares ( mid , ns , name )
367
449
|
368
450
// nested modules do not have unqualified access to items from outer modules,
369
451
// except for items declared at top-level in the source file
@@ -374,16 +456,30 @@ private predicate unqualifiedPathLookup(RelevantPath p, string name, ItemNode en
374
456
|
375
457
// functions in `impl` blocks need to use explicit `Self::` to access other
376
458
// functions in the `impl` block
377
- if encl0 instanceof ImplOrTraitItemNode then encl = encl0 .getImmediateParent ( ) else encl = encl0
459
+ if encl0 instanceof ImplOrTraitItemNode and ns .isValue ( )
460
+ then encl = encl0 .getImmediateParent ( )
461
+ else encl = encl0
378
462
)
379
463
}
380
464
381
- /** Gets the item that `path` resolves to, if any. */
382
- cached
383
- ItemNode resolvePath ( RelevantPath path ) {
384
- exists ( ItemNode encl , string name |
385
- unqualifiedPathLookup ( path , name , encl ) and
386
- result = encl .getASuccessor ( name )
465
+ pragma [ nomagic]
466
+ private ItemNode getASuccessor ( ItemNode pred , string name , Namespace ns ) {
467
+ result = pred .getASuccessor ( name ) and
468
+ ns = result .getNamespace ( )
469
+ }
470
+
471
+ pragma [ nomagic]
472
+ private ItemNode resolvePath0 ( RelevantPath path ) {
473
+ exists ( ItemNode encl , Namespace ns , string name , ItemNode res |
474
+ unqualifiedPathLookup ( path , name , ns , encl ) and
475
+ res = getASuccessor ( encl , name , ns )
476
+ |
477
+ if
478
+ not any ( RelevantPath parent ) .getQualifier ( ) = path and
479
+ name = "Self" and
480
+ res instanceof ImplItemNode
481
+ then result = res .( ImplItemNode ) .resolveSelfTy ( )
482
+ else result = res
387
483
)
388
484
or
389
485
exists ( ItemNode q , string name |
@@ -394,6 +490,47 @@ ItemNode resolvePath(RelevantPath path) {
394
490
result = resolveUseTreeListItem ( _, _, path )
395
491
}
396
492
493
+ /** Holds if path `p` must be looked up in namespace `n`. */
494
+ private predicate pathUsesNamespace ( Path p , Namespace n ) {
495
+ n .isValue ( ) and
496
+ (
497
+ p = any ( PathExpr pe ) .getPath ( )
498
+ or
499
+ p = any ( TupleStructPat tsp ) .getPath ( )
500
+ )
501
+ or
502
+ n .isType ( ) and
503
+ (
504
+ p = any ( Visibility v ) .getPath ( )
505
+ or
506
+ p = any ( RecordExpr re ) .getPath ( )
507
+ or
508
+ p = any ( PathTypeRepr ptr ) .getPath ( )
509
+ or
510
+ p = any ( RecordPat rp ) .getPath ( )
511
+ or
512
+ p =
513
+ any ( UseTree use |
514
+ use .isGlob ( )
515
+ or
516
+ use .hasUseTreeList ( )
517
+ ) .getPath ( )
518
+ or
519
+ p = any ( Path parent ) .getQualifier ( )
520
+ )
521
+ }
522
+
523
+ /** Gets the item that `path` resolves to, if any. */
524
+ cached
525
+ ItemNode resolvePath ( RelevantPath path ) {
526
+ result = resolvePath0 ( path ) and
527
+ (
528
+ pathUsesNamespace ( path , result .getNamespace ( ) )
529
+ or
530
+ not pathUsesNamespace ( path , _)
531
+ )
532
+ }
533
+
397
534
pragma [ nomagic]
398
535
private ItemNode resolvePathQualifier ( RelevantPath path , string name ) {
399
536
result = resolvePath ( path .getQualifier ( ) ) and
@@ -452,14 +589,14 @@ pragma[nomagic]
452
589
private predicate useImportEdge ( Use use , string name , ItemNode item ) {
453
590
exists ( UseTree tree , ItemNode used |
454
591
used = resolveUseTreeListItem ( use , tree ) and
455
- not exists ( tree .getUseTreeList ( ) ) and
592
+ not tree .hasUseTreeList ( ) and
456
593
if tree .isGlob ( )
457
594
then
458
- exists ( ItemNode encl |
595
+ exists ( ItemNode encl , Namespace ns |
459
596
encl .getADescendant ( ) = use and
460
- item = used . getASuccessor ( name ) and
597
+ item = getASuccessor ( used , name , ns ) and
461
598
// glob imports can be shadowed
462
- not declares ( encl , name )
599
+ not declares ( encl , ns , name )
463
600
)
464
601
else item = used
465
602
|
0 commit comments