2012-12-03 18:48:01 -06:00
|
|
|
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2013-08-08 13:38:10 -05:00
|
|
|
//! A pass that checks to make sure private fields and methods aren't used
|
|
|
|
//! outside their scopes.
|
2013-05-17 17:28:44 -05:00
|
|
|
|
2013-02-27 15:45:37 -06:00
|
|
|
use metadata::csearch;
|
2012-12-13 15:05:22 -06:00
|
|
|
use middle::ty::{ty_struct, ty_enum};
|
2012-12-23 16:41:37 -06:00
|
|
|
use middle::ty;
|
2013-07-22 19:42:45 -05:00
|
|
|
use middle::typeck::{method_map, method_origin, method_param};
|
2013-08-13 15:22:58 -05:00
|
|
|
use middle::typeck::{method_static, method_object};
|
2012-12-23 16:41:37 -06:00
|
|
|
|
2013-06-28 17:32:26 -05:00
|
|
|
use std::util::ignore;
|
2013-09-01 20:45:37 -05:00
|
|
|
use syntax::ast::{DeclItem, Def, DefFn, DefId, DefStaticMethod};
|
|
|
|
use syntax::ast::{DefVariant, ExprField, ExprMethodCall, ExprPath};
|
|
|
|
use syntax::ast::{ExprStruct, ExprUnary, Ident, inherited, item_enum};
|
2013-03-18 19:20:45 -05:00
|
|
|
use syntax::ast::{item_foreign_mod, item_fn, item_impl, item_struct};
|
2013-09-01 20:45:37 -05:00
|
|
|
use syntax::ast::{item_trait, LOCAL_CRATE, NodeId, PatStruct, Path};
|
|
|
|
use syntax::ast::{private, provided, public, required, StmtDecl, visibility};
|
2012-12-23 16:41:37 -06:00
|
|
|
use syntax::ast;
|
2013-03-18 19:20:45 -05:00
|
|
|
use syntax::ast_map::{node_foreign_item, node_item, node_method};
|
|
|
|
use syntax::ast_map::{node_trait_method};
|
2012-12-23 16:41:37 -06:00
|
|
|
use syntax::ast_map;
|
2013-01-30 19:20:02 -06:00
|
|
|
use syntax::ast_util::{Private, Public, is_local};
|
|
|
|
use syntax::ast_util::{variant_visibility_to_privacy, visibility_to_privacy};
|
2013-03-18 19:20:45 -05:00
|
|
|
use syntax::attr;
|
2013-08-31 11:13:04 -05:00
|
|
|
use syntax::codemap::Span;
|
2013-05-14 19:27:27 -05:00
|
|
|
use syntax::parse::token;
|
2013-08-13 06:21:45 -05:00
|
|
|
use syntax::visit;
|
|
|
|
use syntax::visit::Visitor;
|
2013-09-01 20:45:37 -05:00
|
|
|
use syntax::ast::{_mod,Expr,item,Block,Pat};
|
2012-09-04 16:48:32 -05:00
|
|
|
|
2013-08-13 06:21:45 -05:00
|
|
|
struct PrivacyVisitor {
|
|
|
|
tcx: ty::ctxt,
|
|
|
|
privileged_items: @mut ~[NodeId],
|
|
|
|
}
|
2012-09-04 16:48:32 -05:00
|
|
|
|
2013-08-13 06:21:45 -05:00
|
|
|
impl PrivacyVisitor {
|
2013-03-18 19:20:45 -05:00
|
|
|
// Adds an item to its scope.
|
2013-08-13 06:21:45 -05:00
|
|
|
fn add_privileged_item(&mut self, item: @ast::item, count: &mut uint) {
|
2013-03-18 19:20:45 -05:00
|
|
|
match item.node {
|
|
|
|
item_struct(*) | item_trait(*) | item_enum(*) |
|
|
|
|
item_fn(*) => {
|
2013-08-13 06:21:45 -05:00
|
|
|
self.privileged_items.push(item.id);
|
2013-03-18 19:20:45 -05:00
|
|
|
*count += 1;
|
|
|
|
}
|
|
|
|
item_impl(_, _, _, ref methods) => {
|
2013-08-03 11:45:23 -05:00
|
|
|
for method in methods.iter() {
|
2013-08-13 06:21:45 -05:00
|
|
|
self.privileged_items.push(method.id);
|
2013-03-18 19:20:45 -05:00
|
|
|
*count += 1;
|
2012-09-04 16:48:32 -05:00
|
|
|
}
|
2013-08-13 06:21:45 -05:00
|
|
|
self.privileged_items.push(item.id);
|
2013-03-18 19:20:45 -05:00
|
|
|
*count += 1;
|
2012-09-04 16:48:32 -05:00
|
|
|
}
|
2013-03-18 19:20:45 -05:00
|
|
|
item_foreign_mod(ref foreign_mod) => {
|
2013-08-03 11:45:23 -05:00
|
|
|
for foreign_item in foreign_mod.items.iter() {
|
2013-08-13 06:21:45 -05:00
|
|
|
self.privileged_items.push(foreign_item.id);
|
2013-03-18 19:20:45 -05:00
|
|
|
*count += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
2013-08-13 06:21:45 -05:00
|
|
|
}
|
2013-03-18 19:20:45 -05:00
|
|
|
|
|
|
|
// Adds items that are privileged to this scope.
|
2013-08-13 06:21:45 -05:00
|
|
|
fn add_privileged_items(&mut self, items: &[@ast::item]) -> uint {
|
2013-03-18 19:20:45 -05:00
|
|
|
let mut count = 0;
|
2013-08-03 11:45:23 -05:00
|
|
|
for &item in items.iter() {
|
2013-08-13 06:21:45 -05:00
|
|
|
self.add_privileged_item(item, &mut count);
|
2012-09-04 16:48:32 -05:00
|
|
|
}
|
|
|
|
count
|
2013-08-13 06:21:45 -05:00
|
|
|
}
|
2012-09-04 16:48:32 -05:00
|
|
|
|
2012-11-30 13:24:16 -06:00
|
|
|
// Checks that an enum variant is in scope
|
2013-09-01 20:45:37 -05:00
|
|
|
fn check_variant(&mut self, span: Span, enum_id: ast::DefId) {
|
2013-08-13 06:21:45 -05:00
|
|
|
let variant_info = ty::enum_variants(self.tcx, enum_id)[0];
|
2012-11-30 13:24:16 -06:00
|
|
|
let parental_privacy = if is_local(enum_id) {
|
2013-08-13 06:21:45 -05:00
|
|
|
let parent_vis = ast_map::node_item_query(self.tcx.items,
|
|
|
|
enum_id.node,
|
2012-11-30 13:24:16 -06:00
|
|
|
|it| { it.vis },
|
|
|
|
~"unbound enum parent when checking \
|
|
|
|
dereference of enum type");
|
2013-01-30 19:20:02 -06:00
|
|
|
visibility_to_privacy(parent_vis)
|
2012-11-30 13:24:16 -06:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
// WRONG
|
|
|
|
Public
|
|
|
|
};
|
|
|
|
debug!("parental_privacy = %?", parental_privacy);
|
2013-01-30 19:20:02 -06:00
|
|
|
debug!("vis = %?, priv = %?",
|
2012-11-30 13:24:16 -06:00
|
|
|
variant_info.vis,
|
2013-01-30 19:20:02 -06:00
|
|
|
visibility_to_privacy(variant_info.vis))
|
2012-11-30 13:24:16 -06:00
|
|
|
// inherited => privacy of the enum item
|
2013-01-30 19:20:02 -06:00
|
|
|
if variant_visibility_to_privacy(variant_info.vis,
|
|
|
|
parental_privacy == Public)
|
|
|
|
== Private {
|
2013-08-13 06:21:45 -05:00
|
|
|
self.tcx.sess.span_err(span,
|
2013-04-30 11:47:52 -05:00
|
|
|
"can only dereference enums \
|
|
|
|
with a single, public variant");
|
2012-11-30 13:24:16 -06:00
|
|
|
}
|
2013-08-13 06:21:45 -05:00
|
|
|
}
|
2012-11-30 13:24:16 -06:00
|
|
|
|
2013-03-18 19:20:45 -05:00
|
|
|
// Returns true if a crate-local method is private and false otherwise.
|
2013-08-31 11:13:04 -05:00
|
|
|
fn method_is_private(&mut self, span: Span, method_id: NodeId) -> bool {
|
2013-09-01 20:45:37 -05:00
|
|
|
let check = |vis: visibility, container_id: DefId| {
|
2013-03-18 19:20:45 -05:00
|
|
|
let mut is_private = false;
|
|
|
|
if vis == private {
|
|
|
|
is_private = true;
|
|
|
|
} else if vis == public {
|
|
|
|
is_private = false;
|
|
|
|
} else {
|
|
|
|
// Look up the enclosing impl.
|
2013-07-27 03:25:59 -05:00
|
|
|
if container_id.crate != LOCAL_CRATE {
|
2013-08-13 06:21:45 -05:00
|
|
|
self.tcx.sess.span_bug(span,
|
2013-04-30 11:47:52 -05:00
|
|
|
"local method isn't in local \
|
|
|
|
impl?!");
|
2013-03-18 19:20:45 -05:00
|
|
|
}
|
|
|
|
|
2013-08-13 06:21:45 -05:00
|
|
|
match self.tcx.items.find(&container_id.node) {
|
2013-03-23 20:45:27 -05:00
|
|
|
Some(&node_item(item, _)) => {
|
2013-03-18 19:20:45 -05:00
|
|
|
match item.node {
|
|
|
|
item_impl(_, None, _, _)
|
|
|
|
if item.vis != public => {
|
|
|
|
is_private = true;
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Some(_) => {
|
2013-08-13 06:21:45 -05:00
|
|
|
self.tcx.sess.span_bug(span, "impl wasn't an item?!");
|
2013-03-18 19:20:45 -05:00
|
|
|
}
|
|
|
|
None => {
|
2013-08-13 06:21:45 -05:00
|
|
|
self.tcx.sess.span_bug(span, "impl wasn't in AST map?!");
|
2013-03-18 19:20:45 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
is_private
|
|
|
|
};
|
|
|
|
|
2013-08-13 06:21:45 -05:00
|
|
|
match self.tcx.items.find(&method_id) {
|
2013-03-23 20:45:27 -05:00
|
|
|
Some(&node_method(method, impl_id, _)) => {
|
2013-03-18 19:20:45 -05:00
|
|
|
check(method.vis, impl_id)
|
|
|
|
}
|
2013-03-23 20:45:27 -05:00
|
|
|
Some(&node_trait_method(trait_method, trait_id, _)) => {
|
2013-03-18 19:20:45 -05:00
|
|
|
match *trait_method {
|
|
|
|
required(_) => check(public, trait_id),
|
|
|
|
provided(method) => check(method.vis, trait_id),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Some(_) => {
|
2013-08-13 06:21:45 -05:00
|
|
|
self.tcx.sess.span_bug(span,
|
2013-03-18 19:20:45 -05:00
|
|
|
fmt!("method_is_private: method was a %s?!",
|
|
|
|
ast_map::node_id_to_str(
|
2013-08-13 06:21:45 -05:00
|
|
|
self.tcx.items,
|
2013-03-18 19:20:45 -05:00
|
|
|
method_id,
|
2013-05-14 19:27:27 -05:00
|
|
|
token::get_ident_interner())));
|
2013-03-18 19:20:45 -05:00
|
|
|
}
|
|
|
|
None => {
|
2013-08-13 06:21:45 -05:00
|
|
|
self.tcx.sess.span_bug(span, "method not found in \
|
2013-04-30 11:47:52 -05:00
|
|
|
AST map?!");
|
2013-03-18 19:20:45 -05:00
|
|
|
}
|
|
|
|
}
|
2013-08-13 06:21:45 -05:00
|
|
|
}
|
2013-03-18 19:20:45 -05:00
|
|
|
|
|
|
|
// Returns true if the given local item is private and false otherwise.
|
2013-08-31 11:13:04 -05:00
|
|
|
fn local_item_is_private(&mut self, span: Span, item_id: NodeId) -> bool {
|
2013-07-27 03:25:59 -05:00
|
|
|
let mut f: &fn(NodeId) -> bool = |_| false;
|
2013-03-18 19:20:45 -05:00
|
|
|
f = |item_id| {
|
2013-08-13 06:21:45 -05:00
|
|
|
match self.tcx.items.find(&item_id) {
|
2013-03-23 20:45:27 -05:00
|
|
|
Some(&node_item(item, _)) => item.vis != public,
|
2013-05-31 13:31:38 -05:00
|
|
|
Some(&node_foreign_item(*)) => false,
|
2013-03-23 20:45:27 -05:00
|
|
|
Some(&node_method(method, impl_did, _)) => {
|
2013-03-18 19:20:45 -05:00
|
|
|
match method.vis {
|
|
|
|
private => true,
|
|
|
|
public => false,
|
|
|
|
inherited => f(impl_did.node)
|
|
|
|
}
|
|
|
|
}
|
2013-03-23 20:45:27 -05:00
|
|
|
Some(&node_trait_method(_, trait_did, _)) => f(trait_did.node),
|
2013-03-18 19:20:45 -05:00
|
|
|
Some(_) => {
|
2013-08-13 06:21:45 -05:00
|
|
|
self.tcx.sess.span_bug(span,
|
2013-03-18 19:20:45 -05:00
|
|
|
fmt!("local_item_is_private: item was \
|
|
|
|
a %s?!",
|
|
|
|
ast_map::node_id_to_str(
|
2013-08-13 06:21:45 -05:00
|
|
|
self.tcx.items,
|
2013-03-18 19:20:45 -05:00
|
|
|
item_id,
|
2013-05-14 19:27:27 -05:00
|
|
|
token::get_ident_interner())));
|
2013-03-18 19:20:45 -05:00
|
|
|
}
|
|
|
|
None => {
|
2013-08-13 06:21:45 -05:00
|
|
|
self.tcx.sess.span_bug(span, "item not found in AST map?!");
|
2013-03-18 19:20:45 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
f(item_id)
|
2013-08-13 06:21:45 -05:00
|
|
|
}
|
2013-03-18 19:20:45 -05:00
|
|
|
|
2012-09-04 20:28:22 -05:00
|
|
|
// Checks that a private field is in scope.
|
2013-09-11 18:21:03 -05:00
|
|
|
// FIXME #6993: change type (and name) from Ident to Name
|
2013-09-01 20:45:37 -05:00
|
|
|
fn check_field(&mut self, span: Span, id: ast::DefId, ident: ast::Ident) {
|
2013-08-13 06:21:45 -05:00
|
|
|
let fields = ty::lookup_struct_fields(self.tcx, id);
|
2013-08-03 11:45:23 -05:00
|
|
|
for field in fields.iter() {
|
2013-09-11 18:21:03 -05:00
|
|
|
if field.name != ident.name { loop; }
|
2012-09-04 20:28:22 -05:00
|
|
|
if field.vis == private {
|
2013-08-13 06:21:45 -05:00
|
|
|
self.tcx.sess.span_err(span, fmt!("field `%s` is private",
|
2013-06-12 12:02:55 -05:00
|
|
|
token::ident_to_str(&ident)));
|
2012-09-04 20:28:22 -05:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2013-08-13 06:21:45 -05:00
|
|
|
}
|
2012-09-04 20:28:22 -05:00
|
|
|
|
2013-03-18 19:20:45 -05:00
|
|
|
// Given the ID of a method, checks to ensure it's in scope.
|
2013-09-01 20:45:37 -05:00
|
|
|
fn check_method_common(&mut self, span: Span, method_id: DefId, name: &Ident) {
|
2013-07-02 16:39:25 -05:00
|
|
|
// 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.
|
2013-09-09 21:57:08 -05:00
|
|
|
let method_id = ty::method(self.tcx, method_id).provided_source.unwrap_or(method_id);
|
2013-07-02 16:39:25 -05:00
|
|
|
|
2013-07-27 03:25:59 -05:00
|
|
|
if method_id.crate == LOCAL_CRATE {
|
2013-08-13 06:21:45 -05:00
|
|
|
let is_private = self.method_is_private(span, method_id.node);
|
2013-08-23 16:34:00 -05:00
|
|
|
let container_id = ty::method(self.tcx, method_id).container_id();
|
2013-03-18 19:20:45 -05:00
|
|
|
if is_private &&
|
2013-07-27 03:25:59 -05:00
|
|
|
(container_id.crate != LOCAL_CRATE ||
|
2013-08-13 06:21:45 -05:00
|
|
|
!self.privileged_items.iter().any(|x| x == &(container_id.node))) {
|
|
|
|
self.tcx.sess.span_err(span,
|
2013-03-18 19:20:45 -05:00
|
|
|
fmt!("method `%s` is private",
|
2013-06-12 12:02:55 -05:00
|
|
|
token::ident_to_str(name)));
|
2013-03-18 19:20:45 -05:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
let visibility =
|
2013-08-13 06:21:45 -05:00
|
|
|
csearch::get_item_visibility(self.tcx.sess.cstore, method_id);
|
2013-03-18 19:20:45 -05:00
|
|
|
if visibility != public {
|
2013-08-13 06:21:45 -05:00
|
|
|
self.tcx.sess.span_err(span,
|
2013-03-18 19:20:45 -05:00
|
|
|
fmt!("method `%s` is private",
|
2013-06-12 12:02:55 -05:00
|
|
|
token::ident_to_str(name)));
|
2013-03-18 19:20:45 -05:00
|
|
|
}
|
|
|
|
}
|
2013-08-13 06:21:45 -05:00
|
|
|
}
|
2013-03-18 19:20:45 -05:00
|
|
|
|
|
|
|
// Checks that a private path is in scope.
|
2013-09-01 20:45:37 -05:00
|
|
|
fn check_path(&mut self, span: Span, def: Def, path: &Path) {
|
2013-03-18 19:20:45 -05:00
|
|
|
debug!("checking path");
|
|
|
|
match def {
|
2013-09-01 20:45:37 -05:00
|
|
|
DefStaticMethod(method_id, _, _) => {
|
2013-03-18 19:20:45 -05:00
|
|
|
debug!("found static method def, checking it");
|
2013-08-07 11:47:28 -05:00
|
|
|
self.check_method_common(span,
|
|
|
|
method_id,
|
|
|
|
&path.segments.last().identifier)
|
2013-03-18 19:20:45 -05:00
|
|
|
}
|
2013-09-01 20:45:37 -05:00
|
|
|
DefFn(def_id, _) => {
|
2013-07-27 03:25:59 -05:00
|
|
|
if def_id.crate == LOCAL_CRATE {
|
2013-08-13 06:21:45 -05:00
|
|
|
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,
|
2013-03-18 19:20:45 -05:00
|
|
|
fmt!("function `%s` is private",
|
2013-08-07 11:47:28 -05:00
|
|
|
token::ident_to_str(
|
|
|
|
&path.segments
|
|
|
|
.last()
|
|
|
|
.identifier)));
|
2013-03-18 19:20:45 -05:00
|
|
|
}
|
2013-08-13 06:21:45 -05:00
|
|
|
} else if csearch::get_item_visibility(self.tcx.sess.cstore,
|
2013-03-20 16:38:57 -05:00
|
|
|
def_id) != public {
|
2013-08-13 06:21:45 -05:00
|
|
|
self.tcx.sess.span_err(span,
|
2013-03-20 16:38:57 -05:00
|
|
|
fmt!("function `%s` is private",
|
2013-08-07 11:47:28 -05:00
|
|
|
token::ident_to_str(
|
|
|
|
&path.segments
|
|
|
|
.last()
|
|
|
|
.identifier)));
|
2013-03-18 19:20:45 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
2013-08-13 06:21:45 -05:00
|
|
|
}
|
2013-03-18 19:20:45 -05:00
|
|
|
|
2012-09-04 20:28:22 -05:00
|
|
|
// Checks that a private method is in scope.
|
2013-09-01 19:50:59 -05:00
|
|
|
fn check_method(&mut self, span: Span, origin: &method_origin, ident: ast::Ident) {
|
2012-09-04 20:28:22 -05:00
|
|
|
match *origin {
|
|
|
|
method_static(method_id) => {
|
2013-08-13 06:21:45 -05:00
|
|
|
self.check_method_common(span, method_id, &ident)
|
2012-09-04 20:28:22 -05:00
|
|
|
}
|
2013-01-16 21:24:10 -06:00
|
|
|
method_param(method_param {
|
|
|
|
trait_id: trait_id,
|
2013-08-13 15:22:58 -05:00
|
|
|
method_num: method_num,
|
2013-01-16 21:24:10 -06:00
|
|
|
_
|
|
|
|
}) |
|
2013-08-13 15:22:58 -05:00
|
|
|
method_object(method_object {
|
|
|
|
trait_id: trait_id,
|
|
|
|
method_num: method_num,
|
|
|
|
_
|
|
|
|
}) => {
|
2013-07-27 03:25:59 -05:00
|
|
|
if trait_id.crate == LOCAL_CRATE {
|
2013-08-13 06:21:45 -05:00
|
|
|
match self.tcx.items.find(&trait_id.node) {
|
2013-03-23 20:45:27 -05:00
|
|
|
Some(&node_item(item, _)) => {
|
2012-09-04 20:28:22 -05:00
|
|
|
match item.node {
|
2012-12-04 12:50:00 -06:00
|
|
|
item_trait(_, _, ref methods) => {
|
|
|
|
if method_num >= (*methods).len() {
|
2013-08-13 06:21:45 -05:00
|
|
|
self.tcx.sess.span_bug(span,
|
|
|
|
"method number out of range?!");
|
2012-09-04 20:28:22 -05:00
|
|
|
}
|
2012-12-04 12:50:00 -06:00
|
|
|
match (*methods)[method_num] {
|
2012-09-04 20:28:22 -05:00
|
|
|
provided(method)
|
2012-09-25 19:39:22 -05:00
|
|
|
if method.vis == private &&
|
2013-08-13 06:21:45 -05:00
|
|
|
!self.privileged_items.iter()
|
2013-07-04 21:13:26 -05:00
|
|
|
.any(|x| x == &(trait_id.node)) => {
|
2013-08-13 06:21:45 -05:00
|
|
|
self.tcx.sess.span_err(span,
|
2013-06-04 14:34:25 -05:00
|
|
|
fmt!("method `%s` is private",
|
2013-06-12 12:02:55 -05:00
|
|
|
token::ident_to_str(&method
|
2013-06-04 14:34:25 -05:00
|
|
|
.ident)));
|
2012-09-04 20:28:22 -05:00
|
|
|
}
|
|
|
|
provided(_) | required(_) => {
|
|
|
|
// Required methods can't be
|
|
|
|
// private.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
2013-08-13 06:21:45 -05:00
|
|
|
self.tcx.sess.span_bug(span, "trait wasn't actually a trait?!");
|
2012-09-04 20:28:22 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Some(_) => {
|
2013-08-13 06:21:45 -05:00
|
|
|
self.tcx.sess.span_bug(span, "trait wasn't an item?!");
|
2012-09-04 20:28:22 -05:00
|
|
|
}
|
|
|
|
None => {
|
2013-08-13 06:21:45 -05:00
|
|
|
self.tcx.sess.span_bug(span,
|
|
|
|
"trait item wasn't found in the AST map?!");
|
2012-09-04 20:28:22 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2013-01-31 21:48:43 -06:00
|
|
|
// FIXME #4732: External crates.
|
2012-09-04 20:28:22 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-08-13 06:21:45 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'self> Visitor<&'self method_map> for PrivacyVisitor {
|
2012-09-04 20:28:22 -05:00
|
|
|
|
2013-08-31 11:13:04 -05:00
|
|
|
fn visit_mod<'mm>(&mut self, the_module:&_mod, _:Span, _:NodeId,
|
2013-08-13 06:21:45 -05:00
|
|
|
method_map:&'mm method_map) {
|
2012-09-04 16:48:32 -05:00
|
|
|
|
2013-08-13 06:21:45 -05:00
|
|
|
let n_added = self.add_privileged_items(the_module.items);
|
|
|
|
|
|
|
|
visit::walk_mod(self, the_module, method_map);
|
2012-09-04 16:48:32 -05:00
|
|
|
|
2013-07-31 21:18:19 -05:00
|
|
|
do n_added.times {
|
2013-08-13 06:21:45 -05:00
|
|
|
ignore(self.privileged_items.pop());
|
2012-09-04 16:48:32 -05:00
|
|
|
}
|
2013-08-13 06:21:45 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn visit_item<'mm>(&mut self, item:@item, method_map:&'mm method_map) {
|
|
|
|
|
2013-03-18 19:20:45 -05:00
|
|
|
// Do not check privacy inside items with the resolve_unexported
|
|
|
|
// attribute. This is used for the test runner.
|
2013-07-19 06:51:37 -05:00
|
|
|
if !attr::contains_name(item.attrs, "!resolve_unexported") {
|
2013-08-13 06:21:45 -05:00
|
|
|
check_sane_privacy(self.tcx, item);
|
|
|
|
visit::walk_item(self, item, method_map);
|
2013-03-18 19:20:45 -05:00
|
|
|
}
|
2013-08-13 06:21:45 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn visit_block<'mm>(&mut self, block:&Block, method_map:&'mm method_map) {
|
|
|
|
|
2013-03-18 19:20:45 -05:00
|
|
|
// Gather up all the privileged items.
|
|
|
|
let mut n_added = 0;
|
2013-08-03 11:45:23 -05:00
|
|
|
for stmt in block.stmts.iter() {
|
2013-03-18 19:20:45 -05:00
|
|
|
match stmt.node {
|
2013-09-01 20:45:37 -05:00
|
|
|
StmtDecl(decl, _) => {
|
2013-03-18 19:20:45 -05:00
|
|
|
match decl.node {
|
2013-09-01 20:45:37 -05:00
|
|
|
DeclItem(item) => {
|
2013-08-13 06:21:45 -05:00
|
|
|
self.add_privileged_item(item, &mut n_added);
|
2013-03-18 19:20:45 -05:00
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-13 06:21:45 -05:00
|
|
|
visit::walk_block(self, block, method_map);
|
2013-03-18 19:20:45 -05:00
|
|
|
|
2013-07-31 21:18:19 -05:00
|
|
|
do n_added.times {
|
2013-08-13 06:21:45 -05:00
|
|
|
ignore(self.privileged_items.pop());
|
2013-03-18 19:20:45 -05:00
|
|
|
}
|
2013-08-13 06:21:45 -05:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2013-09-01 20:45:37 -05:00
|
|
|
fn visit_expr<'mm>(&mut self, expr:@Expr, method_map:&'mm method_map) {
|
2013-08-13 06:21:45 -05:00
|
|
|
|
2012-09-04 16:48:32 -05:00
|
|
|
match expr.node {
|
2013-09-01 20:45:37 -05:00
|
|
|
ExprField(base, ident, _) => {
|
2013-06-01 17:31:56 -05:00
|
|
|
// Method calls are now a special syntactic form,
|
|
|
|
// so `a.b` should always be a field.
|
|
|
|
assert!(!method_map.contains_key(&expr.id));
|
|
|
|
|
2012-12-11 21:15:12 -06:00
|
|
|
// With type_autoderef, make sure we don't
|
|
|
|
// allow pointers to violate privacy
|
2013-08-13 06:21:45 -05:00
|
|
|
match ty::get(ty::type_autoderef(self.tcx, ty::expr_ty(self.tcx,
|
2012-12-11 21:15:12 -06:00
|
|
|
base))).sty {
|
2012-12-10 15:47:54 -06:00
|
|
|
ty_struct(id, _)
|
2013-08-13 06:21:45 -05:00
|
|
|
if id.crate != LOCAL_CRATE || !self.privileged_items.iter()
|
2013-07-04 21:13:26 -05:00
|
|
|
.any(|x| x == &(id.node)) => {
|
2013-06-01 17:31:56 -05:00
|
|
|
debug!("(privacy checking) checking field access");
|
2013-08-13 06:21:45 -05:00
|
|
|
self.check_field(expr.span, id, ident);
|
2012-09-04 16:48:32 -05:00
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
2013-09-01 20:45:37 -05:00
|
|
|
ExprMethodCall(_, base, ident, _, _, _) => {
|
2012-12-11 21:15:12 -06:00
|
|
|
// Ditto
|
2013-08-13 06:21:45 -05:00
|
|
|
match ty::get(ty::type_autoderef(self.tcx, ty::expr_ty(self.tcx,
|
2012-12-11 21:15:12 -06:00
|
|
|
base))).sty {
|
2013-08-07 07:29:29 -05:00
|
|
|
ty_enum(id, _) |
|
2012-12-10 15:47:54 -06:00
|
|
|
ty_struct(id, _)
|
2013-07-27 03:25:59 -05:00
|
|
|
if id.crate != LOCAL_CRATE ||
|
2013-08-13 06:21:45 -05:00
|
|
|
!self.privileged_items.iter().any(|x| x == &(id.node)) => {
|
2013-02-05 21:41:45 -06:00
|
|
|
match method_map.find(&expr.id) {
|
2012-12-03 17:28:51 -06:00
|
|
|
None => {
|
2013-08-13 06:21:45 -05:00
|
|
|
self.tcx.sess.span_bug(expr.span,
|
2013-04-30 11:47:52 -05:00
|
|
|
"method call not in \
|
|
|
|
method map");
|
2012-12-03 17:28:51 -06:00
|
|
|
}
|
2012-12-04 12:50:00 -06:00
|
|
|
Some(ref entry) => {
|
2012-12-03 17:28:51 -06:00
|
|
|
debug!("(privacy checking) checking \
|
|
|
|
impl method");
|
2013-08-13 06:21:45 -05:00
|
|
|
self.check_method(expr.span, &entry.origin, ident);
|
2012-12-03 17:28:51 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
2013-09-01 20:45:37 -05:00
|
|
|
ExprPath(ref path) => {
|
2013-08-13 06:21:45 -05:00
|
|
|
self.check_path(expr.span, self.tcx.def_map.get_copy(&expr.id), path);
|
2013-03-18 19:20:45 -05:00
|
|
|
}
|
2013-09-01 20:45:37 -05:00
|
|
|
ExprStruct(_, ref fields, _) => {
|
2013-08-13 06:21:45 -05:00
|
|
|
match ty::get(ty::expr_ty(self.tcx, expr)).sty {
|
2012-12-10 15:47:54 -06:00
|
|
|
ty_struct(id, _) => {
|
2013-07-27 03:25:59 -05:00
|
|
|
if id.crate != LOCAL_CRATE ||
|
2013-08-13 06:21:45 -05:00
|
|
|
!self.privileged_items.iter().any(|x| x == &(id.node)) {
|
2013-08-03 11:45:23 -05:00
|
|
|
for field in (*fields).iter() {
|
2012-09-04 21:07:23 -05:00
|
|
|
debug!("(privacy checking) checking \
|
|
|
|
field in struct literal");
|
2013-08-13 06:21:45 -05:00
|
|
|
self.check_field(expr.span, id, field.ident);
|
2012-09-04 21:07:23 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-10-23 17:56:40 -05:00
|
|
|
ty_enum(id, _) => {
|
2013-07-27 03:25:59 -05:00
|
|
|
if id.crate != LOCAL_CRATE ||
|
2013-08-13 06:21:45 -05:00
|
|
|
!self.privileged_items.iter().any(|x| x == &(id.node)) {
|
|
|
|
match self.tcx.def_map.get_copy(&expr.id) {
|
2013-09-08 19:36:01 -05:00
|
|
|
DefVariant(_, variant_id, _) => {
|
2013-08-03 11:45:23 -05:00
|
|
|
for field in (*fields).iter() {
|
2012-10-23 17:56:40 -05:00
|
|
|
debug!("(privacy checking) \
|
|
|
|
checking field in \
|
|
|
|
struct variant \
|
|
|
|
literal");
|
2013-08-13 06:21:45 -05:00
|
|
|
self.check_field(expr.span, variant_id, field.ident);
|
2012-10-23 17:56:40 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
2013-08-13 06:21:45 -05:00
|
|
|
self.tcx.sess.span_bug(expr.span,
|
2013-04-30 11:47:52 -05:00
|
|
|
"resolve didn't \
|
|
|
|
map enum struct \
|
|
|
|
constructor to a \
|
|
|
|
variant def");
|
2012-10-23 17:56:40 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-09-04 21:07:23 -05:00
|
|
|
_ => {
|
2013-08-13 06:21:45 -05:00
|
|
|
self.tcx.sess.span_bug(expr.span, "struct expr \
|
2013-04-30 11:47:52 -05:00
|
|
|
didn't have \
|
|
|
|
struct type?!");
|
2012-09-04 21:07:23 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-09-01 20:45:37 -05:00
|
|
|
ExprUnary(_, ast::UnDeref, operand) => {
|
2012-11-30 13:24:16 -06:00
|
|
|
// In *e, we need to check that if e's type is an
|
|
|
|
// enum type t, then t's first variant is public or
|
|
|
|
// privileged. (We can assume it has only one variant
|
|
|
|
// since typeck already happened.)
|
2013-08-13 06:21:45 -05:00
|
|
|
match ty::get(ty::expr_ty(self.tcx, operand)).sty {
|
2012-11-30 13:24:16 -06:00
|
|
|
ty_enum(id, _) => {
|
2013-07-27 03:25:59 -05:00
|
|
|
if id.crate != LOCAL_CRATE ||
|
2013-08-13 06:21:45 -05:00
|
|
|
!self.privileged_items.iter().any(|x| x == &(id.node)) {
|
|
|
|
self.check_variant(expr.span, id);
|
2012-11-30 13:24:16 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => { /* No check needed */ }
|
|
|
|
}
|
|
|
|
}
|
2012-09-04 16:48:32 -05:00
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
|
2013-08-13 06:21:45 -05:00
|
|
|
visit::walk_expr(self, expr, method_map);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2013-09-01 20:45:37 -05:00
|
|
|
fn visit_pat<'mm>(&mut self, pattern:@Pat, method_map:&'mm method_map) {
|
2013-08-13 06:21:45 -05:00
|
|
|
|
2013-03-20 00:17:42 -05:00
|
|
|
match pattern.node {
|
2013-09-01 20:45:37 -05:00
|
|
|
PatStruct(_, ref fields, _) => {
|
2013-08-13 06:21:45 -05:00
|
|
|
match ty::get(ty::pat_ty(self.tcx, pattern)).sty {
|
2012-12-10 15:47:54 -06:00
|
|
|
ty_struct(id, _) => {
|
2013-07-27 03:25:59 -05:00
|
|
|
if id.crate != LOCAL_CRATE ||
|
2013-08-13 06:21:45 -05:00
|
|
|
!self.privileged_items.iter().any(|x| x == &(id.node)) {
|
2013-08-03 11:45:23 -05:00
|
|
|
for field in fields.iter() {
|
2012-09-04 21:07:23 -05:00
|
|
|
debug!("(privacy checking) checking \
|
|
|
|
struct pattern");
|
2013-08-13 06:21:45 -05:00
|
|
|
self.check_field(pattern.span, id, field.ident);
|
2012-09-04 21:07:23 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-10-24 19:04:00 -05:00
|
|
|
ty_enum(enum_id, _) => {
|
2013-07-27 03:25:59 -05:00
|
|
|
if enum_id.crate != LOCAL_CRATE ||
|
2013-08-13 06:21:45 -05:00
|
|
|
!self.privileged_items.iter().any(|x| x == &enum_id.node) {
|
|
|
|
match self.tcx.def_map.find(&pattern.id) {
|
2013-09-08 19:36:01 -05:00
|
|
|
Some(&DefVariant(_, variant_id, _)) => {
|
2013-08-03 11:45:23 -05:00
|
|
|
for field in fields.iter() {
|
2012-10-24 19:04:00 -05:00
|
|
|
debug!("(privacy checking) \
|
|
|
|
checking field in \
|
|
|
|
struct variant pattern");
|
2013-08-13 06:21:45 -05:00
|
|
|
self.check_field(pattern.span, variant_id, field.ident);
|
2012-10-24 19:04:00 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
2013-08-13 06:21:45 -05:00
|
|
|
self.tcx.sess.span_bug(pattern.span,
|
2013-04-30 11:47:52 -05:00
|
|
|
"resolve didn't \
|
|
|
|
map enum struct \
|
|
|
|
pattern to a \
|
|
|
|
variant def");
|
2012-10-24 19:04:00 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-09-04 21:07:23 -05:00
|
|
|
_ => {
|
2013-08-13 06:21:45 -05:00
|
|
|
self.tcx.sess.span_bug(pattern.span,
|
2013-04-30 11:47:52 -05:00
|
|
|
"struct pattern didn't have \
|
|
|
|
struct type?!");
|
2012-09-04 21:07:23 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
|
2013-08-13 06:21:45 -05:00
|
|
|
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);
|
2012-09-04 16:48:32 -05:00
|
|
|
}
|
2013-08-09 03:25:24 -05:00
|
|
|
|
|
|
|
/// Validates all of the visibility qualifers placed on the item given. This
|
|
|
|
/// ensures that there are no extraneous qualifiers that don't actually do
|
|
|
|
/// anything. In theory these qualifiers wouldn't parse, but that may happen
|
|
|
|
/// later on down the road...
|
|
|
|
fn check_sane_privacy(tcx: ty::ctxt, item: @ast::item) {
|
|
|
|
match item.node {
|
|
|
|
// implementations of traits don't need visibility qualifiers because
|
|
|
|
// that's controlled by having the trait in scope.
|
|
|
|
ast::item_impl(_, Some(*), _, ref methods) => {
|
|
|
|
for m in methods.iter() {
|
|
|
|
match m.vis {
|
|
|
|
ast::private | ast::public => {
|
|
|
|
tcx.sess.span_err(m.span, "unnecessary visibility")
|
|
|
|
}
|
|
|
|
ast::inherited => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ast::item_enum(ref def, _) => {
|
|
|
|
for v in def.variants.iter() {
|
|
|
|
match v.node.vis {
|
|
|
|
ast::public => {
|
|
|
|
if item.vis == ast::public {
|
|
|
|
tcx.sess.span_err(v.span, "unnecessary `pub` \
|
|
|
|
visibility");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ast::private => {
|
|
|
|
if item.vis != ast::public {
|
|
|
|
tcx.sess.span_err(v.span, "unnecessary `priv` \
|
|
|
|
visibility");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ast::inherited => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ast::item_struct(ref def, _) => {
|
|
|
|
for f in def.fields.iter() {
|
|
|
|
match f.node.kind {
|
|
|
|
ast::named_field(_, ast::public) => {
|
|
|
|
tcx.sess.span_err(f.span, "unnecessary `pub` \
|
|
|
|
visibility");
|
|
|
|
}
|
|
|
|
ast::named_field(_, ast::private) => {
|
|
|
|
// Fields should really be private by default...
|
|
|
|
}
|
|
|
|
ast::named_field(*) | ast::unnamed_field => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ast::item_trait(_, _, ref methods) => {
|
|
|
|
for m in methods.iter() {
|
|
|
|
match *m {
|
|
|
|
ast::provided(ref m) => {
|
|
|
|
match m.vis {
|
|
|
|
ast::private | ast::public => {
|
|
|
|
tcx.sess.span_err(m.span, "unnecessary \
|
|
|
|
visibility");
|
|
|
|
}
|
|
|
|
ast::inherited => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// this is warned about in the parser
|
|
|
|
ast::required(*) => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ast::item_impl(*) | ast::item_static(*) | ast::item_foreign_mod(*) |
|
|
|
|
ast::item_fn(*) | ast::item_mod(*) | ast::item_ty(*) |
|
|
|
|
ast::item_mac(*) => {}
|
|
|
|
}
|
|
|
|
}
|