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