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