提交 c1ad5af4 编写于 作者: V Vadim Petrochenkov

Changes to data produced by privacy pass

上级 3e48b0e3
......@@ -25,7 +25,7 @@
//! for all lint attributes.
use self::TargetLint::*;
use middle::privacy::ExportedItems;
use middle::privacy::AccessLevels;
use middle::ty::{self, Ty};
use session::{early_error, Session};
use lint::{Level, LevelSource, Lint, LintId, LintArray, LintPass};
......@@ -277,8 +277,8 @@ pub struct LateContext<'a, 'tcx: 'a> {
/// The crate being checked.
pub krate: &'a hir::Crate,
/// Items exported from the crate being checked.
pub exported_items: &'a ExportedItems,
/// Items accessible from the crate being checked.
pub access_levels: &'a AccessLevels,
/// The store of registered lints.
lints: LintStore,
......@@ -564,7 +564,7 @@ fn visit_ids<F>(&mut self, f: F)
impl<'a, 'tcx> LateContext<'a, 'tcx> {
fn new(tcx: &'a ty::ctxt<'tcx>,
krate: &'a hir::Crate,
exported_items: &'a ExportedItems) -> LateContext<'a, 'tcx> {
access_levels: &'a AccessLevels) -> LateContext<'a, 'tcx> {
// We want to own the lint store, so move it out of the session.
let lint_store = mem::replace(&mut *tcx.sess.lint_store.borrow_mut(),
LintStore::new());
......@@ -572,7 +572,7 @@ fn new(tcx: &'a ty::ctxt<'tcx>,
LateContext {
tcx: tcx,
krate: krate,
exported_items: exported_items,
access_levels: access_levels,
lints: lint_store,
level_stack: vec![],
node_levels: RefCell::new(FnvHashMap()),
......@@ -1014,10 +1014,9 @@ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
/// Perform lint checking on a crate.
///
/// Consumes the `lint_store` field of the `Session`.
pub fn check_crate(tcx: &ty::ctxt,
exported_items: &ExportedItems) {
pub fn check_crate(tcx: &ty::ctxt, access_levels: &AccessLevels) {
let krate = tcx.map.krate();
let mut cx = LateContext::new(tcx, krate, exported_items);
let mut cx = LateContext::new(tcx, krate, access_levels);
// Visit the whole crate.
cx.with_lint_attrs(&krate.attrs, |cx| {
......
......@@ -19,7 +19,6 @@
use middle::{def, pat_util, privacy, ty};
use middle::def_id::{DefId};
use lint;
use util::nodemap::NodeSet;
use std::collections::HashSet;
use syntax::{ast, codemap};
......@@ -370,25 +369,10 @@ fn visit_item(&mut self, item: &hir::Item) {
}
fn create_and_seed_worklist(tcx: &ty::ctxt,
exported_items: &privacy::ExportedItems,
reachable_symbols: &NodeSet,
access_levels: &privacy::AccessLevels,
krate: &hir::Crate) -> Vec<ast::NodeId> {
let mut worklist = Vec::new();
// Preferably, we would only need to seed the worklist with reachable
// symbols. However, since the set of reachable symbols differs
// depending on whether a crate is built as bin or lib, and we want
// the warning to be consistent, we also seed the worklist with
// exported symbols.
for id in exported_items {
worklist.push(*id);
}
for id in reachable_symbols {
// Reachable variants can be dead, because we warn about
// variants never constructed, not variants never used.
if let Some(ast_map::NodeVariant(..)) = tcx.map.find(*id) {
continue;
}
for (id, _) in &access_levels.map {
worklist.push(*id);
}
......@@ -408,12 +392,10 @@ fn create_and_seed_worklist(tcx: &ty::ctxt,
}
fn find_live(tcx: &ty::ctxt,
exported_items: &privacy::ExportedItems,
reachable_symbols: &NodeSet,
access_levels: &privacy::AccessLevels,
krate: &hir::Crate)
-> Box<HashSet<ast::NodeId>> {
let worklist = create_and_seed_worklist(tcx, exported_items,
reachable_symbols, krate);
let worklist = create_and_seed_worklist(tcx, access_levels, krate);
let mut symbol_visitor = MarkSymbolVisitor::new(tcx, worklist);
symbol_visitor.mark_live_symbols();
symbol_visitor.live_symbols
......@@ -607,12 +589,9 @@ fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) {
}
}
pub fn check_crate(tcx: &ty::ctxt,
exported_items: &privacy::ExportedItems,
reachable_symbols: &NodeSet) {
pub fn check_crate(tcx: &ty::ctxt, access_levels: &privacy::AccessLevels) {
let krate = tcx.map.krate();
let live_symbols = find_live(tcx, exported_items,
reachable_symbols, krate);
let live_symbols = find_live(tcx, access_levels, krate);
let mut visitor = DeadVisitor { tcx: tcx, live_symbols: live_symbols };
intravisit::walk_crate(&mut visitor, krate);
}
......@@ -17,20 +17,54 @@
pub use self::LastPrivate::*;
use middle::def_id::DefId;
use util::nodemap::{DefIdSet, NodeSet};
use util::nodemap::{DefIdSet, FnvHashMap};
/// A set of AST nodes exported by the crate.
pub type ExportedItems = NodeSet;
use std::hash::Hash;
use syntax::ast::NodeId;
// Accessibility levels, sorted in ascending order
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum AccessLevel {
// Exported items + items participating in various kinds of public interfaces,
// but not directly nameable. For example, if function `fn f() -> T {...}` is
// public, then type `T` is exported. Its values can be obtained by other crates
// even if the type itseld is not nameable.
// FIXME: Mostly unimplemented. Only `type` aliases export items currently.
Reachable,
// Public items + items accessible to other crates with help of `pub use` reexports
Exported,
// Items accessible to other crates directly, without help of reexports
Public,
}
// Accessibility levels for reachable HIR nodes
#[derive(Clone)]
pub struct AccessLevels<Id = NodeId> {
pub map: FnvHashMap<Id, AccessLevel>
}
impl<Id: Hash + Eq> AccessLevels<Id> {
pub fn is_reachable(&self, id: Id) -> bool {
self.map.contains_key(&id)
}
pub fn is_exported(&self, id: Id) -> bool {
self.map.get(&id) >= Some(&AccessLevel::Exported)
}
pub fn is_public(&self, id: Id) -> bool {
self.map.get(&id) >= Some(&AccessLevel::Public)
}
}
impl<Id: Hash + Eq> Default for AccessLevels<Id> {
fn default() -> Self {
AccessLevels { map: Default::default() }
}
}
/// A set containing all exported definitions from external crates.
/// The set does not contain any entries from local crates.
pub type ExternalExports = DefIdSet;
/// A set of AST nodes that are fully public in the crate. This map is used for
/// documentation purposes (reexporting a private struct inlines the doc,
/// reexporting a public struct doesn't inline the doc).
pub type PublicItems = NodeSet;
#[derive(Copy, Clone, Debug)]
pub enum LastPrivate {
LastMod(PrivateDep),
......
......@@ -329,7 +329,7 @@ fn propagate_node(&mut self, node: &ast_map::Node,
// trait items are used from inlinable code through method call syntax or UFCS, or their
// trait is a lang item.
struct CollectPrivateImplItemsVisitor<'a> {
exported_items: &'a privacy::ExportedItems,
access_levels: &'a privacy::AccessLevels,
worklist: &'a mut Vec<ast::NodeId>,
}
......@@ -337,7 +337,7 @@ impl<'a, 'v> Visitor<'v> for CollectPrivateImplItemsVisitor<'a> {
fn visit_item(&mut self, item: &hir::Item) {
// We need only trait impls here, not inherent impls, and only non-exported ones
if let hir::ItemImpl(_, _, _, Some(_), _, ref impl_items) = item.node {
if !self.exported_items.contains(&item.id) {
if !self.access_levels.is_reachable(item.id) {
for impl_item in impl_items {
self.worklist.push(impl_item.id);
}
......@@ -347,7 +347,7 @@ fn visit_item(&mut self, item: &hir::Item) {
}
pub fn find_reachable(tcx: &ty::ctxt,
exported_items: &privacy::ExportedItems)
access_levels: &privacy::AccessLevels)
-> NodeSet {
let mut reachable_context = ReachableContext::new(tcx);
......@@ -357,7 +357,7 @@ pub fn find_reachable(tcx: &ty::ctxt,
// If other crates link to us, they're going to expect to be able to
// use the lang items, so we need to be sure to mark them as
// exported.
for id in exported_items {
for (id, _) in &access_levels.map {
reachable_context.worklist.push(*id);
}
for (_, item) in tcx.lang_items.items() {
......@@ -369,7 +369,7 @@ pub fn find_reachable(tcx: &ty::ctxt,
}
{
let mut collect_private_impl_items = CollectPrivateImplItemsVisitor {
exported_items: exported_items,
access_levels: access_levels,
worklist: &mut reachable_context.worklist,
};
tcx.map.krate().visit_all_items(&mut collect_private_impl_items);
......
......@@ -19,7 +19,7 @@
use middle::def;
use middle::def_id::{CRATE_DEF_INDEX, DefId};
use middle::ty;
use middle::privacy::PublicItems;
use middle::privacy::AccessLevels;
use metadata::csearch;
use syntax::parse::token::InternedString;
use syntax::codemap::{Span, DUMMY_SP};
......@@ -73,7 +73,7 @@ struct Annotator<'a, 'tcx: 'a> {
tcx: &'a ty::ctxt<'tcx>,
index: &'a mut Index<'tcx>,
parent: Option<&'tcx Stability>,
export_map: &'a PublicItems,
access_levels: &'a AccessLevels,
in_trait_impl: bool,
in_enum: bool,
}
......@@ -143,7 +143,7 @@ fn annotate<F>(&mut self, id: NodeId, attrs: &Vec<Attribute>,
} else {
debug!("annotate: not found, parent = {:?}", self.parent);
let mut is_error = kind == AnnotationKind::Required &&
self.export_map.contains(&id) &&
self.access_levels.is_reachable(id) &&
!self.tcx.sess.opts.test;
if let Some(stab) = self.parent {
if stab.level.is_unstable() {
......@@ -266,12 +266,12 @@ fn visit_macro_def(&mut self, md: &'v hir::MacroDef) {
impl<'tcx> Index<'tcx> {
/// Construct the stability index for a crate being compiled.
pub fn build(&mut self, tcx: &ty::ctxt<'tcx>, krate: &'tcx Crate, export_map: &PublicItems) {
pub fn build(&mut self, tcx: &ty::ctxt<'tcx>, krate: &Crate, access_levels: &AccessLevels) {
let mut annotator = Annotator {
tcx: tcx,
index: self,
parent: None,
export_map: export_map,
access_levels: access_levels,
in_trait_impl: false,
in_enum: false,
};
......
......@@ -104,14 +104,12 @@
/// produced by the driver and fed to trans and later passes.
pub struct CrateAnalysis<'a> {
pub export_map: ExportMap,
pub exported_items: middle::privacy::ExportedItems,
pub public_items: middle::privacy::PublicItems,
pub access_levels: middle::privacy::AccessLevels,
pub reachable: NodeSet,
pub name: &'a str,
pub glob_map: Option<GlobMap>,
}
#[derive(Copy, Clone)]
pub enum DtorKind {
NoDtor,
......
......@@ -746,7 +746,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
"const checking",
|| middle::check_const::check_crate(tcx));
let (exported_items, public_items) =
let access_levels =
time(time_passes, "privacy checking", || {
rustc_privacy::check_crate(tcx,
&export_map,
......@@ -755,7 +755,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
// Do not move this check past lint
time(time_passes, "stability index", || {
tcx.stability.borrow_mut().build(tcx, krate, &exported_items)
tcx.stability.borrow_mut().build(tcx, krate, &access_levels)
});
time(time_passes,
......@@ -807,12 +807,10 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
let reachable_map =
time(time_passes,
"reachability checking",
|| reachable::find_reachable(tcx, &exported_items));
|| reachable::find_reachable(tcx, &access_levels));
time(time_passes, "death checking", || {
middle::dead::check_crate(tcx,
&exported_items,
&reachable_map)
middle::dead::check_crate(tcx, &access_levels);
});
let ref lib_features_used =
......@@ -827,7 +825,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
time(time_passes,
"lint checking",
|| lint::check_crate(tcx, &exported_items));
|| lint::check_crate(tcx, &access_levels));
// The above three passes generate errors w/o aborting
tcx.sess.abort_if_errors();
......@@ -836,8 +834,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
mir_map,
ty::CrateAnalysis {
export_map: export_map,
exported_items: exported_items,
public_items: public_items,
access_levels: access_levels,
reachable: reachable_map,
name: name,
glob_map: glob_map,
......
......@@ -301,8 +301,8 @@ fn check_missing_docs_attrs(&self,
// Only check publicly-visible items, using the result from the privacy pass.
// It's an option so the crate root can also use this function (it doesn't
// have a NodeId).
if let Some(ref id) = id {
if !cx.exported_items.contains(id) {
if let Some(id) = id {
if !cx.access_levels.is_exported(id) {
return;
}
}
......@@ -470,7 +470,7 @@ fn get_lints(&self) -> LintArray {
impl LateLintPass for MissingCopyImplementations {
fn check_item(&mut self, cx: &LateContext, item: &hir::Item) {
if !cx.exported_items.contains(&item.id) {
if !cx.access_levels.is_reachable(item.id) {
return;
}
let (def, ty) = match item.node {
......@@ -534,7 +534,7 @@ fn get_lints(&self) -> LintArray {
impl LateLintPass for MissingDebugImplementations {
fn check_item(&mut self, cx: &LateContext, item: &hir::Item) {
if !cx.exported_items.contains(&item.id) {
if !cx.access_levels.is_reachable(item.id) {
return;
}
......@@ -987,7 +987,7 @@ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
match it.node {
hir::ItemFn(..) => {
if attr::contains_name(&it.attrs, "no_mangle") &&
!cx.exported_items.contains(&it.id) {
!cx.access_levels.is_reachable(it.id) {
let msg = format!("function {} is marked #[no_mangle], but not exported",
it.name);
cx.span_lint(PRIVATE_NO_MANGLE_FNS, it.span, &msg);
......@@ -995,7 +995,7 @@ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
},
hir::ItemStatic(..) => {
if attr::contains_name(&it.attrs, "no_mangle") &&
!cx.exported_items.contains(&it.id) {
!cx.access_levels.is_reachable(it.id) {
let msg = format!("static {} is marked #[no_mangle], but not exported",
it.name);
cx.span_lint(PRIVATE_NO_MANGLE_STATICS, it.span, &msg);
......
......@@ -32,6 +32,7 @@
use self::PrivacyResult::*;
use self::FieldName::*;
use std::cmp;
use std::mem::replace;
use rustc_front::hir;
......@@ -39,12 +40,13 @@
use rustc::middle::def;
use rustc::middle::def_id::DefId;
use rustc::middle::privacy::{AccessLevel, AccessLevels};
use rustc::middle::privacy::ImportUse::*;
use rustc::middle::privacy::LastPrivate::*;
use rustc::middle::privacy::PrivateDep::*;
use rustc::middle::privacy::{ExternalExports, ExportedItems, PublicItems};
use rustc::middle::privacy::ExternalExports;
use rustc::middle::ty::{self, Ty};
use rustc::util::nodemap::{NodeMap, NodeSet};
use rustc::util::nodemap::NodeMap;
use rustc::front::map as ast_map;
use syntax::ast;
......@@ -159,64 +161,57 @@ struct EmbargoVisitor<'a, 'tcx: 'a> {
tcx: &'a ty::ctxt<'tcx>,
export_map: &'a def::ExportMap,
// This flag is an indicator of whether the previous item in the
// hierarchical chain was exported or not. This is the indicator of whether
// children should be exported as well. Note that this can flip from false
// to true if a reexported module is entered (or an action similar).
prev_exported: bool,
// This is a list of all exported items in the AST. An exported item is any
// function/method/item which is usable by external crates. This essentially
// means that the result is "public all the way down", but the "path down"
// may jump across private boundaries through reexport statements or type aliases.
exported_items: ExportedItems,
// Items that are directly public without help of reexports or type aliases.
// These two fields are closely related to one another in that they are only
// used for generation of the `public_items` set, not for privacy checking at
// all. Invariant: at any moment public items are a subset of exported items.
public_items: PublicItems,
prev_public: bool,
// Accessibility levels for reachable nodes
access_levels: AccessLevels,
// Previous accessibility level, None means unreachable
prev_level: Option<AccessLevel>,
// Have something changed in the level map?
changed: bool,
}
impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> {
// Returns tuple (is_public, is_exported) for a type
fn is_public_exported_ty(&self, ty: &hir::Ty) -> (bool, bool) {
fn ty_level(&self, ty: &hir::Ty) -> Option<AccessLevel> {
if let hir::TyPath(..) = ty.node {
match self.tcx.def_map.borrow().get(&ty.id).unwrap().full_def() {
def::DefPrimTy(..) | def::DefSelfTy(..) | def::DefTyParam(..) => {
(true, true)
Some(AccessLevel::Public)
}
def => {
if let Some(node_id) = self.tcx.map.as_local_node_id(def.def_id()) {
(self.public_items.contains(&node_id),
self.exported_items.contains(&node_id))
self.get(node_id)
} else {
(true, true)
Some(AccessLevel::Public)
}
}
}
} else {
(true, true)
Some(AccessLevel::Public)
}
}
// Returns tuple (is_public, is_exported) for a trait
fn is_public_exported_trait(&self, trait_ref: &hir::TraitRef) -> (bool, bool) {
fn trait_level(&self, trait_ref: &hir::TraitRef) -> Option<AccessLevel> {
let did = self.tcx.trait_ref_to_def_id(trait_ref);
if let Some(node_id) = self.tcx.map.as_local_node_id(did) {
(self.public_items.contains(&node_id), self.exported_items.contains(&node_id))
self.get(node_id)
} else {
(true, true)
Some(AccessLevel::Public)
}
}
fn maybe_insert_id(&mut self, id: ast::NodeId) {
if self.prev_public {
self.public_items.insert(id);
}
if self.prev_exported {
self.exported_items.insert(id);
fn get(&self, id: ast::NodeId) -> Option<AccessLevel> {
self.access_levels.map.get(&id).cloned()
}
// Updates node level and returns the updated level
fn update(&mut self, id: ast::NodeId, level: Option<AccessLevel>) -> Option<AccessLevel> {
let old_level = self.get(id);
// Accessibility levels can only grow
if level > old_level {
self.access_levels.map.insert(id, level.unwrap());
self.changed = true;
level
} else {
old_level
}
}
}
......@@ -227,187 +222,126 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
fn visit_nested_item(&mut self, item: hir::ItemId) {
self.visit_item(self.tcx.map.expect_item(item.id))
}
fn visit_item(&mut self, item: &hir::Item) {
let orig_all_public = self.prev_public;
let orig_all_exported = self.prev_exported;
match item.node {
// impls/extern blocks do not break the "public chain" because they
// cannot have visibility qualifiers on them anyway. Impls are also not
// added to public/exported sets based on inherited publicity.
hir::ItemImpl(..) | hir::ItemDefaultImpl(..) => {}
let inherited_item_level = match item.node {
// Impls inherit level from their types and traits
hir::ItemImpl(_, _, _, None, ref ty, _) => {
self.ty_level(&ty)
}
hir::ItemImpl(_, _, _, Some(ref trait_ref), ref ty, _) => {
cmp::min(self.ty_level(&ty), self.trait_level(trait_ref))
}
hir::ItemDefaultImpl(_, ref trait_ref) => {
self.trait_level(trait_ref)
}
// Foreign mods inherit level from parents
hir::ItemForeignMod(..) => {
self.maybe_insert_id(item.id);
self.prev_level
}
// Private by default, hence we only retain the "public chain" if
// `pub` is explicitly listed.
// Other `pub` items inherit levels from parents
_ => {
self.prev_public = self.prev_public && item.vis == hir::Public;
self.prev_exported = (self.prev_exported && item.vis == hir::Public) ||
self.exported_items.contains(&item.id);
self.maybe_insert_id(item.id);
if item.vis == hir::Public { self.prev_level } else { None }
}
}
};
// Update id of the item itself
let item_level = self.update(item.id, inherited_item_level);
// Update ids of nested things
match item.node {
// Enum variants inherit from their parent, so if the enum is
// public all variants are public
hir::ItemEnum(ref def, _) => {
for variant in &def.variants {
self.maybe_insert_id(variant.node.data.id());
let variant_level = self.update(variant.node.data.id(), item_level);
for field in variant.node.data.fields() {
// Variant fields are always public
self.maybe_insert_id(field.node.id);
self.update(field.node.id, variant_level);
}
}
}
// Inherent impls for public/exported types and their public items are public/exported
hir::ItemImpl(_, _, _, None, ref ty, ref impl_items) => {
let (public_ty, exported_ty) = self.is_public_exported_ty(&ty);
if public_ty {
self.public_items.insert(item.id);
}
if exported_ty {
self.exported_items.insert(item.id);
}
hir::ItemImpl(_, _, _, None, _, ref impl_items) => {
for impl_item in impl_items {
if impl_item.vis == hir::Public {
if public_ty {
self.public_items.insert(impl_item.id);
}
if exported_ty {
self.exported_items.insert(impl_item.id);
}
self.update(impl_item.id, item_level);
}
}
}
// Trait impl and its items are public/exported if both the self type and the trait
// of this impl are public/exported
hir::ItemImpl(_, _, _, Some(ref trait_ref), ref ty, ref impl_items) => {
let (public_ty, exported_ty) = self.is_public_exported_ty(&ty);
let (public_trait, exported_trait) = self.is_public_exported_trait(trait_ref);
if public_ty && public_trait {
self.public_items.insert(item.id);
}
if exported_ty && exported_trait {
self.exported_items.insert(item.id);
}
hir::ItemImpl(_, _, _, Some(_), _, ref impl_items) => {
for impl_item in impl_items {
if public_ty && public_trait {
self.public_items.insert(impl_item.id);
}
if exported_ty && exported_trait {
self.exported_items.insert(impl_item.id);
}
}
}
// Default trait impls are public/exported for public/exported traits
hir::ItemDefaultImpl(_, ref trait_ref) => {
let (public_trait, exported_trait) = self.is_public_exported_trait(trait_ref);
if public_trait {
self.public_items.insert(item.id);
}
if exported_trait {
self.exported_items.insert(item.id);
self.update(impl_item.id, item_level);
}
}
// Default methods on traits are all public/exported so long as the trait
// is public/exported
hir::ItemTrait(_, _, _, ref trait_items) => {
for trait_item in trait_items {
self.maybe_insert_id(trait_item.id);
self.update(trait_item.id, item_level);
}
}
// Struct constructors are public if the struct is all public.
hir::ItemStruct(ref def, _) => {
if !def.is_struct() {
self.maybe_insert_id(def.id());
self.update(def.id(), item_level);
}
for field in def.fields() {
// Struct fields can be public or private, so lets check
if field.node.kind.visibility() == hir::Public {
self.maybe_insert_id(field.node.id);
self.update(field.node.id, item_level);
}
}
}
hir::ItemTy(ref ty, _) if self.prev_exported => {
hir::ItemForeignMod(ref foreign_mod) => {
for foreign_item in &foreign_mod.items {
if foreign_item.vis == hir::Public {
self.update(foreign_item.id, item_level);
}
}
}
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::DefPrimTy(..) | def::DefSelfTy(..) | def::DefTyParam(..) => {},
def => {
if let Some(node_id) = self.tcx.map.as_local_node_id(def.def_id()) {
self.exported_items.insert(node_id);
self.update(node_id, Some(AccessLevel::Reachable));
}
}
}
}
}
hir::ItemForeignMod(ref foreign_mod) => {
for foreign_item in &foreign_mod.items {
let public = self.prev_public && foreign_item.vis == hir::Public;
let exported = (self.prev_exported && foreign_item.vis == hir::Public) ||
self.exported_items.contains(&foreign_item.id);
if public {
self.public_items.insert(foreign_item.id);
}
if exported {
self.exported_items.insert(foreign_item.id);
}
}
}
_ => {}
}
let orig_level = self.prev_level;
self.prev_level = item_level;
intravisit::walk_item(self, item);
self.prev_public = orig_all_public;
self.prev_exported = orig_all_exported;
self.prev_level = orig_level;
}
fn visit_block(&mut self, b: &'v hir::Block) {
let orig_all_public = replace(&mut self.prev_public, false);
let orig_all_exported = replace(&mut self.prev_exported, false);
let orig_level = replace(&mut self.prev_level, None);
// Blocks can have exported and public items, for example impls, but they always
// start as non-public and non-exported regardless of publicity of a function,
// Blocks can have public items, for example impls, but they always
// start as completely private regardless of publicity of a function,
// constant, type, field, etc. in which this block resides
intravisit::walk_block(self, b);
self.prev_public = orig_all_public;
self.prev_exported = orig_all_exported;
self.prev_level = orig_level;
}
fn visit_mod(&mut self, m: &hir::Mod, _sp: Span, id: ast::NodeId) {
// This code is here instead of in visit_item so that the
// crate module gets processed as well.
if self.prev_exported {
assert!(self.export_map.contains_key(&id), "wut {}", id);
for export in self.export_map.get(&id).unwrap() {
if self.prev_level.is_some() {
for export in self.export_map.get(&id).expect("module isn't found in export map") {
if let Some(node_id) = self.tcx.map.as_local_node_id(export.def_id) {
self.exported_items.insert(node_id);
self.update(node_id, Some(AccessLevel::Exported));
}
}
}
intravisit::walk_mod(self, m)
intravisit::walk_mod(self, m);
}
fn visit_macro_def(&mut self, md: &'v hir::MacroDef) {
self.maybe_insert_id(md.id);
self.update(md.id, Some(AccessLevel::Public));
}
}
......@@ -1169,8 +1103,7 @@ fn check_all_inherited(&self, item: &hir::Item) {
struct VisiblePrivateTypesVisitor<'a, 'tcx: 'a> {
tcx: &'a ty::ctxt<'tcx>,
exported_items: &'a ExportedItems,
public_items: &'a PublicItems,
access_levels: &'a AccessLevels,
in_variant: bool,
}
......@@ -1210,7 +1143,7 @@ fn path_is_private_type(&self, path_id: ast::NodeId) -> bool {
fn trait_is_public(&self, trait_id: ast::NodeId) -> bool {
// FIXME: this would preferably be using `exported_items`, but all
// traits are exported currently (see `EmbargoVisitor.exported_trait`)
self.public_items.contains(&trait_id)
self.access_levels.is_public(trait_id)
}
fn check_ty_param_bound(&self,
......@@ -1226,7 +1159,7 @@ fn check_ty_param_bound(&self,
}
fn item_is_public(&self, id: &ast::NodeId, vis: hir::Visibility) -> bool {
self.exported_items.contains(id) || vis == hir::Public
self.access_levels.is_reachable(*id) || vis == hir::Public
}
}
......@@ -1332,7 +1265,7 @@ fn visit_item(&mut self, item: &hir::Item) {
match impl_item.node {
hir::ImplItemKind::Const(..) |
hir::ImplItemKind::Method(..) => {
self.exported_items.contains(&impl_item.id)
self.access_levels.is_reachable(impl_item.id)
}
hir::ImplItemKind::Type(_) => false,
}
......@@ -1461,7 +1394,7 @@ fn visit_generics(&mut self, generics: &hir::Generics) {
}
fn visit_foreign_item(&mut self, item: &hir::ForeignItem) {
if self.exported_items.contains(&item.id) {
if self.access_levels.is_reachable(item.id) {
intravisit::walk_foreign_item(self, item)
}
}
......@@ -1479,7 +1412,7 @@ fn visit_ty(&mut self, t: &hir::Ty) {
}
fn visit_variant(&mut self, v: &hir::Variant, g: &hir::Generics, item_id: ast::NodeId) {
if self.exported_items.contains(&v.node.data.id()) {
if self.access_levels.is_reachable(v.node.data.id()) {
self.in_variant = true;
intravisit::walk_variant(self, v, g, item_id);
self.in_variant = false;
......@@ -1509,7 +1442,7 @@ fn visit_expr(&mut self, _: &hir::Expr) {}
pub fn check_crate(tcx: &ty::ctxt,
export_map: &def::ExportMap,
external_exports: ExternalExports)
-> (ExportedItems, PublicItems) {
-> AccessLevels {
let krate = tcx.map.krate();
// Sanity check to make sure that all privacy usage and controls are
......@@ -1544,33 +1477,31 @@ pub fn check_crate(tcx: &ty::ctxt,
// items which are reachable from external crates based on visibility.
let mut visitor = EmbargoVisitor {
tcx: tcx,
exported_items: NodeSet(),
public_items: NodeSet(),
export_map: export_map,
prev_exported: true,
prev_public: true,
access_levels: Default::default(),
prev_level: Some(AccessLevel::Public),
changed: false,
};
visitor.exported_items.insert(ast::CRATE_NODE_ID);
visitor.public_items.insert(ast::CRATE_NODE_ID);
loop {
let before = (visitor.exported_items.len(), visitor.public_items.len());
intravisit::walk_crate(&mut visitor, krate);
let after = (visitor.exported_items.len(), visitor.public_items.len());
if after == before {
if visitor.changed {
visitor.changed = false;
} else {
break
}
}
visitor.update(ast::CRATE_NODE_ID, Some(AccessLevel::Public));
let EmbargoVisitor { exported_items, public_items, .. } = visitor;
let EmbargoVisitor { access_levels, .. } = visitor;
{
let mut visitor = VisiblePrivateTypesVisitor {
tcx: tcx,
exported_items: &exported_items,
public_items: &public_items,
access_levels: &access_levels,
in_variant: false,
};
intravisit::walk_crate(&mut visitor, krate);
}
return (exported_items, public_items);
access_levels
}
......@@ -13,10 +13,10 @@
use rustc_driver::{driver, target_features};
use rustc::session::{self, config};
use rustc::middle::def_id::DefId;
use rustc::middle::privacy::AccessLevels;
use rustc::middle::ty;
use rustc::front::map as hir_map;
use rustc::lint;
use rustc::util::nodemap::DefIdSet;
use rustc_trans::back::link;
use rustc_resolve as resolve;
use rustc_front::lowering::{lower_crate, LoweringContext};
......@@ -77,8 +77,7 @@ pub fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> {
}
pub struct CrateAnalysis {
pub exported_items: DefIdSet,
pub public_items: DefIdSet,
pub access_levels: AccessLevels<DefId>,
pub external_paths: ExternalPaths,
pub external_typarams: RefCell<Option<HashMap<DefId, String>>>,
pub inlined: RefCell<Option<HashSet<DefId>>>,
......@@ -147,18 +146,15 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec<String>, externs: Externs,
&name,
resolve::MakeGlobMap::No,
|tcx, _, analysis| {
let ty::CrateAnalysis { exported_items, public_items, .. } = analysis;
let ty::CrateAnalysis { access_levels, .. } = analysis;
// Convert from a NodeId set to a DefId set since we don't always have easy access
// to the map from defid -> nodeid
let exported_items: DefIdSet =
exported_items.into_iter()
.map(|n| tcx.map.local_def_id(n))
.collect();
let public_items: DefIdSet =
public_items.into_iter()
.map(|n| tcx.map.local_def_id(n))
.collect();
let access_levels = AccessLevels {
map: access_levels.map.into_iter()
.map(|(k, v)| (tcx.map.local_def_id(k), v))
.collect()
};
let ctxt = DocContext {
map: &tcx.map,
......@@ -174,8 +170,7 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec<String>, externs: Externs,
debug!("crate: {:?}", ctxt.map.krate());
let mut analysis = CrateAnalysis {
exported_items: exported_items,
public_items: public_items,
access_levels: access_levels,
external_paths: RefCell::new(None),
external_typarams: RefCell::new(None),
inlined: RefCell::new(None),
......
......@@ -56,8 +56,8 @@
use syntax::{abi, ast};
use rustc::metadata::cstore::LOCAL_CRATE;
use rustc::middle::def_id::{CRATE_DEF_INDEX, DefId};
use rustc::middle::privacy::AccessLevels;
use rustc::middle::stability;
use rustc::util::nodemap::DefIdSet;
use rustc_front::hir;
use clean::{self, SelfTy};
......@@ -244,7 +244,7 @@ pub struct Cache {
search_index: Vec<IndexItem>,
privmod: bool,
remove_priv: bool,
public_items: DefIdSet,
access_levels: AccessLevels<DefId>,
deref_trait_did: Option<DefId>,
// In rare case where a structure is defined in one module but implemented
......@@ -415,8 +415,8 @@ pub fn run(mut krate: clean::Crate,
// Crawl the crate to build various caches used for the output
let analysis = ::ANALYSISKEY.with(|a| a.clone());
let analysis = analysis.borrow();
let public_items = analysis.as_ref().map(|a| a.public_items.clone());
let public_items = public_items.unwrap_or(DefIdSet());
let access_levels = analysis.as_ref().map(|a| a.access_levels.clone());
let access_levels = access_levels.unwrap_or(Default::default());
let paths: HashMap<DefId, (Vec<String>, ItemType)> =
analysis.as_ref().map(|a| {
let paths = a.external_paths.borrow_mut().take().unwrap();
......@@ -435,7 +435,7 @@ pub fn run(mut krate: clean::Crate,
primitive_locations: HashMap::new(),
remove_priv: cx.passes.contains("strip-private"),
privmod: false,
public_items: public_items,
access_levels: access_levels,
orphan_methods: Vec::new(),
traits: mem::replace(&mut krate.external_traits, HashMap::new()),
deref_trait_did: analysis.as_ref().and_then(|a| a.deref_trait_did),
......@@ -1053,7 +1053,7 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
if
!self.paths.contains_key(&item.def_id) ||
!item.def_id.is_local() ||
self.public_items.contains(&item.def_id)
self.access_levels.is_public(item.def_id)
{
self.paths.insert(item.def_id,
(self.stack.clone(), shortty(&item)));
......
......@@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use rustc::middle::def_id::DefId;
use rustc::middle::privacy::AccessLevels;
use rustc::util::nodemap::DefIdSet;
use std::cmp;
use std::string::String;
......@@ -96,13 +98,13 @@ pub fn strip_private(mut krate: clean::Crate) -> plugins::PluginResult {
let analysis = super::ANALYSISKEY.with(|a| a.clone());
let analysis = analysis.borrow();
let analysis = analysis.as_ref().unwrap();
let exported_items = analysis.exported_items.clone();
let access_levels = analysis.access_levels.clone();
// strip all private items
{
let mut stripper = Stripper {
retained: &mut retained,
exported_items: &exported_items,
access_levels: &access_levels,
};
krate = stripper.fold_crate(krate);
}
......@@ -117,7 +119,7 @@ pub fn strip_private(mut krate: clean::Crate) -> plugins::PluginResult {
struct Stripper<'a> {
retained: &'a mut DefIdSet,
exported_items: &'a DefIdSet,
access_levels: &'a AccessLevels<DefId>,
}
impl<'a> fold::DocFolder for Stripper<'a> {
......@@ -130,18 +132,14 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
clean::VariantItem(..) | clean::MethodItem(..) |
clean::ForeignFunctionItem(..) | clean::ForeignStaticItem(..) => {
if i.def_id.is_local() {
if !self.exported_items.contains(&i.def_id) {
return None;
}
// Traits are in exported_items even when they're totally private.
if i.is_trait() && i.visibility != Some(hir::Public) {
if !self.access_levels.is_exported(i.def_id) {
return None;
}
}
}
clean::ConstantItem(..) => {
if i.def_id.is_local() && !self.exported_items.contains(&i.def_id) {
if i.def_id.is_local() && !self.access_levels.is_exported(i.def_id) {
return None;
}
}
......@@ -168,7 +166,7 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
clean::ImplItem(clean::Impl{
for_: clean::ResolvedPath{ did, .. }, ..
}) => {
if did.is_local() && !self.exported_items.contains(&did) {
if did.is_local() && !self.access_levels.is_exported(did) {
return None;
}
}
......
......@@ -214,7 +214,7 @@ fn resolve_id(&mut self, id: ast::NodeId, renamed: Option<ast::Name>,
let analysis = match self.analysis {
Some(analysis) => analysis, None => return false
};
if !please_inline && analysis.public_items.contains(&def) {
if !please_inline && analysis.access_levels.is_public(def) {
return false
}
if !self.view_item_stack.insert(def_node_id) { return false }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册