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