Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 25 additions & 5 deletions src/librustdoc/passes/stripper.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -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.effective_visibilities.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<Item> {
if let clean::ImplItem(ref imp) = *i.kind {
Expand Down Expand Up @@ -178,23 +196,25 @@ impl<'a> DocFolder for ImplStripper<'a> {
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;
}
}
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"
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Regression test for <https://github.com/rust-lang/rust/issues/102583>.

// @set impl_S = "$.index[*][?(@.docs=='impl S')].id"
// @has "$.index[*][?(@.name=='S')].inner.impls[*]" $impl_S
// @set is_present = "$.index[*][?(@.name=='is_present')].id"
// @is "$.index[*][?(@.docs=='impl S')].inner.items[*]" $is_present
// @!has "$.index[*][?(@.name=='hidden_impl')]"
// @!has "$.index[*][?(@.name=='hidden_fn')]"

#![no_std]

mod private_mod {
pub struct S;

/// impl S
impl S {
pub fn is_present() {}
#[doc(hidden)]
pub fn hidden_fn() {}
}

#[doc(hidden)]
impl S {
pub fn hidden_impl() {}
}
}

pub use private_mod::*;