]> git.proxmox.com Git - rustc.git/blobdiff - src/librustdoc/visit_ast.rs
New upstream version 1.73.0+dfsg1
[rustc.git] / src / librustdoc / visit_ast.rs
index fcf591a932896143a768010f5bc412b3cb9b0c45..549fd67e32ad1e25b8bde16fe2ecc003c8260fdc 100644 (file)
@@ -16,6 +16,7 @@ use rustc_span::Span;
 
 use std::mem;
 
+use crate::clean::utils::{inherits_doc_hidden, should_ignore_res};
 use crate::clean::{cfg::Cfg, reexport_chain, AttributesExt, NestedAttributesExt};
 use crate::core;
 
@@ -35,6 +36,8 @@ pub(crate) struct Module<'hir> {
         (LocalDefId, Option<Symbol>),
         (&'hir hir::Item<'hir>, Option<Symbol>, Option<LocalDefId>),
     >,
+    /// Same as for `items`.
+    pub(crate) inlined_foreigns: FxIndexMap<(DefId, Option<Symbol>), (Res, LocalDefId)>,
     pub(crate) foreigns: Vec<(&'hir hir::ForeignItem<'hir>, Option<Symbol>)>,
 }
 
@@ -54,6 +57,7 @@ impl Module<'_> {
             import_id,
             mods: Vec::new(),
             items: FxIndexMap::default(),
+            inlined_foreigns: FxIndexMap::default(),
             foreigns: Vec::new(),
         }
     }
@@ -70,33 +74,6 @@ fn def_id_to_path(tcx: TyCtxt<'_>, did: DefId) -> Vec<Symbol> {
     std::iter::once(crate_name).chain(relative).collect()
 }
 
-pub(crate) fn inherits_doc_hidden(
-    tcx: TyCtxt<'_>,
-    mut def_id: LocalDefId,
-    stop_at: Option<LocalDefId>,
-) -> bool {
-    let hir = tcx.hir();
-    while let Some(id) = tcx.opt_local_parent(def_id) {
-        if let Some(stop_at) = stop_at && id == stop_at {
-            return false;
-        }
-        def_id = id;
-        if tcx.is_doc_hidden(def_id.to_def_id()) {
-            return true;
-        } else if let Some(node) = hir.find_by_def_id(def_id) &&
-            matches!(
-                node,
-                hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(_), .. }),
-            )
-        {
-            // `impl` blocks stand a bit on their own: unless they have `#[doc(hidden)]` directly
-            // on them, they don't inherit it from the parent context.
-            return false;
-        }
-    }
-    false
-}
-
 pub(crate) struct RustdocVisitor<'a, 'tcx> {
     cx: &'a mut core::DocContext<'tcx>,
     view_item_stack: LocalDefIdSet,
@@ -203,7 +180,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
     /// 1. The items which are not glob imports/reexports.
     /// 2. The glob imports/reexports.
     fn visit_mod_contents(&mut self, def_id: LocalDefId, m: &'tcx hir::Mod<'tcx>) {
-        debug!("Going through module {:?}", m);
+        debug!("Going through module {m:?}");
         // Keep track of if there were any private modules in the path.
         let orig_inside_public_path = self.inside_public_path;
         self.inside_public_path &= self.cx.tcx.local_visibility(def_id).is_public();
@@ -226,7 +203,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             }
         }
         self.inside_public_path = orig_inside_public_path;
-        debug!("Leaving module {:?}", m);
+        debug!("Leaving module {m:?}");
     }
 
     /// Tries to resolve the target of a `pub use` statement and inlines the
@@ -262,34 +239,44 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             return false;
         };
 
+        let document_hidden = self.cx.render_options.document_hidden;
         let use_attrs = tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(def_id));
         // Don't inline `doc(hidden)` imports so they can be stripped at a later stage.
         let is_no_inline = use_attrs.lists(sym::doc).has_word(sym::no_inline)
-            || use_attrs.lists(sym::doc).has_word(sym::hidden);
+            || (document_hidden && use_attrs.lists(sym::doc).has_word(sym::hidden));
 
         if is_no_inline {
             return false;
         }
 
-        // For cross-crate impl inlining we need to know whether items are
-        // reachable in documentation -- a previously unreachable item can be
-        // made reachable by cross-crate inlining which we're checking here.
-        // (this is done here because we need to know this upfront).
-        if !ori_res_did.is_local() && !is_no_inline {
-            crate::visit_lib::lib_embargo_visit_item(self.cx, ori_res_did);
-            return false;
-        }
-
+        let is_hidden = !document_hidden && tcx.is_doc_hidden(ori_res_did);
         let Some(res_did) = ori_res_did.as_local() else {
-            return false;
+            // For cross-crate impl inlining we need to know whether items are
+            // reachable in documentation -- a previously unreachable item can be
+            // made reachable by cross-crate inlining which we're checking here.
+            // (this is done here because we need to know this upfront).
+            crate::visit_lib::lib_embargo_visit_item(self.cx, ori_res_did);
+            if is_hidden || glob {
+                return false;
+            }
+            // We store inlined foreign items otherwise, it'd mean that the `use` item would be kept
+            // around. It's not a problem unless this `use` imports both a local AND a foreign item.
+            // If a local item is inlined, its `use` is not supposed to still be around in `clean`,
+            // which would make appear the `use` in the generated documentation like the local item
+            // was not inlined even though it actually was.
+            self.modules
+                .last_mut()
+                .unwrap()
+                .inlined_foreigns
+                .insert((ori_res_did, renamed), (res, def_id));
+            return true;
         };
 
         let is_private = !self.cx.cache.effective_visibilities.is_directly_public(tcx, ori_res_did);
-        let is_hidden = tcx.is_doc_hidden(ori_res_did);
         let item = tcx.hir().get_by_def_id(res_did);
 
         if !please_inline {
-            let inherits_hidden = inherits_doc_hidden(tcx, res_did, None);
+            let inherits_hidden = !document_hidden && inherits_doc_hidden(tcx, res_did, None);
             // Only inline if requested or if the item would otherwise be stripped.
             if (!is_private && !inherits_hidden) || (
                 is_hidden &&
@@ -313,7 +300,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             return false;
         }
 
-        let inlined = match tcx.hir().get_by_def_id(res_did) {
+        let inlined = match item {
             // Bang macros are handled a bit on their because of how they are handled by the
             // compiler. If they have `#[doc(hidden)]` and the re-export doesn't have
             // `#[doc(inline)]`, then we don't inline it.
@@ -345,7 +332,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
         };
         self.view_item_stack.remove(&res_did);
         if inlined {
-            self.cx.cache.inlined_items.insert(res_did.to_def_id());
+            self.cx.cache.inlined_items.insert(ori_res_did);
         }
         inlined
     }
@@ -359,8 +346,11 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
         import_def_id: LocalDefId,
         target_def_id: LocalDefId,
     ) -> bool {
+        if self.cx.render_options.document_hidden {
+            return true;
+        }
         let tcx = self.cx.tcx;
-        let item_def_id = reexport_chain(tcx, import_def_id, target_def_id)
+        let item_def_id = reexport_chain(tcx, import_def_id, target_def_id.to_def_id())
             .iter()
             .flat_map(|reexport| reexport.id())
             .map(|id| id.expect_local())
@@ -404,7 +394,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
         renamed: Option<Symbol>,
         import_id: Option<LocalDefId>,
     ) {
-        debug!("visiting item {:?}", item);
+        debug!("visiting item {item:?}");
         if self.inside_body {
             // Only impls can be "seen" outside a body. For example:
             //
@@ -450,7 +440,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                 for &res in &path.res {
                     // Struct and variant constructors and proc macro stubs always show up alongside
                     // their definitions, we've already processed them so just discard these.
-                    if let Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) = res {
+                    if should_ignore_res(res) {
                         continue;
                     }
 
@@ -479,7 +469,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                             continue;
                         }
                     }
-
                     self.add_to_current_mod(item, renamed, import_id);
                 }
             }