privacy: Mark reachable but unnameable items as reachable
This commit is contained in:
parent
2051a92134
commit
767a447470
3 changed files with 176 additions and 11 deletions
|
@ -169,6 +169,10 @@ struct EmbargoVisitor<'a, 'tcx: 'a> {
|
||||||
changed: bool,
|
changed: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ReachEverythingInTheInterfaceVisitor<'b, 'a: 'b, 'tcx: 'a> {
|
||||||
|
ev: &'b mut EmbargoVisitor<'a, 'tcx>,
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> {
|
impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> {
|
||||||
fn ty_level(&self, ty: &hir::Ty) -> Option<AccessLevel> {
|
fn ty_level(&self, ty: &hir::Ty) -> Option<AccessLevel> {
|
||||||
if let hir::TyPath(..) = ty.node {
|
if let hir::TyPath(..) = ty.node {
|
||||||
|
@ -214,6 +218,10 @@ impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> {
|
||||||
old_level
|
old_level
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn reach<'b>(&'b mut self) -> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
|
||||||
|
ReachEverythingInTheInterfaceVisitor { ev: self }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
|
impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
|
||||||
|
@ -245,10 +253,10 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Update id of the item itself
|
// Update level of the item itself
|
||||||
let item_level = self.update(item.id, inherited_item_level);
|
let item_level = self.update(item.id, inherited_item_level);
|
||||||
|
|
||||||
// Update ids of nested things
|
// Update levels of nested things
|
||||||
match item.node {
|
match item.node {
|
||||||
hir::ItemEnum(ref def, _) => {
|
hir::ItemEnum(ref def, _) => {
|
||||||
for variant in &def.variants {
|
for variant in &def.variants {
|
||||||
|
@ -292,19 +300,72 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hir::ItemTy(ref ty, _) if item_level.is_some() => {
|
_ => {}
|
||||||
if let hir::TyPath(..) = ty.node {
|
}
|
||||||
match self.tcx.def_map.borrow().get(&ty.id).unwrap().full_def() {
|
|
||||||
Def::PrimTy(..) | Def::SelfTy(..) | Def::TyParam(..) => {},
|
// Mark all items in interfaces of reachable items as reachable
|
||||||
def => {
|
match item.node {
|
||||||
if let Some(node_id) = self.tcx.map.as_local_node_id(def.def_id()) {
|
// The interface is empty
|
||||||
self.update(node_id, Some(AccessLevel::Reachable));
|
hir::ItemExternCrate(..) => {}
|
||||||
}
|
// All nested items are checked by visit_item
|
||||||
|
hir::ItemMod(..) => {}
|
||||||
|
// Reexports are handled in visit_mod
|
||||||
|
hir::ItemUse(..) => {}
|
||||||
|
// Visit everything
|
||||||
|
hir::ItemConst(..) | hir::ItemStatic(..) | hir::ItemFn(..) |
|
||||||
|
hir::ItemTrait(..) | hir::ItemTy(..) | hir::ItemImpl(_, _, _, Some(..), _, _) => {
|
||||||
|
if item_level.is_some() {
|
||||||
|
self.reach().visit_item(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Visit everything, but enum variants have their own levels
|
||||||
|
hir::ItemEnum(ref def, ref generics) => {
|
||||||
|
if item_level.is_some() {
|
||||||
|
self.reach().visit_generics(generics);
|
||||||
|
}
|
||||||
|
for variant in &def.variants {
|
||||||
|
if self.get(variant.node.data.id()).is_some() {
|
||||||
|
for field in variant.node.data.fields() {
|
||||||
|
self.reach().visit_struct_field(field);
|
||||||
|
}
|
||||||
|
// Corner case: if the variant is reachable, but its
|
||||||
|
// enum is not, make the enum reachable as well.
|
||||||
|
self.update(item.id, Some(AccessLevel::Reachable));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Visit everything, but foreign items have their own levels
|
||||||
|
hir::ItemForeignMod(ref foreign_mod) => {
|
||||||
|
for foreign_item in &foreign_mod.items {
|
||||||
|
if self.get(foreign_item.id).is_some() {
|
||||||
|
self.reach().visit_foreign_item(foreign_item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Visit everything except for private fields
|
||||||
|
hir::ItemStruct(ref struct_def, ref generics) => {
|
||||||
|
if item_level.is_some() {
|
||||||
|
self.reach().visit_generics(generics);
|
||||||
|
for field in struct_def.fields() {
|
||||||
|
if field.node.kind.visibility() == hir::Public {
|
||||||
|
self.reach().visit_struct_field(field);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// The interface is empty
|
||||||
|
hir::ItemDefaultImpl(..) => {}
|
||||||
|
// Visit everything except for private impl items
|
||||||
|
hir::ItemImpl(_, _, ref generics, None, _, ref impl_items) => {
|
||||||
|
if item_level.is_some() {
|
||||||
|
self.reach().visit_generics(generics);
|
||||||
|
for impl_item in impl_items {
|
||||||
|
if impl_item.vis == hir::Public {
|
||||||
|
self.reach().visit_impl_item(impl_item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let orig_level = self.prev_level;
|
let orig_level = self.prev_level;
|
||||||
|
@ -347,6 +408,68 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'b, 'a, 'tcx: 'a> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
|
||||||
|
// Make the type hidden under a type alias reachable
|
||||||
|
fn reach_aliased_type(&mut self, item: &hir::Item, path: &hir::Path) {
|
||||||
|
if let hir::ItemTy(ref ty, ref generics) = item.node {
|
||||||
|
// See `fn is_public_type_alias` for details
|
||||||
|
self.visit_ty(ty);
|
||||||
|
let provided_params = path.segments.last().unwrap().parameters.types().len();
|
||||||
|
for ty_param in &generics.ty_params[provided_params..] {
|
||||||
|
if let Some(ref default_ty) = ty_param.default {
|
||||||
|
self.visit_ty(default_ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'b, 'a, 'tcx: 'a, 'v> Visitor<'v> for ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
|
||||||
|
fn visit_ty(&mut self, ty: &hir::Ty) {
|
||||||
|
if let hir::TyPath(_, ref path) = ty.node {
|
||||||
|
let def = self.ev.tcx.def_map.borrow().get(&ty.id).unwrap().full_def();
|
||||||
|
match def {
|
||||||
|
Def::Struct(def_id) | Def::Enum(def_id) | Def::TyAlias(def_id) |
|
||||||
|
Def::Trait(def_id) | Def::AssociatedTy(def_id, _) => {
|
||||||
|
if let Some(node_id) = self.ev.tcx.map.as_local_node_id(def_id) {
|
||||||
|
let item = self.ev.tcx.map.expect_item(node_id);
|
||||||
|
if let Def::TyAlias(..) = def {
|
||||||
|
// Type aliases are substituted. Associated type aliases are not
|
||||||
|
// substituted yet, but ideally they should be.
|
||||||
|
if self.ev.get(item.id).is_none() {
|
||||||
|
self.reach_aliased_type(item, path);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.ev.update(item.id, Some(AccessLevel::Reachable));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
intravisit::walk_ty(self, ty);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_trait_ref(&mut self, trait_ref: &hir::TraitRef) {
|
||||||
|
let def_id = self.ev.tcx.trait_ref_to_def_id(trait_ref);
|
||||||
|
if let Some(node_id) = self.ev.tcx.map.as_local_node_id(def_id) {
|
||||||
|
let item = self.ev.tcx.map.expect_item(node_id);
|
||||||
|
self.ev.update(item.id, Some(AccessLevel::Reachable));
|
||||||
|
}
|
||||||
|
|
||||||
|
intravisit::walk_trait_ref(self, trait_ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't recurse into function bodies
|
||||||
|
fn visit_block(&mut self, _: &hir::Block) {}
|
||||||
|
// Don't recurse into expressions in array sizes or const initializers
|
||||||
|
fn visit_expr(&mut self, _: &hir::Expr) {}
|
||||||
|
// Don't recurse into patterns in function arguments
|
||||||
|
fn visit_pat(&mut self, _: &hir::Pat) {}
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// The privacy visitor, where privacy checks take place (violations reported)
|
/// The privacy visitor, where privacy checks take place (violations reported)
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
23
src/test/auxiliary/issue-16734.rs
Normal file
23
src/test/auxiliary/issue-16734.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
// Copyright 2016 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.
|
||||||
|
|
||||||
|
mod inner_private_module {
|
||||||
|
pub struct Unnameable;
|
||||||
|
|
||||||
|
impl Unnameable {
|
||||||
|
pub fn method_of_unnameable_type(&self) -> &'static str {
|
||||||
|
"Hello!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn public_function_returning_unnameable_type() -> inner_private_module::Unnameable {
|
||||||
|
inner_private_module::Unnameable
|
||||||
|
}
|
19
src/test/run-pass/issue-16734.rs
Normal file
19
src/test/run-pass/issue-16734.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
// Copyright 2016 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.
|
||||||
|
|
||||||
|
// aux-build:issue-16734.rs
|
||||||
|
|
||||||
|
extern crate issue_16734;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let res = issue_16734::public_function_returning_unnameable_type()
|
||||||
|
.method_of_unnameable_type();
|
||||||
|
assert_eq!(res, "Hello!");
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue