提交 df1686db 编写于 作者: N Nick Cameron

Make priavcy checking aware that a `use` directive can point to two defintions...

Make priavcy checking aware that a `use` directive can point to two defintions (namespaces) with different privacy. Closes #4110
上级 425f5747
......@@ -41,6 +41,11 @@
/// reexporting a public struct doesn't inline the doc).
pub type PublicItems = HashSet<ast::NodeId>;
/// Result of a checking operation - None => no errors were found. Some => an
/// error and contains the span and message for reporting that error and
/// optionally the same for a note about the error.
type CheckResult = Option<(Span, ~str, Option<(Span, ~str)>)>;
////////////////////////////////////////////////////////////////////////////////
/// The parent visitor, used to determine what's the parent of what (node-wise)
////////////////////////////////////////////////////////////////////////////////
......@@ -510,40 +515,50 @@ fn private_accessible(&self, id: ast::NodeId) -> bool {
}
}
/// Guarantee that a particular definition is public, possibly emitting an
/// error message if it's not.
fn report_error(&self, result: CheckResult) -> bool {
match result {
None => true,
Some((span, msg, note)) => {
self.tcx.sess.span_err(span, msg);
match note {
Some((span, msg)) => self.tcx.sess.span_note(span, msg),
None => {},
}
false
},
}
}
/// Guarantee that a particular definition is public. Returns a CheckResult
/// which contains any errors found. These can be reported using `report_error`.
/// If the result is `None`, no errors were found.
fn ensure_public(&self, span: Span, to_check: ast::DefId,
source_did: Option<ast::DefId>, msg: &str) -> bool {
source_did: Option<ast::DefId>, msg: &str) -> CheckResult {
match self.def_privacy(to_check) {
ExternallyDenied => {
self.tcx.sess.span_err(span, format!("{} is private", msg))
}
ExternallyDenied => Some((span, format!("{} is private", msg), None)),
DisallowedBy(id) => {
if id == source_did.unwrap_or(to_check).node {
self.tcx.sess.span_err(span, format!("{} is private", msg));
return false;
let (err_span, err_msg) = if id == source_did.unwrap_or(to_check).node {
return Some((span, format!("{} is private", msg), None));
} else {
self.tcx.sess.span_err(span, format!("{} is inaccessible",
msg));
}
(span, format!("{} is inaccessible", msg))
};
match self.tcx.map.find(id) {
Some(ast_map::NodeItem(item)) => {
let desc = match item.node {
ast::ItemMod(..) => "module",
ast::ItemTrait(..) => "trait",
_ => return false,
_ => return Some((err_span, err_msg, None)),
};
let msg = format!("{} `{}` is private",
desc,
token::get_ident(item.ident));
self.tcx.sess.span_note(span, msg);
}
Some(..) | None => {}
Some((err_span, err_msg, Some((span, msg))))
},
_ => Some((err_span, err_msg, None)),
}
}
Allowable => return true
},
Allowable => None,
}
return false;
}
// Checks that a field is in scope.
......@@ -613,34 +628,99 @@ fn check_static_method(&mut self, span: Span, method_id: ast::DefId,
let method_id = ty::method(self.tcx, method_id).provided_source
.unwrap_or(method_id);
self.ensure_public(span,
method_id,
None,
format!("method `{}`", token::get_ident(name)));
let string = token::get_ident(name);
self.report_error(self.ensure_public(span,
method_id,
None,
format!("method `{}`", string)));
}
// Checks that a path is in scope.
fn check_path(&mut self, span: Span, path_id: ast::NodeId, path: &ast::Path) {
debug!("privacy - path {}", self.nodestr(path_id));
let def_map = self.tcx.def_map.borrow();
let def = def_map.get().get_copy(&path_id);
let orig_def = def_map.get().get_copy(&path_id);
let ck = |tyname: &str| {
let origdid = def_id_of_def(def);
let ck_public = |def: ast::DefId| {
let name = token::get_ident(path.segments
.last()
.unwrap()
.identifier);
let origdid = def_id_of_def(orig_def);
self.ensure_public(span,
def,
Some(origdid),
format!("{} `{}`",
tyname,
name))
};
match *self.last_private_map.get(&path_id) {
resolve::AllPublic => {},
resolve::DependsOn(def) => {
let name = token::get_ident(path.segments
.last()
.unwrap()
.identifier);
self.ensure_public(span,
def,
Some(origdid),
format!("{} `{}`",
tyname, name));
}
resolve::LastMod(resolve::AllPublic) => {},
resolve::LastMod(resolve::DependsOn(def)) => {
self.report_error(ck_public(def));
},
resolve::LastImport{value_priv: value_priv,
value_used: check_value,
type_priv: type_priv,
type_used: check_type} => {
// This dance with found_error is because we don't want to report
// a privacy error twice for the same directive.
let found_error = match (type_priv, check_type) {
(Some(resolve::DependsOn(def)), resolve::Used) => {
!self.report_error(ck_public(def))
},
_ => false,
};
if !found_error {
match (value_priv, check_value) {
(Some(resolve::DependsOn(def)), resolve::Used) => {
self.report_error(ck_public(def));
},
_ => {},
}
}
// If an import is not used in either namespace, we still want to check
// that it could be legal. Therefore we check in both namespaces and only
// report an error if both would be illegal. We only report one error,
// even if it is illegal to import from both namespaces.
match (value_priv, check_value, type_priv, check_type) {
(Some(p), resolve::Unused, None, _) |
(None, _, Some(p), resolve::Unused) => {
let p = match p {
resolve::AllPublic => None,
resolve::DependsOn(def) => ck_public(def),
};
if p.is_some() {
self.report_error(p);
}
},
(Some(v), resolve::Unused, Some(t), resolve::Unused) => {
let v = match v {
resolve::AllPublic => None,
resolve::DependsOn(def) => ck_public(def),
};
let t = match t {
resolve::AllPublic => None,
resolve::DependsOn(def) => ck_public(def),
};
match (v, t) {
(Some(_), Some(t)) => {
self.report_error(Some(t));
},
_ => {},
}
},
_ => {},
}
},
}
};
// FIXME(#12334) Imports can refer to definitions in both the type and
// value namespaces. The privacy information is aware of this, but the
// def map is not. Therefore the names we work out below will not always
// be accurate and we can get slightly wonky error messages (but type
// checking is always correct).
let def_map = self.tcx.def_map.borrow();
match def_map.get().get_copy(&path_id) {
ast::DefStaticMethod(..) => ck("static method"),
......@@ -668,7 +748,7 @@ fn check_method(&mut self, span: Span, origin: &method_origin,
// is whether the trait itself is accessible or not.
method_param(method_param { trait_id: trait_id, .. }) |
method_object(method_object { trait_id: trait_id, .. }) => {
self.ensure_public(span, trait_id, None, "source trait");
self.report_error(self.ensure_public(span, trait_id, None, "source trait"));
}
}
}
......
此差异已折叠。
Subproject commit fd5308383c575472edb2163d823dc6670bf59609
Subproject commit 800b56fe6af21ffd8e56aee8cf12dd758f5bbdf1
// Copyright 2014 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.
// Check we do the correct privacy checks when we import a name and there is an
// item with that name in both the value and type namespaces.
#[feature(globs)];
#[allow(dead_code)];
#[allow(unused_imports)];
// public type, private value
pub mod foo1 {
pub trait Bar {
}
pub struct Baz;
fn Bar() { }
}
fn test_glob1() {
use foo1::*;
Bar(); //~ ERROR unresolved name `Bar`.
}
// private type, public value
pub mod foo2 {
trait Bar {
}
pub struct Baz;
pub fn Bar() { }
}
fn test_glob2() {
use foo2::*;
let _x: ~Bar; //~ ERROR use of undeclared type name `Bar`
}
// neither public
pub mod foo3 {
trait Bar {
}
pub struct Baz;
fn Bar() { }
}
fn test_glob3() {
use foo3::*;
Bar(); //~ ERROR unresolved name `Bar`.
let _x: ~Bar; //~ ERROR use of undeclared type name `Bar`
}
fn main() {
}
// Copyright 2014 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.
// Check we do the correct privacy checks when we import a name and there is an
// item with that name in both the value and type namespaces.
#[feature(globs)];
#[allow(dead_code)];
#[allow(unused_imports)];
// public type, private value
pub mod foo1 {
pub trait Bar {
}
pub struct Baz;
fn Bar() { }
}
fn test_single1() {
// In an ideal world, these would be private instead of inaccessible.
use foo1::Bar; //~ ERROR `Bar` is inaccessible
Bar();
}
fn test_list1() {
use foo1::{Bar,Baz}; //~ ERROR `Bar` is inaccessible
Bar();
}
// private type, public value
pub mod foo2 {
trait Bar {
}
pub struct Baz;
pub fn Bar() { }
}
fn test_single2() {
use foo2::Bar; //~ ERROR `Bar` is private
let _x : ~Bar;
}
fn test_list2() {
use foo2::{Bar,Baz}; //~ ERROR `Bar` is private
let _x: ~Bar;
}
// neither public
pub mod foo3 {
trait Bar {
}
pub struct Baz;
fn Bar() { }
}
fn test_unused3() {
use foo3::Bar; //~ ERROR `Bar` is private
use foo3::{Bar,Baz}; //~ ERROR `Bar` is private
}
fn test_single3() {
use foo3::Bar; //~ ERROR `Bar` is private
Bar();
let _x: ~Bar;
}
fn test_list3() {
use foo3::{Bar,Baz}; //~ ERROR `Bar` is private
Bar();
let _x: ~Bar;
}
fn main() {
}
// Copyright 2014 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.
// ignore-fast
// Check we do the correct privacy checks when we import a name and there is an
// item with that name in both the value and type namespaces.
#[feature(globs)];
#[allow(dead_code)];
#[allow(unused_imports)];
// public type, private value
pub mod foo1 {
pub trait Bar {
}
pub struct Baz;
fn Bar() { }
}
fn test_unused1() {
use foo1::Bar;
use foo1::{Bar,Baz};
use foo1::*;
}
fn test_single1() {
use foo1::Bar;
let _x: ~Bar;
}
fn test_list1() {
use foo1::{Bar,Baz};
let _x: ~Bar;
}
fn test_glob1() {
use foo1::*;
let _x: ~Bar;
}
// private type, public value
pub mod foo2 {
trait Bar {
}
pub struct Baz;
pub fn Bar() { }
}
fn test_unused2() {
use foo2::Bar;
use foo2::{Bar,Baz};
use foo2::*;
}
fn test_single2() {
use foo2::Bar;
Bar();
}
fn test_list2() {
use foo2::{Bar,Baz};
Bar();
}
fn test_glob2() {
use foo2::*;
Bar();
}
// public type, public value
pub mod foo3 {
pub trait Bar {
}
pub struct Baz;
pub fn Bar() { }
}
fn test_unused3() {
use foo3::Bar;
use foo3::{Bar,Baz};
use foo3::*;
}
fn test_single3() {
use foo3::Bar;
Bar();
let _x: ~Bar;
}
fn test_list3() {
use foo3::{Bar,Baz};
Bar();
let _x: ~Bar;
}
fn test_glob3() {
use foo3::*;
Bar();
let _x: ~Bar;
}
fn main() {
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册