1 use rustc_data_structures
::fx
::FxHashSet
;
2 use rustc_hir
::def
::{DefKind, Res}
;
3 use rustc_hir
::def_id
::{CrateNum, DefId}
;
4 use rustc_middle
::middle
::privacy
::{AccessLevel, AccessLevels}
;
5 use rustc_middle
::ty
::TyCtxt
;
7 // FIXME: this may not be exhaustive, but is sufficient for rustdocs current uses
9 /// Similar to `librustc_privacy::EmbargoVisitor`, but also takes
10 /// specific rustdoc annotations into account (i.e., `doc(hidden)`)
11 pub(crate) struct LibEmbargoVisitor
<'a
, 'tcx
> {
13 // Accessibility levels for reachable nodes
14 access_levels
: &'a
mut AccessLevels
<DefId
>,
15 // Previous accessibility level, None means unreachable
16 prev_level
: Option
<AccessLevel
>,
17 // Keeps track of already visited modules, in case a module re-exports its parent
18 visited_mods
: FxHashSet
<DefId
>,
21 impl<'a
, 'tcx
> LibEmbargoVisitor
<'a
, 'tcx
> {
22 pub(crate) fn new(cx
: &'a
mut crate::core
::DocContext
<'tcx
>) -> LibEmbargoVisitor
<'a
, 'tcx
> {
25 access_levels
: &mut cx
.cache
.access_levels
,
26 prev_level
: Some(AccessLevel
::Public
),
27 visited_mods
: FxHashSet
::default(),
31 pub(crate) fn visit_lib(&mut self, cnum
: CrateNum
) {
32 let did
= cnum
.as_def_id();
33 self.update(did
, Some(AccessLevel
::Public
));
37 // Updates node level and returns the updated level
38 fn update(&mut self, did
: DefId
, level
: Option
<AccessLevel
>) -> Option
<AccessLevel
> {
39 let is_hidden
= self.tcx
.is_doc_hidden(did
);
41 let old_level
= self.access_levels
.map
.get(&did
).cloned();
42 // Accessibility levels can only grow
43 if level
> old_level
&& !is_hidden
{
44 self.access_levels
.map
.insert(did
, level
.unwrap());
51 pub(crate) fn visit_mod(&mut self, def_id
: DefId
) {
52 if !self.visited_mods
.insert(def_id
) {
56 for item
in self.tcx
.module_children(def_id
).iter() {
57 if let Some(def_id
) = item
.res
.opt_def_id() {
58 if self.tcx
.def_key(def_id
).parent
.map_or(false, |d
| d
== def_id
.index
)
59 || item
.vis
.is_public()
61 self.visit_item(item
.res
);
67 fn visit_item(&mut self, res
: Res
<!>) {
68 let def_id
= res
.def_id();
69 let vis
= self.tcx
.visibility(def_id
);
70 let inherited_item_level
= if vis
.is_public() { self.prev_level }
else { None }
;
72 let item_level
= self.update(def_id
, inherited_item_level
);
74 if let Res
::Def(DefKind
::Mod
, _
) = res
{
75 let orig_level
= self.prev_level
;
77 self.prev_level
= item_level
;
78 self.visit_mod(def_id
);
79 self.prev_level
= orig_level
;