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