1 use rustc_hir::def_id::DefId;
2 use rustc_middle::middle::privacy::AccessLevels;
3 use std::mem;
4 
5 use crate::clean::{self, Item, ItemIdSet};
6 use crate::fold::{strip_item, DocFolder};
7 
8 crate struct Stripper<'a> {
9     crate retained: &'a mut ItemIdSet,
10     crate access_levels: &'a AccessLevels<DefId>,
11     crate update_retained: bool,
12 }
13 
14 impl<'a> DocFolder for Stripper<'a> {
fold_item(&mut self, i: Item) -> Option<Item>15     fn fold_item(&mut self, i: Item) -> Option<Item> {
16         match *i.kind {
17             clean::StrippedItem(..) => {
18                 // We need to recurse into stripped modules to strip things
19                 // like impl methods but when doing so we must not add any
20                 // items to the `retained` set.
21                 debug!("Stripper: recursing into stripped {:?} {:?}", i.type_(), i.name);
22                 let old = mem::replace(&mut self.update_retained, false);
23                 let ret = self.fold_item_recur(i);
24                 self.update_retained = old;
25                 return Some(ret);
26             }
27             // These items can all get re-exported
28             clean::OpaqueTyItem(..)
29             | clean::TypedefItem(..)
30             | clean::StaticItem(..)
31             | clean::StructItem(..)
32             | clean::EnumItem(..)
33             | clean::TraitItem(..)
34             | clean::FunctionItem(..)
35             | clean::VariantItem(..)
36             | clean::MethodItem(..)
37             | clean::ForeignFunctionItem(..)
38             | clean::ForeignStaticItem(..)
39             | clean::ConstantItem(..)
40             | clean::UnionItem(..)
41             | clean::AssocConstItem(..)
42             | clean::TraitAliasItem(..)
43             | clean::MacroItem(..)
44             | clean::ForeignTypeItem => {
45                 if i.def_id.is_local() {
46                     if !self.access_levels.is_exported(i.def_id.expect_def_id()) {
47                         debug!("Stripper: stripping {:?} {:?}", i.type_(), i.name);
48                         return None;
49                     }
50                 }
51             }
52 
53             clean::StructFieldItem(..) => {
54                 if !i.visibility.is_public() {
55                     return Some(strip_item(i));
56                 }
57             }
58 
59             clean::ModuleItem(..) => {
60                 if i.def_id.is_local() && !i.visibility.is_public() {
61                     debug!("Stripper: stripping module {:?}", i.name);
62                     let old = mem::replace(&mut self.update_retained, false);
63                     let ret = strip_item(self.fold_item_recur(i));
64                     self.update_retained = old;
65                     return Some(ret);
66                 }
67             }
68 
69             // handled in the `strip-priv-imports` pass
70             clean::ExternCrateItem { .. } | clean::ImportItem(..) => {}
71 
72             clean::ImplItem(..) => {}
73 
74             // tymethods have no control over privacy
75             clean::TyMethodItem(..) => {}
76 
77             // Proc-macros are always public
78             clean::ProcMacroItem(..) => {}
79 
80             // Primitives are never stripped
81             clean::PrimitiveItem(..) => {}
82 
83             // Associated types are never stripped
84             clean::AssocTypeItem(..) => {}
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.def_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.def_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 }
122 
123 impl<'a> DocFolder for ImplStripper<'a> {
fold_item(&mut self, i: Item) -> Option<Item>124     fn fold_item(&mut self, i: Item) -> Option<Item> {
125         if let clean::ImplItem(ref imp) = *i.kind {
126             // emptied none trait impls can be stripped
127             if imp.trait_.is_none() && imp.items.is_empty() {
128                 return None;
129             }
130             if let Some(did) = imp.for_.def_id_no_primitives() {
131                 if did.is_local() && !imp.for_.is_assoc_ty() && !self.retained.contains(&did.into())
132                 {
133                     debug!("ImplStripper: impl item for stripped type; removing");
134                     return None;
135                 }
136             }
137             if let Some(did) = imp.trait_.as_ref().map(|t| t.def_id()) {
138                 if did.is_local() && !self.retained.contains(&did.into()) {
139                     debug!("ImplStripper: impl item for stripped trait; removing");
140                     return None;
141                 }
142             }
143             if let Some(generics) = imp.trait_.as_ref().and_then(|t| t.generics()) {
144                 for typaram in generics {
145                     if let Some(did) = typaram.def_id_no_primitives() {
146                         if did.is_local() && !self.retained.contains(&did.into()) {
147                             debug!(
148                                 "ImplStripper: stripped item in trait's generics; removing impl"
149                             );
150                             return None;
151                         }
152                     }
153                 }
154             }
155         }
156         Some(self.fold_item_recur(i))
157     }
158 }
159 
160 /// This stripper discards all private import statements (`use`, `extern crate`)
161 crate struct ImportStripper;
162 
163 impl DocFolder for ImportStripper {
fold_item(&mut self, i: Item) -> Option<Item>164     fn fold_item(&mut self, i: Item) -> Option<Item> {
165         match *i.kind {
166             clean::ExternCrateItem { .. } | clean::ImportItem(..) if !i.visibility.is_public() => {
167                 None
168             }
169             _ => Some(self.fold_item_recur(i)),
170         }
171     }
172 }
173