about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustdoc/clean/mod.rs16
-rw-r--r--src/librustdoc/passes/strip_hidden.rs68
-rw-r--r--src/librustdoc/visit_ast.rs16
3 files changed, 66 insertions, 34 deletions
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 3cb6ad10e72..ee9d0e829f0 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -2225,21 +2225,17 @@ fn clean_maybe_renamed_item<'tcx>(
             get_all_import_attributes(use_node, cx.tcx, item.owner_id.def_id, &mut extra_attrs);
         }
 
-        if !extra_attrs.is_empty() {
+        let mut item = if !extra_attrs.is_empty() {
             extra_attrs.extend_from_slice(inline::load_attrs(cx, def_id));
             let attrs = Attributes::from_ast(&extra_attrs);
             let cfg = extra_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg);
 
-            vec![Item::from_def_id_and_attrs_and_parts(
-                def_id,
-                Some(name),
-                kind,
-                Box::new(attrs),
-                cfg,
-            )]
+            Item::from_def_id_and_attrs_and_parts(def_id, Some(name), kind, Box::new(attrs), cfg)
         } else {
-            vec![Item::from_def_id_and_parts(def_id, Some(name), kind, cx)]
-        }
+            Item::from_def_id_and_parts(def_id, Some(name), kind, cx)
+        };
+        item.inline_stmt_id = import_id.map(|def_id| def_id.to_def_id());
+        vec![item]
     })
 }
 
diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs
index e07a788a72a..cfd2171395c 100644
--- a/src/librustdoc/passes/strip_hidden.rs
+++ b/src/librustdoc/passes/strip_hidden.rs
@@ -1,4 +1,6 @@
 //! Strip all doc(hidden) items from the output.
+
+use rustc_middle::ty::TyCtxt;
 use rustc_span::symbol::sym;
 use std::mem;
 
@@ -7,6 +9,7 @@ use crate::clean::{Item, ItemIdSet, NestedAttributesExt};
 use crate::core::DocContext;
 use crate::fold::{strip_item, DocFolder};
 use crate::passes::{ImplStripper, Pass};
+use crate::visit_ast::inherits_doc_hidden;
 
 pub(crate) const STRIP_HIDDEN: Pass = Pass {
     name: "strip-hidden",
@@ -21,7 +24,12 @@ pub(crate) fn strip_hidden(krate: clean::Crate, cx: &mut DocContext<'_>) -> clea
 
     // strip all #[doc(hidden)] items
     let krate = {
-        let mut stripper = Stripper { retained: &mut retained, update_retained: true };
+        let mut stripper = Stripper {
+            retained: &mut retained,
+            update_retained: true,
+            tcx: cx.tcx,
+            is_in_hidden_item: false,
+        };
         stripper.fold_crate(krate)
     };
 
@@ -36,14 +44,38 @@ pub(crate) fn strip_hidden(krate: clean::Crate, cx: &mut DocContext<'_>) -> clea
     stripper.fold_crate(krate)
 }
 
-struct Stripper<'a> {
+struct Stripper<'a, 'tcx> {
     retained: &'a mut ItemIdSet,
     update_retained: bool,
+    tcx: TyCtxt<'tcx>,
+    is_in_hidden_item: bool,
+}
+
+impl<'a, 'tcx> Stripper<'a, 'tcx> {
+    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);
+        self.is_in_hidden_item = prev;
+        ret
+    }
 }
 
-impl<'a> DocFolder for Stripper<'a> {
+impl<'a, 'tcx> DocFolder for Stripper<'a, 'tcx> {
     fn fold_item(&mut self, i: Item) -> Option<Item> {
-        if i.attrs.lists(sym::doc).has_word(sym::hidden) {
+        let has_doc_hidden = i.attrs.lists(sym::doc).has_word(sym::hidden);
+        let mut 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.
+            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))
+                .unwrap_or(false);
+        }
+        if is_hidden {
             debug!("strip_hidden: stripping {:?} {:?}", i.type_(), i.name);
             // Use a dedicated hidden item for fields, variants, and modules.
             // We need to keep private fields and variants, so that the docs
@@ -53,23 +85,31 @@ impl<'a> DocFolder for Stripper<'a> {
             // module it's defined in. Both of these are marked "stripped," and
             // not included in the final docs, but since they still have an effect
             // on the final doc, cannot be completely removed from the Clean IR.
-            match *i.kind {
+            return match *i.kind {
                 clean::StructFieldItem(..) | clean::ModuleItem(..) | clean::VariantItem(..) => {
                     // We need to recurse into stripped modules to
                     // strip things like impl methods but when doing so
                     // we must not add any items to the `retained` set.
                     let old = mem::replace(&mut self.update_retained, false);
-                    let ret = strip_item(self.fold_item_recur(i));
+                    let ret = strip_item(self.set_is_in_hidden_item_and_fold(true, i));
                     self.update_retained = old;
-                    return Some(ret);
+                    Some(ret)
+                }
+                _ => {
+                    let ret = self.set_is_in_hidden_item_and_fold(true, i);
+                    if has_doc_hidden {
+                        // If the item itself has `#[doc(hidden)]`, then we simply remove it.
+                        None
+                    } else {
+                        // However if it's a "descendant" of a `#[doc(hidden)]` item, then we strip it.
+                        Some(strip_item(ret))
+                    }
                 }
-                _ => return None,
-            }
-        } else {
-            if self.update_retained {
-                self.retained.insert(i.item_id);
-            }
+            };
+        }
+        if self.update_retained {
+            self.retained.insert(i.item_id);
         }
-        Some(self.fold_item_recur(i))
+        Some(self.set_is_in_hidden_item_and_fold(is_hidden, i))
     }
 }
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index c95ca6727b5..2d2afb83f9d 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -187,6 +187,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             }
         }
         self.inside_public_path = orig_inside_public_path;
+        debug!("Leaving module {:?}", m);
     }
 
     /// Tries to resolve the target of a `pub use` statement and inlines the
@@ -290,7 +291,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
         &mut self,
         item: &'tcx hir::Item<'_>,
         renamed: Option<Symbol>,
-        parent_id: Option<LocalDefId>,
+        import_id: Option<LocalDefId>,
     ) -> bool {
         debug!("visiting item {:?}", item);
         let name = renamed.unwrap_or(item.ident.name);
@@ -347,7 +348,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                         }
                     }
 
-                    self.add_to_current_mod(item, renamed, parent_id);
+                    self.add_to_current_mod(item, renamed, import_id);
                 }
             }
             hir::ItemKind::Macro(ref macro_def, _) => {
@@ -383,13 +384,13 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             | hir::ItemKind::Static(..)
             | hir::ItemKind::Trait(..)
             | hir::ItemKind::TraitAlias(..) => {
-                self.add_to_current_mod(item, renamed, parent_id);
+                self.add_to_current_mod(item, renamed, import_id);
             }
             hir::ItemKind::Const(..) => {
                 // Underscore constants do not correspond to a nameable item and
                 // so are never useful in documentation.
                 if name != kw::Underscore {
-                    self.add_to_current_mod(item, renamed, parent_id);
+                    self.add_to_current_mod(item, renamed, import_id);
                 }
             }
             hir::ItemKind::Impl(impl_) => {
@@ -437,12 +438,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RustdocVisitor<'a, 'tcx> {
     }
 
     fn visit_item(&mut self, i: &'tcx hir::Item<'tcx>) {
-        let parent_id = if self.modules.len() > 1 {
-            Some(self.modules[self.modules.len() - 2].def_id)
-        } else {
-            None
-        };
-        if self.visit_item_inner(i, None, parent_id) {
+        if self.visit_item_inner(i, None, None) {
             walk_item(self, i);
         }
     }