]> git.proxmox.com Git - rustc.git/blame - src/librustc_privacy/lib.rs
New upstream version 1.34.2+dfsg1
[rustc.git] / src / librustc_privacy / lib.rs
CommitLineData
9fa01778
XL
1#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
2
3#![deny(rust_2018_idioms)]
85aaf69f 4
0bf4aa26 5#![feature(nll)]
85aaf69f 6#![feature(rustc_diagnostic_macros)]
7cac9316 7
94b46f34
XL
8#![recursion_limit="256"]
9
85aaf69f 10#[macro_use] extern crate syntax;
e9174d1e 11
9fa01778
XL
12use rustc::bug;
13use rustc::hir::{self, Node, PatKind, AssociatedItemKind};
cc61c64b 14use rustc::hir::def::Def;
041b39d2 15use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, CrateNum, DefId};
476ff2be
SL
16use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
17use rustc::hir::itemlikevisit::DeepVisitor;
3157f602 18use rustc::lint;
92a42be0 19use rustc::middle::privacy::{AccessLevel, AccessLevels};
0731742a 20use rustc::ty::{self, TyCtxt, Ty, TraitRef, TypeFoldable, GenericParamDefKind};
476ff2be 21use rustc::ty::fold::TypeVisitor;
94b46f34 22use rustc::ty::query::Providers;
0731742a 23use rustc::ty::subst::Substs;
54a0048b 24use rustc::util::nodemap::NodeSet;
0731742a
XL
25use rustc_data_structures::fx::FxHashSet;
26use rustc_data_structures::sync::Lrc;
9fa01778 27use syntax::ast::{self, DUMMY_NODE_ID, Ident};
0731742a 28use syntax::attr;
7cac9316
XL
29use syntax::symbol::keywords;
30use syntax_pos::Span;
85aaf69f 31
0731742a
XL
32use std::{cmp, fmt, mem};
33use std::marker::PhantomData;
85aaf69f 34
3b2f2976 35mod diagnostics;
85aaf69f 36
0731742a
XL
37////////////////////////////////////////////////////////////////////////////////
38/// Generic infrastructure used to implement specific visitors below.
39////////////////////////////////////////////////////////////////////////////////
40
41/// Implemented to visit all `DefId`s in a type.
42/// Visiting `DefId`s is useful because visibilities and reachabilities are attached to them.
43/// The idea is to visit "all components of a type", as documented in
9fa01778
XL
44/// https://github.com/rust-lang/rfcs/blob/master/text/2145-type-privacy.md#how-to-determine-visibility-of-a-type.
45/// The default type visitor (`TypeVisitor`) does most of the job, but it has some shortcomings.
46/// First, it doesn't have overridable `fn visit_trait_ref`, so we have to catch trait `DefId`s
0731742a
XL
47/// manually. Second, it doesn't visit some type components like signatures of fn types, or traits
48/// in `impl Trait`, see individual comments in `DefIdVisitorSkeleton::visit_ty`.
49trait DefIdVisitor<'a, 'tcx: 'a> {
50 fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx>;
51 fn shallow(&self) -> bool { false }
52 fn skip_assoc_tys(&self) -> bool { false }
53 fn visit_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool;
54
55 /// Not overridden, but used to actually visit types and traits.
56 fn skeleton(&mut self) -> DefIdVisitorSkeleton<'_, 'a, 'tcx, Self> {
57 DefIdVisitorSkeleton {
58 def_id_visitor: self,
59 visited_opaque_tys: Default::default(),
60 dummy: Default::default(),
61 }
62 }
63 fn visit(&mut self, ty_fragment: impl TypeFoldable<'tcx>) -> bool {
64 ty_fragment.visit_with(&mut self.skeleton())
65 }
66 fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> bool {
67 self.skeleton().visit_trait(trait_ref)
68 }
69 fn visit_predicates(&mut self, predicates: Lrc<ty::GenericPredicates<'tcx>>) -> bool {
70 self.skeleton().visit_predicates(predicates)
71 }
72}
73
74struct DefIdVisitorSkeleton<'v, 'a, 'tcx, V>
75 where V: DefIdVisitor<'a, 'tcx> + ?Sized
76{
77 def_id_visitor: &'v mut V,
78 visited_opaque_tys: FxHashSet<DefId>,
79 dummy: PhantomData<TyCtxt<'a, 'tcx, 'tcx>>,
80}
81
82impl<'a, 'tcx, V> DefIdVisitorSkeleton<'_, 'a, 'tcx, V>
83 where V: DefIdVisitor<'a, 'tcx> + ?Sized
84{
85 fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> bool {
86 let TraitRef { def_id, substs } = trait_ref;
87 self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref) ||
88 (!self.def_id_visitor.shallow() && substs.visit_with(self))
89 }
90
91 fn visit_predicates(&mut self, predicates: Lrc<ty::GenericPredicates<'tcx>>) -> bool {
92 let ty::GenericPredicates { parent: _, predicates } = &*predicates;
93 for (predicate, _span) in predicates {
94 match predicate {
95 ty::Predicate::Trait(poly_predicate) => {
96 let ty::TraitPredicate { trait_ref } = *poly_predicate.skip_binder();
97 if self.visit_trait(trait_ref) {
98 return true;
99 }
100 }
101 ty::Predicate::Projection(poly_predicate) => {
102 let ty::ProjectionPredicate { projection_ty, ty } =
103 *poly_predicate.skip_binder();
104 if ty.visit_with(self) {
105 return true;
106 }
107 if self.visit_trait(projection_ty.trait_ref(self.def_id_visitor.tcx())) {
108 return true;
109 }
110 }
111 ty::Predicate::TypeOutlives(poly_predicate) => {
112 let ty::OutlivesPredicate(ty, _region) = *poly_predicate.skip_binder();
113 if ty.visit_with(self) {
114 return true;
115 }
116 }
117 ty::Predicate::RegionOutlives(..) => {},
118 _ => bug!("unexpected predicate: {:?}", predicate),
119 }
120 }
121 false
122 }
123}
124
125impl<'a, 'tcx, V> TypeVisitor<'tcx> for DefIdVisitorSkeleton<'_, 'a, 'tcx, V>
126 where V: DefIdVisitor<'a, 'tcx> + ?Sized
127{
128 fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
129 let tcx = self.def_id_visitor.tcx();
130 // Substs are not visited here because they are visited below in `super_visit_with`.
131 match ty.sty {
132 ty::Adt(&ty::AdtDef { did: def_id, .. }, ..) |
133 ty::Foreign(def_id) |
134 ty::FnDef(def_id, ..) |
135 ty::Closure(def_id, ..) |
136 ty::Generator(def_id, ..) => {
137 if self.def_id_visitor.visit_def_id(def_id, "type", ty) {
138 return true;
139 }
140 if self.def_id_visitor.shallow() {
141 return false;
142 }
143 // Default type visitor doesn't visit signatures of fn types.
144 // Something like `fn() -> Priv {my_func}` is considered a private type even if
145 // `my_func` is public, so we need to visit signatures.
146 if let ty::FnDef(..) = ty.sty {
147 if tcx.fn_sig(def_id).visit_with(self) {
148 return true;
149 }
150 }
151 // Inherent static methods don't have self type in substs.
152 // Something like `fn() {my_method}` type of the method
153 // `impl Pub<Priv> { pub fn my_method() {} }` is considered a private type,
154 // so we need to visit the self type additionally.
155 if let Some(assoc_item) = tcx.opt_associated_item(def_id) {
156 if let ty::ImplContainer(impl_def_id) = assoc_item.container {
157 if tcx.type_of(impl_def_id).visit_with(self) {
158 return true;
159 }
160 }
161 }
162 }
163 ty::Projection(proj) | ty::UnnormalizedProjection(proj) => {
164 if self.def_id_visitor.skip_assoc_tys() {
165 // Visitors searching for minimal visibility/reachability want to
166 // conservatively approximate associated types like `<Type as Trait>::Alias`
167 // as visible/reachable even if both `Type` and `Trait` are private.
168 // Ideally, associated types should be substituted in the same way as
169 // free type aliases, but this isn't done yet.
170 return false;
171 }
172 // This will also visit substs if necessary, so we don't need to recurse.
173 return self.visit_trait(proj.trait_ref(tcx));
174 }
175 ty::Dynamic(predicates, ..) => {
176 // All traits in the list are considered the "primary" part of the type
177 // and are visited by shallow visitors.
178 for predicate in *predicates.skip_binder() {
179 let trait_ref = match *predicate {
180 ty::ExistentialPredicate::Trait(trait_ref) => trait_ref,
181 ty::ExistentialPredicate::Projection(proj) => proj.trait_ref(tcx),
182 ty::ExistentialPredicate::AutoTrait(def_id) =>
183 ty::ExistentialTraitRef { def_id, substs: Substs::empty() },
184 };
185 let ty::ExistentialTraitRef { def_id, substs: _ } = trait_ref;
186 if self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref) {
187 return true;
188 }
189 }
190 }
191 ty::Opaque(def_id, ..) => {
192 // Skip repeated `Opaque`s to avoid infinite recursion.
193 if self.visited_opaque_tys.insert(def_id) {
194 // The intent is to treat `impl Trait1 + Trait2` identically to
195 // `dyn Trait1 + Trait2`. Therefore we ignore def-id of the opaque type itself
196 // (it either has no visibility, or its visibility is insignificant, like
197 // visibilities of type aliases) and recurse into predicates instead to go
198 // through the trait list (default type visitor doesn't visit those traits).
199 // All traits in the list are considered the "primary" part of the type
200 // and are visited by shallow visitors.
201 if self.visit_predicates(tcx.predicates_of(def_id)) {
202 return true;
203 }
204 }
205 }
206 // These types don't have their own def-ids (but may have subcomponents
207 // with def-ids that should be visited recursively).
208 ty::Bool | ty::Char | ty::Int(..) | ty::Uint(..) |
209 ty::Float(..) | ty::Str | ty::Never |
210 ty::Array(..) | ty::Slice(..) | ty::Tuple(..) |
211 ty::RawPtr(..) | ty::Ref(..) | ty::FnPtr(..) |
212 ty::Param(..) | ty::Error | ty::GeneratorWitness(..) => {}
213 ty::Bound(..) | ty::Placeholder(..) | ty::Infer(..) =>
214 bug!("unexpected type: {:?}", ty),
215 }
216
217 !self.def_id_visitor.shallow() && ty.super_visit_with(self)
218 }
219}
220
221fn def_id_visibility<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
222 -> (ty::Visibility, Span, &'static str) {
223 match tcx.hir().as_local_node_id(def_id) {
224 Some(node_id) => {
225 let vis = match tcx.hir().get(node_id) {
226 Node::Item(item) => &item.vis,
227 Node::ForeignItem(foreign_item) => &foreign_item.vis,
228 Node::TraitItem(..) | Node::Variant(..) => {
229 return def_id_visibility(tcx, tcx.hir().get_parent_did(node_id));
230 }
231 Node::ImplItem(impl_item) => {
232 match tcx.hir().get(tcx.hir().get_parent(node_id)) {
233 Node::Item(item) => match &item.node {
234 hir::ItemKind::Impl(.., None, _, _) => &impl_item.vis,
235 hir::ItemKind::Impl(.., Some(trait_ref), _, _)
236 => return def_id_visibility(tcx, trait_ref.path.def.def_id()),
237 kind => bug!("unexpected item kind: {:?}", kind),
238 }
239 node => bug!("unexpected node kind: {:?}", node),
240 }
241 }
242 Node::StructCtor(vdata) => {
243 let struct_node_id = tcx.hir().get_parent(node_id);
244 let item = match tcx.hir().get(struct_node_id) {
245 Node::Item(item) => item,
246 node => bug!("unexpected node kind: {:?}", node),
247 };
248 let (mut ctor_vis, mut span, mut descr) =
249 (ty::Visibility::from_hir(&item.vis, struct_node_id, tcx),
250 item.vis.span, item.vis.node.descr());
251 for field in vdata.fields() {
252 let field_vis = ty::Visibility::from_hir(&field.vis, node_id, tcx);
253 if ctor_vis.is_at_least(field_vis, tcx) {
254 ctor_vis = field_vis;
255 span = field.vis.span;
256 descr = field.vis.node.descr();
257 }
258 }
259
260 // If the structure is marked as non_exhaustive then lower the
261 // visibility to within the crate.
262 if ctor_vis == ty::Visibility::Public {
263 let adt_def = tcx.adt_def(tcx.hir().get_parent_did(node_id));
264 if adt_def.non_enum_variant().is_field_list_non_exhaustive() {
265 ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
266 span = attr::find_by_name(&item.attrs, "non_exhaustive").unwrap().span;
267 descr = "crate-visible";
268 }
269 }
270
271 return (ctor_vis, span, descr);
272 }
273 Node::Expr(expr) => {
274 return (ty::Visibility::Restricted(tcx.hir().get_module_parent(expr.id)),
275 expr.span, "private")
276 }
277 node => bug!("unexpected node kind: {:?}", node)
278 };
279 (ty::Visibility::from_hir(vis, node_id, tcx), vis.span, vis.node.descr())
280 }
281 None => {
282 let vis = tcx.visibility(def_id);
283 let descr = if vis == ty::Visibility::Public { "public" } else { "private" };
284 (vis, tcx.def_span(def_id), descr)
285 }
286 }
287}
288
289// Set the correct `TypeckTables` for the given `item_id` (or an empty table if
290// there is no `TypeckTables` for the item).
291fn item_tables<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
292 node_id: ast::NodeId,
293 empty_tables: &'a ty::TypeckTables<'tcx>)
294 -> &'a ty::TypeckTables<'tcx> {
295 let def_id = tcx.hir().local_def_id(node_id);
296 if tcx.has_typeck_tables(def_id) { tcx.typeck_tables_of(def_id) } else { empty_tables }
297}
298
299fn min<'a, 'tcx>(vis1: ty::Visibility, vis2: ty::Visibility, tcx: TyCtxt<'a, 'tcx, 'tcx>)
300 -> ty::Visibility {
301 if vis1.is_at_least(vis2, tcx) { vis2 } else { vis1 }
302}
303
cc61c64b
XL
304////////////////////////////////////////////////////////////////////////////////
305/// Visitor used to determine if pub(restricted) is used anywhere in the crate.
306///
307/// This is done so that `private_in_public` warnings can be turned into hard errors
308/// in crates that have been updated to use pub(restricted).
309////////////////////////////////////////////////////////////////////////////////
310struct PubRestrictedVisitor<'a, 'tcx: 'a> {
311 tcx: TyCtxt<'a, 'tcx, 'tcx>,
312 has_pub_restricted: bool,
313}
314
315impl<'a, 'tcx> Visitor<'tcx> for PubRestrictedVisitor<'a, 'tcx> {
316 fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
0731742a 317 NestedVisitorMap::All(&self.tcx.hir())
cc61c64b
XL
318 }
319 fn visit_vis(&mut self, vis: &'tcx hir::Visibility) {
8faf50e0 320 self.has_pub_restricted = self.has_pub_restricted || vis.node.is_pub_restricted();
cc61c64b
XL
321 }
322}
323
0731742a
XL
324////////////////////////////////////////////////////////////////////////////////
325/// Visitor used to determine impl visibility and reachability.
326////////////////////////////////////////////////////////////////////////////////
327
328struct FindMin<'a, 'tcx, VL: VisibilityLike> {
329 tcx: TyCtxt<'a, 'tcx, 'tcx>,
330 access_levels: &'a AccessLevels,
331 min: VL,
332}
333
334impl<'a, 'tcx, VL: VisibilityLike> DefIdVisitor<'a, 'tcx> for FindMin<'a, 'tcx, VL> {
335 fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { self.tcx }
336 fn shallow(&self) -> bool { VL::SHALLOW }
337 fn skip_assoc_tys(&self) -> bool { true }
338 fn visit_def_id(&mut self, def_id: DefId, _kind: &str, _descr: &dyn fmt::Display) -> bool {
339 self.min = VL::new_min(self, def_id);
340 false
341 }
342}
343
344trait VisibilityLike: Sized {
345 const MAX: Self;
346 const SHALLOW: bool = false;
347 fn new_min<'a, 'tcx>(find: &FindMin<'a, 'tcx, Self>, def_id: DefId) -> Self;
348
349 // Returns an over-approximation (`skip_assoc_tys` = true) of visibility due to
350 // associated types for which we can't determine visibility precisely.
351 fn of_impl<'a, 'tcx>(node_id: ast::NodeId, tcx: TyCtxt<'a, 'tcx, 'tcx>,
352 access_levels: &'a AccessLevels) -> Self {
353 let mut find = FindMin { tcx, access_levels, min: Self::MAX };
354 let def_id = tcx.hir().local_def_id(node_id);
355 find.visit(tcx.type_of(def_id));
356 if let Some(trait_ref) = tcx.impl_trait_ref(def_id) {
357 find.visit_trait(trait_ref);
358 }
359 find.min
360 }
361}
362impl VisibilityLike for ty::Visibility {
363 const MAX: Self = ty::Visibility::Public;
364 fn new_min<'a, 'tcx>(find: &FindMin<'a, 'tcx, Self>, def_id: DefId) -> Self {
365 min(def_id_visibility(find.tcx, def_id).0, find.min, find.tcx)
366 }
367}
368impl VisibilityLike for Option<AccessLevel> {
369 const MAX: Self = Some(AccessLevel::Public);
370 // Type inference is very smart sometimes.
371 // It can make an impl reachable even some components of its type or trait are unreachable.
372 // E.g. methods of `impl ReachableTrait<UnreachableTy> for ReachableTy<UnreachableTy> { ... }`
373 // can be usable from other crates (#57264). So we skip substs when calculating reachability
374 // and consider an impl reachable if its "shallow" type and trait are reachable.
375 //
376 // The assumption we make here is that type-inference won't let you use an impl without knowing
377 // both "shallow" version of its self type and "shallow" version of its trait if it exists
378 // (which require reaching the `DefId`s in them).
379 const SHALLOW: bool = true;
380 fn new_min<'a, 'tcx>(find: &FindMin<'a, 'tcx, Self>, def_id: DefId) -> Self {
381 cmp::min(if let Some(node_id) = find.tcx.hir().as_local_node_id(def_id) {
382 find.access_levels.map.get(&node_id).cloned()
383 } else {
384 Self::MAX
385 }, find.min)
386 }
387}
388
85aaf69f 389////////////////////////////////////////////////////////////////////////////////
9fa01778 390/// The embargo visitor, used to determine the exports of the AST.
85aaf69f
SL
391////////////////////////////////////////////////////////////////////////////////
392
393struct EmbargoVisitor<'a, 'tcx: 'a> {
a7813a04 394 tcx: TyCtxt<'a, 'tcx, 'tcx>,
85aaf69f 395
0731742a 396 // Accessibility levels for reachable nodes.
92a42be0 397 access_levels: AccessLevels,
0731742a 398 // Previous accessibility level; `None` means unreachable.
92a42be0 399 prev_level: Option<AccessLevel>,
0731742a 400 // Has something changed in the level map?
92a42be0 401 changed: bool,
85aaf69f
SL
402}
403
7453a54e 404struct ReachEverythingInTheInterfaceVisitor<'b, 'a: 'b, 'tcx: 'a> {
b7449926 405 access_level: Option<AccessLevel>,
476ff2be 406 item_def_id: DefId,
7453a54e
SL
407 ev: &'b mut EmbargoVisitor<'a, 'tcx>,
408}
409
85aaf69f 410impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> {
92a42be0
SL
411 fn get(&self, id: ast::NodeId) -> Option<AccessLevel> {
412 self.access_levels.map.get(&id).cloned()
413 }
414
0731742a 415 // Updates node level and returns the updated level.
92a42be0
SL
416 fn update(&mut self, id: ast::NodeId, level: Option<AccessLevel>) -> Option<AccessLevel> {
417 let old_level = self.get(id);
0731742a 418 // Accessibility levels can only grow.
92a42be0
SL
419 if level > old_level {
420 self.access_levels.map.insert(id, level.unwrap());
421 self.changed = true;
422 level
423 } else {
424 old_level
425 }
85aaf69f 426 }
7453a54e 427
0731742a
XL
428 fn reach(&mut self, item_id: ast::NodeId, access_level: Option<AccessLevel>)
429 -> ReachEverythingInTheInterfaceVisitor<'_, 'a, 'tcx> {
476ff2be 430 ReachEverythingInTheInterfaceVisitor {
0731742a
XL
431 access_level: cmp::min(access_level, Some(AccessLevel::Reachable)),
432 item_def_id: self.tcx.hir().local_def_id(item_id),
476ff2be
SL
433 ev: self,
434 }
7453a54e 435 }
9fa01778
XL
436
437
438 /// Given the path segments of a `ItemKind::Use`, then we need
439 /// to update the visibility of the intermediate use so that it isn't linted
440 /// by `unreachable_pub`.
441 ///
442 /// This isn't trivial as `path.def` has the `DefId` of the eventual target
443 /// of the use statement not of the next intermediate use statement.
444 ///
445 /// To do this, consider the last two segments of the path to our intermediate
446 /// use statement. We expect the penultimate segment to be a module and the
447 /// last segment to be the name of the item we are exporting. We can then
448 /// look at the items contained in the module for the use statement with that
449 /// name and update that item's visibility.
450 ///
451 /// FIXME: This solution won't work with glob imports and doesn't respect
452 /// namespaces. See <https://github.com/rust-lang/rust/pull/57922#discussion_r251234202>.
453 fn update_visibility_of_intermediate_use_statements(&mut self, segments: &[hir::PathSegment]) {
454 if let Some([module, segment]) = segments.rchunks_exact(2).next() {
455 if let Some(item) = module.def
456 .and_then(|def| def.mod_def_id())
457 .and_then(|def_id| self.tcx.hir().as_local_hir_id(def_id))
458 .map(|module_hir_id| self.tcx.hir().expect_item_by_hir_id(module_hir_id))
459 {
460 if let hir::ItemKind::Mod(m) = &item.node {
461 for item_id in m.item_ids.as_ref() {
462 let item = self.tcx.hir().expect_item(item_id.id);
463 let def_id = self.tcx.hir().local_def_id(item_id.id);
464 if !self.tcx.hygienic_eq(segment.ident, item.ident, def_id) { continue; }
465 if let hir::ItemKind::Use(..) = item.node {
466 self.update(item.id, Some(AccessLevel::Exported));
467 }
468 }
469 }
470 }
471 }
472 }
85aaf69f
SL
473}
474
476ff2be 475impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> {
92a42be0
SL
476 /// We want to visit items in the context of their containing
477 /// module and so forth, so supply a crate for doing a deep walk.
476ff2be 478 fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
0731742a 479 NestedVisitorMap::All(&self.tcx.hir())
92a42be0 480 }
85aaf69f 481
476ff2be 482 fn visit_item(&mut self, item: &'tcx hir::Item) {
92a42be0 483 let inherited_item_level = match item.node {
0731742a
XL
484 hir::ItemKind::Impl(..) =>
485 Option::<AccessLevel>::of_impl(item.id, self.tcx, &self.access_levels),
486 // Foreign modules inherit level from parents.
487 hir::ItemKind::ForeignMod(..) => self.prev_level,
488 // Other `pub` items inherit levels from parents.
8faf50e0
XL
489 hir::ItemKind::Const(..) | hir::ItemKind::Enum(..) | hir::ItemKind::ExternCrate(..) |
490 hir::ItemKind::GlobalAsm(..) | hir::ItemKind::Fn(..) | hir::ItemKind::Mod(..) |
491 hir::ItemKind::Static(..) | hir::ItemKind::Struct(..) |
492 hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) |
493 hir::ItemKind::Existential(..) |
494 hir::ItemKind::Ty(..) | hir::ItemKind::Union(..) | hir::ItemKind::Use(..) => {
495 if item.vis.node.is_pub() { self.prev_level } else { None }
85aaf69f 496 }
92a42be0 497 };
85aaf69f 498
0731742a 499 // Update level of the item itself.
92a42be0 500 let item_level = self.update(item.id, inherited_item_level);
85aaf69f 501
0731742a 502 // Update levels of nested things.
85aaf69f 503 match item.node {
8faf50e0 504 hir::ItemKind::Enum(ref def, _) => {
85aaf69f 505 for variant in &def.variants {
92a42be0
SL
506 let variant_level = self.update(variant.node.data.id(), item_level);
507 for field in variant.node.data.fields() {
54a0048b 508 self.update(field.id, variant_level);
92a42be0 509 }
85aaf69f
SL
510 }
511 }
0731742a 512 hir::ItemKind::Impl(.., ref trait_ref, _, ref impl_item_refs) => {
476ff2be 513 for impl_item_ref in impl_item_refs {
0731742a 514 if trait_ref.is_some() || impl_item_ref.vis.node.is_pub() {
32a655c1 515 self.update(impl_item_ref.id.node_id, item_level);
85aaf69f
SL
516 }
517 }
518 }
8faf50e0 519 hir::ItemKind::Trait(.., ref trait_item_refs) => {
32a655c1
SL
520 for trait_item_ref in trait_item_refs {
521 self.update(trait_item_ref.id.node_id, item_level);
85aaf69f
SL
522 }
523 }
8faf50e0 524 hir::ItemKind::Struct(ref def, _) | hir::ItemKind::Union(ref def, _) => {
b039eaaf 525 if !def.is_struct() {
92a42be0 526 self.update(def.id(), item_level);
85aaf69f 527 }
b039eaaf 528 for field in def.fields() {
8faf50e0 529 if field.vis.node.is_pub() {
54a0048b 530 self.update(field.id, item_level);
c34b1796
AL
531 }
532 }
85aaf69f 533 }
8faf50e0 534 hir::ItemKind::ForeignMod(ref foreign_mod) => {
92a42be0 535 for foreign_item in &foreign_mod.items {
8faf50e0 536 if foreign_item.vis.node.is_pub() {
92a42be0
SL
537 self.update(foreign_item.id, item_level);
538 }
539 }
540 }
0731742a 541 hir::ItemKind::Existential(..) |
8faf50e0
XL
542 hir::ItemKind::Use(..) |
543 hir::ItemKind::Static(..) |
544 hir::ItemKind::Const(..) |
545 hir::ItemKind::GlobalAsm(..) |
546 hir::ItemKind::Ty(..) |
547 hir::ItemKind::Mod(..) |
548 hir::ItemKind::TraitAlias(..) |
549 hir::ItemKind::Fn(..) |
550 hir::ItemKind::ExternCrate(..) => {}
7453a54e
SL
551 }
552
0731742a 553 // Mark all items in interfaces of reachable items as reachable.
7453a54e 554 match item.node {
0731742a 555 // The interface is empty.
8faf50e0 556 hir::ItemKind::ExternCrate(..) => {}
0731742a 557 // All nested items are checked by `visit_item`.
8faf50e0 558 hir::ItemKind::Mod(..) => {}
9fa01778
XL
559 // Re-exports are handled in `visit_mod`. However, in order to avoid looping over
560 // all of the items of a mod in `visit_mod` looking for use statements, we handle
561 // making sure that intermediate use statements have their visibilities updated here.
562 hir::ItemKind::Use(ref path, _) => {
563 if item_level.is_some() {
564 self.update_visibility_of_intermediate_use_statements(path.segments.as_ref());
565 }
566 }
0731742a 567 // The interface is empty.
8faf50e0 568 hir::ItemKind::GlobalAsm(..) => {}
0731742a
XL
569 hir::ItemKind::Existential(..) => {
570 // FIXME: This is some serious pessimization intended to workaround deficiencies
571 // in the reachability pass (`middle/reachable.rs`). Types are marked as link-time
572 // reachable if they are returned via `impl Trait`, even from private functions.
573 let exist_level = cmp::max(item_level, Some(AccessLevel::ReachableFromImplTrait));
574 self.reach(item.id, exist_level).generics().predicates().ty();
575 }
576 // Visit everything.
8faf50e0 577 hir::ItemKind::Const(..) | hir::ItemKind::Static(..) |
8faf50e0 578 hir::ItemKind::Fn(..) | hir::ItemKind::Ty(..) => {
7453a54e 579 if item_level.is_some() {
0731742a 580 self.reach(item.id, item_level).generics().predicates().ty();
7453a54e
SL
581 }
582 }
8faf50e0 583 hir::ItemKind::Trait(.., ref trait_item_refs) => {
476ff2be 584 if item_level.is_some() {
0731742a 585 self.reach(item.id, item_level).generics().predicates();
476ff2be 586
32a655c1 587 for trait_item_ref in trait_item_refs {
0731742a 588 let mut reach = self.reach(trait_item_ref.id.node_id, item_level);
476ff2be
SL
589 reach.generics().predicates();
590
9fa01778 591 if trait_item_ref.kind == AssociatedItemKind::Type &&
32a655c1 592 !trait_item_ref.defaultness.has_value() {
476ff2be
SL
593 // No type to visit.
594 } else {
7cac9316 595 reach.ty();
476ff2be
SL
596 }
597 }
598 }
599 }
8faf50e0 600 hir::ItemKind::TraitAlias(..) => {
ff7c6d11 601 if item_level.is_some() {
0731742a 602 self.reach(item.id, item_level).generics().predicates();
ff7c6d11
XL
603 }
604 }
0731742a
XL
605 // Visit everything except for private impl items.
606 hir::ItemKind::Impl(.., ref impl_item_refs) => {
476ff2be 607 if item_level.is_some() {
0731742a 608 self.reach(item.id, item_level).generics().predicates().ty().trait_ref();
476ff2be 609
32a655c1 610 for impl_item_ref in impl_item_refs {
0731742a
XL
611 let impl_item_level = self.get(impl_item_ref.id.node_id);
612 if impl_item_level.is_some() {
613 self.reach(impl_item_ref.id.node_id, impl_item_level)
614 .generics().predicates().ty();
476ff2be
SL
615 }
616 }
617 }
618 }
619
0731742a 620 // Visit everything, but enum variants have their own levels.
8faf50e0 621 hir::ItemKind::Enum(ref def, _) => {
7453a54e 622 if item_level.is_some() {
0731742a 623 self.reach(item.id, item_level).generics().predicates();
7453a54e
SL
624 }
625 for variant in &def.variants {
0731742a
XL
626 let variant_level = self.get(variant.node.data.id());
627 if variant_level.is_some() {
7453a54e 628 for field in variant.node.data.fields() {
0731742a 629 self.reach(field.id, variant_level).ty();
7453a54e
SL
630 }
631 // Corner case: if the variant is reachable, but its
632 // enum is not, make the enum reachable as well.
0731742a 633 self.update(item.id, variant_level);
7453a54e
SL
634 }
635 }
636 }
0731742a 637 // Visit everything, but foreign items have their own levels.
8faf50e0 638 hir::ItemKind::ForeignMod(ref foreign_mod) => {
7453a54e 639 for foreign_item in &foreign_mod.items {
0731742a
XL
640 let foreign_item_level = self.get(foreign_item.id);
641 if foreign_item_level.is_some() {
642 self.reach(foreign_item.id, foreign_item_level)
643 .generics().predicates().ty();
7453a54e
SL
644 }
645 }
646 }
0731742a 647 // Visit everything except for private fields.
8faf50e0
XL
648 hir::ItemKind::Struct(ref struct_def, _) |
649 hir::ItemKind::Union(ref struct_def, _) => {
7453a54e 650 if item_level.is_some() {
0731742a 651 self.reach(item.id, item_level).generics().predicates();
7453a54e 652 for field in struct_def.fields() {
0731742a
XL
653 let field_level = self.get(field.id);
654 if field_level.is_some() {
655 self.reach(field.id, field_level).ty();
85aaf69f
SL
656 }
657 }
658 }
659 }
85aaf69f
SL
660 }
661
0731742a 662 let orig_level = mem::replace(&mut self.prev_level, item_level);
92a42be0 663 intravisit::walk_item(self, item);
92a42be0 664 self.prev_level = orig_level;
85aaf69f
SL
665 }
666
476ff2be 667 fn visit_block(&mut self, b: &'tcx hir::Block) {
92a42be0
SL
668 // Blocks can have public items, for example impls, but they always
669 // start as completely private regardless of publicity of a function,
0731742a
XL
670 // constant, type, field, etc., in which this block resides.
671 let orig_level = mem::replace(&mut self.prev_level, None);
92a42be0 672 intravisit::walk_block(self, b);
92a42be0 673 self.prev_level = orig_level;
85aaf69f
SL
674 }
675
9fa01778 676 fn visit_mod(&mut self, m: &'tcx hir::Mod, _sp: Span, id: hir::HirId) {
85aaf69f
SL
677 // This code is here instead of in visit_item so that the
678 // crate module gets processed as well.
92a42be0 679 if self.prev_level.is_some() {
9fa01778 680 let def_id = self.tcx.hir().local_def_id_from_hir_id(id);
ea8adc8c
XL
681 if let Some(exports) = self.tcx.module_exports(def_id) {
682 for export in exports.iter() {
13cf67c4
XL
683 if export.vis == ty::Visibility::Public {
684 if let Some(def_id) = export.def.opt_def_id() {
0731742a 685 if let Some(node_id) = self.tcx.hir().as_local_node_id(def_id) {
13cf67c4
XL
686 self.update(node_id, Some(AccessLevel::Exported));
687 }
ff7c6d11 688 }
9cc50fc6 689 }
85aaf69f
SL
690 }
691 }
692 }
92a42be0 693
5bcae85e 694 intravisit::walk_mod(self, m, id);
92a42be0
SL
695 }
696
476ff2be 697 fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef) {
7cac9316
XL
698 if md.legacy {
699 self.update(md.id, Some(AccessLevel::Public));
700 return
701 }
702
0731742a
XL
703 let module_did = ty::DefIdTree::parent(
704 self.tcx,
705 self.tcx.hir().local_def_id(md.id)
706 ).unwrap();
707 let mut module_id = self.tcx.hir().as_local_node_id(module_did).unwrap();
8faf50e0 708 let level = if md.vis.node.is_pub() { self.get(module_id) } else { None };
7cac9316
XL
709 let level = self.update(md.id, level);
710 if level.is_none() {
711 return
712 }
713
714 loop {
715 let module = if module_id == ast::CRATE_NODE_ID {
0731742a
XL
716 &self.tcx.hir().krate().module
717 } else if let hir::ItemKind::Mod(ref module) =
718 self.tcx.hir().expect_item(module_id).node {
7cac9316
XL
719 module
720 } else {
721 unreachable!()
722 };
723 for id in &module.item_ids {
724 self.update(id.id, level);
725 }
0731742a 726 let def_id = self.tcx.hir().local_def_id(module_id);
ff7c6d11
XL
727 if let Some(exports) = self.tcx.module_exports(def_id) {
728 for export in exports.iter() {
0731742a 729 if let Some(node_id) = self.tcx.hir().as_local_node_id(export.def.def_id()) {
ff7c6d11
XL
730 self.update(node_id, level);
731 }
732 }
733 }
734
7cac9316
XL
735 if module_id == ast::CRATE_NODE_ID {
736 break
737 }
0731742a 738 module_id = self.tcx.hir().get_parent_node(module_id);
7cac9316 739 }
85aaf69f 740 }
7453a54e
SL
741}
742
0731742a 743impl<'a, 'tcx> ReachEverythingInTheInterfaceVisitor<'_, 'a, 'tcx> {
476ff2be 744 fn generics(&mut self) -> &mut Self {
94b46f34
XL
745 for param in &self.ev.tcx.generics_of(self.item_def_id).params {
746 match param.kind {
747 GenericParamDefKind::Type { has_default, .. } => {
748 if has_default {
0731742a 749 self.visit(self.ev.tcx.type_of(param.def_id));
94b46f34
XL
750 }
751 }
752 GenericParamDefKind::Lifetime => {}
8bb4bdeb
XL
753 }
754 }
476ff2be
SL
755 self
756 }
9e0c209e 757
476ff2be 758 fn predicates(&mut self) -> &mut Self {
0731742a 759 self.visit_predicates(self.ev.tcx.predicates_of(self.item_def_id));
476ff2be
SL
760 self
761 }
762
7cac9316 763 fn ty(&mut self) -> &mut Self {
0731742a 764 self.visit(self.ev.tcx.type_of(self.item_def_id));
476ff2be
SL
765 self
766 }
767
0731742a
XL
768 fn trait_ref(&mut self) -> &mut Self {
769 if let Some(trait_ref) = self.ev.tcx.impl_trait_ref(self.item_def_id) {
770 self.visit_trait(trait_ref);
041b39d2 771 }
476ff2be
SL
772 self
773 }
774}
775
0731742a
XL
776impl<'a, 'tcx> DefIdVisitor<'a, 'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'a, 'tcx> {
777 fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { self.ev.tcx }
778 fn visit_def_id(&mut self, def_id: DefId, _kind: &str, _descr: &dyn fmt::Display) -> bool {
779 if let Some(node_id) = self.ev.tcx.hir().as_local_node_id(def_id) {
780 self.ev.update(node_id, self.access_level);
7453a54e 781 }
0731742a 782 false
7453a54e 783 }
7453a54e
SL
784}
785
7cac9316
XL
786//////////////////////////////////////////////////////////////////////////////////////
787/// Name privacy visitor, checks privacy and reports violations.
788/// Most of name privacy checks are performed during the main resolution phase,
789/// or later in type checking when field accesses and associated items are resolved.
790/// This pass performs remaining checks for fields in struct expressions and patterns.
791//////////////////////////////////////////////////////////////////////////////////////
85aaf69f 792
7cac9316 793struct NamePrivacyVisitor<'a, 'tcx: 'a> {
a7813a04 794 tcx: TyCtxt<'a, 'tcx, 'tcx>,
32a655c1 795 tables: &'a ty::TypeckTables<'tcx>,
7cac9316 796 current_item: ast::NodeId,
3b2f2976 797 empty_tables: &'a ty::TypeckTables<'tcx>,
85aaf69f
SL
798}
799
7cac9316 800impl<'a, 'tcx> NamePrivacyVisitor<'a, 'tcx> {
0531ce1d
XL
801 // Checks that a field in a struct constructor (expression or pattern) is accessible.
802 fn check_field(&mut self,
0731742a
XL
803 use_ctxt: Span, // syntax context of the field name at the use site
804 span: Span, // span of the field pattern, e.g., `x: 0`
805 def: &'tcx ty::AdtDef, // definition of the struct or enum
806 field: &'tcx ty::FieldDef) { // definition of the field
94b46f34 807 let ident = Ident::new(keywords::Invalid.name(), use_ctxt);
9fa01778
XL
808 let current_hir = self.tcx.hir().node_to_hir_id(self.current_item);
809 let def_id = self.tcx.adjust_ident(ident, def.did, current_hir).1;
7cac9316 810 if !def.is_enum() && !field.vis.is_accessible_from(def_id, self.tcx) {
9e0c209e 811 struct_span_err!(self.tcx.sess, span, E0451, "field `{}` of {} `{}` is private",
94b46f34
XL
812 field.ident, def.variant_descr(), self.tcx.item_path_str(def.did))
813 .span_label(span, format!("field `{}` is private", field.ident))
9e0c209e 814 .emit();
85aaf69f
SL
815 }
816 }
85aaf69f
SL
817}
818
7cac9316 819impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> {
92a42be0
SL
820 /// We want to visit items in the context of their containing
821 /// module and so forth, so supply a crate for doing a deep walk.
476ff2be 822 fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
0731742a 823 NestedVisitorMap::All(&self.tcx.hir())
32a655c1
SL
824 }
825
9fa01778
XL
826 fn visit_mod(&mut self, _m: &'tcx hir::Mod, _s: Span, _n: hir::HirId) {
827 // Don't visit nested modules, since we run a separate visitor walk
828 // for each module in `privacy_access_levels`
829 }
830
32a655c1 831 fn visit_nested_body(&mut self, body: hir::BodyId) {
0731742a
XL
832 let orig_tables = mem::replace(&mut self.tables, self.tcx.body_tables(body));
833 let body = self.tcx.hir().body(body);
32a655c1 834 self.visit_body(body);
7cac9316 835 self.tables = orig_tables;
92a42be0
SL
836 }
837
476ff2be 838 fn visit_item(&mut self, item: &'tcx hir::Item) {
0731742a
XL
839 let orig_current_item = mem::replace(&mut self.current_item, item.id);
840 let orig_tables =
841 mem::replace(&mut self.tables, item_tables(self.tcx, item.id, self.empty_tables));
92a42be0 842 intravisit::walk_item(self, item);
7cac9316 843 self.current_item = orig_current_item;
3b2f2976
XL
844 self.tables = orig_tables;
845 }
846
847 fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem) {
0731742a
XL
848 let orig_tables =
849 mem::replace(&mut self.tables, item_tables(self.tcx, ti.id, self.empty_tables));
3b2f2976
XL
850 intravisit::walk_trait_item(self, ti);
851 self.tables = orig_tables;
852 }
853
854 fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem) {
0731742a
XL
855 let orig_tables =
856 mem::replace(&mut self.tables, item_tables(self.tcx, ii.id, self.empty_tables));
3b2f2976
XL
857 intravisit::walk_impl_item(self, ii);
858 self.tables = orig_tables;
85aaf69f
SL
859 }
860
476ff2be 861 fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
85aaf69f 862 match expr.node {
8faf50e0 863 hir::ExprKind::Struct(ref qpath, ref fields, ref base) => {
3b2f2976 864 let def = self.tables.qpath_def(qpath, expr.hir_id);
32a655c1 865 let adt = self.tables.expr_ty(expr).ty_adt_def().unwrap();
476ff2be 866 let variant = adt.variant_of_def(def);
7cac9316
XL
867 if let Some(ref base) = *base {
868 // If the expression uses FRU we need to make sure all the unmentioned fields
869 // are checked for privacy (RFC 736). Rather than computing the set of
870 // unmentioned fields, just check them all.
83c7162d
XL
871 for (vf_index, variant_field) in variant.fields.iter().enumerate() {
872 let field = fields.iter().find(|f| {
873 self.tcx.field_index(f.id, self.tables) == vf_index
874 });
0531ce1d 875 let (use_ctxt, span) = match field {
94b46f34 876 Some(field) => (field.ident.span, field.span),
83c7162d 877 None => (base.span, base.span),
0531ce1d
XL
878 };
879 self.check_field(use_ctxt, span, adt, variant_field);
9e0c209e
SL
880 }
881 } else {
7cac9316 882 for field in fields {
94b46f34 883 let use_ctxt = field.ident.span;
83c7162d
XL
884 let index = self.tcx.field_index(field.id, self.tables);
885 self.check_field(use_ctxt, field.span, adt, &variant.fields[index]);
9e0c209e 886 }
85aaf69f
SL
887 }
888 }
85aaf69f
SL
889 _ => {}
890 }
891
92a42be0 892 intravisit::walk_expr(self, expr);
85aaf69f
SL
893 }
894
7cac9316
XL
895 fn visit_pat(&mut self, pat: &'tcx hir::Pat) {
896 match pat.node {
476ff2be 897 PatKind::Struct(ref qpath, ref fields, _) => {
3b2f2976 898 let def = self.tables.qpath_def(qpath, pat.hir_id);
7cac9316 899 let adt = self.tables.pat_ty(pat).ty_adt_def().unwrap();
476ff2be 900 let variant = adt.variant_of_def(def);
e9174d1e 901 for field in fields {
94b46f34 902 let use_ctxt = field.node.ident.span;
83c7162d
XL
903 let index = self.tcx.field_index(field.node.id, self.tables);
904 self.check_field(use_ctxt, field.span, adt, &variant.fields[index]);
85aaf69f
SL
905 }
906 }
85aaf69f
SL
907 _ => {}
908 }
909
7cac9316 910 intravisit::walk_pat(self, pat);
85aaf69f 911 }
85aaf69f
SL
912}
913
041b39d2
XL
914////////////////////////////////////////////////////////////////////////////////////////////
915/// Type privacy visitor, checks types for privacy and reports violations.
916/// Both explicitly written types and inferred types of expressions and patters are checked.
917/// Checks are performed on "semantic" types regardless of names and their hygiene.
918////////////////////////////////////////////////////////////////////////////////////////////
919
920struct TypePrivacyVisitor<'a, 'tcx: 'a> {
921 tcx: TyCtxt<'a, 'tcx, 'tcx>,
922 tables: &'a ty::TypeckTables<'tcx>,
923 current_item: DefId,
ff7c6d11 924 in_body: bool,
041b39d2 925 span: Span,
3b2f2976 926 empty_tables: &'a ty::TypeckTables<'tcx>,
041b39d2
XL
927}
928
929impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> {
041b39d2 930 fn item_is_accessible(&self, did: DefId) -> bool {
0731742a 931 def_id_visibility(self.tcx, did).0.is_accessible_from(self.current_item, self.tcx)
041b39d2
XL
932 }
933
0731742a 934 // Take node-id of an expression or pattern and check its type for privacy.
3b2f2976 935 fn check_expr_pat_type(&mut self, id: hir::HirId, span: Span) -> bool {
041b39d2 936 self.span = span;
9fa01778 937 if self.visit(self.tables.node_type(id)) || self.visit(self.tables.node_substs(id)) {
041b39d2
XL
938 return true;
939 }
3b2f2976 940 if let Some(adjustments) = self.tables.adjustments().get(id) {
041b39d2 941 for adjustment in adjustments {
0731742a 942 if self.visit(adjustment.target) {
041b39d2
XL
943 return true;
944 }
945 }
946 }
947 false
948 }
ff7c6d11 949
0731742a
XL
950 fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {
951 let is_error = !self.item_is_accessible(def_id);
952 if is_error {
953 self.tcx.sess.span_err(self.span, &format!("{} `{}` is private", kind, descr));
ff7c6d11 954 }
0731742a 955 is_error
ff7c6d11 956 }
041b39d2
XL
957}
958
959impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
960 /// We want to visit items in the context of their containing
961 /// module and so forth, so supply a crate for doing a deep walk.
962 fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
0731742a 963 NestedVisitorMap::All(&self.tcx.hir())
041b39d2
XL
964 }
965
9fa01778
XL
966 fn visit_mod(&mut self, _m: &'tcx hir::Mod, _s: Span, _n: hir::HirId) {
967 // Don't visit nested modules, since we run a separate visitor walk
968 // for each module in `privacy_access_levels`
969 }
970
041b39d2 971 fn visit_nested_body(&mut self, body: hir::BodyId) {
0731742a
XL
972 let orig_tables = mem::replace(&mut self.tables, self.tcx.body_tables(body));
973 let orig_in_body = mem::replace(&mut self.in_body, true);
974 let body = self.tcx.hir().body(body);
041b39d2
XL
975 self.visit_body(body);
976 self.tables = orig_tables;
ff7c6d11 977 self.in_body = orig_in_body;
041b39d2
XL
978 }
979
ea8adc8c
XL
980 fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty) {
981 self.span = hir_ty.span;
ff7c6d11 982 if self.in_body {
ea8adc8c 983 // Types in bodies.
9fa01778 984 if self.visit(self.tables.node_type(hir_ty.hir_id)) {
ea8adc8c
XL
985 return;
986 }
987 } else {
988 // Types in signatures.
989 // FIXME: This is very ineffective. Ideally each HIR type should be converted
990 // into a semantic type only once and the result should be cached somehow.
0731742a 991 if self.visit(rustc_typeck::hir_ty_to_ty(self.tcx, hir_ty)) {
ea8adc8c
XL
992 return;
993 }
994 }
995
996 intravisit::walk_ty(self, hir_ty);
997 }
998
999 fn visit_trait_ref(&mut self, trait_ref: &'tcx hir::TraitRef) {
ff7c6d11
XL
1000 self.span = trait_ref.path.span;
1001 if !self.in_body {
1002 // Avoid calling `hir_trait_to_predicates` in bodies, it will ICE.
1003 // The traits' privacy in bodies is already checked as a part of trait object types.
1004 let (principal, projections) =
1005 rustc_typeck::hir_trait_to_predicates(self.tcx, trait_ref);
0731742a 1006 if self.visit_trait(*principal.skip_binder()) {
ff7c6d11
XL
1007 return;
1008 }
0bf4aa26 1009 for (poly_predicate, _) in projections {
ff7c6d11 1010 let tcx = self.tcx;
0731742a
XL
1011 if self.visit(poly_predicate.skip_binder().ty) ||
1012 self.visit_trait(poly_predicate.skip_binder().projection_ty.trait_ref(tcx)) {
ff7c6d11
XL
1013 return;
1014 }
1015 }
ea8adc8c
XL
1016 }
1017
1018 intravisit::walk_trait_ref(self, trait_ref);
1019 }
1020
041b39d2
XL
1021 // Check types of expressions
1022 fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
3b2f2976 1023 if self.check_expr_pat_type(expr.hir_id, expr.span) {
041b39d2
XL
1024 // Do not check nested expressions if the error already happened.
1025 return;
1026 }
1027 match expr.node {
8faf50e0 1028 hir::ExprKind::Assign(.., ref rhs) | hir::ExprKind::Match(ref rhs, ..) => {
041b39d2 1029 // Do not report duplicate errors for `x = y` and `match x { ... }`.
3b2f2976 1030 if self.check_expr_pat_type(rhs.hir_id, rhs.span) {
041b39d2
XL
1031 return;
1032 }
1033 }
8faf50e0 1034 hir::ExprKind::MethodCall(_, span, _) => {
041b39d2 1035 // Method calls have to be checked specially.
041b39d2 1036 self.span = span;
8faf50e0 1037 if let Some(def) = self.tables.type_dependent_defs().get(expr.hir_id) {
0731742a 1038 if self.visit(self.tcx.type_of(def.def_id())) {
8faf50e0
XL
1039 return;
1040 }
1041 } else {
1042 self.tcx.sess.delay_span_bug(expr.span,
1043 "no type-dependent def for method call");
041b39d2
XL
1044 }
1045 }
1046 _ => {}
1047 }
1048
1049 intravisit::walk_expr(self, expr);
1050 }
1051
ff7c6d11
XL
1052 // Prohibit access to associated items with insufficient nominal visibility.
1053 //
1054 // Additionally, until better reachability analysis for macros 2.0 is available,
1055 // we prohibit access to private statics from other crates, this allows to give
1056 // more code internal visibility at link time. (Access to private functions
0531ce1d 1057 // is already prohibited by type privacy for function types.)
b7449926 1058 fn visit_qpath(&mut self, qpath: &'tcx hir::QPath, id: hir::HirId, span: Span) {
ff7c6d11
XL
1059 let def = match *qpath {
1060 hir::QPath::Resolved(_, ref path) => match path.def {
1061 Def::Method(..) | Def::AssociatedConst(..) |
0731742a
XL
1062 Def::AssociatedTy(..) | Def::AssociatedExistential(..) |
1063 Def::Static(..) => Some(path.def),
ff7c6d11
XL
1064 _ => None,
1065 }
1066 hir::QPath::TypeRelative(..) => {
b7449926 1067 self.tables.type_dependent_defs().get(id).cloned()
ff7c6d11
XL
1068 }
1069 };
1070 if let Some(def) = def {
1071 let def_id = def.def_id();
1072 let is_local_static = if let Def::Static(..) = def { def_id.is_local() } else { false };
1073 if !self.item_is_accessible(def_id) && !is_local_static {
1074 let name = match *qpath {
8faf50e0
XL
1075 hir::QPath::Resolved(_, ref path) => path.to_string(),
1076 hir::QPath::TypeRelative(_, ref segment) => segment.ident.to_string(),
ff7c6d11
XL
1077 };
1078 let msg = format!("{} `{}` is private", def.kind_name(), name);
1079 self.tcx.sess.span_err(span, &msg);
1080 return;
041b39d2
XL
1081 }
1082 }
1083
1084 intravisit::walk_qpath(self, qpath, id, span);
1085 }
1086
0731742a 1087 // Check types of patterns.
041b39d2 1088 fn visit_pat(&mut self, pattern: &'tcx hir::Pat) {
3b2f2976 1089 if self.check_expr_pat_type(pattern.hir_id, pattern.span) {
041b39d2
XL
1090 // Do not check nested patterns if the error already happened.
1091 return;
1092 }
1093
1094 intravisit::walk_pat(self, pattern);
1095 }
1096
1097 fn visit_local(&mut self, local: &'tcx hir::Local) {
1098 if let Some(ref init) = local.init {
3b2f2976 1099 if self.check_expr_pat_type(init.hir_id, init.span) {
041b39d2
XL
1100 // Do not report duplicate errors for `let x = y`.
1101 return;
1102 }
1103 }
1104
1105 intravisit::walk_local(self, local);
1106 }
1107
0731742a 1108 // Check types in item interfaces.
041b39d2 1109 fn visit_item(&mut self, item: &'tcx hir::Item) {
0731742a
XL
1110 let orig_current_item =
1111 mem::replace(&mut self.current_item, self.tcx.hir().local_def_id(item.id));
1112 let orig_in_body = mem::replace(&mut self.in_body, false);
1113 let orig_tables =
1114 mem::replace(&mut self.tables, item_tables(self.tcx, item.id, self.empty_tables));
041b39d2 1115 intravisit::walk_item(self, item);
3b2f2976 1116 self.tables = orig_tables;
ff7c6d11 1117 self.in_body = orig_in_body;
041b39d2
XL
1118 self.current_item = orig_current_item;
1119 }
3b2f2976
XL
1120
1121 fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem) {
0731742a
XL
1122 let orig_tables =
1123 mem::replace(&mut self.tables, item_tables(self.tcx, ti.id, self.empty_tables));
3b2f2976
XL
1124 intravisit::walk_trait_item(self, ti);
1125 self.tables = orig_tables;
1126 }
1127
1128 fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem) {
0731742a
XL
1129 let orig_tables =
1130 mem::replace(&mut self.tables, item_tables(self.tcx, ii.id, self.empty_tables));
3b2f2976
XL
1131 intravisit::walk_impl_item(self, ii);
1132 self.tables = orig_tables;
1133 }
041b39d2
XL
1134}
1135
0731742a
XL
1136impl<'a, 'tcx> DefIdVisitor<'a, 'tcx> for TypePrivacyVisitor<'a, 'tcx> {
1137 fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { self.tcx }
1138 fn visit_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {
1139 self.check_def_id(def_id, kind, descr)
041b39d2
XL
1140 }
1141}
1142
9cc50fc6
SL
1143///////////////////////////////////////////////////////////////////////////////
1144/// Obsolete visitors for checking for private items in public interfaces.
1145/// These visitors are supposed to be kept in frozen state and produce an
1146/// "old error node set". For backward compatibility the new visitor reports
1147/// warnings instead of hard errors when the erroneous node is not in this old set.
1148///////////////////////////////////////////////////////////////////////////////
1149
1150struct ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx: 'a> {
a7813a04 1151 tcx: TyCtxt<'a, 'tcx, 'tcx>,
92a42be0 1152 access_levels: &'a AccessLevels,
85aaf69f 1153 in_variant: bool,
0731742a 1154 // Set of errors produced by this obsolete visitor.
9cc50fc6 1155 old_error_set: NodeSet,
85aaf69f
SL
1156}
1157
9cc50fc6
SL
1158struct ObsoleteCheckTypeForPrivatenessVisitor<'a, 'b: 'a, 'tcx: 'b> {
1159 inner: &'a ObsoleteVisiblePrivateTypesVisitor<'b, 'tcx>,
0731742a 1160 /// Whether the type refers to private types.
85aaf69f 1161 contains_private: bool,
0731742a
XL
1162 /// Whether we've recurred at all (i.e., if we're pointing at the
1163 /// first type on which `visit_ty` was called).
85aaf69f 1164 at_outer_type: bool,
0731742a 1165 /// Whether that first type is a public path.
85aaf69f
SL
1166 outer_type_is_public_path: bool,
1167}
1168
9cc50fc6 1169impl<'a, 'tcx> ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
476ff2be
SL
1170 fn path_is_private_type(&self, path: &hir::Path) -> bool {
1171 let did = match path.def {
b7449926 1172 Def::PrimTy(..) | Def::SelfTy(..) | Def::Err => return false,
3157f602 1173 def => def.def_id(),
85aaf69f 1174 };
b039eaaf 1175
85aaf69f
SL
1176 // A path can only be private if:
1177 // it's in this crate...
0731742a 1178 if let Some(node_id) = self.tcx.hir().as_local_node_id(did) {
b039eaaf 1179 // .. and it corresponds to a private type in the AST (this returns
0731742a
XL
1180 // `None` for type parameters).
1181 match self.tcx.hir().find(node_id) {
b7449926 1182 Some(Node::Item(ref item)) => !item.vis.node.is_pub(),
b039eaaf
SL
1183 Some(_) | None => false,
1184 }
1185 } else {
85aaf69f
SL
1186 return false
1187 }
85aaf69f
SL
1188 }
1189
1190 fn trait_is_public(&self, trait_id: ast::NodeId) -> bool {
1191 // FIXME: this would preferably be using `exported_items`, but all
0731742a 1192 // traits are exported currently (see `EmbargoVisitor.exported_trait`).
92a42be0 1193 self.access_levels.is_public(trait_id)
85aaf69f
SL
1194 }
1195
8faf50e0
XL
1196 fn check_generic_bound(&mut self, bound: &hir::GenericBound) {
1197 if let hir::GenericBound::Trait(ref trait_ref, _) = *bound {
476ff2be 1198 if self.path_is_private_type(&trait_ref.trait_ref.path) {
9cc50fc6 1199 self.old_error_set.insert(trait_ref.trait_ref.ref_id);
85aaf69f
SL
1200 }
1201 }
1202 }
c34b1796 1203
54a0048b 1204 fn item_is_public(&self, id: &ast::NodeId, vis: &hir::Visibility) -> bool {
8faf50e0 1205 self.access_levels.is_reachable(*id) || vis.node.is_pub()
c34b1796 1206 }
85aaf69f
SL
1207}
1208
9cc50fc6 1209impl<'a, 'b, 'tcx, 'v> Visitor<'v> for ObsoleteCheckTypeForPrivatenessVisitor<'a, 'b, 'tcx> {
476ff2be
SL
1210 fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> {
1211 NestedVisitorMap::None
1212 }
1213
e9174d1e 1214 fn visit_ty(&mut self, ty: &hir::Ty) {
8faf50e0 1215 if let hir::TyKind::Path(hir::QPath::Resolved(_, ref path)) = ty.node {
476ff2be 1216 if self.inner.path_is_private_type(path) {
85aaf69f 1217 self.contains_private = true;
0731742a 1218 // Found what we're looking for, so let's stop working.
85aaf69f 1219 return
476ff2be
SL
1220 }
1221 }
8faf50e0 1222 if let hir::TyKind::Path(_) = ty.node {
476ff2be 1223 if self.at_outer_type {
85aaf69f
SL
1224 self.outer_type_is_public_path = true;
1225 }
1226 }
1227 self.at_outer_type = false;
92a42be0 1228 intravisit::walk_ty(self, ty)
85aaf69f
SL
1229 }
1230
0731742a 1231 // Don't want to recurse into `[, .. expr]`.
e9174d1e 1232 fn visit_expr(&mut self, _: &hir::Expr) {}
85aaf69f
SL
1233}
1234
476ff2be 1235impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
92a42be0
SL
1236 /// We want to visit items in the context of their containing
1237 /// module and so forth, so supply a crate for doing a deep walk.
476ff2be 1238 fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
0731742a 1239 NestedVisitorMap::All(&self.tcx.hir())
92a42be0
SL
1240 }
1241
476ff2be 1242 fn visit_item(&mut self, item: &'tcx hir::Item) {
85aaf69f 1243 match item.node {
0731742a 1244 // Contents of a private mod can be re-exported, so we need
85aaf69f 1245 // to check internals.
8faf50e0 1246 hir::ItemKind::Mod(_) => {}
85aaf69f
SL
1247
1248 // An `extern {}` doesn't introduce a new privacy
1249 // namespace (the contents have their own privacies).
8faf50e0 1250 hir::ItemKind::ForeignMod(_) => {}
85aaf69f 1251
8faf50e0 1252 hir::ItemKind::Trait(.., ref bounds, _) => {
85aaf69f
SL
1253 if !self.trait_is_public(item.id) {
1254 return
1255 }
1256
62682a34 1257 for bound in bounds.iter() {
8faf50e0 1258 self.check_generic_bound(bound)
85aaf69f
SL
1259 }
1260 }
1261
0731742a 1262 // Impls need some special handling to try to offer useful
85aaf69f 1263 // error messages without (too many) false positives
0731742a 1264 // (i.e., we could just return here to not check them at
85aaf69f 1265 // all, or some worse estimation of whether an impl is
c34b1796 1266 // publicly visible).
8faf50e0 1267 hir::ItemKind::Impl(.., ref g, ref trait_ref, ref self_, ref impl_item_refs) => {
85aaf69f
SL
1268 // `impl [... for] Private` is never visible.
1269 let self_contains_private;
0731742a
XL
1270 // `impl [... for] Public<...>`, but not `impl [... for]
1271 // Vec<Public>` or `(Public,)`, etc.
85aaf69f
SL
1272 let self_is_public_path;
1273
0731742a 1274 // Check the properties of the `Self` type:
85aaf69f 1275 {
9cc50fc6 1276 let mut visitor = ObsoleteCheckTypeForPrivatenessVisitor {
85aaf69f
SL
1277 inner: self,
1278 contains_private: false,
1279 at_outer_type: true,
1280 outer_type_is_public_path: false,
1281 };
7453a54e 1282 visitor.visit_ty(&self_);
85aaf69f
SL
1283 self_contains_private = visitor.contains_private;
1284 self_is_public_path = visitor.outer_type_is_public_path;
1285 }
1286
0731742a 1287 // Miscellaneous info about the impl:
85aaf69f
SL
1288
1289 // `true` iff this is `impl Private for ...`.
1290 let not_private_trait =
1291 trait_ref.as_ref().map_or(true, // no trait counts as public trait
1292 |tr| {
476ff2be 1293 let did = tr.path.def.def_id();
85aaf69f 1294
0731742a 1295 if let Some(node_id) = self.tcx.hir().as_local_node_id(did) {
b039eaaf
SL
1296 self.trait_is_public(node_id)
1297 } else {
1298 true // external traits must be public
1299 }
85aaf69f
SL
1300 });
1301
1302 // `true` iff this is a trait impl or at least one method is public.
1303 //
1304 // `impl Public { $( fn ...() {} )* }` is not visible.
1305 //
1306 // This is required over just using the methods' privacy
1307 // directly because we might have `impl<T: Foo<Private>> ...`,
1308 // and we shouldn't warn about the generics if all the methods
1309 // are private (because `T` won't be visible externally).
1310 let trait_or_some_public_method =
1311 trait_ref.is_some() ||
476ff2be
SL
1312 impl_item_refs.iter()
1313 .any(|impl_item_ref| {
0731742a 1314 let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
476ff2be
SL
1315 match impl_item.node {
1316 hir::ImplItemKind::Const(..) |
1317 hir::ImplItemKind::Method(..) => {
1318 self.access_levels.is_reachable(impl_item.id)
1319 }
8faf50e0 1320 hir::ImplItemKind::Existential(..) |
476ff2be
SL
1321 hir::ImplItemKind::Type(_) => false,
1322 }
1323 });
85aaf69f
SL
1324
1325 if !self_contains_private &&
1326 not_private_trait &&
1327 trait_or_some_public_method {
1328
92a42be0 1329 intravisit::walk_generics(self, g);
85aaf69f
SL
1330
1331 match *trait_ref {
1332 None => {
476ff2be 1333 for impl_item_ref in impl_item_refs {
c34b1796
AL
1334 // This is where we choose whether to walk down
1335 // further into the impl to check its items. We
1336 // should only walk into public items so that we
1337 // don't erroneously report errors for private
1338 // types in private items.
0731742a 1339 let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
c34b1796 1340 match impl_item.node {
92a42be0
SL
1341 hir::ImplItemKind::Const(..) |
1342 hir::ImplItemKind::Method(..)
54a0048b 1343 if self.item_is_public(&impl_item.id, &impl_item.vis) =>
c34b1796 1344 {
92a42be0 1345 intravisit::walk_impl_item(self, impl_item)
c34b1796 1346 }
92a42be0
SL
1347 hir::ImplItemKind::Type(..) => {
1348 intravisit::walk_impl_item(self, impl_item)
85aaf69f 1349 }
c34b1796 1350 _ => {}
85aaf69f
SL
1351 }
1352 }
1353 }
1354 Some(ref tr) => {
c34b1796 1355 // Any private types in a trait impl fall into three
85aaf69f
SL
1356 // categories.
1357 // 1. mentioned in the trait definition
1358 // 2. mentioned in the type params/generics
c34b1796 1359 // 3. mentioned in the associated types of the impl
85aaf69f
SL
1360 //
1361 // Those in 1. can only occur if the trait is in
1362 // this crate and will've been warned about on the
1363 // trait definition (there's no need to warn twice
1364 // so we don't check the methods).
1365 //
1366 // Those in 2. are warned via walk_generics and this
1367 // call here.
92a42be0 1368 intravisit::walk_path(self, &tr.path);
c34b1796
AL
1369
1370 // Those in 3. are warned with this call.
476ff2be 1371 for impl_item_ref in impl_item_refs {
0731742a 1372 let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
92a42be0 1373 if let hir::ImplItemKind::Type(ref ty) = impl_item.node {
d9579d0f 1374 self.visit_ty(ty);
c34b1796
AL
1375 }
1376 }
85aaf69f
SL
1377 }
1378 }
1379 } else if trait_ref.is_none() && self_is_public_path {
0731742a 1380 // `impl Public<Private> { ... }`. Any public static
85aaf69f
SL
1381 // methods will be visible as `Public::foo`.
1382 let mut found_pub_static = false;
476ff2be 1383 for impl_item_ref in impl_item_refs {
32a655c1 1384 if self.item_is_public(&impl_item_ref.id.node_id, &impl_item_ref.vis) {
0731742a 1385 let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
32a655c1 1386 match impl_item_ref.kind {
9fa01778 1387 AssociatedItemKind::Const => {
d9579d0f 1388 found_pub_static = true;
92a42be0 1389 intravisit::walk_impl_item(self, impl_item);
d9579d0f 1390 }
9fa01778 1391 AssociatedItemKind::Method { has_self: false } => {
85aaf69f 1392 found_pub_static = true;
92a42be0 1393 intravisit::walk_impl_item(self, impl_item);
85aaf69f 1394 }
32a655c1 1395 _ => {}
85aaf69f 1396 }
85aaf69f
SL
1397 }
1398 }
1399 if found_pub_static {
92a42be0 1400 intravisit::walk_generics(self, g)
85aaf69f
SL
1401 }
1402 }
1403 return
1404 }
1405
1406 // `type ... = ...;` can contain private types, because
1407 // we're introducing a new name.
8faf50e0 1408 hir::ItemKind::Ty(..) => return,
85aaf69f 1409
0731742a 1410 // Not at all public, so we don't care.
54a0048b 1411 _ if !self.item_is_public(&item.id, &item.vis) => {
c34b1796
AL
1412 return;
1413 }
85aaf69f
SL
1414
1415 _ => {}
1416 }
1417
c34b1796 1418 // We've carefully constructed it so that if we're here, then
85aaf69f 1419 // any `visit_ty`'s will be called on things that are in
0731742a 1420 // public signatures, i.e., things that we're interested in for
85aaf69f 1421 // this visitor.
92a42be0 1422 intravisit::walk_item(self, item);
85aaf69f
SL
1423 }
1424
476ff2be 1425 fn visit_generics(&mut self, generics: &'tcx hir::Generics) {
b7449926
XL
1426 for param in &generics.params {
1427 for bound in &param.bounds {
1428 self.check_generic_bound(bound);
85aaf69f 1429 }
b7449926 1430 }
85aaf69f
SL
1431 for predicate in &generics.where_clause.predicates {
1432 match predicate {
0731742a 1433 hir::WherePredicate::BoundPredicate(bound_pred) => {
62682a34 1434 for bound in bound_pred.bounds.iter() {
8faf50e0 1435 self.check_generic_bound(bound)
85aaf69f
SL
1436 }
1437 }
0731742a
XL
1438 hir::WherePredicate::RegionPredicate(_) => {}
1439 hir::WherePredicate::EqPredicate(eq_pred) => {
32a655c1 1440 self.visit_ty(&eq_pred.rhs_ty);
85aaf69f
SL
1441 }
1442 }
1443 }
1444 }
1445
476ff2be 1446 fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem) {
92a42be0
SL
1447 if self.access_levels.is_reachable(item.id) {
1448 intravisit::walk_foreign_item(self, item)
85aaf69f
SL
1449 }
1450 }
1451
476ff2be 1452 fn visit_ty(&mut self, t: &'tcx hir::Ty) {
8faf50e0 1453 if let hir::TyKind::Path(hir::QPath::Resolved(_, ref path)) = t.node {
476ff2be 1454 if self.path_is_private_type(path) {
9cc50fc6 1455 self.old_error_set.insert(t.id);
85aaf69f
SL
1456 }
1457 }
92a42be0 1458 intravisit::walk_ty(self, t)
85aaf69f
SL
1459 }
1460
476ff2be
SL
1461 fn visit_variant(&mut self,
1462 v: &'tcx hir::Variant,
1463 g: &'tcx hir::Generics,
9fa01778 1464 item_id: hir::HirId) {
92a42be0 1465 if self.access_levels.is_reachable(v.node.data.id()) {
85aaf69f 1466 self.in_variant = true;
92a42be0 1467 intravisit::walk_variant(self, v, g, item_id);
85aaf69f
SL
1468 self.in_variant = false;
1469 }
1470 }
1471
476ff2be 1472 fn visit_struct_field(&mut self, s: &'tcx hir::StructField) {
8faf50e0 1473 if s.vis.node.is_pub() || self.in_variant {
92a42be0 1474 intravisit::walk_struct_field(self, s);
85aaf69f
SL
1475 }
1476 }
1477
0731742a 1478 // We don't need to introspect into these at all: an
85aaf69f
SL
1479 // expression/block context can't possibly contain exported things.
1480 // (Making them no-ops stops us from traversing the whole AST without
1481 // having to be super careful about our `walk_...` calls above.)
476ff2be
SL
1482 fn visit_block(&mut self, _: &'tcx hir::Block) {}
1483 fn visit_expr(&mut self, _: &'tcx hir::Expr) {}
85aaf69f
SL
1484}
1485
9cc50fc6
SL
1486///////////////////////////////////////////////////////////////////////////////
1487/// SearchInterfaceForPrivateItemsVisitor traverses an item's interface and
1488/// finds any private components in it.
1489/// PrivateItemsInPublicInterfacesVisitor ensures there are no private types
1490/// and traits in public interfaces.
1491///////////////////////////////////////////////////////////////////////////////
1492
1493struct SearchInterfaceForPrivateItemsVisitor<'a, 'tcx: 'a> {
a7813a04 1494 tcx: TyCtxt<'a, 'tcx, 'tcx>,
9fa01778 1495 item_id: ast::NodeId,
476ff2be
SL
1496 item_def_id: DefId,
1497 span: Span,
0731742a 1498 /// The visitor checks that each component type is at least this visible.
54a0048b 1499 required_visibility: ty::Visibility,
cc61c64b 1500 has_pub_restricted: bool,
476ff2be 1501 has_old_errors: bool,
ff7c6d11 1502 in_assoc_ty: bool,
9fa01778 1503 private_crates: FxHashSet<CrateNum>
9cc50fc6
SL
1504}
1505
1506impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
476ff2be 1507 fn generics(&mut self) -> &mut Self {
94b46f34
XL
1508 for param in &self.tcx.generics_of(self.item_def_id).params {
1509 match param.kind {
1510 GenericParamDefKind::Type { has_default, .. } => {
1511 if has_default {
0731742a 1512 self.visit(self.tcx.type_of(param.def_id));
94b46f34
XL
1513 }
1514 }
1515 GenericParamDefKind::Lifetime => {}
8bb4bdeb
XL
1516 }
1517 }
476ff2be 1518 self
54a0048b 1519 }
54a0048b 1520
476ff2be 1521 fn predicates(&mut self) -> &mut Self {
0731742a 1522 // N.B., we use `explicit_predicates_of` and not `predicates_of`
0bf4aa26
XL
1523 // because we don't want to report privacy errors due to where
1524 // clauses that the compiler inferred. We only want to
1525 // consider the ones that the user wrote. This is important
1526 // for the inferred outlives rules; see
1527 // `src/test/ui/rfc-2093-infer-outlives/privacy.rs`.
0731742a 1528 self.visit_predicates(self.tcx.explicit_predicates_of(self.item_def_id));
476ff2be
SL
1529 self
1530 }
1531
7cac9316 1532 fn ty(&mut self) -> &mut Self {
0731742a 1533 self.visit(self.tcx.type_of(self.item_def_id));
476ff2be
SL
1534 self
1535 }
1536
0731742a 1537 fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {
9fa01778
XL
1538 if self.leaks_private_dep(def_id) {
1539 self.tcx.lint_node(lint::builtin::EXPORTED_PRIVATE_DEPENDENCIES,
1540 self.item_id,
1541 self.span,
1542 &format!("{} `{}` from private dependency '{}' in public \
1543 interface", kind, descr,
1544 self.tcx.crate_name(def_id.krate)));
1545
1546 }
1547
0731742a
XL
1548 let node_id = match self.tcx.hir().as_local_node_id(def_id) {
1549 Some(node_id) => node_id,
1550 None => return false,
1551 };
041b39d2 1552
0731742a
XL
1553 let (vis, vis_span, vis_descr) = def_id_visibility(self.tcx, def_id);
1554 if !vis.is_at_least(self.required_visibility, self.tcx) {
1555 let msg = format!("{} {} `{}` in public interface", vis_descr, kind, descr);
1556 if self.has_pub_restricted || self.has_old_errors || self.in_assoc_ty {
1557 let mut err = if kind == "trait" {
1558 struct_span_err!(self.tcx.sess, self.span, E0445, "{}", msg)
041b39d2 1559 } else {
0731742a
XL
1560 struct_span_err!(self.tcx.sess, self.span, E0446, "{}", msg)
1561 };
1562 err.span_label(self.span, format!("can't leak {} {}", vis_descr, kind));
1563 err.span_label(vis_span, format!("`{}` declared as {}", descr, vis_descr));
1564 err.emit();
1565 } else {
1566 let err_code = if kind == "trait" { "E0445" } else { "E0446" };
1567 self.tcx.lint_node(lint::builtin::PRIVATE_IN_PUBLIC, node_id, self.span,
1568 &format!("{} (error {})", msg, err_code));
041b39d2 1569 }
9fa01778 1570
041b39d2 1571 }
9fa01778 1572
0731742a 1573 false
041b39d2 1574 }
9fa01778
XL
1575
1576 /// An item is 'leaked' from a private dependency if all
1577 /// of the following are true:
1578 /// 1. It's contained within a public type
1579 /// 2. It comes from a private crate
1580 fn leaks_private_dep(&self, item_id: DefId) -> bool {
1581 let ret = self.required_visibility == ty::Visibility::Public &&
1582 self.private_crates.contains(&item_id.krate);
1583
1584 log::debug!("leaks_private_dep(item_id={:?})={}", item_id, ret);
1585 return ret;
1586 }
9cc50fc6
SL
1587}
1588
0731742a
XL
1589impl<'a, 'tcx> DefIdVisitor<'a, 'tcx> for SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
1590 fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { self.tcx }
1591 fn visit_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {
1592 self.check_def_id(def_id, kind, descr)
9cc50fc6 1593 }
9cc50fc6
SL
1594}
1595
1596struct PrivateItemsInPublicInterfacesVisitor<'a, 'tcx: 'a> {
a7813a04 1597 tcx: TyCtxt<'a, 'tcx, 'tcx>,
cc61c64b 1598 has_pub_restricted: bool,
9cc50fc6 1599 old_error_set: &'a NodeSet,
9fa01778 1600 private_crates: FxHashSet<CrateNum>
9cc50fc6
SL
1601}
1602
1603impl<'a, 'tcx> PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
476ff2be
SL
1604 fn check(&self, item_id: ast::NodeId, required_visibility: ty::Visibility)
1605 -> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
1606 let mut has_old_errors = false;
1607
1608 // Slow path taken only if there any errors in the crate.
1609 for &id in self.old_error_set {
1610 // Walk up the nodes until we find `item_id` (or we hit a root).
1611 let mut id = id;
1612 loop {
1613 if id == item_id {
1614 has_old_errors = true;
1615 break;
1616 }
0731742a 1617 let parent = self.tcx.hir().get_parent_node(id);
476ff2be
SL
1618 if parent == id {
1619 break;
1620 }
1621 id = parent;
1622 }
1623
1624 if has_old_errors {
1625 break;
1626 }
1627 }
9cc50fc6 1628
476ff2be
SL
1629 SearchInterfaceForPrivateItemsVisitor {
1630 tcx: self.tcx,
9fa01778 1631 item_id,
0731742a
XL
1632 item_def_id: self.tcx.hir().local_def_id(item_id),
1633 span: self.tcx.hir().span(item_id),
3b2f2976 1634 required_visibility,
cc61c64b 1635 has_pub_restricted: self.has_pub_restricted,
3b2f2976 1636 has_old_errors,
ff7c6d11 1637 in_assoc_ty: false,
9fa01778
XL
1638 private_crates: self.private_crates.clone()
1639 }
1640 }
1641
1642 fn check_trait_or_impl_item(&self, node_id: ast::NodeId, assoc_item_kind: AssociatedItemKind,
1643 defaultness: hir::Defaultness, vis: ty::Visibility) {
1644 let mut check = self.check(node_id, vis);
1645
1646 let (check_ty, is_assoc_ty) = match assoc_item_kind {
1647 AssociatedItemKind::Const | AssociatedItemKind::Method { .. } => (true, false),
1648 AssociatedItemKind::Type => (defaultness.has_value(), true),
1649 // `ty()` for existential types is the underlying type,
1650 // it's not a part of interface, so we skip it.
1651 AssociatedItemKind::Existential => (false, true),
1652 };
1653 check.in_assoc_ty = is_assoc_ty;
1654 check.generics().predicates();
1655 if check_ty {
1656 check.ty();
476ff2be 1657 }
9cc50fc6
SL
1658 }
1659}
1660
476ff2be
SL
1661impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
1662 fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
0731742a 1663 NestedVisitorMap::OnlyBodies(&self.tcx.hir())
476ff2be
SL
1664 }
1665
1666 fn visit_item(&mut self, item: &'tcx hir::Item) {
1667 let tcx = self.tcx;
476ff2be 1668 let item_visibility = ty::Visibility::from_hir(&item.vis, item.id, tcx);
54a0048b 1669
9cc50fc6 1670 match item.node {
0731742a 1671 // Crates are always public.
8faf50e0 1672 hir::ItemKind::ExternCrate(..) => {}
0731742a 1673 // All nested items are checked by `visit_item`.
8faf50e0 1674 hir::ItemKind::Mod(..) => {}
0731742a 1675 // Checked in resolve.
8faf50e0 1676 hir::ItemKind::Use(..) => {}
0731742a 1677 // No subitems.
8faf50e0 1678 hir::ItemKind::GlobalAsm(..) => {}
0731742a
XL
1679 // Subitems of these items have inherited publicity.
1680 hir::ItemKind::Const(..) | hir::ItemKind::Static(..) |
1681 hir::ItemKind::Fn(..) | hir::ItemKind::Ty(..) => {
7cac9316 1682 self.check(item.id, item_visibility).generics().predicates().ty();
0731742a
XL
1683 }
1684 hir::ItemKind::Existential(..) => {
1685 // `ty()` for existential types is the underlying type,
1686 // it's not a part of interface, so we skip it.
1687 self.check(item.id, item_visibility).generics().predicates();
476ff2be 1688 }
8faf50e0 1689 hir::ItemKind::Trait(.., ref trait_item_refs) => {
476ff2be
SL
1690 self.check(item.id, item_visibility).generics().predicates();
1691
32a655c1 1692 for trait_item_ref in trait_item_refs {
9fa01778
XL
1693 self.check_trait_or_impl_item(trait_item_ref.id.node_id, trait_item_ref.kind,
1694 trait_item_ref.defaultness, item_visibility);
476ff2be
SL
1695 }
1696 }
8faf50e0 1697 hir::ItemKind::TraitAlias(..) => {
ff7c6d11
XL
1698 self.check(item.id, item_visibility).generics().predicates();
1699 }
8faf50e0 1700 hir::ItemKind::Enum(ref def, _) => {
476ff2be
SL
1701 self.check(item.id, item_visibility).generics().predicates();
1702
1703 for variant in &def.variants {
1704 for field in variant.node.data.fields() {
7cac9316 1705 self.check(field.id, item_visibility).ty();
476ff2be
SL
1706 }
1707 }
9cc50fc6 1708 }
0731742a 1709 // Subitems of foreign modules have their own publicity.
8faf50e0 1710 hir::ItemKind::ForeignMod(ref foreign_mod) => {
9cc50fc6 1711 for foreign_item in &foreign_mod.items {
476ff2be 1712 let vis = ty::Visibility::from_hir(&foreign_item.vis, item.id, tcx);
7cac9316 1713 self.check(foreign_item.id, vis).generics().predicates().ty();
9cc50fc6
SL
1714 }
1715 }
0731742a 1716 // Subitems of structs and unions have their own publicity.
8faf50e0
XL
1717 hir::ItemKind::Struct(ref struct_def, _) |
1718 hir::ItemKind::Union(ref struct_def, _) => {
476ff2be 1719 self.check(item.id, item_visibility).generics().predicates();
54a0048b
SL
1720
1721 for field in struct_def.fields() {
476ff2be 1722 let field_visibility = ty::Visibility::from_hir(&field.vis, item.id, tcx);
0731742a 1723 self.check(field.id, min(item_visibility, field_visibility, tcx)).ty();
9cc50fc6
SL
1724 }
1725 }
9cc50fc6 1726 // An inherent impl is public when its type is public
0731742a 1727 // Subitems of inherent impls have their own publicity.
9cc50fc6 1728 // A trait impl is public when both its type and its trait are public
0731742a
XL
1729 // Subitems of trait impls have inherited publicity.
1730 hir::ItemKind::Impl(.., ref trait_ref, _, ref impl_item_refs) => {
1731 let impl_vis = ty::Visibility::of_impl(item.id, tcx, &Default::default());
1732 self.check(item.id, impl_vis).generics().predicates();
476ff2be 1733 for impl_item_ref in impl_item_refs {
0731742a
XL
1734 let impl_item = tcx.hir().impl_item(impl_item_ref.id);
1735 let impl_item_vis = if trait_ref.is_none() {
1736 min(ty::Visibility::from_hir(&impl_item.vis, item.id, tcx), impl_vis, tcx)
1737 } else {
1738 impl_vis
1739 };
9fa01778
XL
1740 self.check_trait_or_impl_item(impl_item_ref.id.node_id, impl_item_ref.kind,
1741 impl_item_ref.defaultness, impl_item_vis);
9cc50fc6
SL
1742 }
1743 }
1744 }
1745 }
1746}
1747
9fa01778 1748pub fn provide(providers: &mut Providers<'_>) {
cc61c64b
XL
1749 *providers = Providers {
1750 privacy_access_levels,
9fa01778 1751 check_mod_privacy,
cc61c64b
XL
1752 ..*providers
1753 };
1754}
1755
0531ce1d 1756pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Lrc<AccessLevels> {
abe05a73 1757 tcx.privacy_access_levels(LOCAL_CRATE)
cc61c64b
XL
1758}
1759
9fa01778 1760fn check_mod_privacy<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>, module_def_id: DefId) {
3b2f2976 1761 let empty_tables = ty::TypeckTables::empty(None);
85aaf69f 1762
9fa01778 1763
7cac9316
XL
1764 // Check privacy of names not checked in previous compilation stages.
1765 let mut visitor = NamePrivacyVisitor {
3b2f2976
XL
1766 tcx,
1767 tables: &empty_tables,
9fa01778 1768 current_item: DUMMY_NODE_ID,
3b2f2976 1769 empty_tables: &empty_tables,
85aaf69f 1770 };
9fa01778
XL
1771 let (module, span, node_id) = tcx.hir().get_module(module_def_id);
1772 let hir_id = tcx.hir().node_to_hir_id(node_id);
1773 intravisit::walk_mod(&mut visitor, module, hir_id);
85aaf69f 1774
041b39d2
XL
1775 // Check privacy of explicitly written types and traits as well as
1776 // inferred types of expressions and patterns.
1777 let mut visitor = TypePrivacyVisitor {
3b2f2976
XL
1778 tcx,
1779 tables: &empty_tables,
9fa01778 1780 current_item: module_def_id,
ff7c6d11 1781 in_body: false,
9fa01778 1782 span,
3b2f2976 1783 empty_tables: &empty_tables,
041b39d2 1784 };
9fa01778
XL
1785 intravisit::walk_mod(&mut visitor, module, hir_id);
1786}
1787
1788fn privacy_access_levels<'tcx>(
1789 tcx: TyCtxt<'_, 'tcx, 'tcx>,
1790 krate: CrateNum,
1791) -> Lrc<AccessLevels> {
1792 assert_eq!(krate, LOCAL_CRATE);
1793
1794 let krate = tcx.hir().krate();
1795
1796 for &module in krate.modules.keys() {
1797 tcx.ensure().check_mod_privacy(tcx.hir().local_def_id(module));
1798 }
1799
1800 let private_crates: FxHashSet<CrateNum> = tcx.sess.opts.extern_private.iter()
1801 .flat_map(|c| {
1802 tcx.crates().iter().find(|&&krate| &tcx.crate_name(krate) == c).cloned()
1803 }).collect();
1804
041b39d2 1805
85aaf69f
SL
1806 // Build up a set of all exported items in the AST. This is a set of all
1807 // items which are reachable from external crates based on visibility.
1808 let mut visitor = EmbargoVisitor {
3b2f2976 1809 tcx,
92a42be0
SL
1810 access_levels: Default::default(),
1811 prev_level: Some(AccessLevel::Public),
1812 changed: false,
85aaf69f
SL
1813 };
1814 loop {
92a42be0
SL
1815 intravisit::walk_crate(&mut visitor, krate);
1816 if visitor.changed {
1817 visitor.changed = false;
1818 } else {
85aaf69f
SL
1819 break
1820 }
1821 }
92a42be0 1822 visitor.update(ast::CRATE_NODE_ID, Some(AccessLevel::Public));
85aaf69f 1823
85aaf69f 1824 {
9cc50fc6 1825 let mut visitor = ObsoleteVisiblePrivateTypesVisitor {
3b2f2976 1826 tcx,
9cc50fc6 1827 access_levels: &visitor.access_levels,
85aaf69f 1828 in_variant: false,
a1dfa0c6 1829 old_error_set: Default::default(),
85aaf69f 1830 };
92a42be0 1831 intravisit::walk_crate(&mut visitor, krate);
9cc50fc6 1832
cc61c64b
XL
1833
1834 let has_pub_restricted = {
1835 let mut pub_restricted_visitor = PubRestrictedVisitor {
3b2f2976 1836 tcx,
cc61c64b
XL
1837 has_pub_restricted: false
1838 };
1839 intravisit::walk_crate(&mut pub_restricted_visitor, krate);
1840 pub_restricted_visitor.has_pub_restricted
1841 };
1842
0731742a 1843 // Check for private types and traits in public interfaces.
9cc50fc6 1844 let mut visitor = PrivateItemsInPublicInterfacesVisitor {
3b2f2976
XL
1845 tcx,
1846 has_pub_restricted,
9cc50fc6 1847 old_error_set: &visitor.old_error_set,
9fa01778 1848 private_crates
9cc50fc6 1849 };
476ff2be 1850 krate.visit_all_item_likes(&mut DeepVisitor::new(&mut visitor));
85aaf69f 1851 }
92a42be0 1852
0531ce1d 1853 Lrc::new(visitor.access_levels)
85aaf69f 1854}
92a42be0
SL
1855
1856__build_diagnostic_array! { librustc_privacy, DIAGNOSTICS }