11//! Strip all doc(hidden) items from the output. 
2+ 
3+ use  rustc_middle:: ty:: TyCtxt ; 
24use  rustc_span:: symbol:: sym; 
35use  std:: mem; 
46
@@ -7,6 +9,7 @@ use crate::clean::{Item, ItemIdSet, NestedAttributesExt};
79use  crate :: core:: DocContext ; 
810use  crate :: fold:: { strip_item,  DocFolder } ; 
911use  crate :: passes:: { ImplStripper ,  Pass } ; 
12+ use  crate :: visit_ast:: inherits_doc_hidden; 
1013
1114pub ( crate )  const  STRIP_HIDDEN :  Pass  = Pass  { 
1215    name :  "strip-hidden" , 
@@ -21,7 +24,12 @@ pub(crate) fn strip_hidden(krate: clean::Crate, cx: &mut DocContext<'_>) -> clea
2124
2225    // strip all #[doc(hidden)] items 
2326    let  krate = { 
24-         let  mut  stripper = Stripper  {  retained :  & mut  retained,  update_retained :  true  } ; 
27+         let  mut  stripper = Stripper  { 
28+             retained :  & mut  retained, 
29+             update_retained :  true , 
30+             tcx :  cx. tcx , 
31+             is_in_hidden_item :  false , 
32+         } ; 
2533        stripper. fold_crate ( krate) 
2634    } ; 
2735
@@ -36,40 +44,89 @@ pub(crate) fn strip_hidden(krate: clean::Crate, cx: &mut DocContext<'_>) -> clea
3644    stripper. fold_crate ( krate) 
3745} 
3846
39- struct  Stripper < ' a >  { 
47+ struct  Stripper < ' a ,   ' tcx >  { 
4048    retained :  & ' a  mut  ItemIdSet , 
4149    update_retained :  bool , 
50+     tcx :  TyCtxt < ' tcx > , 
51+     is_in_hidden_item :  bool , 
52+ } 
53+ 
54+ impl < ' a ,  ' tcx >  Stripper < ' a ,  ' tcx >  { 
55+     fn  set_is_in_hidden_item_and_fold ( & mut  self ,  is_in_hidden_item :  bool ,  i :  Item )  -> Item  { 
56+         let  prev = self . is_in_hidden_item ; 
57+         self . is_in_hidden_item  |= is_in_hidden_item; 
58+         let  ret = self . fold_item_recur ( i) ; 
59+         self . is_in_hidden_item  = prev; 
60+         ret
61+     } 
62+ 
63+     /// In case `i` is a non-hidden impl block, then we special-case it by changing the value 
64+ /// of `is_in_hidden_item` to `true` because the impl children inherit its visibility. 
65+ fn  recurse_in_impl ( & mut  self ,  i :  Item )  -> Item  { 
66+         let  prev = mem:: replace ( & mut  self . is_in_hidden_item ,  false ) ; 
67+         let  ret = self . fold_item_recur ( i) ; 
68+         self . is_in_hidden_item  = prev; 
69+         ret
70+     } 
4271} 
4372
44- impl < ' a >  DocFolder  for  Stripper < ' a >  { 
73+ impl < ' a ,   ' tcx >  DocFolder  for  Stripper < ' a ,   ' tcx >  { 
4574    fn  fold_item ( & mut  self ,  i :  Item )  -> Option < Item >  { 
46-         if  i. attrs . lists ( sym:: doc) . has_word ( sym:: hidden)  { 
47-             debug ! ( "strip_hidden: stripping {:?} {:?}" ,  i. type_( ) ,  i. name) ; 
48-             // Use a dedicated hidden item for fields, variants, and modules. 
49-             // We need to keep private fields and variants, so that the docs 
50-             // can show a placeholder "// some variants omitted". We need to keep 
51-             // private modules, because they can contain impl blocks, and impl 
52-             // block privacy is inherited from the type and trait, not from the 
53-             // module it's defined in. Both of these are marked "stripped," and 
54-             // not included in the final docs, but since they still have an effect 
55-             // on the final doc, cannot be completely removed from the Clean IR. 
56-             match  * i. kind  { 
57-                 clean:: StructFieldItem ( ..)  | clean:: ModuleItem ( ..)  | clean:: VariantItem ( ..)  => { 
58-                     // We need to recurse into stripped modules to 
59-                     // strip things like impl methods but when doing so 
60-                     // we must not add any items to the `retained` set. 
61-                     let  old = mem:: replace ( & mut  self . update_retained ,  false ) ; 
62-                     let  ret = strip_item ( self . fold_item_recur ( i) ) ; 
63-                     self . update_retained  = old; 
64-                     return  Some ( ret) ; 
65-                 } 
66-                 _ => return  None , 
75+         let  has_doc_hidden = i. attrs . lists ( sym:: doc) . has_word ( sym:: hidden) ; 
76+         let  is_impl = matches ! ( * i. kind,  clean:: ImplItem ( ..) ) ; 
77+         let  mut  is_hidden = has_doc_hidden; 
78+         if  !is_impl { 
79+             is_hidden = self . is_in_hidden_item  || has_doc_hidden; 
80+             if  !is_hidden && i. inline_stmt_id . is_none ( )  { 
81+                 // We don't need to check if it's coming from a reexport since the reexport itself was 
82+                 // already checked. 
83+                 is_hidden = i
84+                     . item_id 
85+                     . as_def_id ( ) 
86+                     . and_then ( |def_id| def_id. as_local ( ) ) 
87+                     . map ( |def_id| inherits_doc_hidden ( self . tcx ,  def_id) ) 
88+                     . unwrap_or ( false ) ; 
6789            } 
68-         }  else  { 
90+         } 
91+         if  !is_hidden { 
6992            if  self . update_retained  { 
7093                self . retained . insert ( i. item_id ) ; 
7194            } 
95+             return  Some ( if  is_impl { 
96+                 self . recurse_in_impl ( i) 
97+             }  else  { 
98+                 self . set_is_in_hidden_item_and_fold ( false ,  i) 
99+             } ) ; 
100+         } 
101+         debug ! ( "strip_hidden: stripping {:?} {:?}" ,  i. type_( ) ,  i. name) ; 
102+         // Use a dedicated hidden item for fields, variants, and modules. 
103+         // We need to keep private fields and variants, so that the docs 
104+         // can show a placeholder "// some variants omitted". We need to keep 
105+         // private modules, because they can contain impl blocks, and impl 
106+         // block privacy is inherited from the type and trait, not from the 
107+         // module it's defined in. Both of these are marked "stripped," and 
108+         // not included in the final docs, but since they still have an effect 
109+         // on the final doc, cannot be completely removed from the Clean IR. 
110+         match  * i. kind  { 
111+             clean:: StructFieldItem ( ..)  | clean:: ModuleItem ( ..)  | clean:: VariantItem ( ..)  => { 
112+                 // We need to recurse into stripped modules to 
113+                 // strip things like impl methods but when doing so 
114+                 // we must not add any items to the `retained` set. 
115+                 let  old = mem:: replace ( & mut  self . update_retained ,  false ) ; 
116+                 let  ret = strip_item ( self . set_is_in_hidden_item_and_fold ( true ,  i) ) ; 
117+                 self . update_retained  = old; 
118+                 Some ( ret) 
119+             } 
120+             _ => { 
121+                 let  ret = self . set_is_in_hidden_item_and_fold ( true ,  i) ; 
122+                 if  has_doc_hidden { 
123+                     // If the item itself has `#[doc(hidden)]`, then we simply remove it. 
124+                     None 
125+                 }  else  { 
126+                     // However if it's a "descendant" of a `#[doc(hidden)]` item, then we strip it. 
127+                     Some ( strip_item ( ret) ) 
128+                 } 
129+             } 
72130        } 
73-         Some ( self . fold_item_recur ( i) ) 
74131    } 
75132} 
0 commit comments