@@ -2065,23 +2065,81 @@ fn clean_bare_fn_ty<'tcx>(
20652065 BareFunctionDecl { unsafety : bare_fn. unsafety , abi : bare_fn. abi , decl, generic_params }
20662066}
20672067
2068- /// This visitor is used to go through only the "top level" of a item and not enter any sub
2069- /// item while looking for a given `Ident` which is stored into `item` if found.
2070- struct OneLevelVisitor < ' hir > {
2068+ /// Get DefId of of an item's user-visible parent.
2069+ ///
2070+ /// "User-visible" should account for re-exporting and inlining, which is why this function isn't
2071+ /// just `tcx.parent(def_id)`. If the provided `path` has more than one path element, the `DefId`
2072+ /// of the second-to-last will be given.
2073+ ///
2074+ /// ```text
2075+ /// use crate::foo::Bar;
2076+ /// ^^^ DefId of this item will be returned
2077+ /// ```
2078+ ///
2079+ /// If the provided path has only one item, `tcx.parent(def_id)` will be returned instead.
2080+ fn get_path_parent_def_id (
2081+ tcx : TyCtxt < ' _ > ,
2082+ def_id : DefId ,
2083+ path : & hir:: UsePath < ' _ > ,
2084+ ) -> Option < DefId > {
2085+ if let [ .., parent_segment, _] = & path. segments {
2086+ match parent_segment. res {
2087+ hir:: def:: Res :: Def ( _, parent_def_id) => Some ( parent_def_id) ,
2088+ _ if parent_segment. ident . name == kw:: Crate => {
2089+ // In case the "parent" is the crate, it'll give `Res::Err` so we need to
2090+ // circumvent it this way.
2091+ Some ( tcx. parent ( def_id) )
2092+ }
2093+ _ => None ,
2094+ }
2095+ } else {
2096+ // If the path doesn't have a parent, then the parent is the current module.
2097+ Some ( tcx. parent ( def_id) )
2098+ }
2099+ }
2100+
2101+ /// This visitor is used to find an HIR Item based on its `use` path. This doesn't use the ordinary
2102+ /// name resolver because it does not walk all the way through a chain of re-exports.
2103+ pub ( crate ) struct OneLevelVisitor < ' hir > {
20712104 map : rustc_middle:: hir:: map:: Map < ' hir > ,
2072- item : Option < & ' hir hir:: Item < ' hir > > ,
2105+ pub ( crate ) item : Option < & ' hir hir:: Item < ' hir > > ,
20732106 looking_for : Ident ,
20742107 target_def_id : LocalDefId ,
20752108}
20762109
20772110impl < ' hir > OneLevelVisitor < ' hir > {
2078- fn new ( map : rustc_middle:: hir:: map:: Map < ' hir > , target_def_id : LocalDefId ) -> Self {
2111+ pub ( crate ) fn new ( map : rustc_middle:: hir:: map:: Map < ' hir > , target_def_id : LocalDefId ) -> Self {
20792112 Self { map, item : None , looking_for : Ident :: empty ( ) , target_def_id }
20802113 }
20812114
2082- fn reset ( & mut self , looking_for : Ident ) {
2083- self . looking_for = looking_for;
2115+ pub ( crate ) fn find_target (
2116+ & mut self ,
2117+ tcx : TyCtxt < ' _ > ,
2118+ def_id : DefId ,
2119+ path : & hir:: UsePath < ' _ > ,
2120+ ) -> Option < & ' hir hir:: Item < ' hir > > {
2121+ let parent_def_id = get_path_parent_def_id ( tcx, def_id, path) ?;
2122+ let parent = self . map . get_if_local ( parent_def_id) ?;
2123+
2124+ // We get the `Ident` we will be looking for into `item`.
2125+ self . looking_for = path. segments [ path. segments . len ( ) - 1 ] . ident ;
2126+ // We reset the `item`.
20842127 self . item = None ;
2128+
2129+ match parent {
2130+ hir:: Node :: Item ( parent_item) => {
2131+ hir:: intravisit:: walk_item ( self , parent_item) ;
2132+ }
2133+ hir:: Node :: Crate ( m) => {
2134+ hir:: intravisit:: walk_mod (
2135+ self ,
2136+ m,
2137+ tcx. local_def_id_to_hir_id ( parent_def_id. as_local ( ) . unwrap ( ) ) ,
2138+ ) ;
2139+ }
2140+ _ => return None ,
2141+ }
2142+ self . item
20852143 }
20862144}
20872145
@@ -2129,41 +2187,7 @@ fn get_all_import_attributes<'hir>(
21292187 add_without_unwanted_attributes ( attributes, hir_map. attrs ( item. hir_id ( ) ) , is_inline) ;
21302188 }
21312189
2132- let def_id = if let [ .., parent_segment, _] = & path. segments {
2133- match parent_segment. res {
2134- hir:: def:: Res :: Def ( _, def_id) => def_id,
2135- _ if parent_segment. ident . name == kw:: Crate => {
2136- // In case the "parent" is the crate, it'll give `Res::Err` so we need to
2137- // circumvent it this way.
2138- tcx. parent ( item. owner_id . def_id . to_def_id ( ) )
2139- }
2140- _ => break ,
2141- }
2142- } else {
2143- // If the path doesn't have a parent, then the parent is the current module.
2144- tcx. parent ( item. owner_id . def_id . to_def_id ( ) )
2145- } ;
2146-
2147- let Some ( parent) = hir_map. get_if_local ( def_id) else { break } ;
2148-
2149- // We get the `Ident` we will be looking for into `item`.
2150- let looking_for = path. segments [ path. segments . len ( ) - 1 ] . ident ;
2151- visitor. reset ( looking_for) ;
2152-
2153- match parent {
2154- hir:: Node :: Item ( parent_item) => {
2155- hir:: intravisit:: walk_item ( & mut visitor, parent_item) ;
2156- }
2157- hir:: Node :: Crate ( m) => {
2158- hir:: intravisit:: walk_mod (
2159- & mut visitor,
2160- m,
2161- tcx. local_def_id_to_hir_id ( def_id. as_local ( ) . unwrap ( ) ) ,
2162- ) ;
2163- }
2164- _ => break ,
2165- }
2166- if let Some ( i) = visitor. item {
2190+ if let Some ( i) = visitor. find_target ( tcx, item. owner_id . def_id . to_def_id ( ) , path) {
21672191 item = i;
21682192 } else {
21692193 break ;
0 commit comments