@@ -216,7 +216,7 @@ abstract class ItemNode extends Locatable {
216216 // items made available through `use` are available to nodes that contain the `use`
217217 exists ( UseItemNode use |
218218 use = this .getASuccessor ( _, _) and
219- result = use .( ItemNode ) . getASuccessor ( name , kind )
219+ result = use .getASuccessor ( name , kind )
220220 )
221221 or
222222 exists ( ExternCrateItemNode ec | result = ec .( ItemNode ) .getASuccessor ( name , kind ) |
@@ -240,12 +240,7 @@ abstract class ItemNode extends Locatable {
240240 )
241241 or
242242 // items made available by an implementation where `this` is the implementing type
243- exists ( ItemNode node |
244- this = node .( ImplItemNodeImpl ) .resolveSelfTyCand ( ) and
245- result = node .getASuccessor ( name , kind ) and
246- kind .isExternalOrBoth ( ) and
247- result instanceof AssocItemNode
248- )
243+ typeImplEdge ( this , _, name , kind , result )
249244 or
250245 // trait items with default implementations made available in an implementation
251246 exists ( ImplItemNodeImpl impl , ItemNode trait |
@@ -1311,6 +1306,7 @@ private predicate declares(ItemNode item, Namespace ns, string name) {
13111306class RelevantPath extends Path {
13121307 RelevantPath ( ) { not this = any ( VariableAccess va ) .( PathExpr ) .getPath ( ) }
13131308
1309+ /** Holds if this is an unqualified path with the textual value `name`. */
13141310 pragma [ nomagic]
13151311 predicate isUnqualified ( string name ) {
13161312 not exists ( this .getQualifier ( ) ) and
@@ -1421,6 +1417,35 @@ private ItemNode unqualifiedPathLookup(RelevantPath p, Namespace ns, SuccessorKi
14211417pragma [ nomagic]
14221418private predicate isUnqualifiedSelfPath ( RelevantPath path ) { path .isUnqualified ( "Self" ) }
14231419
1420+ /** Provides the input to `TraitIsVisible`. */
1421+ signature predicate relevantTraitVisibleSig ( Element element , Trait trait ) ;
1422+
1423+ /**
1424+ * Provides the `traitIsVisible` predicate for determining if a trait is visible
1425+ * at a given element.
1426+ */
1427+ module TraitIsVisible< relevantTraitVisibleSig / 2 relevantTraitVisible> {
1428+ /** Holds if the trait might be looked up in `encl`. */
1429+ private predicate traitLookup ( ItemNode encl , Element element , Trait trait ) {
1430+ // lookup in immediately enclosing item
1431+ relevantTraitVisible ( element , trait ) and
1432+ encl .getADescendant ( ) = element
1433+ or
1434+ // lookup in an outer scope, but only if the trait is not declared in inner scope
1435+ exists ( ItemNode mid |
1436+ traitLookup ( mid , element , trait ) and
1437+ not trait = mid .getASuccessor ( _, _) and
1438+ encl = getOuterScope ( mid )
1439+ )
1440+ }
1441+
1442+ /** Holds if the trait `trait` is visible at `element`. */
1443+ pragma [ nomagic]
1444+ predicate traitIsVisible ( Element element , Trait trait ) {
1445+ exists ( ItemNode encl | traitLookup ( encl , element , trait ) and trait = encl .getASuccessor ( _, _) )
1446+ }
1447+ }
1448+
14241449pragma [ nomagic]
14251450private ItemNode resolvePathCand0 ( RelevantPath path , Namespace ns ) {
14261451 exists ( ItemNode res |
@@ -1446,6 +1471,10 @@ private ItemNode resolvePathCandQualifier(RelevantPath qualifier, RelevantPath p
14461471 name = path .getText ( )
14471472}
14481473
1474+ /**
1475+ * Gets the item that `path` resolves to in `ns` when `qualifier` is the
1476+ * qualifier of `path` and `qualifier` resolves to `q`, if any.
1477+ */
14491478pragma [ nomagic]
14501479private ItemNode resolvePathCandQualified (
14511480 RelevantPath qualifier , ItemNode q , RelevantPath path , Namespace ns
@@ -1520,11 +1549,31 @@ private ItemNode resolvePathCand(RelevantPath path) {
15201549 )
15211550}
15221551
1552+ /** Get a trait that should be visible when `path` resolves to `node`, if any. */
1553+ private Trait getResolvePathTraitUsed ( RelevantPath path , AssocItemNode node ) {
1554+ exists ( TypeItemNode type , ImplItemNodeImpl impl |
1555+ node = resolvePathCandQualified ( _, type , path , _) and
1556+ typeImplEdge ( type , impl , _, _, node ) and
1557+ result = impl .resolveTraitTyCand ( )
1558+ )
1559+ }
1560+
1561+ private predicate pathTraitUsed ( Element path , Trait trait ) {
1562+ trait = getResolvePathTraitUsed ( path , _)
1563+ }
1564+
15231565/** Gets the item that `path` resolves to, if any. */
15241566cached
15251567ItemNode resolvePath ( RelevantPath path ) {
15261568 result = resolvePathCand ( path ) and
1527- not path = any ( Path parent | exists ( resolvePathCand ( parent ) ) ) .getQualifier ( )
1569+ not path = any ( Path parent | exists ( resolvePathCand ( parent ) ) ) .getQualifier ( ) and
1570+ (
1571+ // When the result is an associated item of a trait implementation the
1572+ // implemented trait must be visible.
1573+ TraitIsVisible< pathTraitUsed / 2 > :: traitIsVisible ( path , getResolvePathTraitUsed ( path , result ) )
1574+ or
1575+ not exists ( getResolvePathTraitUsed ( path , result ) )
1576+ )
15281577 or
15291578 // if `path` is the qualifier of a resolvable `parent`, then we should
15301579 // resolve `path` to something consistent with what `parent` resolves to
@@ -1606,8 +1655,16 @@ private predicate useImportEdge(Use use, string name, ItemNode item, SuccessorKi
16061655 not tree .hasRename ( ) and
16071656 name = item .getName ( )
16081657 or
1609- name = tree .getRename ( ) .getName ( ) .getText ( ) and
1610- name != "_"
1658+ exists ( Rename rename | rename = tree .getRename ( ) |
1659+ name = rename .getName ( ) .getText ( )
1660+ or
1661+ // When the rename doesn't have a name it's an underscore import. This
1662+ // makes the imported item visible but unnameable. We represent this
1663+ // by using the name `_` which can never occur in a path. See also:
1664+ // https://doc.rust-lang.org/reference/items/use-declarations.html#r-items.use.as-underscore
1665+ not rename .hasName ( ) and
1666+ name = "_"
1667+ )
16111668 )
16121669 )
16131670 )
@@ -1629,6 +1686,18 @@ private predicate externCrateEdge(ExternCrateItemNode ec, string name, CrateItem
16291686 )
16301687}
16311688
1689+ /**
1690+ * Holds if `typeItem` is the implementing type of `impl` and the implementation
1691+ * makes `assoc` available as `name` at `kind`.
1692+ */
1693+ private predicate typeImplEdge (
1694+ TypeItemNode typeItem , ImplItemNodeImpl impl , string name , SuccessorKind kind , AssocItemNode assoc
1695+ ) {
1696+ typeItem = impl .resolveSelfTyCand ( ) and
1697+ assoc = impl .getASuccessor ( name , kind ) and
1698+ kind .isExternalOrBoth ( )
1699+ }
1700+
16321701pragma [ nomagic]
16331702private predicate preludeItem ( string name , ItemNode i ) {
16341703 exists ( Crate stdOrCore , ModuleLikeNode mod , ModuleItemNode prelude , ModuleItemNode rust |
@@ -1693,7 +1762,7 @@ private module Debug {
16931762 useImportEdge ( use , name , item , kind )
16941763 }
16951764
1696- ItemNode debuggetASuccessor ( ItemNode i , string name , SuccessorKind kind ) {
1765+ ItemNode debugGetASuccessor ( ItemNode i , string name , SuccessorKind kind ) {
16971766 i = getRelevantLocatable ( ) and
16981767 result = i .getASuccessor ( name , kind )
16991768 }
0 commit comments