(index<- )        ./librustc/middle/privacy.rs

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


librustc/middle/privacy.rs:53:1-53:1 -struct- definition:
struct ParentVisitor {
    parents: NodeMap<ast::NodeId>,
    curparent: ast::NodeId,
references:- 2
59: impl Visitor<()> for ParentVisitor {
60:     fn visit_item(&mut self, item: &ast::Item, _: ()) {
--
1408:     // Figure out who everyone's parent is
1409:     let mut visitor = ParentVisitor {
1410:         parents: NodeMap::new(),


librustc/middle/privacy.rs:334:1-334:1 -struct- definition:
struct PrivacyVisitor<'a> {
    tcx: &'a ty::ctxt,
    curitem: ast::NodeId,
references:- 3
1415:     // Use the parent map to check the privacy of everything
1416:     let mut visitor = PrivacyVisitor {
1417:         curitem: ast::DUMMY_NODE_ID,


librustc/middle/privacy.rs:134:1-134:1 -struct- definition:
struct EmbargoVisitor<'a> {
    tcx: &'a ty::ctxt,
    exp_map2: &'a resolve::ExportMap2,
references:- 4
1456:     let EmbargoVisitor { exported_items, public_items, .. } = visitor;


librustc/middle/privacy.rs:47:52-47:52 -NK_AS_STR_TODO- definition:
/// optionally the same for a note about the error.
type CheckResult = Option<(Span, ~str, Option<(Span, ~str)>)>;
////////////////////////////////////////////////////////////////////////////////
references:- 2
510:     fn report_error(&self, result: CheckResult) -> bool {
511:         match result {
--
527:     fn ensure_public(&self, span: Span, to_check: ast::DefId,
528:                      source_did: Option<ast::DefId>, msg: &str) -> CheckResult {
529:         let id = match self.def_privacy(to_check) {


librustc/middle/privacy.rs:1105:8-1105:8 -fn- definition:
        fn check_inherited(tcx: &ty::ctxt, sp: Span, vis: ast::Visibility) {
            if vis != ast::Inherited {
                tcx.sess.span_err(sp, "visibility has no effect inside functions");
references:- 6
1131:                 for v in def.variants.iter() {
1132:                     check_inherited(tcx, v.span, v.node.vis);
--
1146:                         ast::Required(..) => {}
1147:                         ast::Provided(ref m) => check_inherited(tcx, m.span,
1148:                                                                 m.vis),


librustc/middle/privacy.rs:1165:1-1165:1 -struct- definition:
struct CheckTypeForPrivatenessVisitor<'a, 'b> {
    inner: &'b VisiblePrivateTypesVisitor<'a>,
    /// whether the type refers to private types.
references:- 2
1250:                 {
1251:                     let mut visitor = CheckTypeForPrivatenessVisitor {
1252:                         inner: self,


librustc/middle/privacy.rs:979:1-979:1 -struct- definition:
struct SanePrivacyVisitor<'a> {
    tcx: &'a ty::ctxt,
    in_fn: bool,
references:- 3
1428:     // reasonable.
1429:     let mut visitor = SanePrivacyVisitor {
1430:         in_fn: false,


librustc/middle/privacy.rs:42:57-42:57 -NK_AS_STR_TODO- definition:
/// reexporting a public struct doesn't inline the doc).
pub type PublicItems = NodeSet;
/// Result of a checking operation - None => no errors were found. Some => an
references:- 4
160:     // all
161:     public_items: PublicItems,
162:     prev_public: bool,
--
1406:                    last_private_map: resolve::LastPrivateMap,
1407:                    krate: &ast::Crate) -> (ExportedItems, PublicItems) {
1408:     // Figure out who everyone's parent is
librustc/driver/driver.rs:
277:     pub exported_items: middle::privacy::ExportedItems,
278:     pub public_items: middle::privacy::PublicItems,
279:     pub ty_cx: ty::ctxt,
librustc/middle/privacy.rs:
1162:     exported_items: &'a ExportedItems,
1163:     public_items: &'a PublicItems,
1164: }


librustc/middle/privacy.rs:37:46-37:46 -NK_AS_STR_TODO- definition:
/// A set of AST nodes exported by the crate.
pub type ExportedItems = NodeSet;
/// A set of AST nodes that are fully public in the crate. This map is used for
references:- 10
1161:     tcx: &'a ty::ctxt,
1162:     exported_items: &'a ExportedItems,
1163:     public_items: &'a PublicItems,
librustc/middle/reachable.rs:
348: pub fn find_reachable(tcx: &ty::ctxt,
349:                       exported_items: &privacy::ExportedItems)
350:                       -> NodeSet {
librustc/middle/dead.rs:
404: pub fn check_crate(tcx: &ty::ctxt,
405:                    exported_items: &privacy::ExportedItems,
406:                    reachable_symbols: &NodeSet,
librustc/driver/driver.rs:
276:     pub exp_map2: middle::resolve::ExportMap2,
277:     pub exported_items: middle::privacy::ExportedItems,
278:     pub public_items: middle::privacy::PublicItems,
librustc/middle/lint.rs:
445:     // Items exported by the crate; used by the missing_doc lint.
446:     exported_items: &'a privacy::ExportedItems,
447:     // The id of the current `ast::StructDef` being walked.
--
1810: pub fn check_crate(tcx: &ty::ctxt,
1811:                    exported_items: &privacy::ExportedItems,
1812:                    krate: &ast::Crate) {
librustc/middle/privacy.rs:
1406:                    last_private_map: resolve::LastPrivateMap,
1407:                    krate: &ast::Crate) -> (ExportedItems, PublicItems) {
1408:     // Figure out who everyone's parent is


librustc/middle/privacy.rs:1159:1-1159:1 -struct- definition:
struct VisiblePrivateTypesVisitor<'a> {
    tcx: &'a ty::ctxt,
    exported_items: &'a ExportedItems,
references:- 4
1458:     {
1459:         let mut visitor = VisiblePrivateTypesVisitor {
1460:             tcx: tcx,