X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Flibrustdoc%2Fvisit_lib.rs;h=e490559b0e92addd40d61d7f25f040749ffa4fb6;hb=d76058d8b3fbc84633e5c706703fe9832f2f91dd;hp=70214e2adba463e7b34cee03e96c64d032dbd930;hpb=8564ee89001629aecd544814a2e549614996f603;p=rust.git diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs index 70214e2adba..e490559b0e9 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); + } } } }