@@ -7,9 +7,9 @@ use rustc_hir::def::{DefKind, Res};
7
7
use rustc_hir:: def_id:: DefId ;
8
8
use rustc_hir:: Node ;
9
9
use rustc_middle:: middle:: privacy:: AccessLevel ;
10
- use rustc_middle:: ty:: TyCtxt ;
10
+ use rustc_middle:: ty:: { TyCtxt , Visibility } ;
11
11
use rustc_span;
12
- use rustc_span:: def_id:: LOCAL_CRATE ;
12
+ use rustc_span:: def_id:: { CRATE_DEF_ID , LOCAL_CRATE } ;
13
13
use rustc_span:: source_map:: Spanned ;
14
14
use rustc_span:: symbol:: { kw, sym, Symbol } ;
15
15
@@ -73,13 +73,31 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
73
73
74
74
crate fn visit ( mut self , krate : & ' tcx hir:: Crate < ' _ > ) -> Module < ' tcx > {
75
75
let span = krate. module ( ) . inner ;
76
- let top_level_module = self . visit_mod_contents (
76
+ let mut top_level_module = self . visit_mod_contents (
77
77
& Spanned { span, node : hir:: VisibilityKind :: Public } ,
78
78
hir:: CRATE_HIR_ID ,
79
79
& krate. module ( ) ,
80
80
self . cx . tcx . crate_name ( LOCAL_CRATE ) ,
81
81
) ;
82
82
83
+ // `#[macro_export] macro_rules!` items are reexported at the top level of the
84
+ // crate, regardless of where they're defined. We want to document the
85
+ // top level rexport of the macro, not its original definition, since
86
+ // the rexport defines the path that a user will actually see. Accordingly,
87
+ // we add the rexport as an item here, and then skip over the original
88
+ // definition in `visit_item()` below.
89
+ for export in self . cx . tcx . module_exports ( CRATE_DEF_ID ) . unwrap_or ( & [ ] ) {
90
+ if let Res :: Def ( DefKind :: Macro ( _) , def_id) = export. res {
91
+ if let Some ( local_def_id) = def_id. as_local ( ) {
92
+ if self . cx . tcx . has_attr ( def_id, sym:: macro_export) {
93
+ let hir_id = self . cx . tcx . hir ( ) . local_def_id_to_hir_id ( local_def_id) ;
94
+ let item = self . cx . tcx . hir ( ) . expect_item ( hir_id) ;
95
+ top_level_module. items . push ( ( item, None ) ) ;
96
+ }
97
+ }
98
+ }
99
+ }
100
+
83
101
self . cx . cache . exact_paths = self . exact_paths ;
84
102
top_level_module
85
103
}
@@ -210,11 +228,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
210
228
debug ! ( "visiting item {:?}" , item) ;
211
229
let name = renamed. unwrap_or ( item. ident . name ) ;
212
230
213
- let is_pub = if let hir:: ItemKind :: Macro { is_exported : true , .. } = item. kind {
214
- true
215
- } else {
216
- item. vis . node . is_pub ( )
217
- } ;
231
+ let is_pub = self . cx . tcx . visibility ( item. def_id ) == Visibility :: Public ;
218
232
219
233
if is_pub {
220
234
self . store_path ( item. def_id . to_def_id ( ) ) ;
@@ -269,8 +283,27 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
269
283
hir:: ItemKind :: Mod ( ref m) => {
270
284
om. mods . push ( self . visit_mod_contents ( & item. vis , item. hir_id ( ) , m, name) ) ;
271
285
}
286
+ hir:: ItemKind :: Macro { ref macro_def, .. } => {
287
+ // `#[macro_export] macro_rules!` items are handled seperately in `visit()`,
288
+ // above, since they need to be documented at the module top level. Accordingly,
289
+ // we only want to handle macros if one of three conditions holds:
290
+ //
291
+ // 1. This macro was defined by `macro`, and thus isn't covered by the case
292
+ // above.
293
+ // 2. This macro isn't marked with `#[macro_export]`, and thus isn't covered
294
+ // by the case above.
295
+ // 3. We're inlining, since a reexport where inlining has been requested
296
+ // should be inlined even if it is also documented at the top level.
297
+
298
+ let def_id = item. def_id . to_def_id ( ) ;
299
+ let is_macro_2_0 = !macro_def. ast . macro_rules ;
300
+ let nonexported = !self . cx . tcx . has_attr ( def_id, sym:: macro_export) ;
301
+
302
+ if is_macro_2_0 || nonexported || self . inlining {
303
+ om. items . push ( ( item, renamed) ) ;
304
+ }
305
+ }
272
306
hir:: ItemKind :: Fn ( ..)
273
- | hir:: ItemKind :: Macro { .. }
274
307
| hir:: ItemKind :: ExternCrate ( ..)
275
308
| hir:: ItemKind :: Enum ( ..)
276
309
| hir:: ItemKind :: Struct ( ..)
0 commit comments