@@ -14,6 +14,7 @@ use rustc_hir::intravisit;
1414use rustc_hir:: intravisit:: Visitor ;
1515use rustc_hir:: itemlikevisit:: ItemLikeVisitor ;
1616use rustc_hir:: * ;
17+ use rustc_index:: vec:: Idx ;
1718use rustc_span:: hygiene:: MacroKind ;
1819use rustc_span:: source_map:: Spanned ;
1920use rustc_span:: symbol:: { kw, Ident , Symbol } ;
@@ -23,13 +24,6 @@ use rustc_target::spec::abi::Abi;
2324pub mod blocks;
2425mod collector;
2526
26- /// Represents an entry and its parent `HirId`.
27- #[ derive( Copy , Clone , Debug ) ]
28- pub struct Entry < ' hir > {
29- parent : HirId ,
30- node : Node < ' hir > ,
31- }
32-
3327fn fn_decl < ' hir > ( node : Node < ' hir > ) -> Option < & ' hir FnDecl < ' hir > > {
3428 match node {
3529 Node :: Item ( Item { kind : ItemKind :: Fn ( sig, _, _) , .. } )
@@ -108,10 +102,48 @@ impl<'hir> Iterator for ParentHirIterator<'_, 'hir> {
108102 }
109103
110104 self . current_id = parent_id;
111- if let Some ( entry) = self . map . find_entry ( parent_id) {
112- return Some ( ( parent_id, entry. node ) ) ;
105+ if let Some ( node) = self . map . find ( parent_id) {
106+ return Some ( ( parent_id, node) ) ;
107+ }
108+ // If this `HirId` doesn't have an entry, skip it and look for its `parent_id`.
109+ }
110+ }
111+ }
112+
113+ /// An iterator that walks up the ancestor tree of a given `HirId`.
114+ /// Constructed using `tcx.hir().parent_owner_iter(hir_id)`.
115+ pub struct ParentOwnerIterator < ' map , ' hir > {
116+ current_id : HirId ,
117+ map : & ' map Map < ' hir > ,
118+ }
119+
120+ impl < ' hir > Iterator for ParentOwnerIterator < ' _ , ' hir > {
121+ type Item = ( HirId , Node < ' hir > ) ;
122+
123+ fn next ( & mut self ) -> Option < Self :: Item > {
124+ if self . current_id . local_id . index ( ) != 0 {
125+ self . current_id . local_id = ItemLocalId :: new ( 0 ) ;
126+ if let Some ( node) = self . map . find ( self . current_id ) {
127+ return Some ( ( self . current_id , node) ) ;
128+ }
129+ }
130+ if self . current_id == CRATE_HIR_ID {
131+ return None ;
132+ }
133+ loop {
134+ // There are nodes that do not have entries, so we need to skip them.
135+ let parent_id = self . map . def_key ( self . current_id . owner ) . parent ;
136+
137+ let parent_id = parent_id. map_or ( CRATE_HIR_ID . owner , |local_def_index| {
138+ let def_id = LocalDefId { local_def_index } ;
139+ self . map . local_def_id_to_hir_id ( def_id) . owner
140+ } ) ;
141+ self . current_id = HirId :: make_owner ( parent_id) ;
142+
143+ // If this `HirId` doesn't have an entry, skip it and look for its `parent_id`.
144+ if let Some ( node) = self . map . find ( self . current_id ) {
145+ return Some ( ( self . current_id , node) ) ;
113146 }
114- // If this `HirId` doesn't have an `Entry`, skip it and look for its `parent_id`.
115147 }
116148 }
117149}
@@ -144,7 +176,7 @@ impl<'hir> Map<'hir> {
144176 bug ! (
145177 "local_def_id: no entry for `{:?}`, which has a map of `{:?}`" ,
146178 hir_id,
147- self . find_entry ( hir_id)
179+ self . find ( hir_id)
148180 )
149181 } )
150182 }
@@ -251,27 +283,61 @@ impl<'hir> Map<'hir> {
251283 . unwrap_or_else ( || bug ! ( "def_kind: unsupported node: {:?}" , local_def_id) )
252284 }
253285
254- fn find_entry ( & self , id : HirId ) -> Option < Entry < ' hir > > {
286+ pub fn find_parent_node ( & self , id : HirId ) -> Option < HirId > {
255287 if id. local_id == ItemLocalId :: from_u32 ( 0 ) {
256- let owner = self . tcx . hir_owner ( id. owner ) ;
257- owner . map ( | owner| Entry { parent : owner . parent , node : owner . node } )
288+ let owner = self . tcx . hir_owner ( id. owner ) ? ;
289+ Some ( owner. parent )
258290 } else {
259- let owner = self . tcx . hir_owner_nodes ( id. owner ) ;
260- owner. and_then ( |owner| {
261- let node = owner. nodes [ id. local_id ] . as_ref ( ) ;
262- // FIXME(eddyb) use a single generic type instead of having both
263- // `Entry` and `ParentedNode`, which are effectively the same.
264- // Alternatively, rewrite code using `Entry` to use `ParentedNode`.
265- node. map ( |node| Entry {
266- parent : HirId { owner : id. owner , local_id : node. parent } ,
267- node : node. node ,
268- } )
269- } )
291+ let owner = self . tcx . hir_owner_nodes ( id. owner ) ?;
292+ let node = owner. nodes [ id. local_id ] . as_ref ( ) ?;
293+ let hir_id = HirId { owner : id. owner , local_id : node. parent } ;
294+ Some ( hir_id)
270295 }
271296 }
272297
273- fn get_entry ( & self , id : HirId ) -> Entry < ' hir > {
274- self . find_entry ( id) . unwrap ( )
298+ pub fn get_parent_node ( & self , hir_id : HirId ) -> HirId {
299+ self . find_parent_node ( hir_id) . unwrap ( )
300+ }
301+
302+ /// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found.
303+ pub fn find ( & self , id : HirId ) -> Option < Node < ' hir > > {
304+ if id. local_id == ItemLocalId :: from_u32 ( 0 ) {
305+ let owner = self . tcx . hir_owner ( id. owner ) ?;
306+ Some ( owner. node )
307+ } else {
308+ let owner = self . tcx . hir_owner_nodes ( id. owner ) ?;
309+ let node = owner. nodes [ id. local_id ] . as_ref ( ) ?;
310+ Some ( node. node )
311+ }
312+ }
313+
314+ /// Retrieves the `Node` corresponding to `id`, panicking if it cannot be found.
315+ pub fn get ( & self , id : HirId ) -> Node < ' hir > {
316+ self . find ( id) . unwrap_or_else ( || bug ! ( "couldn't find hir id {} in the HIR map" , id) )
317+ }
318+
319+ pub fn get_if_local ( & self , id : DefId ) -> Option < Node < ' hir > > {
320+ id. as_local ( ) . and_then ( |id| self . find ( self . local_def_id_to_hir_id ( id) ) )
321+ }
322+
323+ pub fn get_generics ( & self , id : DefId ) -> Option < & ' hir Generics < ' hir > > {
324+ self . get_if_local ( id) . and_then ( |node| match & node {
325+ Node :: ImplItem ( impl_item) => Some ( & impl_item. generics ) ,
326+ Node :: TraitItem ( trait_item) => Some ( & trait_item. generics ) ,
327+ Node :: Item ( Item {
328+ kind :
329+ ItemKind :: Fn ( _, generics, _)
330+ | ItemKind :: TyAlias ( _, generics)
331+ | ItemKind :: Enum ( _, generics)
332+ | ItemKind :: Struct ( _, generics)
333+ | ItemKind :: Union ( _, generics)
334+ | ItemKind :: Trait ( _, _, generics, ..)
335+ | ItemKind :: TraitAlias ( generics, _)
336+ | ItemKind :: Impl ( Impl { generics, .. } ) ,
337+ ..
338+ } ) => Some ( generics) ,
339+ _ => None ,
340+ } )
275341 }
276342
277343 pub fn item ( & self , id : ItemId ) -> & ' hir Item < ' hir > {
@@ -436,7 +502,7 @@ impl<'hir> Map<'hir> {
436502
437503 pub fn get_module ( & self , module : LocalDefId ) -> ( & ' hir Mod < ' hir > , Span , HirId ) {
438504 let hir_id = self . local_def_id_to_hir_id ( module) ;
439- match self . get_entry ( hir_id) . node {
505+ match self . get ( hir_id) {
440506 Node :: Item ( & Item { span, kind : ItemKind :: Mod ( ref m) , .. } ) => ( m, span, hir_id) ,
441507 Node :: Crate ( item) => ( & item, item. inner , hir_id) ,
442508 node => panic ! ( "not a module: {:?}" , node) ,
@@ -475,60 +541,18 @@ impl<'hir> Map<'hir> {
475541 }
476542 }
477543
478- /// Retrieves the `Node` corresponding to `id`, panicking if it cannot be found.
479- pub fn get ( & self , id : HirId ) -> Node < ' hir > {
480- self . find ( id) . unwrap_or_else ( || bug ! ( "couldn't find hir id {} in the HIR map" , id) )
481- }
482-
483- pub fn get_if_local ( & self , id : DefId ) -> Option < Node < ' hir > > {
484- id. as_local ( ) . and_then ( |id| self . find ( self . local_def_id_to_hir_id ( id) ) )
485- }
486-
487- pub fn get_generics ( & self , id : DefId ) -> Option < & ' hir Generics < ' hir > > {
488- self . get_if_local ( id) . and_then ( |node| match & node {
489- Node :: ImplItem ( impl_item) => Some ( & impl_item. generics ) ,
490- Node :: TraitItem ( trait_item) => Some ( & trait_item. generics ) ,
491- Node :: Item ( Item {
492- kind :
493- ItemKind :: Fn ( _, generics, _)
494- | ItemKind :: TyAlias ( _, generics)
495- | ItemKind :: Enum ( _, generics)
496- | ItemKind :: Struct ( _, generics)
497- | ItemKind :: Union ( _, generics)
498- | ItemKind :: Trait ( _, _, generics, ..)
499- | ItemKind :: TraitAlias ( generics, _)
500- | ItemKind :: Impl ( Impl { generics, .. } ) ,
501- ..
502- } ) => Some ( generics) ,
503- _ => None ,
504- } )
505- }
506-
507- /// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found.
508- pub fn find ( & self , hir_id : HirId ) -> Option < Node < ' hir > > {
509- self . find_entry ( hir_id) . map ( |entry| entry. node )
510- }
511-
512- /// Similar to `get_parent`; returns the parent HIR Id, or just `hir_id` if there
513- /// is no parent. Note that the parent may be `CRATE_HIR_ID`, which is not itself
514- /// present in the map, so passing the return value of `get_parent_node` to
515- /// `get` may in fact panic.
516- /// This function returns the immediate parent in the HIR, whereas `get_parent`
517- /// returns the enclosing item. Note that this might not be the actual parent
518- /// node in the HIR -- some kinds of nodes are not in the map and these will
519- /// never appear as the parent node. Thus, you can always walk the parent nodes
520- /// from a node to the root of the HIR (unless you get back the same ID here,
521- /// which can happen if the ID is not in the map itself or is just weird).
522- pub fn get_parent_node ( & self , hir_id : HirId ) -> HirId {
523- self . get_entry ( hir_id) . parent
524- }
525-
526544 /// Returns an iterator for the nodes in the ancestor tree of the `current_id`
527545 /// until the crate root is reached. Prefer this over your own loop using `get_parent_node`.
528546 pub fn parent_iter ( & self , current_id : HirId ) -> ParentHirIterator < ' _ , ' hir > {
529547 ParentHirIterator { current_id, map : self }
530548 }
531549
550+ /// Returns an iterator for the nodes in the ancestor tree of the `current_id`
551+ /// until the crate root is reached. Prefer this over your own loop using `get_parent_node`.
552+ pub fn parent_owner_iter ( & self , current_id : HirId ) -> ParentOwnerIterator < ' _ , ' hir > {
553+ ParentOwnerIterator { current_id, map : self }
554+ }
555+
532556 /// Checks if the node is left-hand side of an assignment.
533557 pub fn is_lhs ( & self , id : HirId ) -> bool {
534558 match self . find ( self . get_parent_node ( id) ) {
@@ -549,7 +573,7 @@ impl<'hir> Map<'hir> {
549573 /// Whether `hir_id` corresponds to a `mod` or a crate.
550574 pub fn is_hir_id_module ( & self , hir_id : HirId ) -> bool {
551575 matches ! (
552- self . get_entry ( hir_id) . node ,
576+ self . get ( hir_id) ,
553577 Node :: Item ( Item { kind: ItemKind :: Mod ( _) , .. } ) | Node :: Crate ( ..)
554578 )
555579 }
@@ -579,8 +603,8 @@ impl<'hir> Map<'hir> {
579603 pub fn get_return_block ( & self , id : HirId ) -> Option < HirId > {
580604 let mut iter = self . parent_iter ( id) . peekable ( ) ;
581605 let mut ignore_tail = false ;
582- if let Some ( entry ) = self . find_entry ( id) {
583- if let Node :: Expr ( Expr { kind : ExprKind :: Ret ( _) , .. } ) = entry . node {
606+ if let Some ( node ) = self . find ( id) {
607+ if let Node :: Expr ( Expr { kind : ExprKind :: Ret ( _) , .. } ) = node {
584608 // When dealing with `return` statements, we don't care about climbing only tail
585609 // expressions.
586610 ignore_tail = true ;
@@ -617,23 +641,23 @@ impl<'hir> Map<'hir> {
617641 /// in the HIR which is recorded by the map and is an item, either an item
618642 /// in a module, trait, or impl.
619643 pub fn get_parent_item ( & self , hir_id : HirId ) -> HirId {
620- for ( hir_id, node) in self . parent_iter ( hir_id) {
621- match node {
622- Node :: Crate ( _)
623- | Node :: Item ( _)
624- | Node :: ForeignItem ( _)
625- | Node :: TraitItem ( _)
626- | Node :: ImplItem ( _ ) => return hir_id ,
627- _ => { }
644+ for ( hir_id, node) in self . parent_owner_iter ( hir_id) {
645+ if let Node :: Crate ( _ )
646+ | Node :: Item ( _)
647+ | Node :: ForeignItem ( _)
648+ | Node :: TraitItem ( _)
649+ | Node :: ImplItem ( _) = node
650+ {
651+ return hir_id ;
628652 }
629653 }
630- hir_id
654+ CRATE_HIR_ID
631655 }
632656
633657 /// Returns the `HirId` of `id`'s nearest module parent, or `id` itself if no
634658 /// module parent is in this map.
635659 pub ( super ) fn get_module_parent_node ( & self , hir_id : HirId ) -> HirId {
636- for ( hir_id, node) in self . parent_iter ( hir_id) {
660+ for ( hir_id, node) in self . parent_owner_iter ( hir_id) {
637661 if let Node :: Item ( & Item { kind : ItemKind :: Mod ( _) , .. } ) = node {
638662 return hir_id;
639663 }
@@ -707,12 +731,8 @@ impl<'hir> Map<'hir> {
707731
708732 pub fn get_foreign_abi ( & self , hir_id : HirId ) -> Abi {
709733 let parent = self . get_parent_item ( hir_id) ;
710- if let Some ( entry) = self . find_entry ( parent) {
711- if let Entry {
712- node : Node :: Item ( Item { kind : ItemKind :: ForeignMod { abi, .. } , .. } ) ,
713- ..
714- } = entry
715- {
734+ if let Some ( node) = self . find ( parent) {
735+ if let Node :: Item ( Item { kind : ItemKind :: ForeignMod { abi, .. } , .. } ) = node {
716736 return * abi;
717737 }
718738 }
@@ -806,7 +826,7 @@ impl<'hir> Map<'hir> {
806826 }
807827
808828 pub fn opt_span ( & self , hir_id : HirId ) -> Option < Span > {
809- let span = match self . find_entry ( hir_id) ?. node {
829+ let span = match self . find ( hir_id) ? {
810830 Node :: Param ( param) => param. span ,
811831 Node :: Item ( item) => match & item. kind {
812832 ItemKind :: Fn ( sig, _, _) => sig. span ,
@@ -855,7 +875,7 @@ impl<'hir> Map<'hir> {
855875 /// Like `hir.span()`, but includes the body of function items
856876 /// (instead of just the function header)
857877 pub fn span_with_body ( & self , hir_id : HirId ) -> Span {
858- match self . find_entry ( hir_id) . map ( |entry| entry . node ) {
878+ match self . find ( hir_id) {
859879 Some ( Node :: TraitItem ( item) ) => item. span ,
860880 Some ( Node :: ImplItem ( impl_item) ) => impl_item. span ,
861881 Some ( Node :: Item ( item) ) => item. span ,
0 commit comments