]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/privacy.rs
doc: remove incomplete sentence
[rust.git] / src / librustc / middle / privacy.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 //! A pass that checks to make sure private fields and methods aren't used
12 //! outside their scopes. This pass will also generate a set of exported items
13 //! which are available for use externally when compiled as a library.
14 pub use self::PrivateDep::*;
15 pub use self::ImportUse::*;
16 pub use self::LastPrivate::*;
17 use self::PrivacyResult::*;
18 use self::FieldName::*;
19
20 use std::mem::replace;
21
22 use metadata::csearch;
23 use middle::def;
24 use middle::ty::{mod, Ty};
25 use middle::ty::{MethodCall, MethodMap, MethodOrigin, MethodParam, MethodTypeParam};
26 use middle::ty::{MethodStatic, MethodStaticUnboxedClosure, MethodObject, MethodTraitObject};
27 use util::nodemap::{DefIdSet, NodeMap, NodeSet};
28
29 use syntax::{ast, ast_map};
30 use syntax::ast_util::{is_local, local_def, PostExpansionMethod};
31 use syntax::codemap::Span;
32 use syntax::parse::token;
33 use syntax::visit::{mod, Visitor};
34
35 type Context<'a, 'tcx> = (&'a MethodMap<'tcx>, &'a def::ExportMap);
36
37 /// A set of AST nodes exported by the crate.
38 pub type ExportedItems = NodeSet;
39
40 /// A set containing all exported definitions from external crates.
41 /// The set does not contain any entries from local crates.
42 pub type ExternalExports = DefIdSet;
43
44 /// A set of AST nodes that are fully public in the crate. This map is used for
45 /// documentation purposes (reexporting a private struct inlines the doc,
46 /// reexporting a public struct doesn't inline the doc).
47 pub type PublicItems = NodeSet;
48
49 // FIXME: dox
50 pub type LastPrivateMap = NodeMap<LastPrivate>;
51
52 #[deriving(Copy, Show)]
53 pub enum LastPrivate {
54     LastMod(PrivateDep),
55     // `use` directives (imports) can refer to two separate definitions in the
56     // type and value namespaces. We record here the last private node for each
57     // and whether the import is in fact used for each.
58     // If the Option<PrivateDep> fields are None, it means there is no definition
59     // in that namespace.
60     LastImport{value_priv: Option<PrivateDep>,
61                value_used: ImportUse,
62                type_priv: Option<PrivateDep>,
63                type_used: ImportUse},
64 }
65
66 #[deriving(Copy, Show)]
67 pub enum PrivateDep {
68     AllPublic,
69     DependsOn(ast::DefId),
70 }
71
72 // How an import is used.
73 #[deriving(Copy, PartialEq, Show)]
74 pub enum ImportUse {
75     Unused,       // The import is not used.
76     Used,         // The import is used.
77 }
78
79 impl LastPrivate {
80     pub fn or(self, other: LastPrivate) -> LastPrivate {
81         match (self, other) {
82             (me, LastMod(AllPublic)) => me,
83             (_, other) => other,
84         }
85     }
86 }
87
88 /// Result of a checking operation - None => no errors were found. Some => an
89 /// error and contains the span and message for reporting that error and
90 /// optionally the same for a note about the error.
91 type CheckResult = Option<(Span, String, Option<(Span, String)>)>;
92
93 ////////////////////////////////////////////////////////////////////////////////
94 /// The parent visitor, used to determine what's the parent of what (node-wise)
95 ////////////////////////////////////////////////////////////////////////////////
96
97 struct ParentVisitor {
98     parents: NodeMap<ast::NodeId>,
99     curparent: ast::NodeId,
100 }
101
102 impl<'v> Visitor<'v> for ParentVisitor {
103     fn visit_item(&mut self, item: &ast::Item) {
104         self.parents.insert(item.id, self.curparent);
105
106         let prev = self.curparent;
107         match item.node {
108             ast::ItemMod(..) => { self.curparent = item.id; }
109             // Enum variants are parented to the enum definition itself because
110             // they inherit privacy
111             ast::ItemEnum(ref def, _) => {
112                 for variant in def.variants.iter() {
113                     // The parent is considered the enclosing enum because the
114                     // enum will dictate the privacy visibility of this variant
115                     // instead.
116                     self.parents.insert(variant.node.id, item.id);
117                 }
118             }
119
120             // Trait methods are always considered "public", but if the trait is
121             // private then we need some private item in the chain from the
122             // method to the root. In this case, if the trait is private, then
123             // parent all the methods to the trait to indicate that they're
124             // private.
125             ast::ItemTrait(_, _, _, ref methods) if item.vis != ast::Public => {
126                 for m in methods.iter() {
127                     match *m {
128                         ast::ProvidedMethod(ref m) => {
129                             self.parents.insert(m.id, item.id);
130                         }
131                         ast::RequiredMethod(ref m) => {
132                             self.parents.insert(m.id, item.id);
133                         }
134                         ast::TypeTraitItem(_) => {}
135                     };
136                 }
137             }
138
139             _ => {}
140         }
141         visit::walk_item(self, item);
142         self.curparent = prev;
143     }
144
145     fn visit_foreign_item(&mut self, a: &ast::ForeignItem) {
146         self.parents.insert(a.id, self.curparent);
147         visit::walk_foreign_item(self, a);
148     }
149
150     fn visit_fn(&mut self, a: visit::FnKind<'v>, b: &'v ast::FnDecl,
151                 c: &'v ast::Block, d: Span, id: ast::NodeId) {
152         // We already took care of some trait methods above, otherwise things
153         // like impl methods and pub trait methods are parented to the
154         // containing module, not the containing trait.
155         if !self.parents.contains_key(&id) {
156             self.parents.insert(id, self.curparent);
157         }
158         visit::walk_fn(self, a, b, c, d);
159     }
160
161     fn visit_struct_def(&mut self, s: &ast::StructDef, _: ast::Ident,
162                         _: &'v ast::Generics, n: ast::NodeId) {
163         // Struct constructors are parented to their struct definitions because
164         // they essentially are the struct definitions.
165         match s.ctor_id {
166             Some(id) => { self.parents.insert(id, n); }
167             None => {}
168         }
169
170         // While we have the id of the struct definition, go ahead and parent
171         // all the fields.
172         for field in s.fields.iter() {
173             self.parents.insert(field.node.id, self.curparent);
174         }
175         visit::walk_struct_def(self, s)
176     }
177 }
178
179 ////////////////////////////////////////////////////////////////////////////////
180 /// The embargo visitor, used to determine the exports of the ast
181 ////////////////////////////////////////////////////////////////////////////////
182
183 struct EmbargoVisitor<'a, 'tcx: 'a> {
184     tcx: &'a ty::ctxt<'tcx>,
185     export_map: &'a def::ExportMap,
186
187     // This flag is an indicator of whether the previous item in the
188     // hierarchical chain was exported or not. This is the indicator of whether
189     // children should be exported as well. Note that this can flip from false
190     // to true if a reexported module is entered (or an action similar).
191     prev_exported: bool,
192
193     // This is a list of all exported items in the AST. An exported item is any
194     // function/method/item which is usable by external crates. This essentially
195     // means that the result is "public all the way down", but the "path down"
196     // may jump across private boundaries through reexport statements.
197     exported_items: ExportedItems,
198
199     // This sets contains all the destination nodes which are publicly
200     // re-exported. This is *not* a set of all reexported nodes, only a set of
201     // all nodes which are reexported *and* reachable from external crates. This
202     // means that the destination of the reexport is exported, and hence the
203     // destination must also be exported.
204     reexports: NodeSet,
205
206     // These two fields are closely related to one another in that they are only
207     // used for generation of the 'PublicItems' set, not for privacy checking at
208     // all
209     public_items: PublicItems,
210     prev_public: bool,
211 }
212
213 impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> {
214     // There are checks inside of privacy which depend on knowing whether a
215     // trait should be exported or not. The two current consumers of this are:
216     //
217     //  1. Should default methods of a trait be exported?
218     //  2. Should the methods of an implementation of a trait be exported?
219     //
220     // The answer to both of these questions partly rely on whether the trait
221     // itself is exported or not. If the trait is somehow exported, then the
222     // answers to both questions must be yes. Right now this question involves
223     // more analysis than is currently done in rustc, so we conservatively
224     // answer "yes" so that all traits need to be exported.
225     fn exported_trait(&self, _id: ast::NodeId) -> bool {
226         true
227     }
228 }
229
230 impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
231     fn visit_item(&mut self, item: &ast::Item) {
232         let orig_all_pub = self.prev_public;
233         self.prev_public = orig_all_pub && item.vis == ast::Public;
234         if self.prev_public {
235             self.public_items.insert(item.id);
236         }
237
238         let orig_all_exported = self.prev_exported;
239         match item.node {
240             // impls/extern blocks do not break the "public chain" because they
241             // cannot have visibility qualifiers on them anyway
242             ast::ItemImpl(..) | ast::ItemForeignMod(..) => {}
243
244             // Traits are a little special in that even if they themselves are
245             // not public they may still be exported.
246             ast::ItemTrait(..) => {
247                 self.prev_exported = self.exported_trait(item.id);
248             }
249
250             // Private by default, hence we only retain the "public chain" if
251             // `pub` is explicitly listed.
252             _ => {
253                 self.prev_exported =
254                     (orig_all_exported && item.vis == ast::Public) ||
255                      self.reexports.contains(&item.id);
256             }
257         }
258
259         let public_first = self.prev_exported &&
260                            self.exported_items.insert(item.id);
261
262         match item.node {
263             // Enum variants inherit from their parent, so if the enum is
264             // public all variants are public unless they're explicitly priv
265             ast::ItemEnum(ref def, _) if public_first => {
266                 for variant in def.variants.iter() {
267                     self.exported_items.insert(variant.node.id);
268                 }
269             }
270
271             // Implementations are a little tricky to determine what's exported
272             // out of them. Here's a few cases which are currently defined:
273             //
274             // * Impls for private types do not need to export their methods
275             //   (either public or private methods)
276             //
277             // * Impls for public types only have public methods exported
278             //
279             // * Public trait impls for public types must have all methods
280             //   exported.
281             //
282             // * Private trait impls for public types can be ignored
283             //
284             // * Public trait impls for private types have their methods
285             //   exported. I'm not entirely certain that this is the correct
286             //   thing to do, but I have seen use cases of where this will cause
287             //   undefined symbols at linkage time if this case is not handled.
288             //
289             // * Private trait impls for private types can be completely ignored
290             ast::ItemImpl(_, _, _, ref ty, ref impl_items) => {
291                 let public_ty = match ty.node {
292                     ast::TyPath(_, id) => {
293                         match self.tcx.def_map.borrow()[id].clone() {
294                             def::DefPrimTy(..) => true,
295                             def => {
296                                 let did = def.def_id();
297                                 !is_local(did) ||
298                                  self.exported_items.contains(&did.node)
299                             }
300                         }
301                     }
302                     _ => true,
303                 };
304                 let tr = ty::impl_trait_ref(self.tcx, local_def(item.id));
305                 let public_trait = tr.clone().map_or(false, |tr| {
306                     !is_local(tr.def_id) ||
307                      self.exported_items.contains(&tr.def_id.node)
308                 });
309
310                 if public_ty || public_trait {
311                     for impl_item in impl_items.iter() {
312                         match *impl_item {
313                             ast::MethodImplItem(ref method) => {
314                                 let meth_public =
315                                     match method.pe_explicit_self().node {
316                                         ast::SelfStatic => public_ty,
317                                         _ => true,
318                                     } && method.pe_vis() == ast::Public;
319                                 if meth_public || tr.is_some() {
320                                     self.exported_items.insert(method.id);
321                                 }
322                             }
323                             ast::TypeImplItem(_) => {}
324                         }
325                     }
326                 }
327             }
328
329             // Default methods on traits are all public so long as the trait
330             // is public
331             ast::ItemTrait(_, _, _, ref methods) if public_first => {
332                 for method in methods.iter() {
333                     match *method {
334                         ast::ProvidedMethod(ref m) => {
335                             debug!("provided {}", m.id);
336                             self.exported_items.insert(m.id);
337                         }
338                         ast::RequiredMethod(ref m) => {
339                             debug!("required {}", m.id);
340                             self.exported_items.insert(m.id);
341                         }
342                         ast::TypeTraitItem(ref t) => {
343                             debug!("typedef {}", t.ty_param.id);
344                             self.exported_items.insert(t.ty_param.id);
345                         }
346                     }
347                 }
348             }
349
350             // Struct constructors are public if the struct is all public.
351             ast::ItemStruct(ref def, _) if public_first => {
352                 match def.ctor_id {
353                     Some(id) => { self.exported_items.insert(id); }
354                     None => {}
355                 }
356             }
357
358             ast::ItemTy(ref ty, _) if public_first => {
359                 if let ast::TyPath(_, id) = ty.node {
360                     match self.tcx.def_map.borrow()[id].clone() {
361                         def::DefPrimTy(..) | def::DefTyParam(..) => {},
362                         def => {
363                             let did = def.def_id();
364                             if is_local(did) {
365                                 self.exported_items.insert(did.node);
366                             }
367                         }
368                     }
369                 }
370             }
371
372             _ => {}
373         }
374
375         visit::walk_item(self, item);
376
377         self.prev_exported = orig_all_exported;
378         self.prev_public = orig_all_pub;
379     }
380
381     fn visit_foreign_item(&mut self, a: &ast::ForeignItem) {
382         if (self.prev_exported && a.vis == ast::Public) || self.reexports.contains(&a.id) {
383             self.exported_items.insert(a.id);
384         }
385     }
386
387     fn visit_mod(&mut self, m: &ast::Mod, _sp: Span, id: ast::NodeId) {
388         // This code is here instead of in visit_item so that the
389         // crate module gets processed as well.
390         if self.prev_exported {
391             assert!(self.export_map.contains_key(&id), "wut {}", id);
392             for export in self.export_map[id].iter() {
393                 if is_local(export.def_id) {
394                     self.reexports.insert(export.def_id.node);
395                 }
396             }
397         }
398         visit::walk_mod(self, m)
399     }
400 }
401
402 ////////////////////////////////////////////////////////////////////////////////
403 /// The privacy visitor, where privacy checks take place (violations reported)
404 ////////////////////////////////////////////////////////////////////////////////
405
406 struct PrivacyVisitor<'a, 'tcx: 'a> {
407     tcx: &'a ty::ctxt<'tcx>,
408     curitem: ast::NodeId,
409     in_foreign: bool,
410     parents: NodeMap<ast::NodeId>,
411     external_exports: ExternalExports,
412     last_private_map: LastPrivateMap,
413 }
414
415 enum PrivacyResult {
416     Allowable,
417     ExternallyDenied,
418     DisallowedBy(ast::NodeId),
419 }
420
421 enum FieldName {
422     UnnamedField(uint), // index
423     // FIXME #6993: change type (and name) from Ident to Name
424     NamedField(ast::Ident),
425 }
426
427 impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
428     // used when debugging
429     fn nodestr(&self, id: ast::NodeId) -> String {
430         self.tcx.map.node_to_string(id).to_string()
431     }
432
433     // Determines whether the given definition is public from the point of view
434     // of the current item.
435     fn def_privacy(&self, did: ast::DefId) -> PrivacyResult {
436         if !is_local(did) {
437             if self.external_exports.contains(&did) {
438                 debug!("privacy - {} was externally exported", did);
439                 return Allowable;
440             }
441             debug!("privacy - is {} a public method", did);
442
443             return match self.tcx.impl_or_trait_items.borrow().get(&did) {
444                 Some(&ty::MethodTraitItem(ref meth)) => {
445                     debug!("privacy - well at least it's a method: {}",
446                            *meth);
447                     match meth.container {
448                         ty::TraitContainer(id) => {
449                             debug!("privacy - recursing on trait {}", id);
450                             self.def_privacy(id)
451                         }
452                         ty::ImplContainer(id) => {
453                             match ty::impl_trait_ref(self.tcx, id) {
454                                 Some(t) => {
455                                     debug!("privacy - impl of trait {}", id);
456                                     self.def_privacy(t.def_id)
457                                 }
458                                 None => {
459                                     debug!("privacy - found a method {}",
460                                             meth.vis);
461                                     if meth.vis == ast::Public {
462                                         Allowable
463                                     } else {
464                                         ExternallyDenied
465                                     }
466                                 }
467                             }
468                         }
469                     }
470                 }
471                 Some(&ty::TypeTraitItem(ref typedef)) => {
472                     match typedef.container {
473                         ty::TraitContainer(id) => {
474                             debug!("privacy - recursing on trait {}", id);
475                             self.def_privacy(id)
476                         }
477                         ty::ImplContainer(id) => {
478                             match ty::impl_trait_ref(self.tcx, id) {
479                                 Some(t) => {
480                                     debug!("privacy - impl of trait {}", id);
481                                     self.def_privacy(t.def_id)
482                                 }
483                                 None => {
484                                     debug!("privacy - found a typedef {}",
485                                             typedef.vis);
486                                     if typedef.vis == ast::Public {
487                                         Allowable
488                                     } else {
489                                         ExternallyDenied
490                                     }
491                                 }
492                             }
493                         }
494                     }
495                 }
496                 None => {
497                     debug!("privacy - nope, not even a method");
498                     ExternallyDenied
499                 }
500             };
501         }
502
503         debug!("privacy - local {} not public all the way down",
504                self.tcx.map.node_to_string(did.node));
505         // return quickly for things in the same module
506         if self.parents.get(&did.node) == self.parents.get(&self.curitem) {
507             debug!("privacy - same parent, we're done here");
508             return Allowable;
509         }
510
511         // We now know that there is at least one private member between the
512         // destination and the root.
513         let mut closest_private_id = did.node;
514         loop {
515             debug!("privacy - examining {}", self.nodestr(closest_private_id));
516             let vis = match self.tcx.map.find(closest_private_id) {
517                 // If this item is a method, then we know for sure that it's an
518                 // actual method and not a static method. The reason for this is
519                 // that these cases are only hit in the ExprMethodCall
520                 // expression, and ExprCall will have its path checked later
521                 // (the path of the trait/impl) if it's a static method.
522                 //
523                 // With this information, then we can completely ignore all
524                 // trait methods. The privacy violation would be if the trait
525                 // couldn't get imported, not if the method couldn't be used
526                 // (all trait methods are public).
527                 //
528                 // However, if this is an impl method, then we dictate this
529                 // decision solely based on the privacy of the method
530                 // invocation.
531                 // FIXME(#10573) is this the right behavior? Why not consider
532                 //               where the method was defined?
533                 Some(ast_map::NodeImplItem(ii)) => {
534                     match *ii {
535                         ast::MethodImplItem(ref m) => {
536                             let imp = self.tcx.map
537                                           .get_parent_did(closest_private_id);
538                             match ty::impl_trait_ref(self.tcx, imp) {
539                                 Some(..) => return Allowable,
540                                 _ if m.pe_vis() == ast::Public => {
541                                     return Allowable
542                                 }
543                                 _ => m.pe_vis()
544                             }
545                         }
546                         ast::TypeImplItem(_) => return Allowable,
547                     }
548                 }
549                 Some(ast_map::NodeTraitItem(_)) => {
550                     return Allowable;
551                 }
552
553                 // This is not a method call, extract the visibility as one
554                 // would normally look at it
555                 Some(ast_map::NodeItem(it)) => it.vis,
556                 Some(ast_map::NodeForeignItem(_)) => {
557                     self.tcx.map.get_foreign_vis(closest_private_id)
558                 }
559                 Some(ast_map::NodeVariant(..)) => {
560                     ast::Public // need to move up a level (to the enum)
561                 }
562                 _ => ast::Public,
563             };
564             if vis != ast::Public { break }
565             // if we've reached the root, then everything was allowable and this
566             // access is public.
567             if closest_private_id == ast::CRATE_NODE_ID { return Allowable }
568             closest_private_id = self.parents[closest_private_id];
569
570             // If we reached the top, then we were public all the way down and
571             // we can allow this access.
572             if closest_private_id == ast::DUMMY_NODE_ID { return Allowable }
573         }
574         debug!("privacy - closest priv {}", self.nodestr(closest_private_id));
575         if self.private_accessible(closest_private_id) {
576             Allowable
577         } else {
578             DisallowedBy(closest_private_id)
579         }
580     }
581
582     /// For a local private node in the AST, this function will determine
583     /// whether the node is accessible by the current module that iteration is
584     /// inside.
585     fn private_accessible(&self, id: ast::NodeId) -> bool {
586         let parent = self.parents[id];
587         debug!("privacy - accessible parent {}", self.nodestr(parent));
588
589         // After finding `did`'s closest private member, we roll ourselves back
590         // to see if this private member's parent is anywhere in our ancestry.
591         // By the privacy rules, we can access all of our ancestor's private
592         // members, so that's why we test the parent, and not the did itself.
593         let mut cur = self.curitem;
594         loop {
595             debug!("privacy - questioning {}, {}", self.nodestr(cur), cur);
596             match cur {
597                 // If the relevant parent is in our history, then we're allowed
598                 // to look inside any of our ancestor's immediate private items,
599                 // so this access is valid.
600                 x if x == parent => return true,
601
602                 // If we've reached the root, then we couldn't access this item
603                 // in the first place
604                 ast::DUMMY_NODE_ID => return false,
605
606                 // Keep going up
607                 _ => {}
608             }
609
610             cur = self.parents[cur];
611         }
612     }
613
614     fn report_error(&self, result: CheckResult) -> bool {
615         match result {
616             None => true,
617             Some((span, msg, note)) => {
618                 self.tcx.sess.span_err(span, msg[]);
619                 match note {
620                     Some((span, msg)) => {
621                         self.tcx.sess.span_note(span, msg[])
622                     }
623                     None => {},
624                 }
625                 false
626             },
627         }
628     }
629
630     /// Guarantee that a particular definition is public. Returns a CheckResult
631     /// which contains any errors found. These can be reported using `report_error`.
632     /// If the result is `None`, no errors were found.
633     fn ensure_public(&self, span: Span, to_check: ast::DefId,
634                      source_did: Option<ast::DefId>, msg: &str) -> CheckResult {
635         let id = match self.def_privacy(to_check) {
636             ExternallyDenied => {
637                 return Some((span, format!("{} is private", msg), None))
638             }
639             Allowable => return None,
640             DisallowedBy(id) => id,
641         };
642
643         // If we're disallowed by a particular id, then we attempt to give a
644         // nice error message to say why it was disallowed. It was either
645         // because the item itself is private or because its parent is private
646         // and its parent isn't in our ancestry.
647         let (err_span, err_msg) = if id == source_did.unwrap_or(to_check).node {
648             return Some((span, format!("{} is private", msg), None));
649         } else {
650             (span, format!("{} is inaccessible", msg))
651         };
652         let item = match self.tcx.map.find(id) {
653             Some(ast_map::NodeItem(item)) => {
654                 match item.node {
655                     // If an impl disallowed this item, then this is resolve's
656                     // way of saying that a struct/enum's static method was
657                     // invoked, and the struct/enum itself is private. Crawl
658                     // back up the chains to find the relevant struct/enum that
659                     // was private.
660                     ast::ItemImpl(_, _, _, ref ty, _) => {
661                         let id = match ty.node {
662                             ast::TyPath(_, id) => id,
663                             _ => return Some((err_span, err_msg, None)),
664                         };
665                         let def = self.tcx.def_map.borrow()[id].clone();
666                         let did = def.def_id();
667                         assert!(is_local(did));
668                         match self.tcx.map.get(did.node) {
669                             ast_map::NodeItem(item) => item,
670                             _ => self.tcx.sess.span_bug(item.span,
671                                                         "path is not an item")
672                         }
673                     }
674                     _ => item
675                 }
676             }
677             Some(..) | None => return Some((err_span, err_msg, None)),
678         };
679         let desc = match item.node {
680             ast::ItemMod(..) => "module",
681             ast::ItemTrait(..) => "trait",
682             ast::ItemStruct(..) => "struct",
683             ast::ItemEnum(..) => "enum",
684             _ => return Some((err_span, err_msg, None))
685         };
686         let msg = format!("{} `{}` is private", desc,
687                           token::get_ident(item.ident));
688         Some((err_span, err_msg, Some((span, msg))))
689     }
690
691     // Checks that a field is in scope.
692     fn check_field(&mut self,
693                    span: Span,
694                    id: ast::DefId,
695                    name: FieldName) {
696         let fields = ty::lookup_struct_fields(self.tcx, id);
697         let field = match name {
698             NamedField(ident) => {
699                 debug!("privacy - check named field {} in struct {}", ident.name, id);
700                 fields.iter().find(|f| f.name == ident.name).unwrap()
701             }
702             UnnamedField(idx) => &fields[idx]
703         };
704         if field.vis == ast::Public ||
705             (is_local(field.id) && self.private_accessible(field.id.node)) {
706             return
707         }
708
709         let struct_type = ty::lookup_item_type(self.tcx, id).ty;
710         let struct_desc = match struct_type.sty {
711             ty::ty_struct(_, _) =>
712                 format!("struct `{}`", ty::item_path_str(self.tcx, id)),
713             // struct variant fields have inherited visibility
714             ty::ty_enum(..) => return,
715             _ => self.tcx.sess.span_bug(span, "can't find struct for field")
716         };
717         let msg = match name {
718             NamedField(name) => format!("field `{}` of {} is private",
719                                         token::get_ident(name), struct_desc),
720             UnnamedField(idx) => format!("field #{} of {} is private",
721                                          idx + 1, struct_desc),
722         };
723         self.tcx.sess.span_err(span, msg[]);
724     }
725
726     // Given the ID of a method, checks to ensure it's in scope.
727     fn check_static_method(&mut self,
728                            span: Span,
729                            method_id: ast::DefId,
730                            name: ast::Ident) {
731         // If the method is a default method, we need to use the def_id of
732         // the default implementation.
733         let method_id = match ty::impl_or_trait_item(self.tcx, method_id) {
734             ty::MethodTraitItem(method_type) => {
735                 method_type.provided_source.unwrap_or(method_id)
736             }
737             ty::TypeTraitItem(_) => method_id,
738         };
739
740         let string = token::get_ident(name);
741         self.report_error(self.ensure_public(span,
742                                              method_id,
743                                              None,
744                                              format!("method `{}`",
745                                                      string)[]));
746     }
747
748     // Checks that a path is in scope.
749     fn check_path(&mut self, span: Span, path_id: ast::NodeId, path: &ast::Path) {
750         debug!("privacy - path {}", self.nodestr(path_id));
751         let orig_def = self.tcx.def_map.borrow()[path_id].clone();
752         let ck = |&: tyname: &str| {
753             let ck_public = |def: ast::DefId| {
754                 let name = token::get_ident(path.segments.last().unwrap().identifier);
755                 let origdid = orig_def.def_id();
756                 self.ensure_public(span,
757                                    def,
758                                    Some(origdid),
759                                    format!("{} `{}`", tyname, name)[])
760             };
761
762             match self.last_private_map[path_id] {
763                 LastMod(AllPublic) => {},
764                 LastMod(DependsOn(def)) => {
765                     self.report_error(ck_public(def));
766                 },
767                 LastImport { value_priv,
768                              value_used: check_value,
769                              type_priv,
770                              type_used: check_type } => {
771                     // This dance with found_error is because we don't want to report
772                     // a privacy error twice for the same directive.
773                     let found_error = match (type_priv, check_type) {
774                         (Some(DependsOn(def)), Used) => {
775                             !self.report_error(ck_public(def))
776                         },
777                         _ => false,
778                     };
779                     if !found_error {
780                         match (value_priv, check_value) {
781                             (Some(DependsOn(def)), Used) => {
782                                 self.report_error(ck_public(def));
783                             },
784                             _ => {},
785                         }
786                     }
787                     // If an import is not used in either namespace, we still
788                     // want to check that it could be legal. Therefore we check
789                     // in both namespaces and only report an error if both would
790                     // be illegal. We only report one error, even if it is
791                     // illegal to import from both namespaces.
792                     match (value_priv, check_value, type_priv, check_type) {
793                         (Some(p), Unused, None, _) |
794                         (None, _, Some(p), Unused) => {
795                             let p = match p {
796                                 AllPublic => None,
797                                 DependsOn(def) => ck_public(def),
798                             };
799                             if p.is_some() {
800                                 self.report_error(p);
801                             }
802                         },
803                         (Some(v), Unused, Some(t), Unused) => {
804                             let v = match v {
805                                 AllPublic => None,
806                                 DependsOn(def) => ck_public(def),
807                             };
808                             let t = match t {
809                                 AllPublic => None,
810                                 DependsOn(def) => ck_public(def),
811                             };
812                             if let (Some(_), Some(t)) = (v, t) {
813                                 self.report_error(Some(t));
814                             }
815                         },
816                         _ => {},
817                     }
818                 },
819             }
820         };
821         // FIXME(#12334) Imports can refer to definitions in both the type and
822         // value namespaces. The privacy information is aware of this, but the
823         // def map is not. Therefore the names we work out below will not always
824         // be accurate and we can get slightly wonky error messages (but type
825         // checking is always correct).
826         match self.tcx.def_map.borrow()[path_id].clone() {
827             def::DefStaticMethod(..) => ck("static method"),
828             def::DefFn(..) => ck("function"),
829             def::DefStatic(..) => ck("static"),
830             def::DefConst(..) => ck("const"),
831             def::DefVariant(..) => ck("variant"),
832             def::DefTy(_, false) => ck("type"),
833             def::DefTy(_, true) => ck("enum"),
834             def::DefTrait(..) => ck("trait"),
835             def::DefStruct(..) => ck("struct"),
836             def::DefMethod(_, Some(..), _) => ck("trait method"),
837             def::DefMethod(..) => ck("method"),
838             def::DefMod(..) => ck("module"),
839             _ => {}
840         }
841     }
842
843     // Checks that a method is in scope.
844     fn check_method(&mut self, span: Span, origin: &MethodOrigin,
845                     ident: ast::Ident) {
846         match *origin {
847             MethodStatic(method_id) => {
848                 self.check_static_method(span, method_id, ident)
849             }
850             MethodStaticUnboxedClosure(_) => {}
851             // Trait methods are always all public. The only controlling factor
852             // is whether the trait itself is accessible or not.
853             MethodTypeParam(MethodParam { ref trait_ref, .. }) |
854             MethodTraitObject(MethodObject { ref trait_ref, .. }) => {
855                 self.report_error(self.ensure_public(span, trait_ref.def_id,
856                                                      None, "source trait"));
857             }
858         }
859     }
860 }
861
862 impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
863     fn visit_item(&mut self, item: &ast::Item) {
864         let orig_curitem = replace(&mut self.curitem, item.id);
865         visit::walk_item(self, item);
866         self.curitem = orig_curitem;
867     }
868
869     fn visit_expr(&mut self, expr: &ast::Expr) {
870         match expr.node {
871             ast::ExprField(ref base, ident) => {
872                 if let ty::ty_struct(id, _) = ty::expr_ty_adjusted(self.tcx, &**base).sty {
873                     self.check_field(expr.span, id, NamedField(ident.node));
874                 }
875             }
876             ast::ExprTupField(ref base, idx) => {
877                 if let ty::ty_struct(id, _) = ty::expr_ty_adjusted(self.tcx, &**base).sty {
878                     self.check_field(expr.span, id, UnnamedField(idx.node));
879                 }
880             }
881             ast::ExprMethodCall(ident, _, _) => {
882                 let method_call = MethodCall::expr(expr.id);
883                 match self.tcx.method_map.borrow().get(&method_call) {
884                     None => {
885                         self.tcx.sess.span_bug(expr.span,
886                                                 "method call not in \
887                                                 method map");
888                     }
889                     Some(method) => {
890                         debug!("(privacy checking) checking impl method");
891                         self.check_method(expr.span, &method.origin, ident.node);
892                     }
893                 }
894             }
895             ast::ExprStruct(_, ref fields, _) => {
896                 match ty::expr_ty(self.tcx, expr).sty {
897                     ty::ty_struct(id, _) => {
898                         for field in (*fields).iter() {
899                             self.check_field(expr.span, id,
900                                              NamedField(field.ident.node));
901                         }
902                     }
903                     ty::ty_enum(_, _) => {
904                         match self.tcx.def_map.borrow()[expr.id].clone() {
905                             def::DefVariant(_, variant_id, _) => {
906                                 for field in fields.iter() {
907                                     self.check_field(expr.span, variant_id,
908                                                      NamedField(field.ident.node));
909                                 }
910                             }
911                             _ => self.tcx.sess.span_bug(expr.span,
912                                                         "resolve didn't \
913                                                          map enum struct \
914                                                          constructor to a \
915                                                          variant def"),
916                         }
917                     }
918                     _ => self.tcx.sess.span_bug(expr.span, "struct expr \
919                                                             didn't have \
920                                                             struct type?!"),
921                 }
922             }
923             ast::ExprPath(..) => {
924                 let guard = |&: did: ast::DefId| {
925                     let fields = ty::lookup_struct_fields(self.tcx, did);
926                     let any_priv = fields.iter().any(|f| {
927                         f.vis != ast::Public && (
928                             !is_local(f.id) ||
929                             !self.private_accessible(f.id.node))
930                     });
931                     if any_priv {
932                         self.tcx.sess.span_err(expr.span,
933                             "cannot invoke tuple struct constructor \
934                              with private fields");
935                     }
936                 };
937                 match self.tcx.def_map.borrow().get(&expr.id) {
938                     Some(&def::DefStruct(did)) => {
939                         guard(if is_local(did) {
940                             local_def(self.tcx.map.get_parent(did.node))
941                         } else {
942                             // "tuple structs" with zero fields (such as
943                             // `pub struct Foo;`) don't have a ctor_id, hence
944                             // the unwrap_or to the same struct id.
945                             let maybe_did =
946                                 csearch::get_tuple_struct_definition_if_ctor(
947                                     &self.tcx.sess.cstore, did);
948                             maybe_did.unwrap_or(did)
949                         })
950                     }
951                     _ => {}
952                 }
953             }
954             _ => {}
955         }
956
957         visit::walk_expr(self, expr);
958     }
959
960     fn visit_view_item(&mut self, a: &ast::ViewItem) {
961         match a.node {
962             ast::ViewItemExternCrate(..) => {}
963             ast::ViewItemUse(ref vpath) => {
964                 match vpath.node {
965                     ast::ViewPathSimple(..) | ast::ViewPathGlob(..) => {}
966                     ast::ViewPathList(ref prefix, ref list, _) => {
967                         for pid in list.iter() {
968                             match pid.node {
969                                 ast::PathListIdent { id, name } => {
970                                     debug!("privacy - ident item {}", id);
971                                     let seg = ast::PathSegment {
972                                         identifier: name,
973                                         parameters: ast::PathParameters::none(),
974                                     };
975                                     let segs = vec![seg];
976                                     let path = ast::Path {
977                                         global: false,
978                                         span: pid.span,
979                                         segments: segs,
980                                     };
981                                     self.check_path(pid.span, id, &path);
982                                 }
983                                 ast::PathListMod { id } => {
984                                     debug!("privacy - mod item {}", id);
985                                     self.check_path(pid.span, id, prefix);
986                                 }
987                             }
988                         }
989                     }
990                 }
991             }
992         }
993         visit::walk_view_item(self, a);
994     }
995
996     fn visit_pat(&mut self, pattern: &ast::Pat) {
997         // Foreign functions do not have their patterns mapped in the def_map,
998         // and there's nothing really relevant there anyway, so don't bother
999         // checking privacy. If you can name the type then you can pass it to an
1000         // external C function anyway.
1001         if self.in_foreign { return }
1002
1003         match pattern.node {
1004             ast::PatStruct(_, ref fields, _) => {
1005                 match ty::pat_ty(self.tcx, pattern).sty {
1006                     ty::ty_struct(id, _) => {
1007                         for field in fields.iter() {
1008                             self.check_field(pattern.span, id,
1009                                              NamedField(field.node.ident));
1010                         }
1011                     }
1012                     ty::ty_enum(_, _) => {
1013                         match self.tcx.def_map.borrow().get(&pattern.id) {
1014                             Some(&def::DefVariant(_, variant_id, _)) => {
1015                                 for field in fields.iter() {
1016                                     self.check_field(pattern.span, variant_id,
1017                                                      NamedField(field.node.ident));
1018                                 }
1019                             }
1020                             _ => self.tcx.sess.span_bug(pattern.span,
1021                                                         "resolve didn't \
1022                                                          map enum struct \
1023                                                          pattern to a \
1024                                                          variant def"),
1025                         }
1026                     }
1027                     _ => self.tcx.sess.span_bug(pattern.span,
1028                                                 "struct pattern didn't have \
1029                                                  struct type?!"),
1030                 }
1031             }
1032
1033             // Patterns which bind no fields are allowable (the path is check
1034             // elsewhere).
1035             ast::PatEnum(_, Some(ref fields)) => {
1036                 match ty::pat_ty(self.tcx, pattern).sty {
1037                     ty::ty_struct(id, _) => {
1038                         for (i, field) in fields.iter().enumerate() {
1039                             if let ast::PatWild(..) = field.node {
1040                                 continue
1041                             }
1042                             self.check_field(field.span, id, UnnamedField(i));
1043                         }
1044                     }
1045                     ty::ty_enum(..) => {
1046                         // enum fields have no privacy at this time
1047                     }
1048                     _ => {}
1049                 }
1050
1051             }
1052             _ => {}
1053         }
1054
1055         visit::walk_pat(self, pattern);
1056     }
1057
1058     fn visit_foreign_item(&mut self, fi: &ast::ForeignItem) {
1059         self.in_foreign = true;
1060         visit::walk_foreign_item(self, fi);
1061         self.in_foreign = false;
1062     }
1063
1064     fn visit_path(&mut self, path: &ast::Path, id: ast::NodeId) {
1065         self.check_path(path.span, id, path);
1066         visit::walk_path(self, path);
1067     }
1068 }
1069
1070 ////////////////////////////////////////////////////////////////////////////////
1071 /// The privacy sanity check visitor, ensures unnecessary visibility isn't here
1072 ////////////////////////////////////////////////////////////////////////////////
1073
1074 struct SanePrivacyVisitor<'a, 'tcx: 'a> {
1075     tcx: &'a ty::ctxt<'tcx>,
1076     in_fn: bool,
1077 }
1078
1079 impl<'a, 'tcx, 'v> Visitor<'v> for SanePrivacyVisitor<'a, 'tcx> {
1080     fn visit_item(&mut self, item: &ast::Item) {
1081         if self.in_fn {
1082             self.check_all_inherited(item);
1083         } else {
1084             self.check_sane_privacy(item);
1085         }
1086
1087         let in_fn = self.in_fn;
1088         let orig_in_fn = replace(&mut self.in_fn, match item.node {
1089             ast::ItemMod(..) => false, // modules turn privacy back on
1090             _ => in_fn,           // otherwise we inherit
1091         });
1092         visit::walk_item(self, item);
1093         self.in_fn = orig_in_fn;
1094     }
1095
1096     fn visit_fn(&mut self, fk: visit::FnKind<'v>, fd: &'v ast::FnDecl,
1097                 b: &'v ast::Block, s: Span, _: ast::NodeId) {
1098         // This catches both functions and methods
1099         let orig_in_fn = replace(&mut self.in_fn, true);
1100         visit::walk_fn(self, fk, fd, b, s);
1101         self.in_fn = orig_in_fn;
1102     }
1103
1104     fn visit_view_item(&mut self, i: &ast::ViewItem) {
1105         match i.vis {
1106             ast::Inherited => {}
1107             ast::Public => {
1108                 if self.in_fn {
1109                     self.tcx.sess.span_err(i.span, "unnecessary `pub`, imports \
1110                                                     in functions are never \
1111                                                     reachable");
1112                 } else if let ast::ViewItemExternCrate(..) = i.node {
1113                     self.tcx.sess.span_err(i.span, "`pub` visibility \
1114                                                     is not allowed");
1115                 }
1116             }
1117         }
1118         visit::walk_view_item(self, i);
1119     }
1120 }
1121
1122 impl<'a, 'tcx> SanePrivacyVisitor<'a, 'tcx> {
1123     /// Validates all of the visibility qualifiers placed on the item given. This
1124     /// ensures that there are no extraneous qualifiers that don't actually do
1125     /// anything. In theory these qualifiers wouldn't parse, but that may happen
1126     /// later on down the road...
1127     fn check_sane_privacy(&self, item: &ast::Item) {
1128         let tcx = self.tcx;
1129         let check_inherited = |&: sp: Span, vis: ast::Visibility, note: &str| {
1130             if vis != ast::Inherited {
1131                 tcx.sess.span_err(sp, "unnecessary visibility qualifier");
1132                 if note.len() > 0 {
1133                     tcx.sess.span_note(sp, note);
1134                 }
1135             }
1136         };
1137         match item.node {
1138             // implementations of traits don't need visibility qualifiers because
1139             // that's controlled by having the trait in scope.
1140             ast::ItemImpl(_, _, Some(..), _, ref impl_items) => {
1141                 check_inherited(item.span, item.vis,
1142                                 "visibility qualifiers have no effect on trait \
1143                                  impls");
1144                 for impl_item in impl_items.iter() {
1145                     match *impl_item {
1146                         ast::MethodImplItem(ref m) => {
1147                             check_inherited(m.span, m.pe_vis(), "");
1148                         }
1149                         ast::TypeImplItem(_) => {}
1150                     }
1151                 }
1152             }
1153
1154             ast::ItemImpl(..) => {
1155                 check_inherited(item.span, item.vis,
1156                                 "place qualifiers on individual methods instead");
1157             }
1158             ast::ItemForeignMod(..) => {
1159                 check_inherited(item.span, item.vis,
1160                                 "place qualifiers on individual functions \
1161                                  instead");
1162             }
1163
1164             ast::ItemEnum(ref def, _) => {
1165                 for v in def.variants.iter() {
1166                     match v.node.vis {
1167                         ast::Public => {
1168                             if item.vis == ast::Public {
1169                                 tcx.sess.span_err(v.span, "unnecessary `pub` \
1170                                                            visibility");
1171                             }
1172                         }
1173                         ast::Inherited => {}
1174                     }
1175                 }
1176             }
1177
1178             ast::ItemTrait(_, _, _, ref methods) => {
1179                 for m in methods.iter() {
1180                     match *m {
1181                         ast::ProvidedMethod(ref m) => {
1182                             check_inherited(m.span, m.pe_vis(),
1183                                             "unnecessary visibility");
1184                         }
1185                         ast::RequiredMethod(ref m) => {
1186                             check_inherited(m.span, m.vis,
1187                                             "unnecessary visibility");
1188                         }
1189                         ast::TypeTraitItem(_) => {}
1190                     }
1191                 }
1192             }
1193
1194             ast::ItemConst(..) | ast::ItemStatic(..) | ast::ItemStruct(..) |
1195             ast::ItemFn(..) | ast::ItemMod(..) | ast::ItemTy(..) |
1196             ast::ItemMac(..) => {}
1197         }
1198     }
1199
1200     /// When inside of something like a function or a method, visibility has no
1201     /// control over anything so this forbids any mention of any visibility
1202     fn check_all_inherited(&self, item: &ast::Item) {
1203         let tcx = self.tcx;
1204         fn check_inherited(tcx: &ty::ctxt, sp: Span, vis: ast::Visibility) {
1205             if vis != ast::Inherited {
1206                 tcx.sess.span_err(sp, "visibility has no effect inside functions");
1207             }
1208         }
1209         let check_struct = |&: def: &ast::StructDef| {
1210             for f in def.fields.iter() {
1211                match f.node.kind {
1212                     ast::NamedField(_, p) => check_inherited(tcx, f.span, p),
1213                     ast::UnnamedField(..) => {}
1214                 }
1215             }
1216         };
1217         check_inherited(tcx, item.span, item.vis);
1218         match item.node {
1219             ast::ItemImpl(_, _, _, _, ref impl_items) => {
1220                 for impl_item in impl_items.iter() {
1221                     match *impl_item {
1222                         ast::MethodImplItem(ref m) => {
1223                             check_inherited(tcx, m.span, m.pe_vis());
1224                         }
1225                         ast::TypeImplItem(_) => {}
1226                     }
1227                 }
1228             }
1229             ast::ItemForeignMod(ref fm) => {
1230                 for i in fm.items.iter() {
1231                     check_inherited(tcx, i.span, i.vis);
1232                 }
1233             }
1234             ast::ItemEnum(ref def, _) => {
1235                 for v in def.variants.iter() {
1236                     check_inherited(tcx, v.span, v.node.vis);
1237                 }
1238             }
1239
1240             ast::ItemStruct(ref def, _) => check_struct(&**def),
1241
1242             ast::ItemTrait(_, _, _, ref methods) => {
1243                 for m in methods.iter() {
1244                     match *m {
1245                         ast::RequiredMethod(..) => {}
1246                         ast::ProvidedMethod(ref m) => check_inherited(tcx, m.span,
1247                                                                 m.pe_vis()),
1248                         ast::TypeTraitItem(_) => {}
1249                     }
1250                 }
1251             }
1252
1253             ast::ItemStatic(..) | ast::ItemConst(..) |
1254             ast::ItemFn(..) | ast::ItemMod(..) | ast::ItemTy(..) |
1255             ast::ItemMac(..) => {}
1256         }
1257     }
1258 }
1259
1260 struct VisiblePrivateTypesVisitor<'a, 'tcx: 'a> {
1261     tcx: &'a ty::ctxt<'tcx>,
1262     exported_items: &'a ExportedItems,
1263     public_items: &'a PublicItems,
1264     in_variant: bool,
1265 }
1266
1267 struct CheckTypeForPrivatenessVisitor<'a, 'b: 'a, 'tcx: 'b> {
1268     inner: &'a VisiblePrivateTypesVisitor<'b, 'tcx>,
1269     /// whether the type refers to private types.
1270     contains_private: bool,
1271     /// whether we've recurred at all (i.e. if we're pointing at the
1272     /// first type on which visit_ty was called).
1273     at_outer_type: bool,
1274     // whether that first type is a public path.
1275     outer_type_is_public_path: bool,
1276 }
1277
1278 impl<'a, 'tcx> VisiblePrivateTypesVisitor<'a, 'tcx> {
1279     fn path_is_private_type(&self, path_id: ast::NodeId) -> bool {
1280         let did = match self.tcx.def_map.borrow().get(&path_id).cloned() {
1281             // `int` etc. (None doesn't seem to occur.)
1282             None | Some(def::DefPrimTy(..)) => return false,
1283             Some(def) => def.def_id()
1284         };
1285         // A path can only be private if:
1286         // it's in this crate...
1287         if !is_local(did) {
1288             return false
1289         }
1290         // .. and it corresponds to a private type in the AST (this returns
1291         // None for type parameters)
1292         match self.tcx.map.find(did.node) {
1293             Some(ast_map::NodeItem(ref item)) => item.vis != ast::Public,
1294             Some(_) | None => false,
1295         }
1296     }
1297
1298     fn trait_is_public(&self, trait_id: ast::NodeId) -> bool {
1299         // FIXME: this would preferably be using `exported_items`, but all
1300         // traits are exported currently (see `EmbargoVisitor.exported_trait`)
1301         self.public_items.contains(&trait_id)
1302     }
1303
1304     fn check_ty_param_bound(&self,
1305                             ty_param_bound: &ast::TyParamBound) {
1306         if let ast::TraitTyParamBound(ref trait_ref, _) = *ty_param_bound {
1307             if !self.tcx.sess.features.borrow().visible_private_types &&
1308                 self.path_is_private_type(trait_ref.trait_ref.ref_id) {
1309                     let span = trait_ref.trait_ref.path.span;
1310                     self.tcx.sess.span_err(span,
1311                                            "private trait in exported type \
1312                                             parameter bound");
1313             }
1314         }
1315     }
1316 }
1317
1318 impl<'a, 'b, 'tcx, 'v> Visitor<'v> for CheckTypeForPrivatenessVisitor<'a, 'b, 'tcx> {
1319     fn visit_ty(&mut self, ty: &ast::Ty) {
1320         if let ast::TyPath(_, path_id) = ty.node {
1321             if self.inner.path_is_private_type(path_id) {
1322                 self.contains_private = true;
1323                 // found what we're looking for so let's stop
1324                 // working.
1325                 return
1326             } else if self.at_outer_type {
1327                 self.outer_type_is_public_path = true;
1328             }
1329         }
1330         self.at_outer_type = false;
1331         visit::walk_ty(self, ty)
1332     }
1333
1334     // don't want to recurse into [, .. expr]
1335     fn visit_expr(&mut self, _: &ast::Expr) {}
1336 }
1337
1338 impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> {
1339     fn visit_item(&mut self, item: &ast::Item) {
1340         match item.node {
1341             // contents of a private mod can be reexported, so we need
1342             // to check internals.
1343             ast::ItemMod(_) => {}
1344
1345             // An `extern {}` doesn't introduce a new privacy
1346             // namespace (the contents have their own privacies).
1347             ast::ItemForeignMod(_) => {}
1348
1349             ast::ItemTrait(_, _, ref bounds, _) => {
1350                 if !self.trait_is_public(item.id) {
1351                     return
1352                 }
1353
1354                 for bound in bounds.iter() {
1355                     self.check_ty_param_bound(bound)
1356                 }
1357             }
1358
1359             // impls need some special handling to try to offer useful
1360             // error messages without (too many) false positives
1361             // (i.e. we could just return here to not check them at
1362             // all, or some worse estimation of whether an impl is
1363             // publicly visible.
1364             ast::ItemImpl(_, ref g, ref trait_ref, ref self_, ref impl_items) => {
1365                 // `impl [... for] Private` is never visible.
1366                 let self_contains_private;
1367                 // impl [... for] Public<...>, but not `impl [... for]
1368                 // ~[Public]` or `(Public,)` etc.
1369                 let self_is_public_path;
1370
1371                 // check the properties of the Self type:
1372                 {
1373                     let mut visitor = CheckTypeForPrivatenessVisitor {
1374                         inner: self,
1375                         contains_private: false,
1376                         at_outer_type: true,
1377                         outer_type_is_public_path: false,
1378                     };
1379                     visitor.visit_ty(&**self_);
1380                     self_contains_private = visitor.contains_private;
1381                     self_is_public_path = visitor.outer_type_is_public_path;
1382                 }
1383
1384                 // miscellaneous info about the impl
1385
1386                 // `true` iff this is `impl Private for ...`.
1387                 let not_private_trait =
1388                     trait_ref.as_ref().map_or(true, // no trait counts as public trait
1389                                               |tr| {
1390                         let did = ty::trait_ref_to_def_id(self.tcx, tr);
1391
1392                         !is_local(did) || self.trait_is_public(did.node)
1393                     });
1394
1395                 // `true` iff this is a trait impl or at least one method is public.
1396                 //
1397                 // `impl Public { $( fn ...() {} )* }` is not visible.
1398                 //
1399                 // This is required over just using the methods' privacy
1400                 // directly because we might have `impl<T: Foo<Private>> ...`,
1401                 // and we shouldn't warn about the generics if all the methods
1402                 // are private (because `T` won't be visible externally).
1403                 let trait_or_some_public_method =
1404                     trait_ref.is_some() ||
1405                     impl_items.iter()
1406                               .any(|impl_item| {
1407                                   match *impl_item {
1408                                       ast::MethodImplItem(ref m) => {
1409                                           self.exported_items.contains(&m.id)
1410                                       }
1411                                       ast::TypeImplItem(_) => false,
1412                                   }
1413                               });
1414
1415                 if !self_contains_private &&
1416                         not_private_trait &&
1417                         trait_or_some_public_method {
1418
1419                     visit::walk_generics(self, g);
1420
1421                     match *trait_ref {
1422                         None => {
1423                             for impl_item in impl_items.iter() {
1424                                 match *impl_item {
1425                                     ast::MethodImplItem(ref method) => {
1426                                         visit::walk_method_helper(self, &**method)
1427                                     }
1428                                     ast::TypeImplItem(_) => {}
1429                                 }
1430                             }
1431                         }
1432                         Some(ref tr) => {
1433                             // Any private types in a trait impl fall into two
1434                             // categories.
1435                             // 1. mentioned in the trait definition
1436                             // 2. mentioned in the type params/generics
1437                             //
1438                             // Those in 1. can only occur if the trait is in
1439                             // this crate and will've been warned about on the
1440                             // trait definition (there's no need to warn twice
1441                             // so we don't check the methods).
1442                             //
1443                             // Those in 2. are warned via walk_generics and this
1444                             // call here.
1445                             self.visit_trait_ref(tr)
1446                         }
1447                     }
1448                 } else if trait_ref.is_none() && self_is_public_path {
1449                     // impl Public<Private> { ... }. Any public static
1450                     // methods will be visible as `Public::foo`.
1451                     let mut found_pub_static = false;
1452                     for impl_item in impl_items.iter() {
1453                         match *impl_item {
1454                             ast::MethodImplItem(ref method) => {
1455                                 if method.pe_explicit_self().node ==
1456                                         ast::SelfStatic &&
1457                                         self.exported_items
1458                                             .contains(&method.id) {
1459                                     found_pub_static = true;
1460                                     visit::walk_method_helper(self, &**method);
1461                                 }
1462                             }
1463                             ast::TypeImplItem(_) => {}
1464                         }
1465                     }
1466                     if found_pub_static {
1467                         visit::walk_generics(self, g)
1468                     }
1469                 }
1470                 return
1471             }
1472
1473             // `type ... = ...;` can contain private types, because
1474             // we're introducing a new name.
1475             ast::ItemTy(..) => return,
1476
1477             // not at all public, so we don't care
1478             _ if !self.exported_items.contains(&item.id) => return,
1479
1480             _ => {}
1481         }
1482
1483         // we've carefully constructed it so that if we're here, then
1484         // any `visit_ty`'s will be called on things that are in
1485         // public signatures, i.e. things that we're interested in for
1486         // this visitor.
1487         visit::walk_item(self, item);
1488     }
1489
1490     fn visit_generics(&mut self, generics: &ast::Generics) {
1491         for ty_param in generics.ty_params.iter() {
1492             for bound in ty_param.bounds.iter() {
1493                 self.check_ty_param_bound(bound)
1494             }
1495         }
1496         for predicate in generics.where_clause.predicates.iter() {
1497             match predicate {
1498                 &ast::WherePredicate::BoundPredicate(ref bound_pred) => {
1499                     for bound in bound_pred.bounds.iter() {
1500                         self.check_ty_param_bound(bound)
1501                     }
1502                 }
1503                 &ast::WherePredicate::RegionPredicate(_) => {}
1504                 &ast::WherePredicate::EqPredicate(ref eq_pred) => {
1505                     self.visit_ty(&*eq_pred.ty);
1506                 }
1507             }
1508         }
1509     }
1510
1511     fn visit_foreign_item(&mut self, item: &ast::ForeignItem) {
1512         if self.exported_items.contains(&item.id) {
1513             visit::walk_foreign_item(self, item)
1514         }
1515     }
1516
1517     fn visit_fn(&mut self, fk: visit::FnKind<'v>, fd: &'v ast::FnDecl,
1518                 b: &'v ast::Block, s: Span, id: ast::NodeId) {
1519         // needs special handling for methods.
1520         if self.exported_items.contains(&id) {
1521             visit::walk_fn(self, fk, fd, b, s);
1522         }
1523     }
1524
1525     fn visit_ty(&mut self, t: &ast::Ty) {
1526         if let ast::TyPath(ref p, path_id) = t.node {
1527             if !self.tcx.sess.features.borrow().visible_private_types &&
1528                 self.path_is_private_type(path_id) {
1529                 self.tcx.sess.span_err(p.span,
1530                                        "private type in exported type signature");
1531             }
1532         }
1533         visit::walk_ty(self, t)
1534     }
1535
1536     fn visit_variant(&mut self, v: &ast::Variant, g: &ast::Generics) {
1537         if self.exported_items.contains(&v.node.id) {
1538             self.in_variant = true;
1539             visit::walk_variant(self, v, g);
1540             self.in_variant = false;
1541         }
1542     }
1543
1544     fn visit_struct_field(&mut self, s: &ast::StructField) {
1545         match s.node.kind {
1546             ast::NamedField(_, vis) if vis == ast::Public || self.in_variant => {
1547                 visit::walk_struct_field(self, s);
1548             }
1549             _ => {}
1550         }
1551     }
1552
1553
1554     // we don't need to introspect into these at all: an
1555     // expression/block context can't possibly contain exported
1556     // things, and neither do view_items. (Making them no-ops stops us
1557     // from traversing the whole AST without having to be super
1558     // careful about our `walk_...` calls above.)
1559     fn visit_view_item(&mut self, _: &ast::ViewItem) {}
1560     fn visit_block(&mut self, _: &ast::Block) {}
1561     fn visit_expr(&mut self, _: &ast::Expr) {}
1562 }
1563
1564 pub fn check_crate(tcx: &ty::ctxt,
1565                    export_map: &def::ExportMap,
1566                    external_exports: ExternalExports,
1567                    last_private_map: LastPrivateMap)
1568                    -> (ExportedItems, PublicItems) {
1569     let krate = tcx.map.krate();
1570
1571     // Figure out who everyone's parent is
1572     let mut visitor = ParentVisitor {
1573         parents: NodeMap::new(),
1574         curparent: ast::DUMMY_NODE_ID,
1575     };
1576     visit::walk_crate(&mut visitor, krate);
1577
1578     // Use the parent map to check the privacy of everything
1579     let mut visitor = PrivacyVisitor {
1580         curitem: ast::DUMMY_NODE_ID,
1581         in_foreign: false,
1582         tcx: tcx,
1583         parents: visitor.parents,
1584         external_exports: external_exports,
1585         last_private_map: last_private_map,
1586     };
1587     visit::walk_crate(&mut visitor, krate);
1588
1589     // Sanity check to make sure that all privacy usage and controls are
1590     // reasonable.
1591     let mut visitor = SanePrivacyVisitor {
1592         in_fn: false,
1593         tcx: tcx,
1594     };
1595     visit::walk_crate(&mut visitor, krate);
1596
1597     tcx.sess.abort_if_errors();
1598
1599     // Build up a set of all exported items in the AST. This is a set of all
1600     // items which are reachable from external crates based on visibility.
1601     let mut visitor = EmbargoVisitor {
1602         tcx: tcx,
1603         exported_items: NodeSet::new(),
1604         public_items: NodeSet::new(),
1605         reexports: NodeSet::new(),
1606         export_map: export_map,
1607         prev_exported: true,
1608         prev_public: true,
1609     };
1610     loop {
1611         let before = visitor.exported_items.len();
1612         visit::walk_crate(&mut visitor, krate);
1613         if before == visitor.exported_items.len() {
1614             break
1615         }
1616     }
1617
1618     let EmbargoVisitor { exported_items, public_items, .. } = visitor;
1619
1620     {
1621         let mut visitor = VisiblePrivateTypesVisitor {
1622             tcx: tcx,
1623             exported_items: &exported_items,
1624             public_items: &public_items,
1625             in_variant: false,
1626         };
1627         visit::walk_crate(&mut visitor, krate);
1628     }
1629     return (exported_items, public_items);
1630 }