55private import rust
66private import codeql.rust.elements.internal.generated.ParentChild
77
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+
833/**
934 * An item that may be referred to by a path, and which is a node in
1035 * the _item graph_.
@@ -46,11 +71,15 @@ private import codeql.rust.elements.internal.generated.ParentChild
4671 * - https://doc.rust-lang.org/reference/names/scopes.html
4772 * - https://doc.rust-lang.org/reference/paths.html
4873 * - https://doc.rust-lang.org/reference/visibility-and-privacy.html
74+ * - https://doc.rust-lang.org/reference/names/namespaces.html
4975 */
5076abstract class ItemNode extends AstNode {
5177 /** Gets the (original) name of this item. */
5278 abstract string getName ( ) ;
5379
80+ /** Gets the namespace that this item belongs to, if any. */
81+ abstract Namespace getNamespace ( ) ;
82+
5483 /** Gets the visibility of this item, if any. */
5584 abstract Visibility getVisibility ( ) ;
5685
@@ -143,30 +172,44 @@ abstract private class ModuleLikeNode extends ItemNode {
143172private class SourceFileItemNode extends ModuleLikeNode , SourceFile {
144173 override string getName ( ) { result = "(source file)" }
145174
175+ override Namespace getNamespace ( ) {
176+ result .isType ( ) // can be referenced with `super`
177+ }
178+
146179 override Visibility getVisibility ( ) { none ( ) }
147180}
148181
149182private class ConstItemNode extends ItemNode instanceof Const {
150183 override string getName ( ) { result = Const .super .getName ( ) .getText ( ) }
151184
185+ override Namespace getNamespace ( ) { result .isValue ( ) }
186+
152187 override Visibility getVisibility ( ) { result = Const .super .getVisibility ( ) }
153188}
154189
155190private class EnumItemNode extends ItemNode instanceof Enum {
156191 override string getName ( ) { result = Enum .super .getName ( ) .getText ( ) }
157192
193+ override Namespace getNamespace ( ) { result .isType ( ) }
194+
158195 override Visibility getVisibility ( ) { result = Enum .super .getVisibility ( ) }
159196}
160197
161198private class VariantItemNode extends ItemNode instanceof Variant {
162199 override string getName ( ) { result = Variant .super .getName ( ) .getText ( ) }
163200
201+ override Namespace getNamespace ( ) {
202+ if super .getFieldList ( ) instanceof RecordFieldList then result .isType ( ) else result .isValue ( )
203+ }
204+
164205 override Visibility getVisibility ( ) { result = Variant .super .getVisibility ( ) }
165206}
166207
167208private class FunctionItemNode extends ItemNode instanceof Function {
168209 override string getName ( ) { result = Function .super .getName ( ) .getText ( ) }
169210
211+ override Namespace getNamespace ( ) { result .isValue ( ) }
212+
170213 override Visibility getVisibility ( ) { result = Function .super .getVisibility ( ) }
171214}
172215
@@ -184,57 +227,92 @@ abstract private class ImplOrTraitItemNode extends ItemNode {
184227 }
185228}
186229
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+
188233 override string getName ( ) { result = "(impl)" }
189234
235+ override Namespace getNamespace ( ) {
236+ result .isType ( ) // can be referenced with `Self`
237+ }
238+
190239 override Visibility getVisibility ( ) { result = Impl .super .getVisibility ( ) }
191240}
192241
193242private class MacroCallItemNode extends ItemNode instanceof MacroCall {
194243 override string getName ( ) { result = "(macro call)" }
195244
245+ override Namespace getNamespace ( ) { none ( ) }
246+
196247 override Visibility getVisibility ( ) { none ( ) }
197248}
198249
199250private class ModuleItemNode extends ModuleLikeNode instanceof Module {
200251 override string getName ( ) { result = Module .super .getName ( ) .getText ( ) }
201252
253+ override Namespace getNamespace ( ) { result .isType ( ) }
254+
202255 override Visibility getVisibility ( ) { result = Module .super .getVisibility ( ) }
203256}
204257
205258private class StructItemNode extends ItemNode instanceof Struct {
206259 override string getName ( ) { result = Struct .super .getName ( ) .getText ( ) }
207260
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+
208268 override Visibility getVisibility ( ) { result = Struct .super .getVisibility ( ) }
209269}
210270
211- private class TraitItemNode extends ImplOrTraitItemNode instanceof Trait {
271+ class TraitItemNode extends ImplOrTraitItemNode instanceof Trait {
212272 override string getName ( ) { result = Trait .super .getName ( ) .getText ( ) }
213273
274+ override Namespace getNamespace ( ) { result .isType ( ) }
275+
214276 override Visibility getVisibility ( ) { result = Trait .super .getVisibility ( ) }
215277}
216278
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+
217287private class UnionItemNode extends ItemNode instanceof Union {
218288 override string getName ( ) { result = Union .super .getName ( ) .getText ( ) }
219289
290+ override Namespace getNamespace ( ) { result .isType ( ) }
291+
220292 override Visibility getVisibility ( ) { result = Union .super .getVisibility ( ) }
221293}
222294
223295private class UseItemNode extends ItemNode instanceof Use {
224296 override string getName ( ) { result = "(use)" }
225297
298+ override Namespace getNamespace ( ) { none ( ) }
299+
226300 override Visibility getVisibility ( ) { none ( ) }
227301}
228302
229303private class BlockExprItemNode extends ItemNode instanceof BlockExpr {
230304 override string getName ( ) { result = "(block expr)" }
231305
306+ override Namespace getNamespace ( ) { none ( ) }
307+
232308 override Visibility getVisibility ( ) { none ( ) }
233309}
234310
235311private class TypeParamItemNode extends ItemNode instanceof TypeParam {
236312 override string getName ( ) { result = TypeParam .super .getName ( ) .getText ( ) }
237313
314+ override Namespace getNamespace ( ) { result .isType ( ) }
315+
238316 override Visibility getVisibility ( ) { none ( ) }
239317}
240318
@@ -320,19 +398,22 @@ private predicate useTreeDeclares(UseTree tree, string name) {
320398}
321399
322400/**
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.
325404 */
326405pragma [ nomagic]
327- private predicate declares ( ItemNode item , string name ) {
406+ private predicate declares ( ItemNode item , Namespace ns , string name ) {
328407 exists ( ItemNode child | child .getImmediateParent ( ) = item |
329- child .getName ( ) = name
408+ child .getName ( ) = name and
409+ child .getNamespace ( ) = ns
330410 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
332413 )
333414 or
334415 exists ( MacroCallItemNode call |
335- declares ( call , name ) and
416+ declares ( call , ns , name ) and
336417 call .getImmediateParent ( ) = item
337418 )
338419}
@@ -351,19 +432,20 @@ private class RelevantPath extends Path {
351432
352433/**
353434 * 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`.
355436 */
356437pragma [ nomagic]
357- private predicate unqualifiedPathLookup ( RelevantPath p , string name , ItemNode encl ) {
438+ private predicate unqualifiedPathLookup ( RelevantPath p , string name , Namespace ns , ItemNode encl ) {
358439 exists ( ItemNode encl0 |
359440 // lookup in the immediately enclosing item
360441 p .isUnqualified ( name ) and
361- encl0 .getADescendant ( ) = p
442+ encl0 .getADescendant ( ) = p and
443+ exists ( ns )
362444 or
363445 // lookup in an outer scope, but only if the item is not declared in inner scope
364446 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 )
367449 |
368450 // nested modules do not have unqualified access to items from outer modules,
369451 // except for items declared at top-level in the source file
@@ -374,16 +456,30 @@ private predicate unqualifiedPathLookup(RelevantPath p, string name, ItemNode en
374456 |
375457 // functions in `impl` blocks need to use explicit `Self::` to access other
376458 // 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
378462 )
379463}
380464
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
387483 )
388484 or
389485 exists ( ItemNode q , string name |
@@ -394,6 +490,47 @@ ItemNode resolvePath(RelevantPath path) {
394490 result = resolveUseTreeListItem ( _, _, path )
395491}
396492
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+
397534pragma [ nomagic]
398535private ItemNode resolvePathQualifier ( RelevantPath path , string name ) {
399536 result = resolvePath ( path .getQualifier ( ) ) and
@@ -452,14 +589,14 @@ pragma[nomagic]
452589private predicate useImportEdge ( Use use , string name , ItemNode item ) {
453590 exists ( UseTree tree , ItemNode used |
454591 used = resolveUseTreeListItem ( use , tree ) and
455- not exists ( tree .getUseTreeList ( ) ) and
592+ not tree .hasUseTreeList ( ) and
456593 if tree .isGlob ( )
457594 then
458- exists ( ItemNode encl |
595+ exists ( ItemNode encl , Namespace ns |
459596 encl .getADescendant ( ) = use and
460- item = used . getASuccessor ( name ) and
597+ item = getASuccessor ( used , name , ns ) and
461598 // glob imports can be shadowed
462- not declares ( encl , name )
599+ not declares ( encl , ns , name )
463600 )
464601 else item = used
465602 |
0 commit comments