diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 4572a712258..8f3e29a31a0 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -8,7 +8,6 @@ use crate::clean::{ }; use crate::core::DocContext; use crate::formats::item_type::ItemType; -use crate::visit_lib::LibEmbargoVisitor; use rustc_ast as ast; use rustc_ast::tokenstream::TokenTree; @@ -32,7 +31,7 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate { for &cnum in cx.tcx.crates(()) { // Analyze doc-reachability for extern items - LibEmbargoVisitor::new(cx).visit_lib(cnum); + crate::visit_lib::lib_embargo_visit_item(cx, cnum.as_def_id()); } // Clean the crate, translating the entire librustc_ast AST to one that is diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 06dffce555f..7960ab251b7 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -7,15 +7,14 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::Node; use rustc_hir::CRATE_HIR_ID; -use rustc_middle::middle::privacy::Level; -use rustc_middle::ty::{TyCtxt, Visibility}; +use rustc_middle::ty::TyCtxt; use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE}; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; use std::mem; -use crate::clean::{self, cfg::Cfg, AttributesExt, NestedAttributesExt}; +use crate::clean::{cfg::Cfg, AttributesExt, NestedAttributesExt}; use crate::core; /// This module is used to store stuff from Rust's AST in a more convenient @@ -221,23 +220,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { // made reachable by cross-crate inlining which we're checking here. // (this is done here because we need to know this upfront). if !res_did.is_local() && !is_no_inline { - let attrs = clean::inline::load_attrs(self.cx, res_did); - let self_is_hidden = attrs.lists(sym::doc).has_word(sym::hidden); - if !self_is_hidden { - if let Res::Def(kind, did) = res { - if kind == DefKind::Mod { - crate::visit_lib::LibEmbargoVisitor::new(self.cx).visit_mod(did) - } else { - // All items need to be handled here in case someone wishes to link - // to them with intra-doc links - self.cx.cache.effective_visibilities.set_public_at_level( - did, - || Visibility::Restricted(CRATE_DEF_ID), - Level::Direct, - ); - } - } - } + crate::visit_lib::lib_embargo_visit_item(self.cx, res_did); return false; } diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs index 70214e2adba..04a3114556e 100644 --- a/src/librustdoc/visit_lib.rs +++ b/src/librustdoc/visit_lib.rs @@ -1,86 +1,57 @@ +use crate::core::DocContext; use rustc_data_structures::fx::FxHashSet; -use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_ID}; +use rustc_hir::def::DefKind; +use rustc_hir::def_id::{DefId, CRATE_DEF_ID}; use rustc_middle::middle::privacy::{EffectiveVisibilities, Level}; use rustc_middle::ty::{TyCtxt, Visibility}; // FIXME: this may not be exhaustive, but is sufficient for rustdocs current uses +pub(crate) fn lib_embargo_visit_item(cx: &mut DocContext<'_>, def_id: DefId) { + assert!(!def_id.is_local()); + LibEmbargoVisitor { + tcx: cx.tcx, + effective_visibilities: &mut cx.cache.effective_visibilities, + visited_mods: FxHashSet::default(), + } + .visit_item(def_id) +} + /// Similar to `librustc_privacy::EmbargoVisitor`, but also takes /// specific rustdoc annotations into account (i.e., `doc(hidden)`) -pub(crate) struct LibEmbargoVisitor<'a, 'tcx> { +struct LibEmbargoVisitor<'a, 'tcx> { tcx: TyCtxt<'tcx>, // Effective visibilities for reachable nodes effective_visibilities: &'a mut EffectiveVisibilities, - // Previous level, None means unreachable - prev_level: Option, // Keeps track of already visited modules, in case a module re-exports its parent visited_mods: FxHashSet, } -impl<'a, 'tcx> LibEmbargoVisitor<'a, 'tcx> { - pub(crate) fn new(cx: &'a mut crate::core::DocContext<'tcx>) -> LibEmbargoVisitor<'a, 'tcx> { - LibEmbargoVisitor { - tcx: cx.tcx, - effective_visibilities: &mut cx.cache.effective_visibilities, - prev_level: Some(Level::Direct), - visited_mods: FxHashSet::default(), - } - } - - pub(crate) fn visit_lib(&mut self, cnum: CrateNum) { - let did = cnum.as_def_id(); - self.update(did, Some(Level::Direct)); - self.visit_mod(did); - } - - // Updates node level and returns the updated level - fn update(&mut self, did: DefId, level: Option) -> Option { - let is_hidden = self.tcx.is_doc_hidden(did); - - let old_level = self.effective_visibilities.public_at_level(did); - // Visibility levels can only grow - if level > old_level && !is_hidden { - self.effective_visibilities.set_public_at_level( - did, - || Visibility::Restricted(CRATE_DEF_ID), - level.unwrap(), - ); - level - } else { - old_level - } - } - - pub(crate) fn visit_mod(&mut self, def_id: DefId) { +impl LibEmbargoVisitor<'_, '_> { + fn visit_mod(&mut self, def_id: DefId) { if !self.visited_mods.insert(def_id) { return; } for item in self.tcx.module_children(def_id).iter() { if let Some(def_id) = item.res.opt_def_id() { - if self.tcx.def_key(def_id).parent.map_or(false, |d| d == def_id.index) - || item.vis.is_public() - { - self.visit_item(item.res); + if item.vis.is_public() { + self.visit_item(def_id); } } } } - fn visit_item(&mut self, res: Res) { - let def_id = res.def_id(); - let vis = self.tcx.visibility(def_id); - let inherited_item_level = if vis.is_public() { self.prev_level } else { None }; - - let item_level = self.update(def_id, inherited_item_level); - - if let Res::Def(DefKind::Mod, _) = res { - let orig_level = self.prev_level; - - self.prev_level = item_level; - self.visit_mod(def_id); - self.prev_level = orig_level; + fn visit_item(&mut self, def_id: DefId) { + if !self.tcx.is_doc_hidden(def_id) { + self.effective_visibilities.set_public_at_level( + def_id, + || Visibility::Restricted(CRATE_DEF_ID), + Level::Direct, + ); + if self.tcx.def_kind(def_id) == DefKind::Mod { + self.visit_mod(def_id); + } } } }