1 use crate::{ImportKind, NameBindingKind, Resolver};
4 use rustc_ast::visit::Visitor;
6 use rustc_ast::EnumDef;
7 use rustc_hir::def_id::LocalDefId;
8 use rustc_hir::def_id::CRATE_DEF_ID;
9 use rustc_middle::middle::privacy::AccessLevel;
10 use rustc_middle::ty::{DefIdTree, Visibility};
12 pub struct AccessLevelsVisitor<'r, 'a> {
13 r: &'r mut Resolver<'a>,
17 impl<'r, 'a> AccessLevelsVisitor<'r, 'a> {
18 /// Fills the `Resolver::access_levels` table with public & exported items
19 /// For now, this doesn't resolve macros (FIXME) and cannot resolve Impl, as we
20 /// need access to a TyCtxt for that.
21 pub fn compute_access_levels<'c>(r: &'r mut Resolver<'a>, krate: &'c Crate) {
22 let mut visitor = AccessLevelsVisitor { r, changed: false };
24 visitor.update(CRATE_DEF_ID, Visibility::Public, CRATE_DEF_ID, AccessLevel::Public);
25 visitor.set_bindings_access_level(CRATE_DEF_ID);
27 while visitor.changed {
29 visit::walk_crate(&mut visitor, krate);
32 info!("resolve::access_levels: {:#?}", r.access_levels);
39 /// Update the access level of the bindings in the given module accordingly. The module access
40 /// level has to be Exported or Public.
41 /// This will also follow `use` chains (see PrivacyVisitor::set_import_binding_access_level).
42 fn set_bindings_access_level(&mut self, module_id: LocalDefId) {
43 assert!(self.r.module_map.contains_key(&&module_id.to_def_id()));
44 let module = self.r.get_module(module_id.to_def_id()).unwrap();
45 let resolutions = self.r.resolutions(module);
47 for (_, name_resolution) in resolutions.borrow().iter() {
48 if let Some(mut binding) = name_resolution.borrow().binding() && !binding.is_ambiguity() {
49 // Set the given binding access level to `AccessLevel::Public` and
50 // sets the rest of the `use` chain to `AccessLevel::Exported` until
51 // we hit the actual exported item.
53 // FIXME: tag and is_public() condition should be removed, but assertions occur.
54 let tag = if binding.is_import() { AccessLevel::Exported } else { AccessLevel::Public };
55 if binding.vis.is_public() {
56 let mut prev_parent_id = module_id;
57 let mut level = AccessLevel::Public;
58 while let NameBindingKind::Import { binding: nested_binding, import, .. } =
61 let mut update = |node_id| self.update(
62 self.r.local_def_id(node_id),
63 binding.vis.expect_local(),
67 // In theory all the import IDs have individual visibilities and effective
68 // visibilities, but in practice these IDs go straigth to HIR where all
69 // their few uses assume that their (effective) visibility applies to the
70 // whole syntactic `use` item. So we update them all to the maximum value
71 // among the potential individual effective visibilities. Maybe HIR for
72 // imports shouldn't use three IDs at all.
74 if let ImportKind::Single { additional_ids, .. } = import.kind {
75 update(additional_ids.0);
76 update(additional_ids.1);
79 level = AccessLevel::Exported;
80 prev_parent_id = self.r.local_def_id(import.id);
81 binding = nested_binding;
85 if let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local()) {
86 self.update(def_id, binding.vis.expect_local(), module_id, tag);
95 nominal_vis: Visibility,
96 parent_id: LocalDefId,
99 let mut access_levels = std::mem::take(&mut self.r.access_levels);
101 self.r.get_nearest_non_block_module(def_id.to_def_id()).def_id().expect_local();
102 let res = access_levels.update(
105 || Visibility::Restricted(module_id),
110 if let Ok(changed) = res {
111 self.changed |= changed;
113 self.r.session.delay_span_bug(
114 self.r.opt_span(def_id.to_def_id()).unwrap(),
115 "Can't update effective visibility",
118 self.r.access_levels = access_levels;
122 impl<'r, 'ast> Visitor<'ast> for AccessLevelsVisitor<'ast, 'r> {
123 fn visit_item(&mut self, item: &'ast ast::Item) {
124 let def_id = self.r.local_def_id(item.id);
125 // Set access level of nested items.
126 // If it's a mod, also make the visitor walk all of its items
128 // Resolved in rustc_privacy when types are available
129 ast::ItemKind::Impl(..) => return,
131 // Should be unreachable at this stage
132 ast::ItemKind::MacCall(..) => panic!(
133 "ast::ItemKind::MacCall encountered, this should not anymore appear at this stage"
136 // Foreign modules inherit level from parents.
137 ast::ItemKind::ForeignMod(..) => {
138 let parent_id = self.r.local_parent(def_id);
139 self.update(def_id, Visibility::Public, parent_id, AccessLevel::Public);
142 // Only exported `macro_rules!` items are public, but they always are
143 ast::ItemKind::MacroDef(ref macro_def) if macro_def.macro_rules => {
144 let parent_id = self.r.local_parent(def_id);
145 let vis = self.r.visibilities[&def_id];
146 self.update(def_id, vis, parent_id, AccessLevel::Public);
149 ast::ItemKind::Mod(..) => {
150 self.set_bindings_access_level(def_id);
151 visit::walk_item(self, item);
154 ast::ItemKind::Enum(EnumDef { ref variants }, _) => {
155 self.set_bindings_access_level(def_id);
156 for variant in variants {
157 let variant_def_id = self.r.local_def_id(variant.id);
158 for field in variant.data.fields() {
159 let field_def_id = self.r.local_def_id(field.id);
160 let vis = self.r.visibilities[&field_def_id];
161 self.update(field_def_id, vis, variant_def_id, AccessLevel::Public);
166 ast::ItemKind::Struct(ref def, _) | ast::ItemKind::Union(ref def, _) => {
167 for field in def.fields() {
168 let field_def_id = self.r.local_def_id(field.id);
169 let vis = self.r.visibilities[&field_def_id];
170 self.update(field_def_id, vis, def_id, AccessLevel::Public);
174 ast::ItemKind::Trait(..) => {
175 self.set_bindings_access_level(def_id);
178 ast::ItemKind::ExternCrate(..)
179 | ast::ItemKind::Use(..)
180 | ast::ItemKind::Static(..)
181 | ast::ItemKind::Const(..)
182 | ast::ItemKind::GlobalAsm(..)
183 | ast::ItemKind::TyAlias(..)
184 | ast::ItemKind::TraitAlias(..)
185 | ast::ItemKind::MacroDef(..)
186 | ast::ItemKind::Fn(..) => return,