]>
Commit | Line | Data |
---|---|---|
dfeec247 XL |
1 | use rustc_data_structures::fx::FxHashSet; |
2 | use rustc_hir::def::{DefKind, Res}; | |
3 | use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX}; | |
ba9703b0 | 4 | use rustc_middle::middle::privacy::{AccessLevel, AccessLevels}; |
3c0e092e | 5 | use rustc_middle::ty::TyCtxt; |
a7813a04 XL |
6 | |
7 | // FIXME: this may not be exhaustive, but is sufficient for rustdocs current uses | |
8 | ||
9 | /// Similar to `librustc_privacy::EmbargoVisitor`, but also takes | |
0731742a | 10 | /// specific rustdoc annotations into account (i.e., `doc(hidden)`) |
fc512014 | 11 | crate struct LibEmbargoVisitor<'a, 'tcx> { |
e1599b0c | 12 | tcx: TyCtxt<'tcx>, |
a7813a04 | 13 | // Accessibility levels for reachable nodes |
e1599b0c | 14 | access_levels: &'a mut AccessLevels<DefId>, |
a7813a04 XL |
15 | // Previous accessibility level, None means unreachable |
16 | prev_level: Option<AccessLevel>, | |
cc61c64b XL |
17 | // Keeps track of already visited modules, in case a module re-exports its parent |
18 | visited_mods: FxHashSet<DefId>, | |
a7813a04 XL |
19 | } |
20 | ||
532ac7d7 | 21 | impl<'a, 'tcx> LibEmbargoVisitor<'a, 'tcx> { |
fc512014 | 22 | crate fn new(cx: &'a mut crate::core::DocContext<'tcx>) -> LibEmbargoVisitor<'a, 'tcx> { |
a7813a04 | 23 | LibEmbargoVisitor { |
e1599b0c | 24 | tcx: cx.tcx, |
6a06907d | 25 | access_levels: &mut cx.cache.access_levels, |
a7813a04 | 26 | prev_level: Some(AccessLevel::Public), |
e1599b0c | 27 | visited_mods: FxHashSet::default(), |
a7813a04 XL |
28 | } |
29 | } | |
30 | ||
fc512014 | 31 | crate fn visit_lib(&mut self, cnum: CrateNum) { |
a7813a04 XL |
32 | let did = DefId { krate: cnum, index: CRATE_DEF_INDEX }; |
33 | self.update(did, Some(AccessLevel::Public)); | |
34 | self.visit_mod(did); | |
35 | } | |
36 | ||
37 | // Updates node level and returns the updated level | |
38 | fn update(&mut self, did: DefId, level: Option<AccessLevel>) -> Option<AccessLevel> { | |
a2a8927a | 39 | let is_hidden = self.tcx.is_doc_hidden(did); |
a7813a04 XL |
40 | |
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()); | |
45 | level | |
46 | } else { | |
47 | old_level | |
48 | } | |
49 | } | |
50 | ||
fc512014 | 51 | crate fn visit_mod(&mut self, def_id: DefId) { |
cc61c64b XL |
52 | if !self.visited_mods.insert(def_id) { |
53 | return; | |
54 | } | |
55 | ||
5099ac24 | 56 | for item in self.tcx.module_children(def_id).iter() { |
48663c56 | 57 | if let Some(def_id) = item.res.opt_def_id() { |
dfeec247 | 58 | if self.tcx.def_key(def_id).parent.map_or(false, |d| d == def_id.index) |
3c0e092e | 59 | || item.vis.is_public() |
dfeec247 | 60 | { |
48663c56 | 61 | self.visit_item(item.res); |
0731742a | 62 | } |
ff7c6d11 | 63 | } |
a7813a04 XL |
64 | } |
65 | } | |
66 | ||
c295e0f8 | 67 | fn visit_item(&mut self, res: Res<!>) { |
48663c56 | 68 | let def_id = res.def_id(); |
e1599b0c | 69 | let vis = self.tcx.visibility(def_id); |
3c0e092e | 70 | let inherited_item_level = if vis.is_public() { self.prev_level } else { None }; |
a7813a04 | 71 | |
9e0c209e | 72 | let item_level = self.update(def_id, inherited_item_level); |
a7813a04 | 73 | |
48663c56 | 74 | if let Res::Def(DefKind::Mod, _) = res { |
a7813a04 XL |
75 | let orig_level = self.prev_level; |
76 | ||
77 | self.prev_level = item_level; | |
9e0c209e | 78 | self.visit_mod(def_id); |
a7813a04 XL |
79 | self.prev_level = orig_level; |
80 | } | |
81 | } | |
82 | } |