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