Skip to content

Commit

Permalink
Auto merge of #107000 - GuillaumeGomez:fix-items-in-doc-hidden-block,…
Browse files Browse the repository at this point in the history
… r=notriddle,petrochenkov

Fix handling of items inside a `doc(hidden)` block

Fixes #106373.

cc `@aDotInTheVoid`
r? `@notriddle`
  • Loading branch information
bors committed Feb 2, 2023
2 parents f312650 + ea84418 commit 6c991b0
Show file tree
Hide file tree
Showing 11 changed files with 357 additions and 111 deletions.
16 changes: 6 additions & 10 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2213,21 +2213,17 @@ fn clean_maybe_renamed_item<'tcx>(
get_all_import_attributes(use_node, cx.tcx, item.owner_id.def_id, &mut extra_attrs);
}

if !extra_attrs.is_empty() {
let mut item = if !extra_attrs.is_empty() {
extra_attrs.extend_from_slice(inline::load_attrs(cx, def_id));
let attrs = Attributes::from_ast(&extra_attrs);
let cfg = extra_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg);

vec![Item::from_def_id_and_attrs_and_parts(
def_id,
Some(name),
kind,
Box::new(attrs),
cfg,
)]
Item::from_def_id_and_attrs_and_parts(def_id, Some(name), kind, Box::new(attrs), cfg)
} else {
vec![Item::from_def_id_and_parts(def_id, Some(name), kind, cx)]
}
Item::from_def_id_and_parts(def_id, Some(name), kind, cx)
};
item.inline_stmt_id = import_id.map(|def_id| def_id.to_def_id());
vec![item]
})
}

Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/html/render/write_shared.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ pub(super) fn write_shared(
Ok((ret, krates))
}

/// Read a file and return all lines that match the <code>"{crate}":{data},\</code> format,
/// Read a file and return all lines that match the <code>"{crate}":{data},\ </code> format,
/// and return a tuple `(Vec<DataString>, Vec<CrateNameString>)`.
///
/// This forms the payload of files that look like this:
Expand Down
109 changes: 83 additions & 26 deletions src/librustdoc/passes/strip_hidden.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
//! Strip all doc(hidden) items from the output.

use rustc_middle::ty::TyCtxt;
use rustc_span::symbol::sym;
use std::mem;

Expand All @@ -7,6 +9,7 @@ use crate::clean::{Item, ItemIdSet, NestedAttributesExt};
use crate::core::DocContext;
use crate::fold::{strip_item, DocFolder};
use crate::passes::{ImplStripper, Pass};
use crate::visit_ast::inherits_doc_hidden;

pub(crate) const STRIP_HIDDEN: Pass = Pass {
name: "strip-hidden",
Expand All @@ -21,7 +24,12 @@ pub(crate) fn strip_hidden(krate: clean::Crate, cx: &mut DocContext<'_>) -> clea

// strip all #[doc(hidden)] items
let krate = {
let mut stripper = Stripper { retained: &mut retained, update_retained: true };
let mut stripper = Stripper {
retained: &mut retained,
update_retained: true,
tcx: cx.tcx,
is_in_hidden_item: false,
};
stripper.fold_crate(krate)
};

Expand All @@ -36,40 +44,89 @@ pub(crate) fn strip_hidden(krate: clean::Crate, cx: &mut DocContext<'_>) -> clea
stripper.fold_crate(krate)
}

struct Stripper<'a> {
struct Stripper<'a, 'tcx> {
retained: &'a mut ItemIdSet,
update_retained: bool,
tcx: TyCtxt<'tcx>,
is_in_hidden_item: bool,
}

impl<'a, 'tcx> Stripper<'a, 'tcx> {
fn set_is_in_hidden_item_and_fold(&mut self, is_in_hidden_item: bool, i: Item) -> Item {
let prev = self.is_in_hidden_item;
self.is_in_hidden_item |= is_in_hidden_item;
let ret = self.fold_item_recur(i);
self.is_in_hidden_item = prev;
ret
}

/// In case `i` is a non-hidden impl block, then we special-case it by changing the value
/// of `is_in_hidden_item` to `true` because the impl children inherit its visibility.
fn recurse_in_impl(&mut self, i: Item) -> Item {
let prev = mem::replace(&mut self.is_in_hidden_item, false);
let ret = self.fold_item_recur(i);
self.is_in_hidden_item = prev;
ret
}
}

impl<'a> DocFolder for Stripper<'a> {
impl<'a, 'tcx> DocFolder for Stripper<'a, 'tcx> {
fn fold_item(&mut self, i: Item) -> Option<Item> {
if i.attrs.lists(sym::doc).has_word(sym::hidden) {
debug!("strip_hidden: stripping {:?} {:?}", i.type_(), i.name);
// Use a dedicated hidden item for fields, variants, and modules.
// We need to keep private fields and variants, so that the docs
// can show a placeholder "// some variants omitted". We need to keep
// private modules, because they can contain impl blocks, and impl
// block privacy is inherited from the type and trait, not from the
// module it's defined in. Both of these are marked "stripped," and
// not included in the final docs, but since they still have an effect
// on the final doc, cannot be completely removed from the Clean IR.
match *i.kind {
clean::StructFieldItem(..) | clean::ModuleItem(..) | clean::VariantItem(..) => {
// 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.
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);
}
_ => return None,
let has_doc_hidden = i.attrs.lists(sym::doc).has_word(sym::hidden);
let is_impl = matches!(*i.kind, clean::ImplItem(..));
let mut is_hidden = has_doc_hidden;
if !is_impl {
is_hidden = self.is_in_hidden_item || has_doc_hidden;
if !is_hidden && i.inline_stmt_id.is_none() {
// We don't need to check if it's coming from a reexport since the reexport itself was
// already checked.
is_hidden = i
.item_id
.as_def_id()
.and_then(|def_id| def_id.as_local())
.map(|def_id| inherits_doc_hidden(self.tcx, def_id))
.unwrap_or(false);
}
} else {
}
if !is_hidden {
if self.update_retained {
self.retained.insert(i.item_id);
}
return Some(if is_impl {
self.recurse_in_impl(i)
} else {
self.set_is_in_hidden_item_and_fold(false, i)
});
}
debug!("strip_hidden: stripping {:?} {:?}", i.type_(), i.name);
// Use a dedicated hidden item for fields, variants, and modules.
// We need to keep private fields and variants, so that the docs
// can show a placeholder "// some variants omitted". We need to keep
// private modules, because they can contain impl blocks, and impl
// block privacy is inherited from the type and trait, not from the
// module it's defined in. Both of these are marked "stripped," and
// not included in the final docs, but since they still have an effect
// on the final doc, cannot be completely removed from the Clean IR.
match *i.kind {
clean::StructFieldItem(..) | clean::ModuleItem(..) | clean::VariantItem(..) => {
// 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.
let old = mem::replace(&mut self.update_retained, false);
let ret = strip_item(self.set_is_in_hidden_item_and_fold(true, i));
self.update_retained = old;
Some(ret)
}
_ => {
let ret = self.set_is_in_hidden_item_and_fold(true, i);
if has_doc_hidden {
// If the item itself has `#[doc(hidden)]`, then we simply remove it.
None
} else {
// However if it's a "descendant" of a `#[doc(hidden)]` item, then we strip it.
Some(strip_item(ret))
}
}
}
Some(self.fold_item_recur(i))
}
}
Loading

0 comments on commit 6c991b0

Please sign in to comment.