rustdoc/passes/
strip_hidden.rs1use std::mem;
4
5use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
6use rustc_middle::ty::TyCtxt;
7use tracing::debug;
8
9use crate::clean::utils::inherits_doc_hidden;
10use crate::clean::{self, Item, ItemIdSet, reexport_chain};
11use crate::core::DocContext;
12use crate::fold::{DocFolder, strip_item};
13use crate::passes::ImplStripper;
14
15pub(super) fn strip_hidden(krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate {
16 if cx.document_hidden() {
17 return krate;
18 }
19
20 let mut retained = ItemIdSet::default();
21 let is_json_output = cx.is_json_output();
22
23 let krate = {
25 let mut stripper = Stripper {
26 retained: &mut retained,
27 update_retained: true,
28 tcx: cx.tcx,
29 is_in_hidden_item: false,
30 last_reexport: None,
31 };
32 stripper.fold_crate(krate)
33 };
34
35 let mut stripper = ImplStripper {
37 tcx: cx.tcx,
38 retained: &retained,
39 cache: &cx.cache,
40 is_json_output,
41 document_private: cx.document_private(),
42 document_hidden: cx.document_hidden(),
43 };
44 stripper.fold_crate(krate)
45}
46
47struct Stripper<'a, 'tcx> {
48 retained: &'a mut ItemIdSet,
49 update_retained: bool,
50 tcx: TyCtxt<'tcx>,
51 is_in_hidden_item: bool,
52 last_reexport: Option<LocalDefId>,
53}
54
55impl Stripper<'_, '_> {
56 fn set_last_reexport_then_fold_item(&mut self, i: Item) -> Item {
57 let prev_from_reexport = self.last_reexport;
58 if i.inline_stmt_id.is_some() {
59 self.last_reexport = i.item_id.as_def_id().and_then(|def_id| def_id.as_local());
60 }
61 let ret = self.fold_item_recur(i);
62 self.last_reexport = prev_from_reexport;
63 ret
64 }
65
66 fn set_is_in_hidden_item_and_fold(&mut self, is_in_hidden_item: bool, i: Item) -> Item {
67 let prev = self.is_in_hidden_item;
68 self.is_in_hidden_item |= is_in_hidden_item;
69 let ret = self.set_last_reexport_then_fold_item(i);
70 self.is_in_hidden_item = prev;
71 ret
72 }
73
74 fn recurse_in_impl_or_exported_macro(&mut self, i: Item) -> Item {
77 let prev = mem::replace(&mut self.is_in_hidden_item, false);
78 let ret = self.set_last_reexport_then_fold_item(i);
79 self.is_in_hidden_item = prev;
80 ret
81 }
82}
83
84impl DocFolder for Stripper<'_, '_> {
85 fn fold_item(&mut self, i: Item) -> Option<Item> {
86 let has_doc_hidden = i.is_doc_hidden();
87
88 if let clean::ImportItem(clean::Import { source, .. }) = &i.kind
89 && let Some(source_did) = source.did
90 {
91 if self.tcx.is_doc_hidden(source_did) {
92 return None;
93 } else if let Some(import_def_id) = i.def_id().and_then(|def_id| def_id.as_local()) {
94 let reexports = reexport_chain(self.tcx, import_def_id, source_did);
95
96 let has_hidden_source = reexports
98 .iter()
99 .filter_map(|reexport| reexport.id())
100 .any(|reexport_did| self.tcx.is_doc_hidden(reexport_did));
101
102 if has_hidden_source {
103 return None;
104 }
105 }
106 }
107
108 let is_impl_or_exported_macro = match i.kind {
109 clean::ImplItem(..) => true,
110 clean::MacroItem(..) => i.is_exported_macro(),
113 _ => false,
114 };
115 let mut is_hidden = has_doc_hidden;
116 if !is_impl_or_exported_macro {
117 is_hidden = self.is_in_hidden_item || has_doc_hidden;
118 if !is_hidden && i.inline_stmt_id.is_none() {
119 is_hidden = i
129 .item_id
130 .as_def_id()
131 .and_then(|def_id| def_id.as_local())
132 .map(|def_id| inherits_doc_hidden(self.tcx, def_id, self.last_reexport))
133 .unwrap_or(false);
134 }
135 }
136 if !is_hidden {
137 if self.update_retained {
138 self.retained.insert(i.item_id);
139 }
140 return Some(if is_impl_or_exported_macro {
141 self.recurse_in_impl_or_exported_macro(i)
142 } else {
143 self.set_is_in_hidden_item_and_fold(false, i)
144 });
145 }
146 debug!("strip_hidden: stripping {:?} {:?}", i.type_(), i.name);
147 match i.kind {
156 clean::StructFieldItem(..) | clean::ModuleItem(..) | clean::VariantItem(..) => {
157 let old = mem::replace(&mut self.update_retained, false);
161 let ret = self.set_is_in_hidden_item_and_fold(true, i);
162 self.update_retained = old;
163 if ret.item_id == clean::ItemId::DefId(CRATE_DEF_ID.into()) {
164 debug!("strip_hidden: Not stripping local crate");
166 Some(ret)
167 } else {
168 Some(strip_item(ret))
169 }
170 }
171 _ => {
172 let ret = self.set_is_in_hidden_item_and_fold(true, i);
173 if has_doc_hidden {
174 None
176 } else {
177 Some(strip_item(ret))
179 }
180 }
181 }
182 }
183}