about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2024-04-11 20:20:49 +0200
committerGitHub <noreply@github.com>2024-04-11 20:20:49 +0200
commitbcdc281e5c0429450dc6122930bbde3753491f3f (patch)
tree1b4fb9abf2f4e760ee98532295a6c7533676a507
parentdf7daa815f4047a1cfe24ecfbc12cfd4f40fa928 (diff)
parent5a0be6ff3dcc89a14e22c8613c86acbb0cd55b4a (diff)
downloadrust-bcdc281e5c0429450dc6122930bbde3753491f3f.tar.gz
rust-bcdc281e5c0429450dc6122930bbde3753491f3f.zip
Rollup merge of #123459 - GuillaumeGomez:fix-123435, r=notriddle
Correctly handle inlining of doc hidden foreign items

Fixes #123435.

In case a foreign item has doc(hidden) attribute, we simply merged its attributes with the re-export's, making it being removed once in the `strip_hidden` pass.

The solution was to use the same as for local reexported items: merge attributes, but not some of them (like `doc(hidden)`).

I originally checked if we could simply update `Item::is_doc_hidden` method to use `self.inline_stmt_id.is_some_and(|def_id| tcx.is_doc_hidden(def_id))` but unfortunately, it added (local) items that shouldn't be inlined. At least it unifies local and foreign items inlining, which I think is the best course of action here.

r? `@notriddle`
-rw-r--r--src/librustdoc/clean/inline.rs19
-rw-r--r--src/librustdoc/clean/mod.rs22
-rw-r--r--src/librustdoc/clean/utils.rs9
-rw-r--r--src/librustdoc/formats/cache.rs10
-rw-r--r--tests/rustdoc/inline_cross/inline_hidden.rs14
5 files changed, 51 insertions, 23 deletions
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 6f86c6450d9..4d506edc47b 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -63,8 +63,6 @@ pub(crate) fn try_inline(
 
     let import_def_id = attrs.and_then(|(_, def_id)| def_id);
 
-    let (attrs, cfg) = merge_attrs(cx, load_attrs(cx, did), attrs);
-
     let kind = match res {
         Res::Def(DefKind::Trait, did) => {
             record_extern_fqn(cx, did, ItemType::Trait);
@@ -134,7 +132,11 @@ pub(crate) fn try_inline(
             cx.with_param_env(did, |cx| clean::ConstantItem(build_const(cx, did)))
         }
         Res::Def(DefKind::Macro(kind), did) => {
-            let mac = build_macro(cx, did, name, import_def_id, kind, attrs.is_doc_hidden());
+            let is_doc_hidden = cx.tcx.is_doc_hidden(did)
+                || attrs_without_docs
+                    .map(|(attrs, _)| attrs)
+                    .is_some_and(|attrs| utils::attrs_have_doc_flag(attrs.iter(), sym::hidden));
+            let mac = build_macro(cx, did, name, import_def_id, kind, is_doc_hidden);
 
             let type_kind = match kind {
                 MacroKind::Bang => ItemType::Macro,
@@ -148,8 +150,14 @@ pub(crate) fn try_inline(
     };
 
     cx.inlined.insert(did.into());
-    let mut item =
-        clean::Item::from_def_id_and_attrs_and_parts(did, Some(name), kind, Box::new(attrs), cfg);
+    let mut item = crate::clean::generate_item_with_correct_attrs(
+        cx,
+        kind,
+        did,
+        name,
+        import_def_id.and_then(|def_id| def_id.as_local()),
+        None,
+    );
     // The visibility needs to reflect the one from the reexport and not from the "source" DefId.
     item.inline_stmt_id = import_def_id;
     ret.push(item);
@@ -179,6 +187,7 @@ pub(crate) fn try_inline_glob(
                 .iter()
                 .filter(|child| !child.reexport_chain.is_empty())
                 .filter_map(|child| child.res.opt_def_id())
+                .filter(|def_id| !cx.tcx.is_doc_hidden(def_id))
                 .collect();
             let attrs = cx.tcx.hir().attrs(import.hir_id());
             let mut items = build_module_items(
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 12f45fe4979..925d41e67f8 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -3007,22 +3007,22 @@ fn clean_use_statement_inner<'tcx>(
             // were specifically asked for it
             denied = true;
         }
-        if !denied {
-            if let Some(mut items) = inline::try_inline(
+        if !denied
+            && let Some(mut items) = inline::try_inline(
                 cx,
                 path.res,
                 name,
                 Some((attrs, Some(import_def_id))),
                 &mut Default::default(),
-            ) {
-                items.push(Item::from_def_id_and_parts(
-                    import_def_id,
-                    None,
-                    ImportItem(Import::new_simple(name, resolve_use_source(cx, path), false)),
-                    cx,
-                ));
-                return items;
-            }
+            )
+        {
+            items.push(Item::from_def_id_and_parts(
+                import_def_id,
+                None,
+                ImportItem(Import::new_simple(name, resolve_use_source(cx, path), false)),
+                cx,
+            ));
+            return items;
         }
         Import::new_simple(name, resolve_use_source(cx, path), true)
     };
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index dc62fbb5edb..aa923cc6117 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -580,7 +580,14 @@ pub(crate) fn find_nearest_parent_module(tcx: TyCtxt<'_>, def_id: DefId) -> Opti
 /// This function exists because it runs on `hir::Attributes` whereas the other is a
 /// `clean::Attributes` method.
 pub(crate) fn has_doc_flag(tcx: TyCtxt<'_>, did: DefId, flag: Symbol) -> bool {
-    tcx.get_attrs(did, sym::doc)
+    attrs_have_doc_flag(tcx.get_attrs(did, sym::doc), flag)
+}
+
+pub(crate) fn attrs_have_doc_flag<'a>(
+    mut attrs: impl Iterator<Item = &'a ast::Attribute>,
+    flag: Symbol,
+) -> bool {
+    attrs
         .any(|attr| attr.meta_item_list().is_some_and(|l| rustc_attr::list_contains_name(&l, flag)))
 }
 
diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs
index 9802097ea29..11fc99eb511 100644
--- a/src/librustdoc/formats/cache.rs
+++ b/src/librustdoc/formats/cache.rs
@@ -203,10 +203,10 @@ impl Cache {
 impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
     fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
         if item.item_id.is_local() {
-            let is_stripped = matches!(*item.kind, clean::ItemKind::StrippedItem(..));
             debug!(
-                "folding {} (stripped: {is_stripped:?}) \"{:?}\", id {:?}",
+                "folding {} (stripped: {:?}) \"{:?}\", id {:?}",
                 item.type_(),
+                item.is_stripped(),
                 item.name,
                 item.item_id
             );
@@ -246,13 +246,11 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
         // trait.
         if let clean::TraitItem(ref t) = *item.kind {
             self.cache.traits.entry(item.item_id.expect_def_id()).or_insert_with(|| (**t).clone());
-        }
-
-        // Collect all the implementors of traits.
-        if let clean::ImplItem(ref i) = *item.kind
+        } else if let clean::ImplItem(ref i) = *item.kind
             && let Some(trait_) = &i.trait_
             && !i.kind.is_blanket()
         {
+            // Collect all the implementors of traits.
             self.cache
                 .implementors
                 .entry(trait_.def_id())
diff --git a/tests/rustdoc/inline_cross/inline_hidden.rs b/tests/rustdoc/inline_cross/inline_hidden.rs
index ec06f2f0c5d..2a3dd72749c 100644
--- a/tests/rustdoc/inline_cross/inline_hidden.rs
+++ b/tests/rustdoc/inline_cross/inline_hidden.rs
@@ -4,9 +4,23 @@
 
 extern crate rustdoc_hidden;
 
+// @has inline_hidden/index.html
+// Ensures this item is not inlined.
+// @has - '//*[@id="reexport.Foo"]/code' 'pub use rustdoc_hidden::Foo;'
 #[doc(no_inline)]
 pub use rustdoc_hidden::Foo;
 
+// Even if the foreign item has `doc(hidden)`, we should be able to inline it.
+// @has - '//*[@class="item-name"]/a[@class="struct"]' 'Inlined'
+#[doc(inline)]
+pub use rustdoc_hidden::Foo as Inlined;
+
+// Even with this import, we should not see `Foo`.
+// @count - '//*[@class="item-name"]' 4
+// @has - '//*[@class="item-name"]/a[@class="struct"]' 'Bar'
+// @has - '//*[@class="item-name"]/a[@class="fn"]' 'foo'
+pub use rustdoc_hidden::*;
+
 // @has inline_hidden/fn.foo.html
 // @!has - '//a/@title' 'Foo'
 pub fn foo(_: Foo) {}