Rollup merge of #110450 - GuillaumeGomez:fix-nested-items-on-private-doc, r=notriddle,jyn514

rustdoc: Fix invalid handling of nested items with `--document-private-items`

Fixes #110422.

The problem is that only impl block and re-exported `macro_rules!` items are "visible" as nested items. This PR adds the missing checks to handle this correctly.

cc `@compiler-errors`
r? `@notriddle`
This commit is contained in:
Matthias Krüger 2023-04-18 06:44:47 +02:00 committed by GitHub
commit d6468916c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 106 additions and 27 deletions

View File

@ -10,6 +10,7 @@ use rustc_hir::{Node, CRATE_HIR_ID};
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::TyCtxt;
use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE};
use rustc_span::hygiene::MacroKind;
use rustc_span::symbol::{kw, sym, Symbol};
use rustc_span::Span;
@ -87,6 +88,7 @@ pub(crate) struct RustdocVisitor<'a, 'tcx> {
inside_public_path: bool,
exact_paths: DefIdMap<Vec<Symbol>>,
modules: Vec<Module<'tcx>>,
is_importable_from_parent: bool,
}
impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
@ -107,6 +109,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
inside_public_path: true,
exact_paths: Default::default(),
modules: vec![om],
is_importable_from_parent: true,
}
}
@ -319,11 +322,23 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
renamed: Option<Symbol>,
parent_id: Option<LocalDefId>,
) {
self.modules
.last_mut()
.unwrap()
.items
.insert((item.owner_id.def_id, renamed), (item, renamed, parent_id));
if self.is_importable_from_parent
// If we're inside an item, only impl blocks and `macro_rules!` with the `macro_export`
// attribute can still be visible.
|| match item.kind {
hir::ItemKind::Impl(..) => true,
hir::ItemKind::Macro(_, MacroKind::Bang) => {
self.cx.tcx.has_attr(item.owner_id.def_id, sym::macro_export)
}
_ => false,
}
{
self.modules
.last_mut()
.unwrap()
.items
.insert((item.owner_id.def_id, renamed), (item, renamed, parent_id));
}
}
fn visit_item_inner(
@ -331,7 +346,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
item: &'tcx hir::Item<'_>,
renamed: Option<Symbol>,
import_id: Option<LocalDefId>,
) -> bool {
) {
debug!("visiting item {:?}", item);
let name = renamed.unwrap_or(item.ident.name);
let tcx = self.cx.tcx;
@ -448,7 +463,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
}
}
}
true
}
fn visit_foreign_item_inner(
@ -485,9 +499,23 @@ impl<'a, 'tcx> Visitor<'tcx> for RustdocVisitor<'a, 'tcx> {
}
fn visit_item(&mut self, i: &'tcx hir::Item<'tcx>) {
if self.visit_item_inner(i, None, None) {
walk_item(self, i);
}
self.visit_item_inner(i, None, None);
let new_value = if self.is_importable_from_parent {
matches!(
i.kind,
hir::ItemKind::Mod(..)
| hir::ItemKind::ForeignMod { .. }
| hir::ItemKind::Impl(..)
| hir::ItemKind::Trait(..)
)
} else {
// Whatever the context, if it's an impl block, the items inside it can be used so they
// should be visible.
matches!(i.kind, hir::ItemKind::Impl(..))
};
let prev = mem::replace(&mut self.is_importable_from_parent, new_value);
walk_item(self, i);
self.is_importable_from_parent = prev;
}
fn visit_mod(&mut self, _: &hir::Mod<'tcx>, _: Span, _: hir::HirId) {

View File

@ -1,6 +1,9 @@
// check-pass
fn f() -> impl Sized {
enum E { //~ ERROR
enum E {
V(E),
}
unimplemented!()
}

View File

@ -1,16 +0,0 @@
error[E0072]: recursive type `f::E` has infinite size
--> $DIR/infinite-recursive-type-impl-trait.rs:2:5
|
LL | enum E {
| ^^^^^^
LL | V(E),
| - recursive without indirection
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
LL | V(Box<E>),
| ++++ +
error: aborting due to previous error
For more information about this error, try `rustc --explain E0072`.

View File

@ -0,0 +1,64 @@
// Regression test for <https://github.com/rust-lang/rust/issues/110422>.
// This test ensures that inner items (except for implementations and macros)
// don't appear in documentation.
// compile-flags: --document-private-items
#![crate_name = "foo"]
// @has 'foo/index.html'
// Checking there is no "trait" entry.
// @count - '//*[@id="main-content"]/*[@class="small-section-header"]' 4
// @has - '//*[@id="main-content"]/*[@class="small-section-header"]' 'Structs'
// @has - '//*[@id="main-content"]/*[@class="small-section-header"]' 'Constants'
// @has - '//*[@id="main-content"]/*[@class="small-section-header"]' 'Functions'
// @has - '//*[@id="main-content"]/*[@class="small-section-header"]' 'Macros'
// @has - '//a[@href="fn.foo.html"]' 'foo'
fn foo() {
fn bar() {}
// @has - '//a[@class="macro"]' 'visible_macro'
// @!has - '//a[@class="macro"]' 'non_visible_macro'
// @has 'foo/macro.visible_macro.html'
// @!has 'foo/macro.non_visible_macro.html'
#[macro_export]
macro_rules! visible_macro {
() => {}
}
macro_rules! non_visible_macro {
() => {}
}
}
// @has 'foo/index.html'
// @has - '//a[@href="struct.Bar.html"]' 'Bar'
struct Bar;
const BAR: i32 = {
// @!has - '//a[@href="fn.yo.html"]' 'yo'
// @!has 'foo/fn.yo.html'
fn yo() {}
// @!has 'foo/index.html' '//a[@href="trait.Foo.html"]' 'Foo'
// @!has 'foo/trait.Foo.html'
trait Foo {
fn babar() {}
}
impl Foo for Bar {}
// @has 'foo/struct.Bar.html'
// @has - '//*[@id="method.foo"]/*[@class="code-header"]' 'pub(crate) fn foo()'
// @count - '//*[@id="main-content"]/*[@class="small-section-header"]' 3
// We now check that the `Foo` trait is not documented nor visible on `Bar` page.
// @has - '//*[@id="main-content"]/*[@class="small-section-header"]' 'Implementations'
// @has - '//*[@id="main-content"]/*[@class="small-section-header"]' 'Auto Trait Implementations'
// @has - '//*[@id="main-content"]/*[@class="small-section-header"]' 'Blanket Implementations'
// @!has - '//*[@href="trait.Foo.html#method.babar"]/*[@class="code-header"]' 'fn babar()'
impl Bar {
fn foo() {}
}
1
};