@@ -112,13 +112,18 @@ abstract class ItemNode extends Locatable {
112112 result = this .( SourceFileItemNode ) .getSuper ( )
113113 }
114114
115+ pragma [ nomagic]
116+ private ItemNode getAChildSuccessor ( string name ) {
117+ this = result .getImmediateParent ( ) and
118+ name = result .getName ( )
119+ }
120+
115121 cached
116122 ItemNode getASuccessorRec ( string name ) {
117123 Stages:: PathResolutionStage:: ref ( ) and
118124 sourceFileEdge ( this , name , result )
119125 or
120- this = result .getImmediateParent ( ) and
121- name = result .getName ( )
126+ result = this .getAChildSuccessor ( name )
122127 or
123128 fileImportEdge ( this , name , result )
124129 or
@@ -224,6 +229,38 @@ abstract class ItemNode extends Locatable {
224229 result .( CrateItemNode ) .isPotentialDollarCrateTarget ( )
225230 }
226231
232+ /**
233+ * Holds if the successor `item` with the name `name` is not available locally
234+ * for unqualified paths.
235+ *
236+ * This has the effect that a path of the form `name` inside `this` will not
237+ * resolve to `item`.
238+ */
239+ pragma [ nomagic]
240+ predicate excludedLocally ( string name , ItemNode item ) {
241+ // Associated items in an impl or trait block are not directly available
242+ // inside the block, they require a qualified path with a `Self` prefix.
243+ item = this .getAChildSuccessor ( name ) and
244+ this instanceof ImplOrTraitItemNode and
245+ item instanceof AssocItemNode
246+ }
247+
248+ /**
249+ * Holds if the successor `item` with the name `name` is not available
250+ * externally for qualified paths that resolve to this item.
251+ *
252+ * This has the effect that a path of the form `Qualifier::name`, where
253+ * `Qualifier` resolves to this item, will not resolve to `item`.
254+ */
255+ pragma [ nomagic]
256+ predicate excludedExternally ( string name , ItemNode item ) {
257+ // Type parameters for an `impl` or trait block are not available outside of
258+ // the block.
259+ item = this .getAChildSuccessor ( name ) and
260+ this instanceof ImplOrTraitItemNode and
261+ item instanceof TypeParamItemNode
262+ }
263+
227264 pragma [ nomagic]
228265 private predicate hasSourceFunction ( string name ) {
229266 this .getASuccessorFull ( name ) .( Function ) .fromSource ( )
@@ -1145,7 +1182,9 @@ pragma[nomagic]
11451182private predicate declares ( ItemNode item , Namespace ns , string name ) {
11461183 exists ( ItemNode child | child .getImmediateParent ( ) = item |
11471184 child .getName ( ) = name and
1148- child .getNamespace ( ) = ns
1185+ child .getNamespace ( ) = ns and
1186+ // If `item` is excluded locally then it does not declare `name`.
1187+ not item .excludedLocally ( name , child )
11491188 or
11501189 useTreeDeclares ( child .( Use ) .getUseTree ( ) , name ) and
11511190 exists ( ns ) // `use foo::bar` can refer to both a value and a type
@@ -1193,38 +1232,27 @@ private ItemNode getOuterScope(ItemNode i) {
11931232 result = i .getImmediateParent ( )
11941233}
11951234
1196- pragma [ nomagic]
1197- private ItemNode getAdjustedEnclosing ( ItemNode encl0 , Namespace ns ) {
1198- // functions in `impl` blocks need to use explicit `Self::` to access other
1199- // functions in the `impl` block
1200- if encl0 instanceof ImplOrTraitItemNode and ns .isValue ( )
1201- then result = encl0 .getImmediateParent ( )
1202- else result = encl0
1203- }
1204-
12051235/**
12061236 * Holds if the unqualified path `p` references an item named `name`, and `name`
12071237 * may be looked up in the `ns` namespace inside enclosing item `encl`.
12081238 */
12091239pragma [ nomagic]
12101240private predicate unqualifiedPathLookup ( ItemNode encl , string name , Namespace ns , RelevantPath p ) {
1211- exists ( ItemNode encl0 | encl = getAdjustedEnclosing ( encl0 , ns ) |
1212- // lookup in the immediately enclosing item
1213- p .isUnqualified ( name ) and
1214- encl0 .getADescendant ( ) = p and
1215- exists ( ns ) and
1216- not name = [ "crate" , "$crate" , "super" , "self" ]
1217- or
1218- // lookup in an outer scope, but only if the item is not declared in inner scope
1219- exists ( ItemNode mid |
1220- unqualifiedPathLookup ( mid , name , ns , p ) and
1221- not declares ( mid , ns , name ) and
1222- not (
1223- name = "Self" and
1224- mid = any ( ImplOrTraitItemNode i ) .getAnItemInSelfScope ( )
1225- ) and
1226- encl0 = getOuterScope ( mid )
1227- )
1241+ // lookup in the immediately enclosing item
1242+ p .isUnqualified ( name ) and
1243+ encl .getADescendant ( ) = p and
1244+ exists ( ns ) and
1245+ not name = [ "crate" , "$crate" , "super" , "self" ]
1246+ or
1247+ // lookup in an outer scope, but only if the item is not declared in inner scope
1248+ exists ( ItemNode mid |
1249+ unqualifiedPathLookup ( mid , name , ns , p ) and
1250+ not declares ( mid , ns , name ) and
1251+ not (
1252+ name = "Self" and
1253+ mid = any ( ImplOrTraitItemNode i ) .getAnItemInSelfScope ( )
1254+ ) and
1255+ encl = getOuterScope ( mid )
12281256 )
12291257}
12301258
@@ -1245,10 +1273,10 @@ private predicate sourceFileHasCratePathTc(ItemNode i1, ItemNode i2) =
12451273
12461274/**
12471275 * Holds if the unqualified path `p` references a keyword item named `name`, and
1248- * `name` may be looked up in the `ns` namespace inside enclosing item `encl`.
1276+ * `name` may be looked up inside enclosing item `encl`.
12491277 */
12501278pragma [ nomagic]
1251- private predicate keywordLookup ( ItemNode encl , string name , Namespace ns , RelevantPath p ) {
1279+ private predicate keywordLookup ( ItemNode encl , string name , RelevantPath p ) {
12521280 // For `($)crate`, jump directly to the root module
12531281 exists ( ItemNode i | p .isCratePath ( name , i ) |
12541282 encl instanceof SourceFile and
@@ -1259,18 +1287,17 @@ private predicate keywordLookup(ItemNode encl, string name, Namespace ns, Releva
12591287 or
12601288 name = [ "super" , "self" ] and
12611289 p .isUnqualified ( name ) and
1262- exists ( ItemNode encl0 |
1263- encl0 .getADescendant ( ) = p and
1264- encl = getAdjustedEnclosing ( encl0 , ns )
1265- )
1290+ encl .getADescendant ( ) = p
12661291}
12671292
12681293pragma [ nomagic]
12691294private ItemNode unqualifiedPathLookup ( RelevantPath p , Namespace ns ) {
1270- exists ( ItemNode encl , string name | result = getASuccessorFull ( encl , name , ns ) |
1295+ exists ( ItemNode encl , string name |
1296+ result = getASuccessorFull ( encl , name , ns ) and not encl .excludedLocally ( name , result )
1297+ |
12711298 unqualifiedPathLookup ( encl , name , ns , p )
12721299 or
1273- keywordLookup ( encl , name , ns , p )
1300+ keywordLookup ( encl , name , p ) and exists ( ns )
12741301 )
12751302}
12761303
@@ -1291,7 +1318,8 @@ private ItemNode resolvePath0(RelevantPath path, Namespace ns) {
12911318 or
12921319 exists ( ItemNode q , string name |
12931320 q = resolvePathQualifier ( path , name ) and
1294- result = getASuccessorFull ( q , name , ns )
1321+ result = getASuccessorFull ( q , name , ns ) and
1322+ not q .excludedExternally ( name , result )
12951323 )
12961324 or
12971325 result = resolveUseTreeListItem ( _, _, path ) and
0 commit comments