@@ -8,6 +8,7 @@ use rustc_hir::def_id::DefId;
8
8
use rustc_hir:: intravisit:: { walk_item, Visitor } ;
9
9
use rustc_hir:: Node ;
10
10
use rustc_hir:: CRATE_HIR_ID ;
11
+ use rustc_middle:: hir:: map:: Map ;
11
12
use rustc_middle:: hir:: nested_filter;
12
13
use rustc_middle:: ty:: TyCtxt ;
13
14
use rustc_span:: def_id:: { CRATE_DEF_ID , LOCAL_CRATE } ;
@@ -67,6 +68,7 @@ pub(crate) struct RustdocVisitor<'a, 'tcx> {
67
68
inside_public_path : bool ,
68
69
exact_paths : FxHashMap < DefId , Vec < Symbol > > ,
69
70
modules : Vec < Module < ' tcx > > ,
71
+ map : Map < ' tcx > ,
70
72
}
71
73
72
74
impl < ' a , ' tcx > RustdocVisitor < ' a , ' tcx > {
@@ -79,6 +81,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
79
81
hir:: CRATE_HIR_ID ,
80
82
cx. tcx . hir ( ) . root_module ( ) . spans . inner_span ,
81
83
) ;
84
+ let map = cx. tcx . hir ( ) ;
82
85
83
86
RustdocVisitor {
84
87
cx,
@@ -87,6 +90,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
87
90
inside_public_path : true ,
88
91
exact_paths : FxHashMap :: default ( ) ,
89
92
modules : vec ! [ om] ,
93
+ map,
90
94
}
91
95
}
92
96
@@ -95,95 +99,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
95
99
self . exact_paths . entry ( did) . or_insert_with ( || def_id_to_path ( tcx, did) ) ;
96
100
}
97
101
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
-
187
102
/// Tries to resolve the target of a `pub use` statement and inlines the
188
103
/// target if it is defined locally and would not be documented otherwise,
189
104
/// or when it is specifically requested with `please_inline`.
@@ -408,6 +323,65 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
408
323
}
409
324
}
410
325
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
+
411
385
/// This method will create a new module and push it onto the "modules stack" then call
412
386
/// `visit_mod_contents`. Once done, it'll remove it from the "modules stack" and instead
413
387
/// add into the list of modules of the current module.
@@ -419,6 +393,35 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
419
393
let last = self . modules . pop ( ) . unwrap ( ) ;
420
394
self . modules . last_mut ( ) . unwrap ( ) . mods . push ( last) ;
421
395
}
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
+ }
422
425
}
423
426
424
427
// 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> {
427
430
type NestedFilter = nested_filter:: All ;
428
431
429
432
fn nested_visit_map ( & mut self ) -> Self :: Map {
430
- self . cx . tcx . hir ( )
433
+ self . map
431
434
}
432
435
433
436
fn visit_item ( & mut self , i : & ' tcx hir:: Item < ' tcx > ) {
0 commit comments