@@ -8,6 +8,7 @@ use rustc_hir::def_id::DefId;
88use rustc_hir:: intravisit:: { walk_item, Visitor } ;
99use rustc_hir:: Node ;
1010use rustc_hir:: CRATE_HIR_ID ;
11+ use rustc_middle:: hir:: map:: Map ;
1112use rustc_middle:: hir:: nested_filter;
1213use rustc_middle:: ty:: TyCtxt ;
1314use rustc_span:: def_id:: { CRATE_DEF_ID , LOCAL_CRATE } ;
@@ -67,6 +68,7 @@ pub(crate) struct RustdocVisitor<'a, 'tcx> {
6768 inside_public_path : bool ,
6869 exact_paths : FxHashMap < DefId , Vec < Symbol > > ,
6970 modules : Vec < Module < ' tcx > > ,
71+ map : Map < ' tcx > ,
7072}
7173
7274impl < ' a , ' tcx > RustdocVisitor < ' a , ' tcx > {
@@ -79,6 +81,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
7981 hir:: CRATE_HIR_ID ,
8082 cx. tcx . hir ( ) . root_module ( ) . spans . inner_span ,
8183 ) ;
84+ let map = cx. tcx . hir ( ) ;
8285
8386 RustdocVisitor {
8487 cx,
@@ -87,6 +90,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
8790 inside_public_path : true ,
8891 exact_paths : FxHashMap :: default ( ) ,
8992 modules : vec ! [ om] ,
93+ map,
9094 }
9195 }
9296
@@ -95,95 +99,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
9599 self . exact_paths . entry ( did) . or_insert_with ( || def_id_to_path ( tcx, did) ) ;
96100 }
97101
98- pub ( crate ) fn visit ( mut self ) -> Module < ' tcx > {
99- let root_module = self . cx . tcx . hir ( ) . root_module ( ) ;
100- self . visit_mod_contents ( CRATE_HIR_ID , root_module) ;
101-
102- let mut top_level_module = self . modules . pop ( ) . unwrap ( ) ;
103-
104- // `#[macro_export] macro_rules!` items are reexported at the top level of the
105- // crate, regardless of where they're defined. We want to document the
106- // top level rexport of the macro, not its original definition, since
107- // the rexport defines the path that a user will actually see. Accordingly,
108- // we add the rexport as an item here, and then skip over the original
109- // definition in `visit_item()` below.
110- //
111- // We also skip `#[macro_export] macro_rules!` that have already been inserted,
112- // it can happen if within the same module a `#[macro_export] macro_rules!`
113- // is declared but also a reexport of itself producing two exports of the same
114- // macro in the same module.
115- let mut inserted = FxHashSet :: default ( ) ;
116- for export in self . cx . tcx . module_reexports ( CRATE_DEF_ID ) . unwrap_or ( & [ ] ) {
117- if let Res :: Def ( DefKind :: Macro ( _) , def_id) = export. res &&
118- let Some ( local_def_id) = def_id. as_local ( ) &&
119- self . cx . tcx . has_attr ( def_id, sym:: macro_export) &&
120- inserted. insert ( def_id)
121- {
122- let item = self . cx . tcx . hir ( ) . expect_item ( local_def_id) ;
123- top_level_module. items . push ( ( item, None , None ) ) ;
124- }
125- }
126-
127- self . cx . cache . hidden_cfg = self
128- . cx
129- . tcx
130- . hir ( )
131- . attrs ( CRATE_HIR_ID )
132- . iter ( )
133- . filter ( |attr| attr. has_name ( sym:: doc) )
134- . flat_map ( |attr| attr. meta_item_list ( ) . into_iter ( ) . flatten ( ) )
135- . filter ( |attr| attr. has_name ( sym:: cfg_hide) )
136- . flat_map ( |attr| {
137- attr. meta_item_list ( )
138- . unwrap_or ( & [ ] )
139- . iter ( )
140- . filter_map ( |attr| {
141- Cfg :: parse ( attr. meta_item ( ) ?)
142- . map_err ( |e| self . cx . sess ( ) . diagnostic ( ) . span_err ( e. span , e. msg ) )
143- . ok ( )
144- } )
145- . collect :: < Vec < _ > > ( )
146- } )
147- . chain (
148- [ Cfg :: Cfg ( sym:: test, None ) , Cfg :: Cfg ( sym:: doc, None ) , Cfg :: Cfg ( sym:: doctest, None ) ]
149- . into_iter ( ) ,
150- )
151- . collect ( ) ;
152-
153- self . cx . cache . exact_paths = self . exact_paths ;
154- top_level_module
155- }
156-
157- /// This method will go through the given module items in two passes:
158- /// 1. The items which are not glob imports/reexports.
159- /// 2. The glob imports/reexports.
160- fn visit_mod_contents ( & mut self , id : hir:: HirId , m : & ' tcx hir:: Mod < ' tcx > ) {
161- debug ! ( "Going through module {:?}" , m) ;
162- let def_id = self . cx . tcx . hir ( ) . local_def_id ( id) . to_def_id ( ) ;
163- // Keep track of if there were any private modules in the path.
164- let orig_inside_public_path = self . inside_public_path ;
165- self . inside_public_path &= self . cx . tcx . visibility ( def_id) . is_public ( ) ;
166-
167- // Reimplementation of `walk_mod` because we need to do it in two passes (explanations in
168- // the second loop):
169- for & i in m. item_ids {
170- let item = self . cx . tcx . hir ( ) . item ( i) ;
171- if !matches ! ( item. kind, hir:: ItemKind :: Use ( _, hir:: UseKind :: Glob ) ) {
172- self . visit_item ( item) ;
173- }
174- }
175- for & i in m. item_ids {
176- let item = self . cx . tcx . hir ( ) . item ( i) ;
177- // To match the way import precedence works, visit glob imports last.
178- // Later passes in rustdoc will de-duplicate by name and kind, so if glob-
179- // imported items appear last, then they'll be the ones that get discarded.
180- if matches ! ( item. kind, hir:: ItemKind :: Use ( _, hir:: UseKind :: Glob ) ) {
181- self . visit_item ( item) ;
182- }
183- }
184- self . inside_public_path = orig_inside_public_path;
185- }
186-
187102 /// Tries to resolve the target of a `pub use` statement and inlines the
188103 /// target if it is defined locally and would not be documented otherwise,
189104 /// or when it is specifically requested with `please_inline`.
@@ -408,6 +323,65 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
408323 }
409324 }
410325
326+ pub ( crate ) fn visit ( mut self ) -> Module < ' tcx > {
327+ let root_module = self . cx . tcx . hir ( ) . root_module ( ) ;
328+ self . visit_mod_contents ( CRATE_HIR_ID , root_module) ;
329+
330+ let mut top_level_module = self . modules . pop ( ) . unwrap ( ) ;
331+
332+ // `#[macro_export] macro_rules!` items are reexported at the top level of the
333+ // crate, regardless of where they're defined. We want to document the
334+ // top level rexport of the macro, not its original definition, since
335+ // the rexport defines the path that a user will actually see. Accordingly,
336+ // we add the rexport as an item here, and then skip over the original
337+ // definition in `visit_item()` below.
338+ //
339+ // We also skip `#[macro_export] macro_rules!` that have already been inserted,
340+ // it can happen if within the same module a `#[macro_export] macro_rules!`
341+ // is declared but also a reexport of itself producing two exports of the same
342+ // macro in the same module.
343+ let mut inserted = FxHashSet :: default ( ) ;
344+ for export in self . cx . tcx . module_reexports ( CRATE_DEF_ID ) . unwrap_or ( & [ ] ) {
345+ if let Res :: Def ( DefKind :: Macro ( _) , def_id) = export. res &&
346+ let Some ( local_def_id) = def_id. as_local ( ) &&
347+ self . cx . tcx . has_attr ( def_id, sym:: macro_export) &&
348+ inserted. insert ( def_id)
349+ {
350+ let item = self . cx . tcx . hir ( ) . expect_item ( local_def_id) ;
351+ top_level_module. items . push ( ( item, None , None ) ) ;
352+ }
353+ }
354+
355+ self . cx . cache . hidden_cfg = self
356+ . cx
357+ . tcx
358+ . hir ( )
359+ . attrs ( CRATE_HIR_ID )
360+ . iter ( )
361+ . filter ( |attr| attr. has_name ( sym:: doc) )
362+ . flat_map ( |attr| attr. meta_item_list ( ) . into_iter ( ) . flatten ( ) )
363+ . filter ( |attr| attr. has_name ( sym:: cfg_hide) )
364+ . flat_map ( |attr| {
365+ attr. meta_item_list ( )
366+ . unwrap_or ( & [ ] )
367+ . iter ( )
368+ . filter_map ( |attr| {
369+ Cfg :: parse ( attr. meta_item ( ) ?)
370+ . map_err ( |e| self . cx . sess ( ) . diagnostic ( ) . span_err ( e. span , e. msg ) )
371+ . ok ( )
372+ } )
373+ . collect :: < Vec < _ > > ( )
374+ } )
375+ . chain (
376+ [ Cfg :: Cfg ( sym:: test, None ) , Cfg :: Cfg ( sym:: doc, None ) , Cfg :: Cfg ( sym:: doctest, None ) ]
377+ . into_iter ( ) ,
378+ )
379+ . collect ( ) ;
380+
381+ self . cx . cache . exact_paths = self . exact_paths ;
382+ top_level_module
383+ }
384+
411385 /// This method will create a new module and push it onto the "modules stack" then call
412386 /// `visit_mod_contents`. Once done, it'll remove it from the "modules stack" and instead
413387 /// add into the list of modules of the current module.
@@ -419,6 +393,35 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
419393 let last = self . modules . pop ( ) . unwrap ( ) ;
420394 self . modules . last_mut ( ) . unwrap ( ) . mods . push ( last) ;
421395 }
396+
397+ /// This method will go through the given module items in two passes:
398+ /// 1. The items which are not glob imports/reexports.
399+ /// 2. The glob imports/reexports.
400+ fn visit_mod_contents ( & mut self , id : hir:: HirId , m : & ' tcx hir:: Mod < ' tcx > ) {
401+ debug ! ( "Going through module {:?}" , m) ;
402+ let def_id = self . cx . tcx . hir ( ) . local_def_id ( id) . to_def_id ( ) ;
403+ // Keep track of if there were any private modules in the path.
404+ let orig_inside_public_path = self . inside_public_path ;
405+ self . inside_public_path &= self . cx . tcx . visibility ( def_id) . is_public ( ) ;
406+
407+ // Reimplementation of `walk_mod`:
408+ for & i in m. item_ids {
409+ let item = self . cx . tcx . hir ( ) . item ( i) ;
410+ if !matches ! ( item. kind, hir:: ItemKind :: Use ( _, hir:: UseKind :: Glob ) ) {
411+ self . visit_item ( item) ;
412+ }
413+ }
414+ for & i in m. item_ids {
415+ let item = self . cx . tcx . hir ( ) . item ( i) ;
416+ // To match the way import precedence works, visit glob imports last.
417+ // Later passes in rustdoc will de-duplicate by name and kind, so if glob-
418+ // imported items appear last, then they'll be the ones that get discarded.
419+ if matches ! ( item. kind, hir:: ItemKind :: Use ( _, hir:: UseKind :: Glob ) ) {
420+ self . visit_item ( item) ;
421+ }
422+ }
423+ self . inside_public_path = orig_inside_public_path;
424+ }
422425}
423426
424427// We need to implement this visitor so it'll go everywhere and retrieve items we're interested in
@@ -427,7 +430,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RustdocVisitor<'a, 'tcx> {
427430 type NestedFilter = nested_filter:: All ;
428431
429432 fn nested_visit_map ( & mut self ) -> Self :: Map {
430- self . cx . tcx . hir ( )
433+ self . map
431434 }
432435
433436 fn visit_item ( & mut self , i : & ' tcx hir:: Item < ' tcx > ) {
0 commit comments