diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs index 9c68c7504754a..ffbd6d10da6b2 100644 --- a/compiler/rustc_middle/src/middle/privacy.rs +++ b/compiler/rustc_middle/src/middle/privacy.rs @@ -6,8 +6,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_macros::HashStable; use rustc_query_system::ich::StableHashingContext; -use rustc_span::def_id::{DefId, LocalDefId}; -use std::hash::Hash; +use rustc_span::def_id::LocalDefId; /// Represents the levels of effective visibility an item can have. /// @@ -75,33 +74,33 @@ impl EffectiveVisibility { } /// Holds a map of effective visibilities for reachable HIR nodes. -#[derive(Debug, Clone)] -pub struct EffectiveVisibilities { - map: FxHashMap, +#[derive(Default, Clone, Debug)] +pub struct EffectiveVisibilities { + map: FxHashMap, } -impl EffectiveVisibilities { - pub fn is_public_at_level(&self, id: Id, level: Level) -> bool { +impl EffectiveVisibilities { + pub fn is_public_at_level(&self, id: LocalDefId, level: Level) -> bool { self.effective_vis(id) .map_or(false, |effective_vis| effective_vis.is_public_at_level(level)) } /// See `Level::Reachable`. - pub fn is_reachable(&self, id: Id) -> bool { + pub fn is_reachable(&self, id: LocalDefId) -> bool { self.is_public_at_level(id, Level::Reachable) } /// See `Level::Reexported`. - pub fn is_exported(&self, id: Id) -> bool { + pub fn is_exported(&self, id: LocalDefId) -> bool { self.is_public_at_level(id, Level::Reexported) } /// See `Level::Direct`. - pub fn is_directly_public(&self, id: Id) -> bool { + pub fn is_directly_public(&self, id: LocalDefId) -> bool { self.is_public_at_level(id, Level::Direct) } - pub fn public_at_level(&self, id: Id) -> Option { + pub fn public_at_level(&self, id: LocalDefId) -> Option { self.effective_vis(id).and_then(|effective_vis| { for level in Level::all_levels() { if effective_vis.is_public_at_level(level) { @@ -112,24 +111,17 @@ impl EffectiveVisibilities { }) } - pub fn effective_vis(&self, id: Id) -> Option<&EffectiveVisibility> { + pub fn effective_vis(&self, id: LocalDefId) -> Option<&EffectiveVisibility> { self.map.get(&id) } - pub fn iter(&self) -> impl Iterator { + pub fn iter(&self) -> impl Iterator { self.map.iter() } - pub fn map_id( - &self, - f: impl Fn(Id) -> OutId, - ) -> EffectiveVisibilities { - EffectiveVisibilities { map: self.map.iter().map(|(k, v)| (f(*k), *v)).collect() } - } - pub fn set_public_at_level( &mut self, - id: Id, + id: LocalDefId, default_vis: impl FnOnce() -> Visibility, level: Level, ) { @@ -144,23 +136,21 @@ impl EffectiveVisibilities { } self.map.insert(id, effective_vis); } -} -impl> EffectiveVisibilities { // `parent_id` is not necessarily a parent in source code tree, // it is the node from which the maximum effective visibility is inherited. pub fn update( &mut self, - id: Id, + id: LocalDefId, nominal_vis: Visibility, default_vis: impl FnOnce() -> Visibility, - parent_id: Id, + parent_id: LocalDefId, level: Level, tree: impl DefIdTree, ) -> bool { let mut changed = false; let mut current_effective_vis = self.effective_vis(id).copied().unwrap_or_else(|| { - if id.into().is_crate_root() { + if id.is_top_level_module() { EffectiveVisibility::from_vis(Visibility::Public) } else { EffectiveVisibility::from_vis(default_vis()) @@ -204,12 +194,6 @@ impl> EffectiveVisibilities { } } -impl Default for EffectiveVisibilities { - fn default() -> Self { - EffectiveVisibilities { map: Default::default() } - } -} - impl<'a> HashStable> for EffectiveVisibilities { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let EffectiveVisibilities { ref map } = *self; diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 8b63c3db3c335..f82fb498131eb 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -20,7 +20,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { trace!("get_blanket_impls({:?})", ty); let mut impls = Vec::new(); for trait_def_id in cx.tcx.all_traits() { - if !cx.cache.effective_visibilities.is_directly_public(trait_def_id) + if !cx.cache.effective_visibilities.is_directly_public(cx.tcx, trait_def_id) || cx.generated_synthetics.get(&(ty.0, trait_def_id)).is_some() { continue; diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index b9f787729c148..c823ed0f16efb 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -374,7 +374,7 @@ pub(crate) fn build_impl( if !did.is_local() { if let Some(traitref) = associated_trait { let did = traitref.def_id; - if !cx.cache.effective_visibilities.is_directly_public(did) { + if !cx.cache.effective_visibilities.is_directly_public(tcx, did) { return; } @@ -403,7 +403,7 @@ pub(crate) fn build_impl( // reachable in rustdoc generated documentation if !did.is_local() { if let Some(did) = for_.def_id(&cx.cache) { - if !cx.cache.effective_visibilities.is_directly_public(did) { + if !cx.cache.effective_visibilities.is_directly_public(tcx, did) { return; } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 64a18757b26e5..8a0e6a82126bc 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1431,7 +1431,7 @@ fn maybe_expand_private_type_alias<'tcx>( let Res::Def(DefKind::TyAlias, def_id) = path.res else { return None }; // Substitute private type aliases let def_id = def_id.as_local()?; - let alias = if !cx.cache.effective_visibilities.is_exported(def_id.to_def_id()) { + let alias = if !cx.cache.effective_visibilities.is_exported(cx.tcx, def_id.to_def_id()) { &cx.tcx.hir().expect_item(def_id).kind } else { return None; diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 4572a712258ab..8f3e29a31a072 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/core.rs b/src/librustdoc/core.rs index 3e5f42b7a80dc..3961802529b29 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -348,7 +348,6 @@ pub(crate) fn run_global_ctxt( let auto_traits = tcx.all_traits().filter(|&trait_def_id| tcx.trait_is_auto(trait_def_id)).collect(); - let effective_visibilities = tcx.effective_visibilities(()).map_id(Into::into); let mut ctxt = DocContext { tcx, @@ -361,7 +360,7 @@ pub(crate) fn run_global_ctxt( impl_trait_bounds: Default::default(), generated_synthetics: Default::default(), auto_traits, - cache: Cache::new(effective_visibilities, render_options.document_private), + cache: Cache::new(render_options.document_private), inlined: FxHashSet::default(), output_format, render_options, diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index afe2264e8bf85..a0cf1ec78e256 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -2,7 +2,6 @@ use std::mem; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def_id::{CrateNum, DefId}; -use rustc_middle::middle::privacy::EffectiveVisibilities; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::Symbol; @@ -15,6 +14,7 @@ use crate::html::format::join_with_double_colon; use crate::html::markdown::short_markdown_summary; use crate::html::render::search_index::get_function_type_for_search; use crate::html::render::IndexItem; +use crate::visit_lib::RustdocEffectiveVisibilities; /// This cache is used to store information about the [`clean::Crate`] being /// rendered in order to provide more useful documentation. This contains @@ -78,7 +78,7 @@ pub(crate) struct Cache { // Note that external items for which `doc(hidden)` applies to are shown as // non-reachable while local items aren't. This is because we're reusing // the effective visibilities from the privacy check pass. - pub(crate) effective_visibilities: EffectiveVisibilities, + pub(crate) effective_visibilities: RustdocEffectiveVisibilities, /// The version of the crate being documented, if given from the `--crate-version` flag. pub(crate) crate_version: Option, @@ -132,11 +132,8 @@ struct CacheBuilder<'a, 'tcx> { } impl Cache { - pub(crate) fn new( - effective_visibilities: EffectiveVisibilities, - document_private: bool, - ) -> Self { - Cache { effective_visibilities, document_private, ..Cache::default() } + pub(crate) fn new(document_private: bool) -> Self { + Cache { document_private, ..Cache::default() } } /// Populates the `Cache` with more data. The returned `Crate` will be missing some data that was @@ -387,7 +384,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { || self .cache .effective_visibilities - .is_directly_public(item.item_id.expect_def_id()) + .is_directly_public(self.tcx, item.item_id.expect_def_id()) { self.cache.paths.insert( item.item_id.expect_def_id(), diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 92e7f2739afbb..37202f786ed80 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -659,7 +659,7 @@ pub(crate) fn href_with_root_path( } if !did.is_local() - && !cache.effective_visibilities.is_directly_public(did) + && !cache.effective_visibilities.is_directly_public(tcx, did) && !cache.document_private && !cache.primitive_locations.values().any(|&id| id == did) { diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs index 7740c6d5bbbb8..057d2fdd9d5fc 100644 --- a/src/librustdoc/passes/check_doc_test_visibility.rs +++ b/src/librustdoc/passes/check_doc_test_visibility.rs @@ -56,7 +56,7 @@ impl crate::doctest::Tester for Tests { } pub(crate) fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -> bool { - if !cx.cache.effective_visibilities.is_directly_public(item.item_id.expect_def_id()) + if !cx.cache.effective_visibilities.is_directly_public(cx.tcx, item.item_id.expect_def_id()) || matches!( *item.kind, clean::StructFieldItem(_) @@ -130,7 +130,7 @@ pub(crate) fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item ); } } else if tests.found_tests > 0 - && !cx.cache.effective_visibilities.is_exported(item.item_id.expect_def_id()) + && !cx.cache.effective_visibilities.is_exported(cx.tcx, item.item_id.expect_def_id()) { cx.tcx.struct_span_lint_hir( crate::lint::PRIVATE_DOC_TESTS, diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs index 9914edf3036e4..e07a788a72a41 100644 --- a/src/librustdoc/passes/strip_hidden.rs +++ b/src/librustdoc/passes/strip_hidden.rs @@ -27,6 +27,7 @@ pub(crate) fn strip_hidden(krate: clean::Crate, cx: &mut DocContext<'_>) -> clea // strip all impls referencing stripped items let mut stripper = ImplStripper { + tcx: cx.tcx, retained: &retained, cache: &cx.cache, is_json_output, diff --git a/src/librustdoc/passes/strip_private.rs b/src/librustdoc/passes/strip_private.rs index 450f69e15d1af..e3b958b2036e3 100644 --- a/src/librustdoc/passes/strip_private.rs +++ b/src/librustdoc/passes/strip_private.rs @@ -22,6 +22,7 @@ pub(crate) fn strip_private(mut krate: clean::Crate, cx: &mut DocContext<'_>) -> // strip all private items { let mut stripper = Stripper { + tcx: cx.tcx, retained: &mut retained, effective_visibilities: &cx.cache.effective_visibilities, update_retained: true, @@ -32,6 +33,7 @@ pub(crate) fn strip_private(mut krate: clean::Crate, cx: &mut DocContext<'_>) -> // strip all impls referencing private items let mut stripper = ImplStripper { + tcx: cx.tcx, retained: &retained, cache: &cx.cache, is_json_output, diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs index 0089ce63d07ba..4fa5c04ddf61d 100644 --- a/src/librustdoc/passes/stripper.rs +++ b/src/librustdoc/passes/stripper.rs @@ -1,6 +1,6 @@ //! A collection of utility functions for the `strip_*` passes. use rustc_hir::def_id::DefId; -use rustc_middle::middle::privacy::EffectiveVisibilities; +use rustc_middle::ty::TyCtxt; use rustc_span::symbol::sym; use std::mem; @@ -8,10 +8,12 @@ use std::mem; use crate::clean::{self, Item, ItemId, ItemIdSet, NestedAttributesExt}; use crate::fold::{strip_item, DocFolder}; use crate::formats::cache::Cache; +use crate::visit_lib::RustdocEffectiveVisibilities; -pub(crate) struct Stripper<'a> { +pub(crate) struct Stripper<'a, 'tcx> { + pub(crate) tcx: TyCtxt<'tcx>, pub(crate) retained: &'a mut ItemIdSet, - pub(crate) effective_visibilities: &'a EffectiveVisibilities, + pub(crate) effective_visibilities: &'a RustdocEffectiveVisibilities, pub(crate) update_retained: bool, pub(crate) is_json_output: bool, } @@ -21,18 +23,19 @@ pub(crate) struct Stripper<'a> { // are in the public API, which is not enough. #[inline] fn is_item_reachable( + tcx: TyCtxt<'_>, is_json_output: bool, - effective_visibilities: &EffectiveVisibilities, + effective_visibilities: &RustdocEffectiveVisibilities, item_id: ItemId, ) -> bool { if is_json_output { - effective_visibilities.is_reachable(item_id.expect_def_id()) + effective_visibilities.is_reachable(tcx, item_id.expect_def_id()) } else { - effective_visibilities.is_exported(item_id.expect_def_id()) + effective_visibilities.is_exported(tcx, item_id.expect_def_id()) } } -impl<'a> DocFolder for Stripper<'a> { +impl<'a> DocFolder for Stripper<'a, '_> { fn fold_item(&mut self, i: Item) -> Option { match *i.kind { clean::StrippedItem(..) => { @@ -66,7 +69,12 @@ impl<'a> DocFolder for Stripper<'a> { | clean::ForeignTypeItem => { let item_id = i.item_id; if item_id.is_local() - && !is_item_reachable(self.is_json_output, self.effective_visibilities, item_id) + && !is_item_reachable( + self.tcx, + self.is_json_output, + self.effective_visibilities, + item_id, + ) { debug!("Stripper: stripping {:?} {:?}", i.type_(), i.name); return None; @@ -146,14 +154,15 @@ impl<'a> DocFolder for Stripper<'a> { } /// This stripper discards all impls which reference stripped items -pub(crate) struct ImplStripper<'a> { +pub(crate) struct ImplStripper<'a, 'tcx> { + pub(crate) tcx: TyCtxt<'tcx>, pub(crate) retained: &'a ItemIdSet, pub(crate) cache: &'a Cache, pub(crate) is_json_output: bool, pub(crate) document_private: bool, } -impl<'a> ImplStripper<'a> { +impl<'a> ImplStripper<'a, '_> { #[inline] fn should_keep_impl(&self, item: &Item, for_def_id: DefId) -> bool { if !for_def_id.is_local() || self.retained.contains(&for_def_id.into()) { @@ -161,7 +170,7 @@ impl<'a> ImplStripper<'a> { } else if self.is_json_output { // If the "for" item is exported and the impl block isn't `#[doc(hidden)]`, then we // need to keep it. - self.cache.effective_visibilities.is_exported(for_def_id) + self.cache.effective_visibilities.is_exported(self.tcx, for_def_id) && !item.attrs.lists(sym::doc).has_word(sym::hidden) } else { false @@ -169,7 +178,7 @@ impl<'a> ImplStripper<'a> { } } -impl<'a> DocFolder for ImplStripper<'a> { +impl<'a> DocFolder for ImplStripper<'a, '_> { fn fold_item(&mut self, i: Item) -> Option { if let clean::ImplItem(ref imp) = *i.kind { // Impl blocks can be skipped if they are: empty; not a trait impl; and have no @@ -185,6 +194,7 @@ impl<'a> DocFolder for ImplStripper<'a> { let item_id = i.item_id; item_id.is_local() && !is_item_reachable( + self.tcx, self.is_json_output, &self.cache.effective_visibilities, item_id, diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 06dffce555f95..7ee7eb25e0d90 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; } @@ -246,7 +229,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { None => return false, }; - let is_private = !self.cx.cache.effective_visibilities.is_directly_public(res_did); + let is_private = + !self.cx.cache.effective_visibilities.is_directly_public(self.cx.tcx, res_did); let is_hidden = inherits_doc_hidden(self.cx.tcx, res_hir_id); // Only inline if requested or if the item would otherwise be stripped. diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs index 70214e2adba46..e490559b0e92a 100644 --- a/src/librustdoc/visit_lib.rs +++ b/src/librustdoc/visit_lib.rs @@ -1,86 +1,74 @@ +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_middle::middle::privacy::{EffectiveVisibilities, Level}; -use rustc_middle::ty::{TyCtxt, Visibility}; +use rustc_hir::def::DefKind; +use rustc_hir::def_id::DefId; +use rustc_middle::ty::TyCtxt; // FIXME: this may not be exhaustive, but is sufficient for rustdocs current uses +#[derive(Default)] +pub(crate) struct RustdocEffectiveVisibilities { + extern_public: FxHashSet, +} + +macro_rules! define_method { + ($method:ident) => { + pub(crate) fn $method(&self, tcx: TyCtxt<'_>, def_id: DefId) -> bool { + match def_id.as_local() { + Some(def_id) => tcx.effective_visibilities(()).$method(def_id), + None => self.extern_public.contains(&def_id), + } + } + }; +} + +impl RustdocEffectiveVisibilities { + define_method!(is_directly_public); + define_method!(is_exported); + define_method!(is_reachable); +} + +pub(crate) fn lib_embargo_visit_item(cx: &mut DocContext<'_>, def_id: DefId) { + assert!(!def_id.is_local()); + LibEmbargoVisitor { + tcx: cx.tcx, + extern_public: &mut cx.cache.effective_visibilities.extern_public, + visited_mods: Default::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, + extern_public: &'a mut FxHashSet, // 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.extern_public.insert(def_id); + if self.tcx.def_kind(def_id) == DefKind::Mod { + self.visit_mod(def_id); + } } } }