diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs index f293a6fcc6d..89efddf76ef 100644 --- a/src/librustdoc/passes/stripper.rs +++ b/src/librustdoc/passes/stripper.rs @@ -1,9 +1,11 @@ //! A collection of utility functions for the `strip_*` passes. use rustc_hir::def_id::DefId; use rustc_middle::middle::privacy::EffectiveVisibilities; +use rustc_span::symbol::sym; + use std::mem; -use crate::clean::{self, Item, ItemId, ItemIdSet}; +use crate::clean::{self, Item, ItemId, ItemIdSet, NestedAttributesExt}; use crate::fold::{strip_item, DocFolder}; use crate::formats::cache::Cache; @@ -151,6 +153,22 @@ pub(crate) struct ImplStripper<'a> { pub(crate) document_private: bool, } +impl<'a> ImplStripper<'a> { + #[inline] + fn should_keep_impl(&self, item: &Item, for_def_id: DefId) -> bool { + if !for_def_id.is_local() || self.retained.contains(&for_def_id.into()) { + true + } else if self.is_json_output { + // If the "for" item is exported and the impl block isn't `#[doc(hidden)]`, then we + // need to keep it. + self.cache.access_levels.is_exported(for_def_id) + && !item.attrs.lists(sym::doc).has_word(sym::hidden) + } else { + false + } + } +} + impl<'a> DocFolder for ImplStripper<'a> { fn fold_item(&mut self, i: Item) -> Option { if let clean::ImplItem(ref imp) = *i.kind { @@ -178,15 +196,17 @@ fn fold_item(&mut self, i: Item) -> Option { return None; } } + // Because we don't inline in `maybe_inline_local` if the output format is JSON, + // we need to make a special check for JSON output: we want to keep it unless it has + // a `#[doc(hidden)]` attribute if the `for_` type is exported. if let Some(did) = imp.for_.def_id(self.cache) { - if did.is_local() && !imp.for_.is_assoc_ty() && !self.retained.contains(&did.into()) - { + if !imp.for_.is_assoc_ty() && !self.should_keep_impl(&i, did) { 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()) { + if !self.should_keep_impl(&i, did) { debug!("ImplStripper: impl item for stripped trait; removing"); return None; } @@ -194,7 +214,7 @@ fn fold_item(&mut self, i: Item) -> Option { 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()) { + if !self.should_keep_impl(&i, did) { debug!( "ImplStripper: stripped item in trait's generics; removing impl" );