Skip to content

Commit 5a93223

Browse files
committed
[rustdoc] Inline reexport item
Signed-off-by: xizheyin <[email protected]>
1 parent f43e549 commit 5a93223

File tree

2 files changed

+52
-14
lines changed

2 files changed

+52
-14
lines changed

src/librustdoc/passes/strip_hidden.rs

+11-4
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ impl Stripper<'_, '_> {
8989
impl DocFolder for Stripper<'_, '_> {
9090
fn fold_item(&mut self, i: Item) -> Option<Item> {
9191
let has_doc_hidden = i.is_doc_hidden();
92+
debug!(
93+
"item: {:?}, has_doc_hidden: {}, is_in_hidden_item: {}",
94+
i, has_doc_hidden, self.is_in_hidden_item
95+
);
9296
let is_impl_or_exported_macro = match i.kind {
9397
clean::ImplItem(..) => true,
9498
// If the macro has the `#[macro_export]` attribute, it means it's accessible at the
@@ -119,7 +123,7 @@ impl DocFolder for Stripper<'_, '_> {
119123
.unwrap_or(false);
120124
}
121125
}
122-
if !is_hidden {
126+
if !is_hidden || i.inline_stmt_id.is_some() {
123127
if self.update_retained {
124128
self.retained.insert(i.item_id);
125129
}
@@ -144,23 +148,26 @@ impl DocFolder for Stripper<'_, '_> {
144148
// strip things like impl methods but when doing so
145149
// we must not add any items to the `retained` set.
146150
let old = mem::replace(&mut self.update_retained, false);
147-
let ret = self.set_is_in_hidden_item_and_fold(true, i);
151+
let ret = self.set_is_in_hidden_item_and_fold(true, i.clone());
148152
self.update_retained = old;
149153
if ret.item_id == clean::ItemId::DefId(CRATE_DEF_ID.into()) {
150154
// We don't strip the current crate, even if it has `#[doc(hidden)]`.
151-
debug!("strip_hidden: Not strippping local crate");
155+
debug!("strip_hidden0: Not strippping local crate");
152156
Some(ret)
153157
} else {
158+
debug!("strip_hidden1: stripping(strip_item) {:?} {:?}", i.type_(), i.name);
154159
Some(strip_item(ret))
155160
}
156161
}
157162
_ => {
158-
let ret = self.set_is_in_hidden_item_and_fold(true, i);
163+
let ret = self.set_is_in_hidden_item_and_fold(true, i.clone());
159164
if has_doc_hidden {
160165
// If the item itself has `#[doc(hidden)]`, then we simply remove it.
166+
debug!("strip_hidden2: stripping(remove) {:?} {:?}", i.type_(), i.name);
161167
None
162168
} else {
163169
// However if it's a "descendant" of a `#[doc(hidden)]` item, then we strip it.
170+
debug!("strip_hidden3: stripping(strip_item) {:?} {:?}", i.type_(), i.name);
164171
Some(strip_item(ret))
165172
}
166173
}

src/librustdoc/visit_ast.rs

+41-10
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
251251
|| (document_hidden && hir_attr_lists(use_attrs, sym::doc).has_word(sym::hidden));
252252

253253
if is_no_inline {
254+
debug!("maybe_inline_local: is_no_inline, (renamed: {renamed:?}) res: {res:?}");
254255
return false;
255256
}
256257

@@ -277,20 +278,33 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
277278
return true;
278279
};
279280

280-
let is_private = !self.cx.cache.effective_visibilities.is_directly_public(tcx, ori_res_did);
281281
let item = tcx.hir_node_by_def_id(res_did);
282282

283283
if !please_inline {
284+
// Check if item is private
285+
let is_private =
286+
!self.cx.cache.effective_visibilities.is_directly_public(tcx, ori_res_did);
287+
// Check if item inherits #[doc(hidden)] from a parent
284288
let inherits_hidden = !document_hidden && inherits_doc_hidden(tcx, res_did, None);
285-
// Only inline if requested or if the item would otherwise be stripped.
286-
if (!is_private && !inherits_hidden) || (
287-
is_hidden &&
288-
// If it's a doc hidden module, we need to keep it in case some of its inner items
289-
// are re-exported.
290-
!matches!(item, Node::Item(&hir::Item { kind: hir::ItemKind::Mod(_), .. }))
291-
) ||
292-
// The imported item is public and not `doc(hidden)` so no need to inline it.
293-
self.reexport_public_and_not_hidden(def_id, res_did)
289+
290+
// Don't inline if the item is public and visible (not hidden)
291+
// This preserves the original import for public items that should be documented
292+
let is_public_and_visible = !is_private && !inherits_hidden && !is_hidden;
293+
294+
// Don't inline if the item is hidden but not a module, and not publicly re-exported
295+
// We skip modules since their items may be re-exported elsewhere
296+
let is_hidden_and_non_module_non_reexported = is_hidden
297+
&& !self.is_reexport_public(def_id, res_did)
298+
&& !matches!(item, Node::Item(&hir::Item { kind: hir::ItemKind::Mod(_), .. }));
299+
300+
// Don't inline if this is a public re-export of a non-hidden item
301+
// This preserves the re-export path in the documentation
302+
let is_public_reexport = self.reexport_public_and_not_hidden(def_id, res_did);
303+
304+
// Return false to prevent inlining if any of these conditions are met
305+
if is_public_and_visible
306+
|| is_hidden_and_non_module_non_reexported
307+
|| is_public_reexport
294308
{
295309
return false;
296310
}
@@ -339,9 +353,26 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
339353
if inlined {
340354
self.cx.cache.inlined_items.insert(ori_res_did);
341355
}
356+
debug!("maybe_inline_local: inlined: {inlined}, (renamed: {renamed:?}) res: {res:?}");
342357
inlined
343358
}
344359

360+
fn is_reexport_public(&self, import_def_id: LocalDefId, target_def_id: LocalDefId) -> bool {
361+
if self.cx.render_options.document_hidden {
362+
return true;
363+
}
364+
let tcx = self.cx.tcx;
365+
let item_def_id = reexport_chain(tcx, import_def_id, target_def_id.to_def_id())
366+
.iter()
367+
.flat_map(|reexport| reexport.id())
368+
.map(|id| id.expect_local())
369+
.nth(1)
370+
.unwrap_or(target_def_id);
371+
372+
item_def_id != import_def_id
373+
&& self.cx.cache.effective_visibilities.is_directly_public(tcx, item_def_id.to_def_id())
374+
}
375+
345376
/// Returns `true` if the item is visible, meaning it's not `#[doc(hidden)]` or private.
346377
///
347378
/// This function takes into account the entire re-export `use` chain, so it needs the

0 commit comments

Comments
 (0)