@@ -19,6 +19,13 @@ use std::{iter, mem};
1919use crate :: clean:: { cfg:: Cfg , reexport_chain, AttributesExt , NestedAttributesExt } ;
2020use crate :: core;
2121
22+ #[ derive( Debug ) ]
23+ pub ( crate ) struct ItemEntry < ' hir > {
24+ pub ( crate ) item : & ' hir hir:: Item < ' hir > ,
25+ pub ( crate ) renamed : Option < Symbol > ,
26+ pub ( crate ) import_id : Option < LocalDefId > ,
27+ }
28+
2229/// This module is used to store stuff from Rust's AST in a more convenient
2330/// manner (and with prettier names) before cleaning.
2431#[ derive( Debug ) ]
@@ -31,10 +38,7 @@ pub(crate) struct Module<'hir> {
3138 pub ( crate ) import_id : Option < LocalDefId > ,
3239 /// The key is the item `ItemId` and the value is: (item, renamed, import_id).
3340 /// We use `FxIndexMap` to keep the insert order.
34- pub ( crate ) items : FxIndexMap <
35- ( LocalDefId , Option < Symbol > ) ,
36- ( & ' hir hir:: Item < ' hir > , Option < Symbol > , Option < LocalDefId > ) ,
37- > ,
41+ pub ( crate ) items : FxIndexMap < ( LocalDefId , Option < Symbol > ) , ItemEntry < ' hir > > ,
3842 pub ( crate ) foreigns : Vec < ( & ' hir hir:: ForeignItem < ' hir > , Option < Symbol > ) > ,
3943}
4044
@@ -107,6 +111,7 @@ pub(crate) struct RustdocVisitor<'a, 'tcx> {
107111 modules : Vec < Module < ' tcx > > ,
108112 is_importable_from_parent : bool ,
109113 inside_body : bool ,
114+ ignored_items : usize ,
110115}
111116
112117impl < ' a , ' tcx > RustdocVisitor < ' a , ' tcx > {
@@ -131,6 +136,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
131136 modules : vec ! [ om] ,
132137 is_importable_from_parent : true ,
133138 inside_body : false ,
139+ ignored_items : 0 ,
134140 }
135141 }
136142
@@ -165,7 +171,11 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
165171 inserted. insert ( def_id)
166172 {
167173 let item = self . cx . tcx . hir ( ) . expect_item ( local_def_id) ;
168- top_level_module. items . insert ( ( local_def_id, Some ( item. ident . name ) ) , ( item, None , None ) ) ;
174+ top_level_module. items . insert ( ( local_def_id, Some ( item. ident . name ) ) , ItemEntry {
175+ item,
176+ renamed : None ,
177+ import_id : None ,
178+ } ) ;
169179 }
170180 }
171181
@@ -263,9 +273,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
263273 } ;
264274
265275 let use_attrs = tcx. hir ( ) . attrs ( tcx. hir ( ) . local_def_id_to_hir_id ( def_id) ) ;
266- // Don't inline `doc(hidden)` imports so they can be stripped at a later stage.
267- let is_no_inline = use_attrs. lists ( sym:: doc) . has_word ( sym:: no_inline)
268- || use_attrs. lists ( sym:: doc) . has_word ( sym:: hidden) ;
276+ let is_no_inline = use_attrs. lists ( sym:: doc) . has_word ( sym:: no_inline) ;
269277
270278 // For cross-crate impl inlining we need to know whether items are
271279 // reachable in documentation -- a previously unreachable item can be
@@ -280,12 +288,11 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
280288 return false ;
281289 } ;
282290
283- let is_private =
284- !self . cx . cache . effective_visibilities . is_directly_public ( self . cx . tcx , ori_res_did) ;
285- let is_hidden = inherits_doc_hidden ( self . cx . tcx , res_did, None ) ;
291+ let is_private = !self . cx . cache . effective_visibilities . is_directly_public ( tcx, ori_res_did) ;
292+ let is_hidden = tcx. is_doc_hidden ( res_did) || inherits_doc_hidden ( tcx, res_did, None ) ;
286293
287294 // Only inline if requested or if the item would otherwise be stripped.
288- if ( !please_inline && !is_private && !is_hidden) || is_no_inline {
295+ if is_no_inline || ( !please_inline && !is_private && !is_hidden) {
289296 return false ;
290297 }
291298
@@ -298,8 +305,9 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
298305 . cx
299306 . cache
300307 . effective_visibilities
301- . is_directly_public ( self . cx . tcx , item_def_id. to_def_id ( ) ) &&
302- !inherits_doc_hidden ( self . cx . tcx , item_def_id, None )
308+ . is_directly_public ( tcx, item_def_id. to_def_id ( ) ) &&
309+ !tcx. is_doc_hidden ( item_def_id) &&
310+ !inherits_doc_hidden ( tcx, item_def_id, None )
303311 {
304312 // The imported item is public and not `doc(hidden)` so no need to inline it.
305313 return false ;
@@ -312,22 +320,25 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
312320 let ret = match tcx. hir ( ) . get_by_def_id ( res_did) {
313321 Node :: Item ( & hir:: Item { kind : hir:: ItemKind :: Mod ( ref m) , .. } ) if glob => {
314322 let prev = mem:: replace ( & mut self . inlining , true ) ;
323+ let prev_ignored = self . ignored_items ;
315324 for & i in m. item_ids {
316- let i = self . cx . tcx . hir ( ) . item ( i) ;
317- self . visit_item_inner ( i, None , Some ( def_id) ) ;
325+ let i = tcx. hir ( ) . item ( i) ;
326+ self . visit_item_inner ( i, None , Some ( def_id) , true ) ;
318327 }
319328 self . inlining = prev;
320- true
329+ let inline = self . ignored_items - prev_ignored == 0 ;
330+ self . ignored_items = prev_ignored;
331+ inline
321332 }
322333 Node :: Item ( it) if !glob => {
323334 let prev = mem:: replace ( & mut self . inlining , true ) ;
324- self . visit_item_inner ( it, renamed, Some ( def_id) ) ;
335+ self . visit_item_inner ( it, renamed, Some ( def_id) , false ) ;
325336 self . inlining = prev;
326337 true
327338 }
328339 Node :: ForeignItem ( it) if !glob => {
329340 let prev = mem:: replace ( & mut self . inlining , true ) ;
330- self . visit_foreign_item_inner ( it, renamed) ;
341+ self . visit_foreign_item_inner ( it, renamed, false ) ;
331342 self . inlining = prev;
332343 true
333344 }
@@ -343,6 +354,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
343354 item : & ' tcx hir:: Item < ' _ > ,
344355 renamed : Option < Symbol > ,
345356 parent_id : Option < LocalDefId > ,
357+ from_glob_reexport : bool ,
346358 ) {
347359 if self . is_importable_from_parent
348360 // If we're inside an item, only impl blocks and `macro_rules!` with the `macro_export`
@@ -355,11 +367,14 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
355367 _ => false ,
356368 }
357369 {
358- self . modules
359- . last_mut ( )
360- . unwrap ( )
361- . items
362- . insert ( ( item. owner_id . def_id , renamed) , ( item, renamed, parent_id) ) ;
370+ if !from_glob_reexport || !self . cx . tcx . is_doc_hidden ( item. owner_id . to_def_id ( ) ) {
371+ self . modules . last_mut ( ) . unwrap ( ) . items . insert (
372+ ( item. owner_id . def_id , renamed) ,
373+ ItemEntry { item, renamed, import_id : parent_id } ,
374+ ) ;
375+ } else {
376+ self . ignored_items += 1 ;
377+ }
363378 }
364379 }
365380
@@ -368,6 +383,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
368383 item : & ' tcx hir:: Item < ' _ > ,
369384 renamed : Option < Symbol > ,
370385 import_id : Option < LocalDefId > ,
386+ from_glob_reexport : bool ,
371387 ) {
372388 debug ! ( "visiting item {:?}" , item) ;
373389 if self . inside_body {
@@ -386,7 +402,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
386402 // them up regardless of where they're located.
387403 impl_. of_trait . is_none ( )
388404 {
389- self . add_to_current_mod ( item, None , None ) ;
405+ self . add_to_current_mod ( item, None , None , false ) ;
390406 }
391407 return ;
392408 }
@@ -404,7 +420,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
404420 hir:: ItemKind :: ForeignMod { items, .. } => {
405421 for item in items {
406422 let item = tcx. hir ( ) . foreign_item ( item. id ) ;
407- self . visit_foreign_item_inner ( item, None ) ;
423+ self . visit_foreign_item_inner ( item, None , from_glob_reexport ) ;
408424 }
409425 }
410426 // If we're inlining, skip private items.
@@ -419,6 +435,15 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
419435 continue ;
420436 }
421437
438+ if from_glob_reexport &&
439+ tcx. is_doc_hidden ( def_id) &&
440+ let Some ( res_def_id) = res. opt_def_id ( ) &&
441+ tcx. is_doc_hidden ( res_def_id)
442+ {
443+ self . ignored_items += 1 ;
444+ continue ;
445+ }
446+
422447 let attrs =
423448 tcx. hir ( ) . attrs ( tcx. hir ( ) . local_def_id_to_hir_id ( item. owner_id . def_id ) ) ;
424449
@@ -444,7 +469,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
444469 }
445470 }
446471
447- self . add_to_current_mod ( item, renamed, import_id) ;
472+ self . add_to_current_mod ( item, renamed, import_id, false ) ;
448473 }
449474 }
450475 hir:: ItemKind :: Macro ( ref macro_def, _) => {
@@ -464,7 +489,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
464489 let nonexported = !tcx. has_attr ( def_id, sym:: macro_export) ;
465490
466491 if is_macro_2_0 || nonexported || self . inlining {
467- self . add_to_current_mod ( item, renamed, import_id) ;
492+ self . add_to_current_mod ( item, renamed, import_id, from_glob_reexport ) ;
468493 }
469494 }
470495 hir:: ItemKind :: Mod ( ref m) => {
@@ -483,7 +508,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
483508 | hir:: ItemKind :: Static ( ..)
484509 | hir:: ItemKind :: Trait ( ..)
485510 | hir:: ItemKind :: TraitAlias ( ..) => {
486- self . add_to_current_mod ( item, renamed, import_id) ;
511+ self . add_to_current_mod ( item, renamed, import_id, from_glob_reexport ) ;
487512 }
488513 hir:: ItemKind :: OpaqueTy ( hir:: OpaqueTy {
489514 origin : hir:: OpaqueTyOrigin :: AsyncFn ( _) | hir:: OpaqueTyOrigin :: FnReturn ( _) ,
@@ -495,14 +520,14 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
495520 // Underscore constants do not correspond to a nameable item and
496521 // so are never useful in documentation.
497522 if name != kw:: Underscore {
498- self . add_to_current_mod ( item, renamed, import_id) ;
523+ self . add_to_current_mod ( item, renamed, import_id, from_glob_reexport ) ;
499524 }
500525 }
501526 hir:: ItemKind :: Impl ( impl_) => {
502527 // Don't duplicate impls when inlining or if it's implementing a trait, we'll pick
503528 // them up regardless of where they're located.
504529 if !self . inlining && impl_. of_trait . is_none ( ) {
505- self . add_to_current_mod ( item, None , None ) ;
530+ self . add_to_current_mod ( item, None , None , false ) ;
506531 }
507532 }
508533 }
@@ -512,10 +537,15 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
512537 & mut self ,
513538 item : & ' tcx hir:: ForeignItem < ' _ > ,
514539 renamed : Option < Symbol > ,
540+ from_glob_reexport : bool ,
515541 ) {
516542 // If inlining we only want to include public functions.
517543 if !self . inlining || self . cx . tcx . visibility ( item. owner_id ) . is_public ( ) {
518- self . modules . last_mut ( ) . unwrap ( ) . foreigns . push ( ( item, renamed) ) ;
544+ if !from_glob_reexport || !self . cx . tcx . is_doc_hidden ( item. owner_id . to_def_id ( ) ) {
545+ self . modules . last_mut ( ) . unwrap ( ) . foreigns . push ( ( item, renamed) ) ;
546+ } else {
547+ self . ignored_items += 1 ;
548+ }
519549 }
520550 }
521551
@@ -549,7 +579,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RustdocVisitor<'a, 'tcx> {
549579 }
550580
551581 fn visit_item ( & mut self , i : & ' tcx hir:: Item < ' tcx > ) {
552- self . visit_item_inner ( i, None , None ) ;
582+ self . visit_item_inner ( i, None , None , false ) ;
553583 let new_value = self . is_importable_from_parent
554584 && matches ! (
555585 i. kind,
0 commit comments