diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:02:58 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:02:58 +0000 |
commit | 698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch) | |
tree | 173a775858bd501c378080a10dca74132f05bc50 /src/librustdoc/passes/stripper.rs | |
parent | Initial commit. (diff) | |
download | rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip |
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/librustdoc/passes/stripper.rs')
-rw-r--r-- | src/librustdoc/passes/stripper.rs | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs new file mode 100644 index 000000000..0d419042a --- /dev/null +++ b/src/librustdoc/passes/stripper.rs @@ -0,0 +1,188 @@ +//! A collection of utility functions for the `strip_*` passes. +use rustc_hir::def_id::DefId; +use rustc_middle::middle::privacy::AccessLevels; +use std::mem; + +use crate::clean::{self, Item, ItemId, ItemIdSet}; +use crate::fold::{strip_item, DocFolder}; +use crate::formats::cache::Cache; + +pub(crate) struct Stripper<'a> { + pub(crate) retained: &'a mut ItemIdSet, + pub(crate) access_levels: &'a AccessLevels<DefId>, + pub(crate) update_retained: bool, + pub(crate) is_json_output: bool, +} + +impl<'a> Stripper<'a> { + // We need to handle this differently for the JSON output because some non exported items could + // be used in public API. And so, we need these items as well. `is_exported` only checks if they + // are in the public API, which is not enough. + #[inline] + fn is_item_reachable(&self, item_id: ItemId) -> bool { + if self.is_json_output { + self.access_levels.is_reachable(item_id.expect_def_id()) + } else { + self.access_levels.is_exported(item_id.expect_def_id()) + } + } +} + +impl<'a> DocFolder for Stripper<'a> { + fn fold_item(&mut self, i: Item) -> Option<Item> { + match *i.kind { + clean::StrippedItem(..) => { + // We need to recurse into stripped modules to strip things + // like impl methods but when doing so we must not add any + // items to the `retained` set. + debug!("Stripper: recursing into stripped {:?} {:?}", i.type_(), i.name); + let old = mem::replace(&mut self.update_retained, false); + let ret = self.fold_item_recur(i); + self.update_retained = old; + return Some(ret); + } + // These items can all get re-exported + clean::OpaqueTyItem(..) + | clean::TypedefItem(..) + | clean::StaticItem(..) + | clean::StructItem(..) + | clean::EnumItem(..) + | clean::TraitItem(..) + | clean::FunctionItem(..) + | clean::VariantItem(..) + | clean::MethodItem(..) + | clean::ForeignFunctionItem(..) + | clean::ForeignStaticItem(..) + | clean::ConstantItem(..) + | clean::UnionItem(..) + | clean::AssocConstItem(..) + | clean::AssocTypeItem(..) + | clean::TraitAliasItem(..) + | clean::MacroItem(..) + | clean::ForeignTypeItem => { + let item_id = i.item_id; + if item_id.is_local() && !self.is_item_reachable(item_id) { + debug!("Stripper: stripping {:?} {:?}", i.type_(), i.name); + return None; + } + } + + clean::StructFieldItem(..) => { + if !i.visibility.is_public() { + return Some(strip_item(i)); + } + } + + clean::ModuleItem(..) => { + if i.item_id.is_local() && !i.visibility.is_public() { + debug!("Stripper: stripping module {:?}", i.name); + let old = mem::replace(&mut self.update_retained, false); + let ret = strip_item(self.fold_item_recur(i)); + self.update_retained = old; + return Some(ret); + } + } + + // handled in the `strip-priv-imports` pass + clean::ExternCrateItem { .. } | clean::ImportItem(..) => {} + + clean::ImplItem(..) => {} + + // tymethods etc. have no control over privacy + clean::TyMethodItem(..) | clean::TyAssocConstItem(..) | clean::TyAssocTypeItem(..) => {} + + // Proc-macros are always public + clean::ProcMacroItem(..) => {} + + // Primitives are never stripped + clean::PrimitiveItem(..) => {} + + // Keywords are never stripped + clean::KeywordItem => {} + } + + let fastreturn = match *i.kind { + // nothing left to do for traits (don't want to filter their + // methods out, visibility controlled by the trait) + clean::TraitItem(..) => true, + + // implementations of traits are always public. + clean::ImplItem(ref imp) if imp.trait_.is_some() => true, + // Variant fields have inherited visibility + clean::VariantItem(clean::Variant::Struct(..) | clean::Variant::Tuple(..)) => true, + _ => false, + }; + + let i = if fastreturn { + if self.update_retained { + self.retained.insert(i.item_id); + } + return Some(i); + } else { + self.fold_item_recur(i) + }; + + if self.update_retained { + self.retained.insert(i.item_id); + } + Some(i) + } +} + +/// This stripper discards all impls which reference stripped items +pub(crate) struct ImplStripper<'a> { + pub(crate) retained: &'a ItemIdSet, + pub(crate) cache: &'a Cache, +} + +impl<'a> DocFolder for ImplStripper<'a> { + fn fold_item(&mut self, i: Item) -> Option<Item> { + if let clean::ImplItem(ref imp) = *i.kind { + // Impl blocks can be skipped if they are: empty; not a trait impl; and have no + // documentation. + if imp.trait_.is_none() && imp.items.is_empty() && i.doc_value().is_none() { + return None; + } + if let Some(did) = imp.for_.def_id(self.cache) { + if did.is_local() && !imp.for_.is_assoc_ty() && !self.retained.contains(&did.into()) + { + debug!("ImplStripper: impl item for stripped type; removing"); + return None; + } + } + if let Some(did) = imp.trait_.as_ref().map(|t| t.def_id()) { + if did.is_local() && !self.retained.contains(&did.into()) { + debug!("ImplStripper: impl item for stripped trait; removing"); + return None; + } + } + if let Some(generics) = imp.trait_.as_ref().and_then(|t| t.generics()) { + for typaram in generics { + if let Some(did) = typaram.def_id(self.cache) { + if did.is_local() && !self.retained.contains(&did.into()) { + debug!( + "ImplStripper: stripped item in trait's generics; removing impl" + ); + return None; + } + } + } + } + } + Some(self.fold_item_recur(i)) + } +} + +/// This stripper discards all private import statements (`use`, `extern crate`) +pub(crate) struct ImportStripper; + +impl DocFolder for ImportStripper { + fn fold_item(&mut self, i: Item) -> Option<Item> { + match *i.kind { + clean::ExternCrateItem { .. } | clean::ImportItem(..) if !i.visibility.is_public() => { + None + } + _ => Some(self.fold_item_recur(i)), + } + } +} |