]>
Commit | Line | Data |
---|---|---|
a7813a04 XL |
1 | // Copyright 2016 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
9e0c209e | 11 | use rustc::middle::cstore::CrateStore; |
a7813a04 XL |
12 | use rustc::middle::privacy::{AccessLevels, AccessLevel}; |
13 | use rustc::hir::def::Def; | |
9e0c209e | 14 | use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId}; |
a7813a04 | 15 | use rustc::ty::Visibility; |
a7813a04 XL |
16 | |
17 | use std::cell::RefMut; | |
18 | ||
19 | use clean::{Attributes, Clean}; | |
20 | ||
21 | // FIXME: this may not be exhaustive, but is sufficient for rustdocs current uses | |
22 | ||
23 | /// Similar to `librustc_privacy::EmbargoVisitor`, but also takes | |
24 | /// specific rustdoc annotations into account (i.e. `doc(hidden)`) | |
25 | pub struct LibEmbargoVisitor<'a, 'b: 'a, 'tcx: 'b> { | |
26 | cx: &'a ::core::DocContext<'b, 'tcx>, | |
27 | cstore: &'a CrateStore<'tcx>, | |
28 | // Accessibility levels for reachable nodes | |
29 | access_levels: RefMut<'a, AccessLevels<DefId>>, | |
30 | // Previous accessibility level, None means unreachable | |
31 | prev_level: Option<AccessLevel>, | |
32 | } | |
33 | ||
34 | impl<'a, 'b, 'tcx> LibEmbargoVisitor<'a, 'b, 'tcx> { | |
35 | pub fn new(cx: &'a ::core::DocContext<'b, 'tcx>) -> LibEmbargoVisitor<'a, 'b, 'tcx> { | |
36 | LibEmbargoVisitor { | |
37 | cx: cx, | |
38 | cstore: &*cx.sess().cstore, | |
39 | access_levels: cx.access_levels.borrow_mut(), | |
40 | prev_level: Some(AccessLevel::Public), | |
41 | } | |
42 | } | |
43 | ||
9e0c209e | 44 | pub fn visit_lib(&mut self, cnum: CrateNum) { |
a7813a04 XL |
45 | let did = DefId { krate: cnum, index: CRATE_DEF_INDEX }; |
46 | self.update(did, Some(AccessLevel::Public)); | |
47 | self.visit_mod(did); | |
48 | } | |
49 | ||
50 | // Updates node level and returns the updated level | |
51 | fn update(&mut self, did: DefId, level: Option<AccessLevel>) -> Option<AccessLevel> { | |
52 | let attrs: Vec<_> = self.cx.tcx().get_attrs(did).iter() | |
53 | .map(|a| a.clean(self.cx)) | |
54 | .collect(); | |
55 | let is_hidden = attrs.list("doc").has_word("hidden"); | |
56 | ||
57 | let old_level = self.access_levels.map.get(&did).cloned(); | |
58 | // Accessibility levels can only grow | |
59 | if level > old_level && !is_hidden { | |
60 | self.access_levels.map.insert(did, level.unwrap()); | |
61 | level | |
62 | } else { | |
63 | old_level | |
64 | } | |
65 | } | |
66 | ||
9e0c209e SL |
67 | pub fn visit_mod(&mut self, def_id: DefId) { |
68 | for item in self.cstore.item_children(def_id) { | |
69 | self.visit_item(item.def_id); | |
a7813a04 XL |
70 | } |
71 | } | |
72 | ||
9e0c209e SL |
73 | fn visit_item(&mut self, def_id: DefId) { |
74 | let vis = self.cstore.visibility(def_id); | |
75 | let inherited_item_level = if vis == Visibility::Public { | |
76 | self.prev_level | |
77 | } else { | |
78 | None | |
a7813a04 XL |
79 | }; |
80 | ||
9e0c209e | 81 | let item_level = self.update(def_id, inherited_item_level); |
a7813a04 | 82 | |
9e0c209e | 83 | if let Some(Def::Mod(_)) = self.cstore.describe_def(def_id) { |
a7813a04 XL |
84 | let orig_level = self.prev_level; |
85 | ||
86 | self.prev_level = item_level; | |
9e0c209e | 87 | self.visit_mod(def_id); |
a7813a04 XL |
88 | self.prev_level = orig_level; |
89 | } | |
90 | } | |
91 | } |