From 18be88f64a9e8ed398843431783230dc5f076799 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 13 Aug 2013 13:21:45 +0200 Subject: [PATCH] Port privacy.rs from oldvisit to trait. --- src/librustc/middle/privacy.rs | 279 +++++++++++++++++---------------- 1 file changed, 146 insertions(+), 133 deletions(-) diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index 54e7c79e97cc..6a566f10f1e6 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -34,54 +34,57 @@ use syntax::ast_util::{variant_visibility_to_privacy, visibility_to_privacy}; use syntax::attr; use syntax::codemap::span; use syntax::parse::token; -use syntax::oldvisit; +use syntax::visit; +use syntax::visit::Visitor; +use syntax::ast::{_mod,expr,item,Block,pat}; -pub fn check_crate<'mm>(tcx: ty::ctxt, - method_map: &'mm method_map, - crate: &ast::Crate) { - let privileged_items = @mut ~[]; +struct PrivacyVisitor { + tcx: ty::ctxt, + privileged_items: @mut ~[NodeId], +} +impl PrivacyVisitor { // Adds an item to its scope. - let add_privileged_item: @fn(@ast::item, &mut uint) = |item, count| { + fn add_privileged_item(&mut self, item: @ast::item, count: &mut uint) { match item.node { item_struct(*) | item_trait(*) | item_enum(*) | item_fn(*) => { - privileged_items.push(item.id); + self.privileged_items.push(item.id); *count += 1; } item_impl(_, _, _, ref methods) => { for method in methods.iter() { - privileged_items.push(method.id); + self.privileged_items.push(method.id); *count += 1; } - privileged_items.push(item.id); + self.privileged_items.push(item.id); *count += 1; } item_foreign_mod(ref foreign_mod) => { for foreign_item in foreign_mod.items.iter() { - privileged_items.push(foreign_item.id); + self.privileged_items.push(foreign_item.id); *count += 1; } } _ => {} } - }; + } // Adds items that are privileged to this scope. - let add_privileged_items: @fn(&[@ast::item]) -> uint = |items| { + fn add_privileged_items(&mut self, items: &[@ast::item]) -> uint { let mut count = 0; for &item in items.iter() { - add_privileged_item(item, &mut count); + self.add_privileged_item(item, &mut count); } count - }; + } // Checks that an enum variant is in scope - let check_variant: @fn(span: span, enum_id: ast::def_id) = - |span, enum_id| { - let variant_info = ty::enum_variants(tcx, enum_id)[0]; + fn check_variant(&mut self, span: span, enum_id: ast::def_id) { + let variant_info = ty::enum_variants(self.tcx, enum_id)[0]; let parental_privacy = if is_local(enum_id) { - let parent_vis = ast_map::node_item_query(tcx.items, enum_id.node, + let parent_vis = ast_map::node_item_query(self.tcx.items, + enum_id.node, |it| { it.vis }, ~"unbound enum parent when checking \ dereference of enum type"); @@ -99,15 +102,14 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, if variant_visibility_to_privacy(variant_info.vis, parental_privacy == Public) == Private { - tcx.sess.span_err(span, + self.tcx.sess.span_err(span, "can only dereference enums \ with a single, public variant"); } - }; + } // Returns true if a crate-local method is private and false otherwise. - let method_is_private: @fn(span: span, method_id: NodeId) -> bool = - |span, method_id| { + fn method_is_private(&mut self, span: span, method_id: NodeId) -> bool { let check = |vis: visibility, container_id: def_id| { let mut is_private = false; if vis == private { @@ -117,12 +119,12 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, } else { // Look up the enclosing impl. if container_id.crate != LOCAL_CRATE { - tcx.sess.span_bug(span, + self.tcx.sess.span_bug(span, "local method isn't in local \ impl?!"); } - match tcx.items.find(&container_id.node) { + match self.tcx.items.find(&container_id.node) { Some(&node_item(item, _)) => { match item.node { item_impl(_, None, _, _) @@ -133,10 +135,10 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, } } Some(_) => { - tcx.sess.span_bug(span, "impl wasn't an item?!"); + self.tcx.sess.span_bug(span, "impl wasn't an item?!"); } None => { - tcx.sess.span_bug(span, "impl wasn't in AST map?!"); + self.tcx.sess.span_bug(span, "impl wasn't in AST map?!"); } } } @@ -144,7 +146,7 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, is_private }; - match tcx.items.find(&method_id) { + match self.tcx.items.find(&method_id) { Some(&node_method(method, impl_id, _)) => { check(method.vis, impl_id) } @@ -155,26 +157,25 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, } } Some(_) => { - tcx.sess.span_bug(span, + self.tcx.sess.span_bug(span, fmt!("method_is_private: method was a %s?!", ast_map::node_id_to_str( - tcx.items, + self.tcx.items, method_id, token::get_ident_interner()))); } None => { - tcx.sess.span_bug(span, "method not found in \ + self.tcx.sess.span_bug(span, "method not found in \ AST map?!"); } } - }; + } // Returns true if the given local item is private and false otherwise. - let local_item_is_private: @fn(span: span, item_id: NodeId) -> bool = - |span, item_id| { + fn local_item_is_private(&mut self, span: span, item_id: NodeId) -> bool { let mut f: &fn(NodeId) -> bool = |_| false; f = |item_id| { - match tcx.items.find(&item_id) { + match self.tcx.items.find(&item_id) { Some(&node_item(item, _)) => item.vis != public, Some(&node_foreign_item(*)) => false, Some(&node_method(method, impl_did, _)) => { @@ -186,104 +187,96 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, } Some(&node_trait_method(_, trait_did, _)) => f(trait_did.node), Some(_) => { - tcx.sess.span_bug(span, + self.tcx.sess.span_bug(span, fmt!("local_item_is_private: item was \ a %s?!", ast_map::node_id_to_str( - tcx.items, + self.tcx.items, item_id, token::get_ident_interner()))); } None => { - tcx.sess.span_bug(span, "item not found in AST map?!"); + self.tcx.sess.span_bug(span, "item not found in AST map?!"); } } }; f(item_id) - }; + } // Checks that a private field is in scope. - let check_field: @fn(span: span, id: ast::def_id, ident: ast::ident) = - |span, id, ident| { - let fields = ty::lookup_struct_fields(tcx, id); + fn check_field(&mut self, span: span, id: ast::def_id, ident: ast::ident) { + let fields = ty::lookup_struct_fields(self.tcx, id); for field in fields.iter() { if field.ident != ident { loop; } if field.vis == private { - tcx.sess.span_err(span, fmt!("field `%s` is private", + self.tcx.sess.span_err(span, fmt!("field `%s` is private", token::ident_to_str(&ident))); } break; } - }; + } // Given the ID of a method, checks to ensure it's in scope. - let check_method_common: @fn(span: span, - method_id: def_id, - name: &ident) = - |span, method_id, name| { + fn check_method_common(&mut self, span: span, method_id: def_id, name: &ident) { // If the method is a default method, we need to use the def_id of // the default implementation. // Having to do this this is really unfortunate. - let method_id = ty::method(tcx, method_id).provided_source + let method_id = ty::method(self.tcx, method_id).provided_source .unwrap_or_default(method_id); if method_id.crate == LOCAL_CRATE { - let is_private = method_is_private(span, method_id.node); - let container_id = ty::method(tcx, method_id).container_id; + let is_private = self.method_is_private(span, method_id.node); + let container_id = ty::method(self.tcx, method_id).container_id; if is_private && (container_id.crate != LOCAL_CRATE || - !privileged_items.iter().any(|x| x == &(container_id.node))) { - tcx.sess.span_err(span, + !self.privileged_items.iter().any(|x| x == &(container_id.node))) { + self.tcx.sess.span_err(span, fmt!("method `%s` is private", token::ident_to_str(name))); } } else { let visibility = - csearch::get_item_visibility(tcx.sess.cstore, method_id); + csearch::get_item_visibility(self.tcx.sess.cstore, method_id); if visibility != public { - tcx.sess.span_err(span, + self.tcx.sess.span_err(span, fmt!("method `%s` is private", token::ident_to_str(name))); } } - }; + } // Checks that a private path is in scope. - let check_path: @fn(span: span, def: def, path: &Path) = - |span, def, path| { + fn check_path(&mut self, span: span, def: def, path: &Path) { debug!("checking path"); match def { def_static_method(method_id, _, _) => { debug!("found static method def, checking it"); - check_method_common(span, method_id, path.idents.last()) + self.check_method_common(span, method_id, path.idents.last()) } def_fn(def_id, _) => { if def_id.crate == LOCAL_CRATE { - if local_item_is_private(span, def_id.node) && - !privileged_items.iter().any(|x| x == &def_id.node) { - tcx.sess.span_err(span, + if self.local_item_is_private(span, def_id.node) && + !self.privileged_items.iter().any(|x| x == &def_id.node) { + self.tcx.sess.span_err(span, fmt!("function `%s` is private", token::ident_to_str(path.idents.last()))); } - } else if csearch::get_item_visibility(tcx.sess.cstore, + } else if csearch::get_item_visibility(self.tcx.sess.cstore, def_id) != public { - tcx.sess.span_err(span, + self.tcx.sess.span_err(span, fmt!("function `%s` is private", token::ident_to_str(path.idents.last()))); } } _ => {} } - }; + } // Checks that a private method is in scope. - let check_method: @fn(span: span, - origin: &method_origin, - ident: ast::ident) = - |span, origin, ident| { + fn check_method(&mut self, span: span, origin: &method_origin, ident: ast::ident) { match *origin { method_static(method_id) => { - check_method_common(span, method_id, &ident) + self.check_method_common(span, method_id, &ident) } method_param(method_param { trait_id: trait_id, @@ -292,19 +285,20 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, }) | method_trait(trait_id, method_num) => { if trait_id.crate == LOCAL_CRATE { - match tcx.items.find(&trait_id.node) { + match self.tcx.items.find(&trait_id.node) { Some(&node_item(item, _)) => { match item.node { item_trait(_, _, ref methods) => { if method_num >= (*methods).len() { - tcx.sess.span_bug(span, "method number out of range?!"); + self.tcx.sess.span_bug(span, + "method number out of range?!"); } match (*methods)[method_num] { provided(method) if method.vis == private && - !privileged_items.iter() + !self.privileged_items.iter() .any(|x| x == &(trait_id.node)) => { - tcx.sess.span_err(span, + self.tcx.sess.span_err(span, fmt!("method `%s` is private", token::ident_to_str(&method .ident))); @@ -316,15 +310,16 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, } } _ => { - tcx.sess.span_bug(span, "trait wasn't actually a trait?!"); + self.tcx.sess.span_bug(span, "trait wasn't actually a trait?!"); } } } Some(_) => { - tcx.sess.span_bug(span, "trait wasn't an item?!"); + self.tcx.sess.span_bug(span, "trait wasn't an item?!"); } None => { - tcx.sess.span_bug(span, "trait item wasn't found in the AST map?!"); + self.tcx.sess.span_bug(span, + "trait item wasn't found in the AST map?!"); } } } else { @@ -332,30 +327,35 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, } } } - }; + } +} - let visitor = oldvisit::mk_vt(@oldvisit::Visitor { - visit_mod: |the_module, span, node_id, (method_map, visitor)| { - let n_added = add_privileged_items(the_module.items); +impl<'self> Visitor<&'self method_map> for PrivacyVisitor { - oldvisit::visit_mod(the_module, - span, - node_id, - (method_map, visitor)); + fn visit_mod<'mm>(&mut self, the_module:&_mod, _:span, _:NodeId, + method_map:&'mm method_map) { + + let n_added = self.add_privileged_items(the_module.items); + + visit::walk_mod(self, the_module, method_map); do n_added.times { - ignore(privileged_items.pop()); + ignore(self.privileged_items.pop()); } - }, - visit_item: |item, (method_map, visitor)| { + } + + fn visit_item<'mm>(&mut self, item:@item, method_map:&'mm method_map) { + // Do not check privacy inside items with the resolve_unexported // attribute. This is used for the test runner. if !attr::contains_name(item.attrs, "!resolve_unexported") { - check_sane_privacy(tcx, item); - oldvisit::visit_item(item, (method_map, visitor)); + check_sane_privacy(self.tcx, item); + visit::walk_item(self, item, method_map); } - }, - visit_block: |block, (method_map, visitor)| { + } + + fn visit_block<'mm>(&mut self, block:&Block, method_map:&'mm method_map) { + // Gather up all the privileged items. let mut n_added = 0; for stmt in block.stmts.iter() { @@ -363,7 +363,7 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, stmt_decl(decl, _) => { match decl.node { decl_item(item) => { - add_privileged_item(item, &mut n_added); + self.add_privileged_item(item, &mut n_added); } _ => {} } @@ -372,15 +372,16 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, } } - oldvisit::visit_block(block, (method_map, visitor)); + visit::walk_block(self, block, method_map); do n_added.times { - ignore(privileged_items.pop()); + ignore(self.privileged_items.pop()); } - }, - visit_expr: |expr, - (method_map, visitor): - (&'mm method_map, oldvisit::vt<&'mm method_map>)| { + + } + + fn visit_expr<'mm>(&mut self, expr:@expr, method_map:&'mm method_map) { + match expr.node { expr_field(base, ident, _) => { // Method calls are now a special syntactic form, @@ -389,35 +390,35 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, // With type_autoderef, make sure we don't // allow pointers to violate privacy - match ty::get(ty::type_autoderef(tcx, ty::expr_ty(tcx, + match ty::get(ty::type_autoderef(self.tcx, ty::expr_ty(self.tcx, base))).sty { ty_struct(id, _) - if id.crate != LOCAL_CRATE || !privileged_items.iter() + if id.crate != LOCAL_CRATE || !self.privileged_items.iter() .any(|x| x == &(id.node)) => { debug!("(privacy checking) checking field access"); - check_field(expr.span, id, ident); + self.check_field(expr.span, id, ident); } _ => {} } } expr_method_call(_, base, ident, _, _, _) => { // Ditto - match ty::get(ty::type_autoderef(tcx, ty::expr_ty(tcx, + match ty::get(ty::type_autoderef(self.tcx, ty::expr_ty(self.tcx, base))).sty { ty_enum(id, _) | ty_struct(id, _) if id.crate != LOCAL_CRATE || - !privileged_items.iter().any(|x| x == &(id.node)) => { + !self.privileged_items.iter().any(|x| x == &(id.node)) => { match method_map.find(&expr.id) { None => { - tcx.sess.span_bug(expr.span, + self.tcx.sess.span_bug(expr.span, "method call not in \ method map"); } Some(ref entry) => { debug!("(privacy checking) checking \ impl method"); - check_method(expr.span, &entry.origin, ident); + self.check_method(expr.span, &entry.origin, ident); } } } @@ -425,35 +426,35 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, } } expr_path(ref path) => { - check_path(expr.span, tcx.def_map.get_copy(&expr.id), path); + self.check_path(expr.span, self.tcx.def_map.get_copy(&expr.id), path); } expr_struct(_, ref fields, _) => { - match ty::get(ty::expr_ty(tcx, expr)).sty { + match ty::get(ty::expr_ty(self.tcx, expr)).sty { ty_struct(id, _) => { if id.crate != LOCAL_CRATE || - !privileged_items.iter().any(|x| x == &(id.node)) { + !self.privileged_items.iter().any(|x| x == &(id.node)) { for field in (*fields).iter() { debug!("(privacy checking) checking \ field in struct literal"); - check_field(expr.span, id, field.ident); + self.check_field(expr.span, id, field.ident); } } } ty_enum(id, _) => { if id.crate != LOCAL_CRATE || - !privileged_items.iter().any(|x| x == &(id.node)) { - match tcx.def_map.get_copy(&expr.id) { + !self.privileged_items.iter().any(|x| x == &(id.node)) { + match self.tcx.def_map.get_copy(&expr.id) { def_variant(_, variant_id) => { for field in (*fields).iter() { debug!("(privacy checking) \ checking field in \ struct variant \ literal"); - check_field(expr.span, variant_id, field.ident); + self.check_field(expr.span, variant_id, field.ident); } } _ => { - tcx.sess.span_bug(expr.span, + self.tcx.sess.span_bug(expr.span, "resolve didn't \ map enum struct \ constructor to a \ @@ -463,7 +464,7 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, } } _ => { - tcx.sess.span_bug(expr.span, "struct expr \ + self.tcx.sess.span_bug(expr.span, "struct expr \ didn't have \ struct type?!"); } @@ -474,11 +475,11 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, // enum type t, then t's first variant is public or // privileged. (We can assume it has only one variant // since typeck already happened.) - match ty::get(ty::expr_ty(tcx, operand)).sty { + match ty::get(ty::expr_ty(self.tcx, operand)).sty { ty_enum(id, _) => { if id.crate != LOCAL_CRATE || - !privileged_items.iter().any(|x| x == &(id.node)) { - check_variant(expr.span, id); + !self.privileged_items.iter().any(|x| x == &(id.node)) { + self.check_variant(expr.span, id); } } _ => { /* No check needed */ } @@ -487,36 +488,39 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, _ => {} } - oldvisit::visit_expr(expr, (method_map, visitor)); - }, - visit_pat: |pattern, (method_map, visitor)| { + visit::walk_expr(self, expr, method_map); + + } + + fn visit_pat<'mm>(&mut self, pattern:@pat, method_map:&'mm method_map) { + match pattern.node { pat_struct(_, ref fields, _) => { - match ty::get(ty::pat_ty(tcx, pattern)).sty { + match ty::get(ty::pat_ty(self.tcx, pattern)).sty { ty_struct(id, _) => { if id.crate != LOCAL_CRATE || - !privileged_items.iter().any(|x| x == &(id.node)) { + !self.privileged_items.iter().any(|x| x == &(id.node)) { for field in fields.iter() { debug!("(privacy checking) checking \ struct pattern"); - check_field(pattern.span, id, field.ident); + self.check_field(pattern.span, id, field.ident); } } } ty_enum(enum_id, _) => { if enum_id.crate != LOCAL_CRATE || - !privileged_items.iter().any(|x| x == &enum_id.node) { - match tcx.def_map.find(&pattern.id) { + !self.privileged_items.iter().any(|x| x == &enum_id.node) { + match self.tcx.def_map.find(&pattern.id) { Some(&def_variant(_, variant_id)) => { for field in fields.iter() { debug!("(privacy checking) \ checking field in \ struct variant pattern"); - check_field(pattern.span, variant_id, field.ident); + self.check_field(pattern.span, variant_id, field.ident); } } _ => { - tcx.sess.span_bug(pattern.span, + self.tcx.sess.span_bug(pattern.span, "resolve didn't \ map enum struct \ pattern to a \ @@ -526,7 +530,7 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, } } _ => { - tcx.sess.span_bug(pattern.span, + self.tcx.sess.span_bug(pattern.span, "struct pattern didn't have \ struct type?!"); } @@ -535,11 +539,20 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, _ => {} } - oldvisit::visit_pat(pattern, (method_map, visitor)); - }, - .. *oldvisit::default_visitor() - }); - oldvisit::visit_crate(crate, (method_map, visitor)); + visit::walk_pat(self, pattern, method_map); + } +} + +pub fn check_crate<'mm>(tcx: ty::ctxt, + method_map: &'mm method_map, + crate: &ast::Crate) { + let privileged_items = @mut ~[]; + + let mut visitor = PrivacyVisitor { + tcx: tcx, + privileged_items: privileged_items, + }; + visit::walk_crate(&mut visitor, crate, method_map); } /// Validates all of the visibility qualifers placed on the item given. This