about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume.gomez@huawei.com>2023-05-02 14:35:34 +0200
committerGuillaume Gomez <guillaume.gomez@huawei.com>2023-05-05 21:33:44 +0200
commit879f8de4096b2db4769e64e4c1af5ffb10b53a22 (patch)
treea9c6d867409e870625cdce0a69e118a54a22a26b
parentb778688f913bf6d3735b0b603b41c6989f513399 (diff)
downloadrust-879f8de4096b2db4769e64e4c1af5ffb10b53a22.tar.gz
rust-879f8de4096b2db4769e64e4c1af5ffb10b53a22.zip
Correctly handle associated items of a trait inside a `#[doc(hidden)]` item
-rw-r--r--src/librustdoc/formats/cache.rs8
-rw-r--r--src/librustdoc/passes/strip_hidden.rs30
-rw-r--r--src/librustdoc/visit_ast.rs11
3 files changed, 35 insertions, 14 deletions
diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs
index 841abfab666..c0730e90740 100644
--- a/src/librustdoc/formats/cache.rs
+++ b/src/librustdoc/formats/cache.rs
@@ -195,7 +195,13 @@ 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() {
-            debug!("folding {} \"{:?}\", id {:?}", item.type_(), item.name, item.item_id);
+            let is_stripped = matches!(*item.kind, clean::ItemKind::StrippedItem(..));
+            debug!(
+                "folding {} (stripped: {is_stripped:?}) \"{:?}\", id {:?}",
+                item.type_(),
+                item.name,
+                item.item_id
+            );
         }
 
         // If this is a stripped module,
diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs
index a688aa14863..972b0c5ec19 100644
--- a/src/librustdoc/passes/strip_hidden.rs
+++ b/src/librustdoc/passes/strip_hidden.rs
@@ -1,5 +1,6 @@
 //! Strip all doc(hidden) items from the output.
 
+use rustc_hir::def_id::LocalDefId;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::symbol::sym;
 use std::mem;
@@ -29,6 +30,7 @@ pub(crate) fn strip_hidden(krate: clean::Crate, cx: &mut DocContext<'_>) -> clea
             update_retained: true,
             tcx: cx.tcx,
             is_in_hidden_item: false,
+            last_reexport: None,
         };
         stripper.fold_crate(krate)
     };
@@ -49,13 +51,24 @@ struct Stripper<'a, 'tcx> {
     update_retained: bool,
     tcx: TyCtxt<'tcx>,
     is_in_hidden_item: bool,
+    last_reexport: Option<LocalDefId>,
 }
 
 impl<'a, 'tcx> Stripper<'a, 'tcx> {
+    fn set_last_reexport_then_fold_item(&mut self, i: Item) -> Item {
+        let prev_from_reexport = self.last_reexport;
+        if i.inline_stmt_id.is_some() {
+            self.last_reexport = i.item_id.as_def_id().and_then(|def_id| def_id.as_local());
+        }
+        let ret = self.fold_item_recur(i);
+        self.last_reexport = prev_from_reexport;
+        ret
+    }
+
     fn set_is_in_hidden_item_and_fold(&mut self, is_in_hidden_item: bool, i: Item) -> Item {
         let prev = self.is_in_hidden_item;
         self.is_in_hidden_item |= is_in_hidden_item;
-        let ret = self.fold_item_recur(i);
+        let ret = self.set_last_reexport_then_fold_item(i);
         self.is_in_hidden_item = prev;
         ret
     }
@@ -64,7 +77,7 @@ impl<'a, 'tcx> Stripper<'a, 'tcx> {
     /// of `is_in_hidden_item` to `true` because the impl children inherit its visibility.
     fn recurse_in_impl_or_exported_macro(&mut self, i: Item) -> Item {
         let prev = mem::replace(&mut self.is_in_hidden_item, false);
-        let ret = self.fold_item_recur(i);
+        let ret = self.set_last_reexport_then_fold_item(i);
         self.is_in_hidden_item = prev;
         ret
     }
@@ -86,13 +99,20 @@ impl<'a, 'tcx> DocFolder for Stripper<'a, 'tcx> {
         if !is_impl_or_exported_macro {
             is_hidden = self.is_in_hidden_item || has_doc_hidden;
             if !is_hidden && i.inline_stmt_id.is_none() {
-                // We don't need to check if it's coming from a reexport since the reexport itself was
-                // already checked.
+                // `i.inline_stmt_id` is `Some` if the item is directly reexported. If it is, we
+                // don't need to check it, because the reexport itself was already checked.
+                //
+                // If this item is the child of a reexported module, `self.last_reexport` will be
+                // `Some` even though `i.inline_stmt_id` is `None`. Hiddenness inheritance needs to
+                // account for the possibility that an item's true parent module is hidden, but it's
+                // inlined into a visible module true. This code shouldn't be reachable if the
+                // module's reexport is itself hidden, for the same reason it doesn't need to be
+                // checked if `i.inline_stmt_id` is Some: hidden reexports are never inlined.
                 is_hidden = i
                     .item_id
                     .as_def_id()
                     .and_then(|def_id| def_id.as_local())
-                    .map(|def_id| inherits_doc_hidden(self.tcx, def_id))
+                    .map(|def_id| inherits_doc_hidden(self.tcx, def_id, self.last_reexport))
                     .unwrap_or(false);
             }
         }
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index a6089680fae..a6c24041380 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -500,19 +500,14 @@ impl<'a, 'tcx> Visitor<'tcx> for RustdocVisitor<'a, 'tcx> {
 
     fn visit_item(&mut self, i: &'tcx hir::Item<'tcx>) {
         self.visit_item_inner(i, None, None);
-        let new_value = if self.is_importable_from_parent {
-            matches!(
+        let new_value = 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;