@@ -73,7 +73,7 @@ final class Namespace extends TNamespace {
7373 * - https://doc.rust-lang.org/reference/visibility-and-privacy.html
7474 * - https://doc.rust-lang.org/reference/names/namespaces.html
7575 */
76- abstract class ItemNode extends AstNode {
76+ abstract class ItemNode extends Locatable {
7777 /** Gets the (original) name of this item. */
7878 abstract string getName ( ) ;
7979
@@ -109,7 +109,11 @@ abstract class ItemNode extends AstNode {
109109
110110 /** Gets the immediately enclosing module (or source file) of this item. */
111111 pragma [ nomagic]
112- ModuleLikeNode getImmediateParentModule ( ) { this = result .getAnItemInScope ( ) }
112+ ModuleLikeNode getImmediateParentModule ( ) {
113+ this = result .getAnItemInScope ( )
114+ or
115+ result = this .( SourceFileItemNode ) .getSuper ( )
116+ }
113117
114118 pragma [ nomagic]
115119 private ItemNode getASuccessorRec ( string name ) {
@@ -122,6 +126,10 @@ abstract class ItemNode extends AstNode {
122126 or
123127 useImportEdge ( this , name , result )
124128 or
129+ crateDefEdge ( this , name , result )
130+ or
131+ crateDependencyEdge ( this , name , result )
132+ or
125133 // items made available through `use` are available to nodes that contain the `use`
126134 exists ( UseItemNode use |
127135 use = this .getASuccessorRec ( _) and
@@ -168,19 +176,18 @@ abstract class ItemNode extends AstNode {
168176 result = this .getASuccessorRec ( name )
169177 or
170178 name = "super" and
171- if this instanceof Module
179+ if this instanceof Module or this instanceof SourceFile
172180 then result = this .getImmediateParentModule ( )
173181 else result = this .getImmediateParentModule ( ) .getImmediateParentModule ( )
174182 or
175183 name = "self" and
176- not this instanceof Module and
177- result = this .getImmediateParentModule ( )
184+ if this instanceof Module then result = this else result = this .getImmediateParentModule ( )
178185 or
179186 name = "Self" and
180187 this = result .( ImplOrTraitItemNode ) .getAnItemInSelfScope ( )
181188 or
182189 name = "crate" and
183- result .( SourceFileItemNode ) . getFile ( ) = this . getFile ( )
190+ this = result .( CrateItemNode ) . getASourceFile ( )
184191 }
185192
186193 /** Gets the location of this item. */
@@ -203,6 +210,11 @@ abstract private class ModuleLikeNode extends ItemNode {
203210}
204211
205212private class SourceFileItemNode extends ModuleLikeNode , SourceFile {
213+ pragma [ nomagic]
214+ ModuleLikeNode getSuper ( ) {
215+ result = any ( ModuleItemNode mod | fileImport ( mod , this ) ) .getASuccessor ( "super" )
216+ }
217+
206218 override string getName ( ) { result = "(source file)" }
207219
208220 override Namespace getNamespace ( ) {
@@ -211,6 +223,55 @@ private class SourceFileItemNode extends ModuleLikeNode, SourceFile {
211223
212224 override Visibility getVisibility ( ) { none ( ) }
213225
226+ override predicate isPublic ( ) { any ( ) }
227+
228+ override TypeParam getTypeParam ( int i ) { none ( ) }
229+ }
230+
231+ class CrateItemNode extends ItemNode instanceof Crate {
232+ /**
233+ * Gets the module node that defines this crate.
234+ *
235+ * This is either a source file, when the crate is defined in source code,
236+ * or a module, when the crate is defined in a dependency.
237+ */
238+ pragma [ nomagic]
239+ ModuleLikeNode getModuleNode ( ) {
240+ result = super .getSourceFile ( )
241+ or
242+ not exists ( super .getSourceFile ( ) ) and
243+ result = super .getModule ( )
244+ }
245+
246+ /**
247+ * Gets a source file that belongs to this crate, if any.
248+ *
249+ * This is calculated as those source files that can be reached from the entry
250+ * file of this crate using zero or more `mod` imports, without going through
251+ * the entry point of some other crate.
252+ */
253+ pragma [ nomagic]
254+ SourceFileItemNode getASourceFile ( ) {
255+ result = super .getSourceFile ( )
256+ or
257+ exists ( SourceFileItemNode mid , Module mod |
258+ mid = this .getASourceFile ( ) and
259+ mod .getFile ( ) = mid .getFile ( ) and
260+ fileImport ( mod , result ) and
261+ not result = any ( Crate other ) .getSourceFile ( )
262+ )
263+ }
264+
265+ override string getName ( ) { result = Crate .super .getName ( ) }
266+
267+ override Namespace getNamespace ( ) {
268+ result .isType ( ) // can be referenced with `crate`
269+ }
270+
271+ override Visibility getVisibility ( ) { none ( ) }
272+
273+ override predicate isPublic ( ) { any ( ) }
274+
214275 override TypeParam getTypeParam ( int i ) { none ( ) }
215276}
216277
@@ -460,7 +521,7 @@ private class UseItemNode extends ItemNode instanceof Use {
460521
461522 override Namespace getNamespace ( ) { none ( ) }
462523
463- override Visibility getVisibility ( ) { none ( ) }
524+ override Visibility getVisibility ( ) { result = Use . super . getVisibility ( ) }
464525
465526 override TypeParam getTypeParam ( int i ) { none ( ) }
466527}
@@ -586,11 +647,33 @@ private predicate fileImport(Module m, SourceFile f) {
586647 * Holds if `mod` is a `mod name;` item targeting a file resulting in `item` being
587648 * in scope under the name `name`.
588649 */
650+ pragma [ nomagic]
589651private predicate fileImportEdge ( Module mod , string name , ItemNode item ) {
590- item .isPublic ( ) and
591- exists ( SourceFile f |
652+ exists ( SourceFileItemNode f |
592653 fileImport ( mod , f ) and
593- sourceFileEdge ( f , name , item )
654+ item = f .getASuccessor ( name )
655+ )
656+ }
657+
658+ /**
659+ * Holds if crate `c` defines the item `i` named `name`.
660+ */
661+ pragma [ nomagic]
662+ private predicate crateDefEdge ( CrateItemNode c , string name , ItemNode i ) {
663+ i = c .getModuleNode ( ) .getASuccessor ( name ) and
664+ not i instanceof Crate
665+ }
666+
667+ /**
668+ * Holds if `m` depends on crate `dep` named `name`.
669+ */
670+ private predicate crateDependencyEdge ( ModuleLikeNode m , string name , CrateItemNode dep ) {
671+ exists ( CrateItemNode c | dep = c .( Crate ) .getDependency ( name ) |
672+ // entry module/entry source file
673+ m = c .getModuleNode ( )
674+ or
675+ // entry/transitive source file
676+ m = c .getASourceFile ( )
594677 )
595678}
596679
@@ -745,13 +828,53 @@ private predicate pathUsesNamespace(Path p, Namespace n) {
745828 )
746829}
747830
748- /** Gets the item that `path` resolves to, if any. */
749- cached
750- ItemNode resolvePath ( RelevantPath path ) {
831+ pragma [ nomagic]
832+ private ItemNode resolvePath1 ( RelevantPath path ) {
751833 exists ( Namespace ns | result = resolvePath0 ( path , ns ) |
752834 pathUsesNamespace ( path , ns )
753835 or
754- not pathUsesNamespace ( path , _)
836+ not pathUsesNamespace ( path , _) and
837+ not path = any ( MacroCall mc ) .getPath ( )
838+ )
839+ }
840+
841+ pragma [ nomagic]
842+ private ItemNode resolvePathPrivate (
843+ RelevantPath path , ModuleLikeNode itemParent , ModuleLikeNode pathParent
844+ ) {
845+ result = resolvePath1 ( path ) and
846+ itemParent = result .getImmediateParentModule ( ) and
847+ not result .isPublic ( ) and
848+ (
849+ pathParent .getADescendant ( ) = path
850+ or
851+ pathParent = any ( ItemNode mid | path = mid .getADescendant ( ) ) .getImmediateParentModule ( )
852+ )
853+ }
854+
855+ /**
856+ * Gets a module that has access to private items defined inside `itemParent`.
857+ *
858+ * According to [The Rust Reference][1] this is either `itemParent` itself or any
859+ * descendant of `itemParent`.
860+ *
861+ * [1]: https://doc.rust-lang.org/reference/visibility-and-privacy.html#r-vis.access
862+ */
863+ pragma [ nomagic]
864+ private ModuleLikeNode getAPrivateVisibleModule ( ModuleLikeNode itemParent ) {
865+ exists ( resolvePathPrivate ( _, itemParent , _) ) and
866+ result .getImmediateParentModule * ( ) = itemParent
867+ }
868+
869+ /** Gets the item that `path` resolves to, if any. */
870+ cached
871+ ItemNode resolvePath ( RelevantPath path ) {
872+ result = resolvePath1 ( path ) and
873+ result .isPublic ( )
874+ or
875+ exists ( ModuleLikeNode itemParent , ModuleLikeNode pathParent |
876+ result = resolvePathPrivate ( path , itemParent , pathParent ) and
877+ pathParent = getAPrivateVisibleModule ( itemParent )
755878 )
756879}
757880
@@ -831,3 +954,44 @@ private predicate useImportEdge(Use use, string name, ItemNode item) {
831954 name != "_"
832955 )
833956}
957+
958+ /** Provides predicates for debugging the path resolution implementation. */
959+ private module Debug {
960+ private Locatable getRelevantLocatable ( ) {
961+ exists ( string filepath , int startline , int startcolumn , int endline , int endcolumn |
962+ result .getLocation ( ) .hasLocationInfo ( filepath , startline , startcolumn , endline , endcolumn ) and
963+ filepath .matches ( "%/main.rs" ) and
964+ startline = 1
965+ )
966+ }
967+
968+ predicate debugUnqualifiedPathLookup ( RelevantPath p , string name , Namespace ns , ItemNode encl ) {
969+ p = getRelevantLocatable ( ) and
970+ unqualifiedPathLookup ( p , name , ns , encl )
971+ }
972+
973+ ItemNode debugResolvePath ( RelevantPath path ) {
974+ path = getRelevantLocatable ( ) and
975+ result = resolvePath ( path )
976+ }
977+
978+ predicate debugUseImportEdge ( Use use , string name , ItemNode item ) {
979+ use = getRelevantLocatable ( ) and
980+ useImportEdge ( use , name , item )
981+ }
982+
983+ ItemNode debugGetASuccessorRec ( ItemNode i , string name ) {
984+ i = getRelevantLocatable ( ) and
985+ result = i .getASuccessor ( name )
986+ }
987+
988+ predicate debugFileImportEdge ( Module mod , string name , ItemNode item ) {
989+ mod = getRelevantLocatable ( ) and
990+ fileImportEdge ( mod , name , item )
991+ }
992+
993+ predicate debugFileImport ( Module m , SourceFile f ) {
994+ m = getRelevantLocatable ( ) and
995+ fileImport ( m , f )
996+ }
997+ }
0 commit comments