]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/passes/stripper.rs
Add bound_predicates_of and bound_explicit_predicates_of
[rust.git] / src / librustdoc / passes / stripper.rs
1 //! A collection of utility functions for the `strip_*` passes.
2 use rustc_hir::def_id::DefId;
3 use rustc_middle::middle::privacy::AccessLevels;
4 use std::mem;
5
6 use crate::clean::{self, Item, ItemId, ItemIdSet};
7 use crate::fold::{strip_item, DocFolder};
8 use crate::formats::cache::Cache;
9
10 pub(crate) struct Stripper<'a> {
11     pub(crate) retained: &'a mut ItemIdSet,
12     pub(crate) access_levels: &'a AccessLevels<DefId>,
13     pub(crate) update_retained: bool,
14     pub(crate) is_json_output: bool,
15 }
16
17 impl<'a> Stripper<'a> {
18     // We need to handle this differently for the JSON output because some non exported items could
19     // be used in public API. And so, we need these items as well. `is_exported` only checks if they
20     // are in the public API, which is not enough.
21     #[inline]
22     fn is_item_reachable(&self, item_id: ItemId) -> bool {
23         if self.is_json_output {
24             self.access_levels.is_reachable(item_id.expect_def_id())
25         } else {
26             self.access_levels.is_exported(item_id.expect_def_id())
27         }
28     }
29 }
30
31 impl<'a> DocFolder for Stripper<'a> {
32     fn fold_item(&mut self, i: Item) -> Option<Item> {
33         match *i.kind {
34             clean::StrippedItem(..) => {
35                 // We need to recurse into stripped modules to strip things
36                 // like impl methods but when doing so we must not add any
37                 // items to the `retained` set.
38                 debug!("Stripper: recursing into stripped {:?} {:?}", i.type_(), i.name);
39                 let old = mem::replace(&mut self.update_retained, false);
40                 let ret = self.fold_item_recur(i);
41                 self.update_retained = old;
42                 return Some(ret);
43             }
44             // These items can all get re-exported
45             clean::OpaqueTyItem(..)
46             | clean::TypedefItem(..)
47             | clean::StaticItem(..)
48             | clean::StructItem(..)
49             | clean::EnumItem(..)
50             | clean::TraitItem(..)
51             | clean::FunctionItem(..)
52             | clean::VariantItem(..)
53             | clean::MethodItem(..)
54             | clean::ForeignFunctionItem(..)
55             | clean::ForeignStaticItem(..)
56             | clean::ConstantItem(..)
57             | clean::UnionItem(..)
58             | clean::AssocConstItem(..)
59             | clean::AssocTypeItem(..)
60             | clean::TraitAliasItem(..)
61             | clean::MacroItem(..)
62             | clean::ForeignTypeItem => {
63                 let item_id = i.item_id;
64                 if item_id.is_local() && !self.is_item_reachable(item_id) {
65                     debug!("Stripper: stripping {:?} {:?}", i.type_(), i.name);
66                     return None;
67                 }
68             }
69
70             clean::StructFieldItem(..) => {
71                 if !i.visibility.is_public() {
72                     return Some(strip_item(i));
73                 }
74             }
75
76             clean::ModuleItem(..) => {
77                 if i.item_id.is_local() && !i.visibility.is_public() {
78                     debug!("Stripper: stripping module {:?}", i.name);
79                     let old = mem::replace(&mut self.update_retained, false);
80                     let ret = strip_item(self.fold_item_recur(i));
81                     self.update_retained = old;
82                     return Some(ret);
83                 }
84             }
85
86             // handled in the `strip-priv-imports` pass
87             clean::ExternCrateItem { .. } | clean::ImportItem(..) => {}
88
89             clean::ImplItem(..) => {}
90
91             // tymethods etc. have no control over privacy
92             clean::TyMethodItem(..) | clean::TyAssocConstItem(..) | clean::TyAssocTypeItem(..) => {}
93
94             // Proc-macros are always public
95             clean::ProcMacroItem(..) => {}
96
97             // Primitives are never stripped
98             clean::PrimitiveItem(..) => {}
99
100             // Keywords are never stripped
101             clean::KeywordItem => {}
102         }
103
104         let fastreturn = match *i.kind {
105             // nothing left to do for traits (don't want to filter their
106             // methods out, visibility controlled by the trait)
107             clean::TraitItem(..) => true,
108
109             // implementations of traits are always public.
110             clean::ImplItem(ref imp) if imp.trait_.is_some() => true,
111             // Variant fields have inherited visibility
112             clean::VariantItem(clean::Variant::Struct(..) | clean::Variant::Tuple(..)) => true,
113             _ => false,
114         };
115
116         let i = if fastreturn {
117             if self.update_retained {
118                 self.retained.insert(i.item_id);
119             }
120             return Some(i);
121         } else {
122             self.fold_item_recur(i)
123         };
124
125         if self.update_retained {
126             self.retained.insert(i.item_id);
127         }
128         Some(i)
129     }
130 }
131
132 /// This stripper discards all impls which reference stripped items
133 pub(crate) struct ImplStripper<'a> {
134     pub(crate) retained: &'a ItemIdSet,
135     pub(crate) cache: &'a Cache,
136 }
137
138 impl<'a> DocFolder for ImplStripper<'a> {
139     fn fold_item(&mut self, i: Item) -> Option<Item> {
140         if let clean::ImplItem(ref imp) = *i.kind {
141             // Impl blocks can be skipped if they are: empty; not a trait impl; and have no
142             // documentation.
143             if imp.trait_.is_none() && imp.items.is_empty() && i.doc_value().is_none() {
144                 return None;
145             }
146             if let Some(did) = imp.for_.def_id(self.cache) {
147                 if did.is_local() && !imp.for_.is_assoc_ty() && !self.retained.contains(&did.into())
148                 {
149                     debug!("ImplStripper: impl item for stripped type; removing");
150                     return None;
151                 }
152             }
153             if let Some(did) = imp.trait_.as_ref().map(|t| t.def_id()) {
154                 if did.is_local() && !self.retained.contains(&did.into()) {
155                     debug!("ImplStripper: impl item for stripped trait; removing");
156                     return None;
157                 }
158             }
159             if let Some(generics) = imp.trait_.as_ref().and_then(|t| t.generics()) {
160                 for typaram in generics {
161                     if let Some(did) = typaram.def_id(self.cache) {
162                         if did.is_local() && !self.retained.contains(&did.into()) {
163                             debug!(
164                                 "ImplStripper: stripped item in trait's generics; removing impl"
165                             );
166                             return None;
167                         }
168                     }
169                 }
170             }
171         }
172         Some(self.fold_item_recur(i))
173     }
174 }
175
176 /// This stripper discards all private import statements (`use`, `extern crate`)
177 pub(crate) struct ImportStripper;
178
179 impl DocFolder for ImportStripper {
180     fn fold_item(&mut self, i: Item) -> Option<Item> {
181         match *i.kind {
182             clean::ExternCrateItem { .. } | clean::ImportItem(..) if !i.visibility.is_public() => {
183                 None
184             }
185             _ => Some(self.fold_item_recur(i)),
186         }
187     }
188 }