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