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-01-07 16:16:52 -06:00
|
|
|
|
2012-09-04 16:48:32 -05:00
|
|
|
// A pass that checks to make sure private fields and methods aren't used
|
|
|
|
// outside their scopes.
|
|
|
|
|
2013-01-08 21:37:25 -06:00
|
|
|
use core::prelude::*;
|
|
|
|
|
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-02-27 15:45:37 -06:00
|
|
|
use middle::typeck::{method_map, method_origin, method_param, method_self};
|
|
|
|
use middle::typeck::{method_super};
|
2012-12-13 15:05:22 -06:00
|
|
|
use middle::typeck::{method_static, method_trait};
|
2012-12-23 16:41:37 -06:00
|
|
|
|
|
|
|
use core::util::ignore;
|
2013-03-18 19:20:45 -05:00
|
|
|
use syntax::ast::{decl_item, def, def_fn, def_id, def_static_method};
|
|
|
|
use syntax::ast::{def_variant, expr_field, expr_method_call, expr_path};
|
|
|
|
use syntax::ast::{expr_struct, expr_unary, ident, inherited, item_enum};
|
|
|
|
use syntax::ast::{item_foreign_mod, item_fn, item_impl, item_struct};
|
|
|
|
use syntax::ast::{item_trait, local_crate, node_id, pat_struct, path};
|
|
|
|
use syntax::ast::{private, provided, public, required, stmt_decl, 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-01-15 18:33:20 -06:00
|
|
|
use syntax::codemap::span;
|
2012-12-23 16:41:37 -06:00
|
|
|
use syntax::visit;
|
2012-09-04 16:48:32 -05:00
|
|
|
|
2013-01-30 15:44:24 -06:00
|
|
|
pub fn check_crate(tcx: ty::ctxt,
|
|
|
|
method_map: &method_map,
|
|
|
|
crate: @ast::crate) {
|
2013-03-07 17:37:14 -06:00
|
|
|
let privileged_items = @mut ~[];
|
2012-09-04 16:48:32 -05:00
|
|
|
|
2013-03-18 19:20:45 -05:00
|
|
|
// Adds an item to its scope.
|
|
|
|
let add_privileged_item: @fn(@ast::item, &mut uint) = |item, count| {
|
|
|
|
match item.node {
|
|
|
|
item_struct(*) | item_trait(*) | item_enum(*) |
|
|
|
|
item_fn(*) => {
|
|
|
|
privileged_items.push(item.id);
|
|
|
|
*count += 1;
|
|
|
|
}
|
|
|
|
item_impl(_, _, _, ref methods) => {
|
|
|
|
for methods.each |method| {
|
|
|
|
privileged_items.push(method.id);
|
|
|
|
*count += 1;
|
2012-09-04 16:48:32 -05:00
|
|
|
}
|
2013-03-18 19:20:45 -05:00
|
|
|
privileged_items.push(item.id);
|
|
|
|
*count += 1;
|
2012-09-04 16:48:32 -05:00
|
|
|
}
|
2013-03-18 19:20:45 -05:00
|
|
|
item_foreign_mod(ref foreign_mod) => {
|
|
|
|
for foreign_mod.items.each |foreign_item| {
|
|
|
|
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| {
|
|
|
|
let mut count = 0;
|
|
|
|
for items.each |&item| {
|
|
|
|
add_privileged_item(item, &mut count);
|
2012-09-04 16:48:32 -05:00
|
|
|
}
|
|
|
|
count
|
|
|
|
};
|
|
|
|
|
2012-11-30 13:24:16 -06:00
|
|
|
// Checks that an enum variant is in scope
|
2013-01-15 18:33:20 -06:00
|
|
|
let check_variant: @fn(span: span, enum_id: ast::def_id) =
|
|
|
|
|span, enum_id| {
|
2012-11-30 13:24:16 -06:00
|
|
|
let variant_info = ty::enum_variants(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,
|
|
|
|
|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 {
|
2012-11-30 13:24:16 -06:00
|
|
|
tcx.sess.span_err(span,
|
|
|
|
~"can only dereference enums \
|
|
|
|
with a single, public variant");
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-03-18 19:20:45 -05:00
|
|
|
// Returns the ID of the container (impl or trait) that a crate-local
|
|
|
|
// method belongs to.
|
|
|
|
let local_method_container_id:
|
|
|
|
@fn(span: span, method_id: node_id) -> def_id =
|
|
|
|
|span, method_id| {
|
|
|
|
match tcx.items.find(&method_id) {
|
|
|
|
Some(node_method(_, impl_id, _)) => impl_id,
|
|
|
|
Some(node_trait_method(_, trait_id, _)) => trait_id,
|
|
|
|
Some(_) => {
|
|
|
|
tcx.sess.span_bug(span,
|
|
|
|
fmt!("method was a %s?!",
|
|
|
|
ast_map::node_id_to_str(
|
|
|
|
tcx.items,
|
|
|
|
method_id,
|
|
|
|
tcx.sess.parse_sess.interner)));
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
tcx.sess.span_bug(span, ~"method not found in \
|
|
|
|
AST map?!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// Returns true if a crate-local method is private and false otherwise.
|
|
|
|
let method_is_private: @fn(span: span, method_id: node_id) -> bool =
|
|
|
|
|span, method_id| {
|
|
|
|
let check = |vis: visibility, container_id: def_id| {
|
|
|
|
let mut is_private = false;
|
|
|
|
if vis == private {
|
|
|
|
is_private = true;
|
|
|
|
} else if vis == public {
|
|
|
|
is_private = false;
|
|
|
|
} else {
|
|
|
|
// Look up the enclosing impl.
|
|
|
|
if container_id.crate != local_crate {
|
|
|
|
tcx.sess.span_bug(span,
|
|
|
|
~"local method isn't in local \
|
|
|
|
impl?!");
|
|
|
|
}
|
|
|
|
|
|
|
|
match tcx.items.find(&container_id.node) {
|
|
|
|
Some(node_item(item, _)) => {
|
|
|
|
match item.node {
|
|
|
|
item_impl(_, None, _, _)
|
|
|
|
if item.vis != public => {
|
|
|
|
is_private = true;
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Some(_) => {
|
|
|
|
tcx.sess.span_bug(span, ~"impl wasn't an item?!");
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
tcx.sess.span_bug(span, ~"impl wasn't in AST map?!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
is_private
|
|
|
|
};
|
|
|
|
|
|
|
|
match tcx.items.find(&method_id) {
|
|
|
|
Some(node_method(method, impl_id, _)) => {
|
|
|
|
check(method.vis, impl_id)
|
|
|
|
}
|
|
|
|
Some(node_trait_method(trait_method, trait_id, _)) => {
|
|
|
|
match *trait_method {
|
|
|
|
required(_) => check(public, trait_id),
|
|
|
|
provided(method) => check(method.vis, trait_id),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Some(_) => {
|
|
|
|
tcx.sess.span_bug(span,
|
|
|
|
fmt!("method_is_private: method was a %s?!",
|
|
|
|
ast_map::node_id_to_str(
|
|
|
|
tcx.items,
|
|
|
|
method_id,
|
|
|
|
tcx.sess.parse_sess.interner)));
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
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: node_id) -> bool =
|
|
|
|
|span, item_id| {
|
|
|
|
let mut f: &fn(node_id) -> bool = |_| false;
|
|
|
|
f = |item_id| {
|
|
|
|
match tcx.items.find(&item_id) {
|
|
|
|
Some(node_item(item, _)) => item.vis != public,
|
|
|
|
Some(node_foreign_item(_, _, vis, _)) => vis != public,
|
|
|
|
Some(node_method(method, impl_did, _)) => {
|
|
|
|
match method.vis {
|
|
|
|
private => true,
|
|
|
|
public => false,
|
|
|
|
inherited => f(impl_did.node)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Some(node_trait_method(_, trait_did, _)) => f(trait_did.node),
|
|
|
|
Some(_) => {
|
|
|
|
tcx.sess.span_bug(span,
|
|
|
|
fmt!("local_item_is_private: item was \
|
|
|
|
a %s?!",
|
|
|
|
ast_map::node_id_to_str(
|
|
|
|
tcx.items,
|
|
|
|
item_id,
|
|
|
|
tcx.sess
|
|
|
|
.parse_sess
|
|
|
|
.interner)));
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
tcx.sess.span_bug(span, ~"item not found in AST map?!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
f(item_id)
|
|
|
|
};
|
|
|
|
|
2012-09-04 20:28:22 -05:00
|
|
|
// Checks that a private field is in scope.
|
2013-01-15 18:33:20 -06:00
|
|
|
let check_field: @fn(span: span, id: ast::def_id, ident: ast::ident) =
|
|
|
|
|span, id, ident| {
|
2012-12-10 15:47:54 -06:00
|
|
|
let fields = ty::lookup_struct_fields(tcx, id);
|
2012-09-04 20:28:22 -05:00
|
|
|
for fields.each |field| {
|
2012-09-07 17:32:04 -05:00
|
|
|
if field.ident != ident { loop; }
|
2012-09-04 20:28:22 -05:00
|
|
|
if field.vis == private {
|
|
|
|
tcx.sess.span_err(span, fmt!("field `%s` is private",
|
|
|
|
*tcx.sess.parse_sess.interner
|
|
|
|
.get(ident)));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-03-18 19:20:45 -05:00
|
|
|
// 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| {
|
|
|
|
if method_id.crate == local_crate {
|
|
|
|
let is_private = method_is_private(span, method_id.node);
|
|
|
|
let container_id = local_method_container_id(span,
|
|
|
|
method_id.node);
|
|
|
|
if is_private &&
|
|
|
|
(container_id.crate != local_crate ||
|
|
|
|
!privileged_items.contains(&(container_id.node))) {
|
|
|
|
tcx.sess.span_err(span,
|
|
|
|
fmt!("method `%s` is private",
|
|
|
|
*tcx.sess
|
|
|
|
.parse_sess
|
|
|
|
.interner
|
|
|
|
.get(*name)));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
let visibility =
|
2013-03-20 16:38:57 -05:00
|
|
|
csearch::get_item_visibility(tcx.sess.cstore, method_id);
|
2013-03-18 19:20:45 -05:00
|
|
|
if visibility != public {
|
|
|
|
tcx.sess.span_err(span,
|
|
|
|
fmt!("method `%s` is private",
|
|
|
|
*tcx.sess.parse_sess.interner
|
|
|
|
.get(*name)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// Checks that a private path is in scope.
|
|
|
|
let check_path: @fn(span: span, def: def, path: @path) =
|
|
|
|
|span, def, 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())
|
|
|
|
}
|
|
|
|
def_fn(def_id, _) => {
|
|
|
|
if def_id.crate == local_crate {
|
|
|
|
if local_item_is_private(span, def_id.node) &&
|
|
|
|
!privileged_items.contains(&def_id.node) {
|
|
|
|
tcx.sess.span_err(span,
|
|
|
|
fmt!("function `%s` is private",
|
|
|
|
*tcx.sess
|
|
|
|
.parse_sess
|
|
|
|
.interner
|
|
|
|
.get(copy *path
|
|
|
|
.idents
|
|
|
|
.last())));
|
|
|
|
}
|
2013-03-20 16:38:57 -05:00
|
|
|
} else if csearch::get_item_visibility(tcx.sess.cstore,
|
|
|
|
def_id) != public {
|
|
|
|
tcx.sess.span_err(span,
|
|
|
|
fmt!("function `%s` is private",
|
|
|
|
*tcx.sess
|
|
|
|
.parse_sess
|
|
|
|
.interner
|
|
|
|
.get(copy *path
|
|
|
|
.idents
|
|
|
|
.last())));
|
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-02-27 15:45:37 -06:00
|
|
|
let check_method: @fn(span: span,
|
|
|
|
origin: &method_origin,
|
|
|
|
ident: ast::ident) =
|
|
|
|
|span, origin, ident| {
|
2012-09-04 20:28:22 -05:00
|
|
|
match *origin {
|
|
|
|
method_static(method_id) => {
|
2013-03-18 19:20:45 -05:00
|
|
|
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,
|
|
|
|
method_num: method_num,
|
|
|
|
_
|
|
|
|
}) |
|
2012-10-05 20:51:36 -05:00
|
|
|
method_trait(trait_id, method_num, _) |
|
2013-01-16 20:45:05 -06:00
|
|
|
method_self(trait_id, method_num) |
|
|
|
|
method_super(trait_id, method_num) => {
|
2012-09-04 20:28:22 -05:00
|
|
|
if trait_id.crate == local_crate {
|
2013-02-05 21:41:45 -06:00
|
|
|
match tcx.items.find(&trait_id.node) {
|
2012-09-04 20:28:22 -05:00
|
|
|
Some(node_item(item, _)) => {
|
|
|
|
match item.node {
|
2012-12-04 12:50:00 -06:00
|
|
|
item_trait(_, _, ref methods) => {
|
|
|
|
if method_num >= (*methods).len() {
|
2012-09-04 20:28:22 -05:00
|
|
|
tcx.sess.span_bug(span, ~"method \
|
|
|
|
number \
|
|
|
|
out of \
|
|
|
|
range?!");
|
|
|
|
}
|
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 &&
|
|
|
|
!privileged_items
|
|
|
|
.contains(&(trait_id.node)) => {
|
2012-09-04 20:28:22 -05:00
|
|
|
tcx.sess.span_err(span,
|
|
|
|
fmt!("method
|
|
|
|
`%s` \
|
|
|
|
is \
|
|
|
|
private",
|
|
|
|
*tcx
|
|
|
|
.sess
|
|
|
|
.parse_sess
|
|
|
|
.interner
|
|
|
|
.get
|
|
|
|
(method
|
|
|
|
.ident)));
|
|
|
|
}
|
|
|
|
provided(_) | required(_) => {
|
|
|
|
// Required methods can't be
|
|
|
|
// private.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
tcx.sess.span_bug(span, ~"trait wasn't \
|
|
|
|
actually a \
|
|
|
|
trait?!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Some(_) => {
|
|
|
|
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?!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2013-01-31 21:48:43 -06:00
|
|
|
// FIXME #4732: External crates.
|
2012-09-04 20:28:22 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-01-08 16:00:45 -06:00
|
|
|
let visitor = visit::mk_vt(@visit::Visitor {
|
2012-09-04 20:28:22 -05:00
|
|
|
visit_mod: |the_module, span, node_id, method_map, visitor| {
|
|
|
|
let n_added = add_privileged_items(the_module.items);
|
2012-09-04 16:48:32 -05:00
|
|
|
|
2012-09-04 20:28:22 -05:00
|
|
|
visit::visit_mod(the_module, span, node_id, method_map, visitor);
|
2012-09-04 16:48:32 -05:00
|
|
|
|
|
|
|
for n_added.times {
|
2012-09-04 20:28:22 -05:00
|
|
|
ignore(privileged_items.pop());
|
2012-09-04 16:48:32 -05:00
|
|
|
}
|
|
|
|
},
|
2013-03-18 19:20:45 -05:00
|
|
|
visit_item: |item, method_map, visitor| {
|
|
|
|
// Do not check privacy inside items with the resolve_unexported
|
|
|
|
// attribute. This is used for the test runner.
|
|
|
|
if !attr::contains_name(attr::attr_metas(/*bad*/copy item.attrs),
|
|
|
|
~"!resolve_unexported") {
|
|
|
|
visit::visit_item(item, method_map, visitor);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
visit_block: |block, method_map, visitor| {
|
|
|
|
// Gather up all the privileged items.
|
|
|
|
let mut n_added = 0;
|
|
|
|
for block.node.stmts.each |stmt| {
|
|
|
|
match stmt.node {
|
|
|
|
stmt_decl(decl, _) => {
|
|
|
|
match decl.node {
|
|
|
|
decl_item(item) => {
|
|
|
|
add_privileged_item(item, &mut n_added);
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
visit::visit_block(block, method_map, visitor);
|
|
|
|
|
|
|
|
for n_added.times {
|
|
|
|
ignore(privileged_items.pop());
|
|
|
|
}
|
|
|
|
},
|
2012-09-04 20:28:22 -05:00
|
|
|
visit_expr: |expr, method_map: &method_map, visitor| {
|
2012-09-04 16:48:32 -05:00
|
|
|
match expr.node {
|
|
|
|
expr_field(base, ident, _) => {
|
2012-12-11 21:15:12 -06:00
|
|
|
// With type_autoderef, make sure we don't
|
|
|
|
// allow pointers to violate privacy
|
|
|
|
match ty::get(ty::type_autoderef(tcx, ty::expr_ty(tcx,
|
|
|
|
base))).sty {
|
2012-12-10 15:47:54 -06:00
|
|
|
ty_struct(id, _)
|
2012-09-04 16:48:32 -05:00
|
|
|
if id.crate != local_crate ||
|
2012-09-25 19:39:22 -05:00
|
|
|
!privileged_items.contains(&(id.node)) => {
|
2013-02-05 21:41:45 -06:00
|
|
|
match method_map.find(&expr.id) {
|
2012-09-04 20:28:22 -05:00
|
|
|
None => {
|
|
|
|
debug!("(privacy checking) checking \
|
2012-09-04 21:07:23 -05:00
|
|
|
field access");
|
2012-09-04 20:28:22 -05:00
|
|
|
check_field(expr.span, id, ident);
|
|
|
|
}
|
2012-12-04 12:50:00 -06:00
|
|
|
Some(ref entry) => {
|
2012-09-04 20:28:22 -05:00
|
|
|
debug!("(privacy checking) checking \
|
|
|
|
impl method");
|
2013-02-27 15:45:37 -06:00
|
|
|
check_method(expr.span,
|
|
|
|
&entry.origin,
|
|
|
|
ident);
|
2012-09-04 16:48:32 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
2013-02-27 15:45:37 -06:00
|
|
|
expr_method_call(base, ident, _, _, _) => {
|
2012-12-11 21:15:12 -06:00
|
|
|
// Ditto
|
|
|
|
match ty::get(ty::type_autoderef(tcx, ty::expr_ty(tcx,
|
|
|
|
base))).sty {
|
2012-12-10 15:47:54 -06:00
|
|
|
ty_struct(id, _)
|
2012-12-03 17:28:51 -06:00
|
|
|
if id.crate != local_crate ||
|
|
|
|
!privileged_items.contains(&(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 => {
|
|
|
|
tcx.sess.span_bug(expr.span,
|
|
|
|
~"method call not in \
|
|
|
|
method map");
|
|
|
|
}
|
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-02-27 15:45:37 -06:00
|
|
|
check_method(expr.span,
|
|
|
|
&entry.origin,
|
|
|
|
ident);
|
2012-12-03 17:28:51 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
2013-03-18 19:20:45 -05:00
|
|
|
expr_path(path) => {
|
2013-03-22 21:26:41 -05:00
|
|
|
check_path(expr.span, *tcx.def_map.get(&expr.id), path);
|
2013-03-18 19:20:45 -05:00
|
|
|
}
|
2012-12-04 12:50:00 -06:00
|
|
|
expr_struct(_, ref fields, _) => {
|
2012-09-11 18:20:31 -05:00
|
|
|
match ty::get(ty::expr_ty(tcx, expr)).sty {
|
2012-12-10 15:47:54 -06:00
|
|
|
ty_struct(id, _) => {
|
2012-09-04 21:07:23 -05:00
|
|
|
if id.crate != local_crate ||
|
2012-09-25 19:39:22 -05:00
|
|
|
!privileged_items.contains(&(id.node)) {
|
2012-12-04 12:50:00 -06:00
|
|
|
for (*fields).each |field| {
|
2012-09-04 21:07:23 -05:00
|
|
|
debug!("(privacy checking) checking \
|
|
|
|
field in struct literal");
|
|
|
|
check_field(expr.span, id,
|
|
|
|
field.node.ident);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-10-23 17:56:40 -05:00
|
|
|
ty_enum(id, _) => {
|
|
|
|
if id.crate != local_crate ||
|
|
|
|
!privileged_items.contains(&(id.node)) {
|
2013-03-22 21:26:41 -05:00
|
|
|
match *tcx.def_map.get(&expr.id) {
|
2012-10-23 17:56:40 -05:00
|
|
|
def_variant(_, variant_id) => {
|
2012-12-04 12:50:00 -06:00
|
|
|
for (*fields).each |field| {
|
2012-10-23 17:56:40 -05:00
|
|
|
debug!("(privacy checking) \
|
|
|
|
checking field in \
|
|
|
|
struct variant \
|
|
|
|
literal");
|
|
|
|
check_field(expr.span, variant_id,
|
|
|
|
field.node.ident);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
tcx.sess.span_bug(expr.span,
|
|
|
|
~"resolve didn't \
|
|
|
|
map enum struct \
|
|
|
|
constructor to a \
|
|
|
|
variant def");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-09-04 21:07:23 -05:00
|
|
|
_ => {
|
|
|
|
tcx.sess.span_bug(expr.span, ~"struct expr \
|
|
|
|
didn't have \
|
|
|
|
struct type?!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-11-30 13:24:16 -06:00
|
|
|
expr_unary(ast::deref, operand) => {
|
|
|
|
// 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.)
|
|
|
|
match ty::get(ty::expr_ty(tcx, operand)).sty {
|
|
|
|
ty_enum(id, _) => {
|
|
|
|
if id.crate != local_crate ||
|
|
|
|
!privileged_items.contains(&(id.node)) {
|
|
|
|
check_variant(expr.span, id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => { /* No check needed */ }
|
|
|
|
}
|
|
|
|
}
|
2012-09-04 16:48:32 -05:00
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
|
2012-09-04 20:28:22 -05:00
|
|
|
visit::visit_expr(expr, method_map, visitor);
|
2012-09-04 15:29:32 -05:00
|
|
|
},
|
2012-09-04 21:07:23 -05:00
|
|
|
visit_pat: |pattern, method_map, visitor| {
|
2013-03-20 00:17:42 -05:00
|
|
|
match pattern.node {
|
|
|
|
pat_struct(_, ref fields, _) => {
|
2012-09-11 18:20:31 -05:00
|
|
|
match ty::get(ty::pat_ty(tcx, pattern)).sty {
|
2012-12-10 15:47:54 -06:00
|
|
|
ty_struct(id, _) => {
|
2012-09-04 21:07:23 -05:00
|
|
|
if id.crate != local_crate ||
|
2012-09-25 19:39:22 -05:00
|
|
|
!privileged_items.contains(&(id.node)) {
|
2012-09-04 21:07:23 -05:00
|
|
|
for fields.each |field| {
|
|
|
|
debug!("(privacy checking) checking \
|
|
|
|
struct pattern");
|
|
|
|
check_field(pattern.span, id,
|
|
|
|
field.ident);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-10-24 19:04:00 -05:00
|
|
|
ty_enum(enum_id, _) => {
|
|
|
|
if enum_id.crate != local_crate ||
|
|
|
|
!privileged_items.contains(
|
|
|
|
&enum_id.node) {
|
2013-02-05 21:41:45 -06:00
|
|
|
match tcx.def_map.find(&pattern.id) {
|
2013-03-22 21:26:41 -05:00
|
|
|
Some(&def_variant(_, variant_id)) => {
|
2012-10-24 19:04:00 -05:00
|
|
|
for fields.each |field| {
|
|
|
|
debug!("(privacy checking) \
|
|
|
|
checking field in \
|
|
|
|
struct variant pattern");
|
|
|
|
check_field(pattern.span,
|
|
|
|
variant_id,
|
|
|
|
field.ident);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
tcx.sess.span_bug(pattern.span,
|
|
|
|
~"resolve didn't \
|
|
|
|
map enum struct \
|
|
|
|
pattern to a \
|
|
|
|
variant def");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-09-04 21:07:23 -05:00
|
|
|
_ => {
|
|
|
|
tcx.sess.span_bug(pattern.span,
|
|
|
|
~"struct pattern didn't have \
|
|
|
|
struct type?!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
|
|
|
|
visit::visit_pat(pattern, method_map, visitor);
|
|
|
|
},
|
2012-09-04 15:29:32 -05:00
|
|
|
.. *visit::default_visitor()
|
2012-09-04 16:48:32 -05:00
|
|
|
});
|
2012-09-04 20:28:22 -05:00
|
|
|
visit::visit_crate(*crate, method_map, visitor);
|
2012-09-04 16:48:32 -05:00
|
|
|
}
|
|
|
|
|