@@ -73,7 +73,7 @@ final class Namespace extends TNamespace {
73
73
* - https://doc.rust-lang.org/reference/visibility-and-privacy.html
74
74
* - https://doc.rust-lang.org/reference/names/namespaces.html
75
75
*/
76
- abstract class ItemNode extends AstNode {
76
+ abstract class ItemNode extends Locatable {
77
77
/** Gets the (original) name of this item. */
78
78
abstract string getName ( ) ;
79
79
@@ -109,7 +109,11 @@ abstract class ItemNode extends AstNode {
109
109
110
110
/** Gets the immediately enclosing module (or source file) of this item. */
111
111
pragma [ nomagic]
112
- ModuleLikeNode getImmediateParentModule ( ) { this = result .getAnItemInScope ( ) }
112
+ ModuleLikeNode getImmediateParentModule ( ) {
113
+ this = result .getAnItemInScope ( )
114
+ or
115
+ result = this .( SourceFileItemNode ) .getSuper ( )
116
+ }
113
117
114
118
pragma [ nomagic]
115
119
private ItemNode getASuccessorRec ( string name ) {
@@ -122,6 +126,10 @@ abstract class ItemNode extends AstNode {
122
126
or
123
127
useImportEdge ( this , name , result )
124
128
or
129
+ crateDefEdge ( this , name , result )
130
+ or
131
+ crateDependencyEdge ( this , name , result )
132
+ or
125
133
// items made available through `use` are available to nodes that contain the `use`
126
134
exists ( UseItemNode use |
127
135
use = this .getASuccessorRec ( _) and
@@ -168,19 +176,18 @@ abstract class ItemNode extends AstNode {
168
176
result = this .getASuccessorRec ( name )
169
177
or
170
178
name = "super" and
171
- if this instanceof Module
179
+ if this instanceof Module or this instanceof SourceFile
172
180
then result = this .getImmediateParentModule ( )
173
181
else result = this .getImmediateParentModule ( ) .getImmediateParentModule ( )
174
182
or
175
183
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 ( )
178
185
or
179
186
name = "Self" and
180
187
this = result .( ImplOrTraitItemNode ) .getAnItemInSelfScope ( )
181
188
or
182
189
name = "crate" and
183
- result .( SourceFileItemNode ) . getFile ( ) = this . getFile ( )
190
+ this = result .( CrateItemNode ) . getASourceFile ( )
184
191
}
185
192
186
193
/** Gets the location of this item. */
@@ -203,6 +210,11 @@ abstract private class ModuleLikeNode extends ItemNode {
203
210
}
204
211
205
212
private class SourceFileItemNode extends ModuleLikeNode , SourceFile {
213
+ pragma [ nomagic]
214
+ ModuleLikeNode getSuper ( ) {
215
+ result = any ( ModuleItemNode mod | fileImport ( mod , this ) ) .getASuccessor ( "super" )
216
+ }
217
+
206
218
override string getName ( ) { result = "(source file)" }
207
219
208
220
override Namespace getNamespace ( ) {
@@ -211,6 +223,55 @@ private class SourceFileItemNode extends ModuleLikeNode, SourceFile {
211
223
212
224
override Visibility getVisibility ( ) { none ( ) }
213
225
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
+
214
275
override TypeParam getTypeParam ( int i ) { none ( ) }
215
276
}
216
277
@@ -460,7 +521,7 @@ private class UseItemNode extends ItemNode instanceof Use {
460
521
461
522
override Namespace getNamespace ( ) { none ( ) }
462
523
463
- override Visibility getVisibility ( ) { none ( ) }
524
+ override Visibility getVisibility ( ) { result = Use . super . getVisibility ( ) }
464
525
465
526
override TypeParam getTypeParam ( int i ) { none ( ) }
466
527
}
@@ -586,11 +647,33 @@ private predicate fileImport(Module m, SourceFile f) {
586
647
* Holds if `mod` is a `mod name;` item targeting a file resulting in `item` being
587
648
* in scope under the name `name`.
588
649
*/
650
+ pragma [ nomagic]
589
651
private predicate fileImportEdge ( Module mod , string name , ItemNode item ) {
590
- item .isPublic ( ) and
591
- exists ( SourceFile f |
652
+ exists ( SourceFileItemNode f |
592
653
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 ( )
594
677
)
595
678
}
596
679
@@ -745,13 +828,53 @@ private predicate pathUsesNamespace(Path p, Namespace n) {
745
828
)
746
829
}
747
830
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 ) {
751
833
exists ( Namespace ns | result = resolvePath0 ( path , ns ) |
752
834
pathUsesNamespace ( path , ns )
753
835
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 )
755
878
)
756
879
}
757
880
@@ -831,3 +954,44 @@ private predicate useImportEdge(Use use, string name, ItemNode item) {
831
954
name != "_"
832
955
)
833
956
}
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