Rollup merge of #103653 - GuillaumeGomez:missing-impl-private-json, r=notriddle
Add missing impl blocks for item reexported from private mod in JSON output Fixes #102583. Since we don't inline for the JSON output, the impl blocks from private modules are not present when we generate the output. To go around this limitation, in case the impl block doesn't have `#[doc(hidden)]` and is implementing a public item, we don't strip it. cc `@fmease` `@aDotInTheVoid` r? `@notriddle`
This commit is contained in:
commit
05ab16b54e
2 changed files with 53 additions and 5 deletions
|
@ -1,9 +1,11 @@
|
||||||
//! A collection of utility functions for the `strip_*` passes.
|
//! A collection of utility functions for the `strip_*` passes.
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_middle::middle::privacy::EffectiveVisibilities;
|
use rustc_middle::middle::privacy::EffectiveVisibilities;
|
||||||
|
use rustc_span::symbol::sym;
|
||||||
|
|
||||||
use std::mem;
|
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::fold::{strip_item, DocFolder};
|
||||||
use crate::formats::cache::Cache;
|
use crate::formats::cache::Cache;
|
||||||
|
|
||||||
|
@ -151,6 +153,22 @@ pub(crate) struct ImplStripper<'a> {
|
||||||
pub(crate) document_private: bool,
|
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> {
|
impl<'a> DocFolder for ImplStripper<'a> {
|
||||||
fn fold_item(&mut self, i: Item) -> Option<Item> {
|
fn fold_item(&mut self, i: Item) -> Option<Item> {
|
||||||
if let clean::ImplItem(ref imp) = *i.kind {
|
if let clean::ImplItem(ref imp) = *i.kind {
|
||||||
|
@ -178,15 +196,17 @@ impl<'a> DocFolder for ImplStripper<'a> {
|
||||||
return None;
|
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 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");
|
debug!("ImplStripper: impl item for stripped type; removing");
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(did) = imp.trait_.as_ref().map(|t| t.def_id()) {
|
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");
|
debug!("ImplStripper: impl item for stripped trait; removing");
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
@ -194,7 +214,7 @@ impl<'a> DocFolder for ImplStripper<'a> {
|
||||||
if let Some(generics) = imp.trait_.as_ref().and_then(|t| t.generics()) {
|
if let Some(generics) = imp.trait_.as_ref().and_then(|t| t.generics()) {
|
||||||
for typaram in generics {
|
for typaram in generics {
|
||||||
if let Some(did) = typaram.def_id(self.cache) {
|
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!(
|
debug!(
|
||||||
"ImplStripper: stripped item in trait's generics; removing impl"
|
"ImplStripper: stripped item in trait's generics; removing impl"
|
||||||
);
|
);
|
||||||
|
|
|
@ -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::*;
|
Loading…
Add table
Add a link
Reference in a new issue