@@ -14,6 +14,7 @@ use rustc_hir::intravisit;
14
14
use rustc_hir:: intravisit:: Visitor ;
15
15
use rustc_hir:: itemlikevisit:: ItemLikeVisitor ;
16
16
use rustc_hir:: * ;
17
+ use rustc_index:: vec:: Idx ;
17
18
use rustc_span:: hygiene:: MacroKind ;
18
19
use rustc_span:: source_map:: Spanned ;
19
20
use rustc_span:: symbol:: { kw, Ident , Symbol } ;
@@ -23,13 +24,6 @@ use rustc_target::spec::abi::Abi;
23
24
pub mod blocks;
24
25
mod collector;
25
26
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
-
33
27
fn fn_decl < ' hir > ( node : Node < ' hir > ) -> Option < & ' hir FnDecl < ' hir > > {
34
28
match node {
35
29
Node :: Item ( Item { kind : ItemKind :: Fn ( sig, _, _) , .. } )
@@ -108,10 +102,48 @@ impl<'hir> Iterator for ParentHirIterator<'_, 'hir> {
108
102
}
109
103
110
104
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) ) ;
113
146
}
114
- // If this `HirId` doesn't have an `Entry`, skip it and look for its `parent_id`.
115
147
}
116
148
}
117
149
}
@@ -144,7 +176,7 @@ impl<'hir> Map<'hir> {
144
176
bug ! (
145
177
"local_def_id: no entry for `{:?}`, which has a map of `{:?}`" ,
146
178
hir_id,
147
- self . find_entry ( hir_id)
179
+ self . find ( hir_id)
148
180
)
149
181
} )
150
182
}
@@ -251,27 +283,61 @@ impl<'hir> Map<'hir> {
251
283
. unwrap_or_else ( || bug ! ( "def_kind: unsupported node: {:?}" , local_def_id) )
252
284
}
253
285
254
- fn find_entry ( & self , id : HirId ) -> Option < Entry < ' hir > > {
286
+ pub fn find_parent_node ( & self , id : HirId ) -> Option < HirId > {
255
287
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 )
258
290
} 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)
270
295
}
271
296
}
272
297
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
+ } )
275
341
}
276
342
277
343
pub fn item ( & self , id : ItemId ) -> & ' hir Item < ' hir > {
@@ -436,7 +502,7 @@ impl<'hir> Map<'hir> {
436
502
437
503
pub fn get_module ( & self , module : LocalDefId ) -> ( & ' hir Mod < ' hir > , Span , HirId ) {
438
504
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) {
440
506
Node :: Item ( & Item { span, kind : ItemKind :: Mod ( ref m) , .. } ) => ( m, span, hir_id) ,
441
507
Node :: Crate ( item) => ( & item, item. inner , hir_id) ,
442
508
node => panic ! ( "not a module: {:?}" , node) ,
@@ -475,60 +541,18 @@ impl<'hir> Map<'hir> {
475
541
}
476
542
}
477
543
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
-
526
544
/// Returns an iterator for the nodes in the ancestor tree of the `current_id`
527
545
/// until the crate root is reached. Prefer this over your own loop using `get_parent_node`.
528
546
pub fn parent_iter ( & self , current_id : HirId ) -> ParentHirIterator < ' _ , ' hir > {
529
547
ParentHirIterator { current_id, map : self }
530
548
}
531
549
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
+
532
556
/// Checks if the node is left-hand side of an assignment.
533
557
pub fn is_lhs ( & self , id : HirId ) -> bool {
534
558
match self . find ( self . get_parent_node ( id) ) {
@@ -549,7 +573,7 @@ impl<'hir> Map<'hir> {
549
573
/// Whether `hir_id` corresponds to a `mod` or a crate.
550
574
pub fn is_hir_id_module ( & self , hir_id : HirId ) -> bool {
551
575
matches ! (
552
- self . get_entry ( hir_id) . node ,
576
+ self . get ( hir_id) ,
553
577
Node :: Item ( Item { kind: ItemKind :: Mod ( _) , .. } ) | Node :: Crate ( ..)
554
578
)
555
579
}
@@ -579,8 +603,8 @@ impl<'hir> Map<'hir> {
579
603
pub fn get_return_block ( & self , id : HirId ) -> Option < HirId > {
580
604
let mut iter = self . parent_iter ( id) . peekable ( ) ;
581
605
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 {
584
608
// When dealing with `return` statements, we don't care about climbing only tail
585
609
// expressions.
586
610
ignore_tail = true ;
@@ -617,23 +641,23 @@ impl<'hir> Map<'hir> {
617
641
/// in the HIR which is recorded by the map and is an item, either an item
618
642
/// in a module, trait, or impl.
619
643
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 ;
628
652
}
629
653
}
630
- hir_id
654
+ CRATE_HIR_ID
631
655
}
632
656
633
657
/// Returns the `HirId` of `id`'s nearest module parent, or `id` itself if no
634
658
/// module parent is in this map.
635
659
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) {
637
661
if let Node :: Item ( & Item { kind : ItemKind :: Mod ( _) , .. } ) = node {
638
662
return hir_id;
639
663
}
@@ -707,12 +731,8 @@ impl<'hir> Map<'hir> {
707
731
708
732
pub fn get_foreign_abi ( & self , hir_id : HirId ) -> Abi {
709
733
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 {
716
736
return * abi;
717
737
}
718
738
}
@@ -806,7 +826,7 @@ impl<'hir> Map<'hir> {
806
826
}
807
827
808
828
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) ? {
810
830
Node :: Param ( param) => param. span ,
811
831
Node :: Item ( item) => match & item. kind {
812
832
ItemKind :: Fn ( sig, _, _) => sig. span ,
@@ -855,7 +875,7 @@ impl<'hir> Map<'hir> {
855
875
/// Like `hir.span()`, but includes the body of function items
856
876
/// (instead of just the function header)
857
877
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) {
859
879
Some ( Node :: TraitItem ( item) ) => item. span ,
860
880
Some ( Node :: ImplItem ( impl_item) ) => impl_item. span ,
861
881
Some ( Node :: Item ( item) ) => item. span ,
0 commit comments