Changes to data produced by privacy pass
This commit is contained in:
parent
3e48b0e380
commit
c1ad5af4a6
@ -25,7 +25,7 @@
|
|||||||
//! for all lint attributes.
|
//! for all lint attributes.
|
||||||
use self::TargetLint::*;
|
use self::TargetLint::*;
|
||||||
|
|
||||||
use middle::privacy::ExportedItems;
|
use middle::privacy::AccessLevels;
|
||||||
use middle::ty::{self, Ty};
|
use middle::ty::{self, Ty};
|
||||||
use session::{early_error, Session};
|
use session::{early_error, Session};
|
||||||
use lint::{Level, LevelSource, Lint, LintId, LintArray, LintPass};
|
use lint::{Level, LevelSource, Lint, LintId, LintArray, LintPass};
|
||||||
@ -277,8 +277,8 @@ pub struct LateContext<'a, 'tcx: 'a> {
|
|||||||
/// The crate being checked.
|
/// The crate being checked.
|
||||||
pub krate: &'a hir::Crate,
|
pub krate: &'a hir::Crate,
|
||||||
|
|
||||||
/// Items exported from the crate being checked.
|
/// Items accessible from the crate being checked.
|
||||||
pub exported_items: &'a ExportedItems,
|
pub access_levels: &'a AccessLevels,
|
||||||
|
|
||||||
/// The store of registered lints.
|
/// The store of registered lints.
|
||||||
lints: LintStore,
|
lints: LintStore,
|
||||||
@ -564,7 +564,7 @@ impl<'a> EarlyContext<'a> {
|
|||||||
impl<'a, 'tcx> LateContext<'a, 'tcx> {
|
impl<'a, 'tcx> LateContext<'a, 'tcx> {
|
||||||
fn new(tcx: &'a ty::ctxt<'tcx>,
|
fn new(tcx: &'a ty::ctxt<'tcx>,
|
||||||
krate: &'a hir::Crate,
|
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.
|
// 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(),
|
let lint_store = mem::replace(&mut *tcx.sess.lint_store.borrow_mut(),
|
||||||
LintStore::new());
|
LintStore::new());
|
||||||
@ -572,7 +572,7 @@ impl<'a, 'tcx> LateContext<'a, 'tcx> {
|
|||||||
LateContext {
|
LateContext {
|
||||||
tcx: tcx,
|
tcx: tcx,
|
||||||
krate: krate,
|
krate: krate,
|
||||||
exported_items: exported_items,
|
access_levels: access_levels,
|
||||||
lints: lint_store,
|
lints: lint_store,
|
||||||
level_stack: vec![],
|
level_stack: vec![],
|
||||||
node_levels: RefCell::new(FnvHashMap()),
|
node_levels: RefCell::new(FnvHashMap()),
|
||||||
@ -1014,10 +1014,9 @@ impl LateLintPass for GatherNodeLevels {
|
|||||||
/// Perform lint checking on a crate.
|
/// Perform lint checking on a crate.
|
||||||
///
|
///
|
||||||
/// Consumes the `lint_store` field of the `Session`.
|
/// Consumes the `lint_store` field of the `Session`.
|
||||||
pub fn check_crate(tcx: &ty::ctxt,
|
pub fn check_crate(tcx: &ty::ctxt, access_levels: &AccessLevels) {
|
||||||
exported_items: &ExportedItems) {
|
|
||||||
let krate = tcx.map.krate();
|
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.
|
// Visit the whole crate.
|
||||||
cx.with_lint_attrs(&krate.attrs, |cx| {
|
cx.with_lint_attrs(&krate.attrs, |cx| {
|
||||||
|
@ -19,7 +19,6 @@ use rustc_front::intravisit::{self, Visitor};
|
|||||||
use middle::{def, pat_util, privacy, ty};
|
use middle::{def, pat_util, privacy, ty};
|
||||||
use middle::def_id::{DefId};
|
use middle::def_id::{DefId};
|
||||||
use lint;
|
use lint;
|
||||||
use util::nodemap::NodeSet;
|
|
||||||
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use syntax::{ast, codemap};
|
use syntax::{ast, codemap};
|
||||||
@ -370,25 +369,10 @@ impl<'v> Visitor<'v> for LifeSeeder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn create_and_seed_worklist(tcx: &ty::ctxt,
|
fn create_and_seed_worklist(tcx: &ty::ctxt,
|
||||||
exported_items: &privacy::ExportedItems,
|
access_levels: &privacy::AccessLevels,
|
||||||
reachable_symbols: &NodeSet,
|
|
||||||
krate: &hir::Crate) -> Vec<ast::NodeId> {
|
krate: &hir::Crate) -> Vec<ast::NodeId> {
|
||||||
let mut worklist = Vec::new();
|
let mut worklist = Vec::new();
|
||||||
|
for (id, _) in &access_levels.map {
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
worklist.push(*id);
|
worklist.push(*id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -408,12 +392,10 @@ fn create_and_seed_worklist(tcx: &ty::ctxt,
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn find_live(tcx: &ty::ctxt,
|
fn find_live(tcx: &ty::ctxt,
|
||||||
exported_items: &privacy::ExportedItems,
|
access_levels: &privacy::AccessLevels,
|
||||||
reachable_symbols: &NodeSet,
|
|
||||||
krate: &hir::Crate)
|
krate: &hir::Crate)
|
||||||
-> Box<HashSet<ast::NodeId>> {
|
-> Box<HashSet<ast::NodeId>> {
|
||||||
let worklist = create_and_seed_worklist(tcx, exported_items,
|
let worklist = create_and_seed_worklist(tcx, access_levels, krate);
|
||||||
reachable_symbols, krate);
|
|
||||||
let mut symbol_visitor = MarkSymbolVisitor::new(tcx, worklist);
|
let mut symbol_visitor = MarkSymbolVisitor::new(tcx, worklist);
|
||||||
symbol_visitor.mark_live_symbols();
|
symbol_visitor.mark_live_symbols();
|
||||||
symbol_visitor.live_symbols
|
symbol_visitor.live_symbols
|
||||||
@ -607,12 +589,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_crate(tcx: &ty::ctxt,
|
pub fn check_crate(tcx: &ty::ctxt, access_levels: &privacy::AccessLevels) {
|
||||||
exported_items: &privacy::ExportedItems,
|
|
||||||
reachable_symbols: &NodeSet) {
|
|
||||||
let krate = tcx.map.krate();
|
let krate = tcx.map.krate();
|
||||||
let live_symbols = find_live(tcx, exported_items,
|
let live_symbols = find_live(tcx, access_levels, krate);
|
||||||
reachable_symbols, krate);
|
|
||||||
let mut visitor = DeadVisitor { tcx: tcx, live_symbols: live_symbols };
|
let mut visitor = DeadVisitor { tcx: tcx, live_symbols: live_symbols };
|
||||||
intravisit::walk_crate(&mut visitor, krate);
|
intravisit::walk_crate(&mut visitor, krate);
|
||||||
}
|
}
|
||||||
|
@ -17,20 +17,54 @@ pub use self::ImportUse::*;
|
|||||||
pub use self::LastPrivate::*;
|
pub use self::LastPrivate::*;
|
||||||
|
|
||||||
use middle::def_id::DefId;
|
use middle::def_id::DefId;
|
||||||
use util::nodemap::{DefIdSet, NodeSet};
|
use util::nodemap::{DefIdSet, FnvHashMap};
|
||||||
|
|
||||||
/// A set of AST nodes exported by the crate.
|
use std::hash::Hash;
|
||||||
pub type ExportedItems = NodeSet;
|
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.
|
/// A set containing all exported definitions from external crates.
|
||||||
/// The set does not contain any entries from local crates.
|
/// The set does not contain any entries from local crates.
|
||||||
pub type ExternalExports = DefIdSet;
|
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)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub enum LastPrivate {
|
pub enum LastPrivate {
|
||||||
LastMod(PrivateDep),
|
LastMod(PrivateDep),
|
||||||
|
@ -329,7 +329,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
|
|||||||
// trait items are used from inlinable code through method call syntax or UFCS, or their
|
// trait items are used from inlinable code through method call syntax or UFCS, or their
|
||||||
// trait is a lang item.
|
// trait is a lang item.
|
||||||
struct CollectPrivateImplItemsVisitor<'a> {
|
struct CollectPrivateImplItemsVisitor<'a> {
|
||||||
exported_items: &'a privacy::ExportedItems,
|
access_levels: &'a privacy::AccessLevels,
|
||||||
worklist: &'a mut Vec<ast::NodeId>,
|
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) {
|
fn visit_item(&mut self, item: &hir::Item) {
|
||||||
// We need only trait impls here, not inherent impls, and only non-exported ones
|
// 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 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 {
|
for impl_item in impl_items {
|
||||||
self.worklist.push(impl_item.id);
|
self.worklist.push(impl_item.id);
|
||||||
}
|
}
|
||||||
@ -347,7 +347,7 @@ impl<'a, 'v> Visitor<'v> for CollectPrivateImplItemsVisitor<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_reachable(tcx: &ty::ctxt,
|
pub fn find_reachable(tcx: &ty::ctxt,
|
||||||
exported_items: &privacy::ExportedItems)
|
access_levels: &privacy::AccessLevels)
|
||||||
-> NodeSet {
|
-> NodeSet {
|
||||||
|
|
||||||
let mut reachable_context = ReachableContext::new(tcx);
|
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
|
// 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
|
// use the lang items, so we need to be sure to mark them as
|
||||||
// exported.
|
// exported.
|
||||||
for id in exported_items {
|
for (id, _) in &access_levels.map {
|
||||||
reachable_context.worklist.push(*id);
|
reachable_context.worklist.push(*id);
|
||||||
}
|
}
|
||||||
for (_, item) in tcx.lang_items.items() {
|
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 {
|
let mut collect_private_impl_items = CollectPrivateImplItemsVisitor {
|
||||||
exported_items: exported_items,
|
access_levels: access_levels,
|
||||||
worklist: &mut reachable_context.worklist,
|
worklist: &mut reachable_context.worklist,
|
||||||
};
|
};
|
||||||
tcx.map.krate().visit_all_items(&mut collect_private_impl_items);
|
tcx.map.krate().visit_all_items(&mut collect_private_impl_items);
|
||||||
|
@ -19,7 +19,7 @@ use metadata::cstore::LOCAL_CRATE;
|
|||||||
use middle::def;
|
use middle::def;
|
||||||
use middle::def_id::{CRATE_DEF_INDEX, DefId};
|
use middle::def_id::{CRATE_DEF_INDEX, DefId};
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use middle::privacy::PublicItems;
|
use middle::privacy::AccessLevels;
|
||||||
use metadata::csearch;
|
use metadata::csearch;
|
||||||
use syntax::parse::token::InternedString;
|
use syntax::parse::token::InternedString;
|
||||||
use syntax::codemap::{Span, DUMMY_SP};
|
use syntax::codemap::{Span, DUMMY_SP};
|
||||||
@ -73,7 +73,7 @@ struct Annotator<'a, 'tcx: 'a> {
|
|||||||
tcx: &'a ty::ctxt<'tcx>,
|
tcx: &'a ty::ctxt<'tcx>,
|
||||||
index: &'a mut Index<'tcx>,
|
index: &'a mut Index<'tcx>,
|
||||||
parent: Option<&'tcx Stability>,
|
parent: Option<&'tcx Stability>,
|
||||||
export_map: &'a PublicItems,
|
access_levels: &'a AccessLevels,
|
||||||
in_trait_impl: bool,
|
in_trait_impl: bool,
|
||||||
in_enum: bool,
|
in_enum: bool,
|
||||||
}
|
}
|
||||||
@ -143,7 +143,7 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> {
|
|||||||
} else {
|
} else {
|
||||||
debug!("annotate: not found, parent = {:?}", self.parent);
|
debug!("annotate: not found, parent = {:?}", self.parent);
|
||||||
let mut is_error = kind == AnnotationKind::Required &&
|
let mut is_error = kind == AnnotationKind::Required &&
|
||||||
self.export_map.contains(&id) &&
|
self.access_levels.is_reachable(id) &&
|
||||||
!self.tcx.sess.opts.test;
|
!self.tcx.sess.opts.test;
|
||||||
if let Some(stab) = self.parent {
|
if let Some(stab) = self.parent {
|
||||||
if stab.level.is_unstable() {
|
if stab.level.is_unstable() {
|
||||||
@ -266,12 +266,12 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Annotator<'a, 'tcx> {
|
|||||||
|
|
||||||
impl<'tcx> Index<'tcx> {
|
impl<'tcx> Index<'tcx> {
|
||||||
/// Construct the stability index for a crate being compiled.
|
/// 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 {
|
let mut annotator = Annotator {
|
||||||
tcx: tcx,
|
tcx: tcx,
|
||||||
index: self,
|
index: self,
|
||||||
parent: None,
|
parent: None,
|
||||||
export_map: export_map,
|
access_levels: access_levels,
|
||||||
in_trait_impl: false,
|
in_trait_impl: false,
|
||||||
in_enum: false,
|
in_enum: false,
|
||||||
};
|
};
|
||||||
|
@ -104,14 +104,12 @@ pub const INITIAL_DISCRIMINANT_VALUE: Disr = 0;
|
|||||||
/// produced by the driver and fed to trans and later passes.
|
/// produced by the driver and fed to trans and later passes.
|
||||||
pub struct CrateAnalysis<'a> {
|
pub struct CrateAnalysis<'a> {
|
||||||
pub export_map: ExportMap,
|
pub export_map: ExportMap,
|
||||||
pub exported_items: middle::privacy::ExportedItems,
|
pub access_levels: middle::privacy::AccessLevels,
|
||||||
pub public_items: middle::privacy::PublicItems,
|
|
||||||
pub reachable: NodeSet,
|
pub reachable: NodeSet,
|
||||||
pub name: &'a str,
|
pub name: &'a str,
|
||||||
pub glob_map: Option<GlobMap>,
|
pub glob_map: Option<GlobMap>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub enum DtorKind {
|
pub enum DtorKind {
|
||||||
NoDtor,
|
NoDtor,
|
||||||
|
@ -746,7 +746,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
|
|||||||
"const checking",
|
"const checking",
|
||||||
|| middle::check_const::check_crate(tcx));
|
|| middle::check_const::check_crate(tcx));
|
||||||
|
|
||||||
let (exported_items, public_items) =
|
let access_levels =
|
||||||
time(time_passes, "privacy checking", || {
|
time(time_passes, "privacy checking", || {
|
||||||
rustc_privacy::check_crate(tcx,
|
rustc_privacy::check_crate(tcx,
|
||||||
&export_map,
|
&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
|
// Do not move this check past lint
|
||||||
time(time_passes, "stability index", || {
|
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,
|
time(time_passes,
|
||||||
@ -807,12 +807,10 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
|
|||||||
let reachable_map =
|
let reachable_map =
|
||||||
time(time_passes,
|
time(time_passes,
|
||||||
"reachability checking",
|
"reachability checking",
|
||||||
|| reachable::find_reachable(tcx, &exported_items));
|
|| reachable::find_reachable(tcx, &access_levels));
|
||||||
|
|
||||||
time(time_passes, "death checking", || {
|
time(time_passes, "death checking", || {
|
||||||
middle::dead::check_crate(tcx,
|
middle::dead::check_crate(tcx, &access_levels);
|
||||||
&exported_items,
|
|
||||||
&reachable_map)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let ref lib_features_used =
|
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,
|
time(time_passes,
|
||||||
"lint checking",
|
"lint checking",
|
||||||
|| lint::check_crate(tcx, &exported_items));
|
|| lint::check_crate(tcx, &access_levels));
|
||||||
|
|
||||||
// The above three passes generate errors w/o aborting
|
// The above three passes generate errors w/o aborting
|
||||||
tcx.sess.abort_if_errors();
|
tcx.sess.abort_if_errors();
|
||||||
@ -836,8 +834,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
|
|||||||
mir_map,
|
mir_map,
|
||||||
ty::CrateAnalysis {
|
ty::CrateAnalysis {
|
||||||
export_map: export_map,
|
export_map: export_map,
|
||||||
exported_items: exported_items,
|
access_levels: access_levels,
|
||||||
public_items: public_items,
|
|
||||||
reachable: reachable_map,
|
reachable: reachable_map,
|
||||||
name: name,
|
name: name,
|
||||||
glob_map: glob_map,
|
glob_map: glob_map,
|
||||||
|
@ -301,8 +301,8 @@ impl MissingDoc {
|
|||||||
// Only check publicly-visible items, using the result from the privacy pass.
|
// 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
|
// It's an option so the crate root can also use this function (it doesn't
|
||||||
// have a NodeId).
|
// have a NodeId).
|
||||||
if let Some(ref id) = id {
|
if let Some(id) = id {
|
||||||
if !cx.exported_items.contains(id) {
|
if !cx.access_levels.is_exported(id) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -470,7 +470,7 @@ impl LintPass for MissingCopyImplementations {
|
|||||||
|
|
||||||
impl LateLintPass for MissingCopyImplementations {
|
impl LateLintPass for MissingCopyImplementations {
|
||||||
fn check_item(&mut self, cx: &LateContext, item: &hir::Item) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
let (def, ty) = match item.node {
|
let (def, ty) = match item.node {
|
||||||
@ -534,7 +534,7 @@ impl LintPass for MissingDebugImplementations {
|
|||||||
|
|
||||||
impl LateLintPass for MissingDebugImplementations {
|
impl LateLintPass for MissingDebugImplementations {
|
||||||
fn check_item(&mut self, cx: &LateContext, item: &hir::Item) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -987,7 +987,7 @@ impl LateLintPass for InvalidNoMangleItems {
|
|||||||
match it.node {
|
match it.node {
|
||||||
hir::ItemFn(..) => {
|
hir::ItemFn(..) => {
|
||||||
if attr::contains_name(&it.attrs, "no_mangle") &&
|
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",
|
let msg = format!("function {} is marked #[no_mangle], but not exported",
|
||||||
it.name);
|
it.name);
|
||||||
cx.span_lint(PRIVATE_NO_MANGLE_FNS, it.span, &msg);
|
cx.span_lint(PRIVATE_NO_MANGLE_FNS, it.span, &msg);
|
||||||
@ -995,7 +995,7 @@ impl LateLintPass for InvalidNoMangleItems {
|
|||||||
},
|
},
|
||||||
hir::ItemStatic(..) => {
|
hir::ItemStatic(..) => {
|
||||||
if attr::contains_name(&it.attrs, "no_mangle") &&
|
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",
|
let msg = format!("static {} is marked #[no_mangle], but not exported",
|
||||||
it.name);
|
it.name);
|
||||||
cx.span_lint(PRIVATE_NO_MANGLE_STATICS, it.span, &msg);
|
cx.span_lint(PRIVATE_NO_MANGLE_STATICS, it.span, &msg);
|
||||||
|
@ -32,6 +32,7 @@ extern crate rustc_front;
|
|||||||
use self::PrivacyResult::*;
|
use self::PrivacyResult::*;
|
||||||
use self::FieldName::*;
|
use self::FieldName::*;
|
||||||
|
|
||||||
|
use std::cmp;
|
||||||
use std::mem::replace;
|
use std::mem::replace;
|
||||||
|
|
||||||
use rustc_front::hir;
|
use rustc_front::hir;
|
||||||
@ -39,12 +40,13 @@ use rustc_front::intravisit::{self, Visitor};
|
|||||||
|
|
||||||
use rustc::middle::def;
|
use rustc::middle::def;
|
||||||
use rustc::middle::def_id::DefId;
|
use rustc::middle::def_id::DefId;
|
||||||
|
use rustc::middle::privacy::{AccessLevel, AccessLevels};
|
||||||
use rustc::middle::privacy::ImportUse::*;
|
use rustc::middle::privacy::ImportUse::*;
|
||||||
use rustc::middle::privacy::LastPrivate::*;
|
use rustc::middle::privacy::LastPrivate::*;
|
||||||
use rustc::middle::privacy::PrivateDep::*;
|
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::middle::ty::{self, Ty};
|
||||||
use rustc::util::nodemap::{NodeMap, NodeSet};
|
use rustc::util::nodemap::NodeMap;
|
||||||
use rustc::front::map as ast_map;
|
use rustc::front::map as ast_map;
|
||||||
|
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
@ -159,64 +161,57 @@ struct EmbargoVisitor<'a, 'tcx: 'a> {
|
|||||||
tcx: &'a ty::ctxt<'tcx>,
|
tcx: &'a ty::ctxt<'tcx>,
|
||||||
export_map: &'a def::ExportMap,
|
export_map: &'a def::ExportMap,
|
||||||
|
|
||||||
// This flag is an indicator of whether the previous item in the
|
// Accessibility levels for reachable nodes
|
||||||
// hierarchical chain was exported or not. This is the indicator of whether
|
access_levels: AccessLevels,
|
||||||
// children should be exported as well. Note that this can flip from false
|
// Previous accessibility level, None means unreachable
|
||||||
// to true if a reexported module is entered (or an action similar).
|
prev_level: Option<AccessLevel>,
|
||||||
prev_exported: bool,
|
// Have something changed in the level map?
|
||||||
|
changed: 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,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> {
|
impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> {
|
||||||
// Returns tuple (is_public, is_exported) for a type
|
fn ty_level(&self, ty: &hir::Ty) -> Option<AccessLevel> {
|
||||||
fn is_public_exported_ty(&self, ty: &hir::Ty) -> (bool, bool) {
|
|
||||||
if let hir::TyPath(..) = ty.node {
|
if let hir::TyPath(..) = ty.node {
|
||||||
match self.tcx.def_map.borrow().get(&ty.id).unwrap().full_def() {
|
match self.tcx.def_map.borrow().get(&ty.id).unwrap().full_def() {
|
||||||
def::DefPrimTy(..) | def::DefSelfTy(..) | def::DefTyParam(..) => {
|
def::DefPrimTy(..) | def::DefSelfTy(..) | def::DefTyParam(..) => {
|
||||||
(true, true)
|
Some(AccessLevel::Public)
|
||||||
}
|
}
|
||||||
def => {
|
def => {
|
||||||
if let Some(node_id) = self.tcx.map.as_local_node_id(def.def_id()) {
|
if let Some(node_id) = self.tcx.map.as_local_node_id(def.def_id()) {
|
||||||
(self.public_items.contains(&node_id),
|
self.get(node_id)
|
||||||
self.exported_items.contains(&node_id))
|
|
||||||
} else {
|
} else {
|
||||||
(true, true)
|
Some(AccessLevel::Public)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
(true, true)
|
Some(AccessLevel::Public)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns tuple (is_public, is_exported) for a trait
|
fn trait_level(&self, trait_ref: &hir::TraitRef) -> Option<AccessLevel> {
|
||||||
fn is_public_exported_trait(&self, trait_ref: &hir::TraitRef) -> (bool, bool) {
|
|
||||||
let did = self.tcx.trait_ref_to_def_id(trait_ref);
|
let did = self.tcx.trait_ref_to_def_id(trait_ref);
|
||||||
if let Some(node_id) = self.tcx.map.as_local_node_id(did) {
|
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 {
|
} else {
|
||||||
(true, true)
|
Some(AccessLevel::Public)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn maybe_insert_id(&mut self, id: ast::NodeId) {
|
fn get(&self, id: ast::NodeId) -> Option<AccessLevel> {
|
||||||
if self.prev_public {
|
self.access_levels.map.get(&id).cloned()
|
||||||
self.public_items.insert(id);
|
}
|
||||||
}
|
|
||||||
if self.prev_exported {
|
// Updates node level and returns the updated level
|
||||||
self.exported_items.insert(id);
|
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) {
|
fn visit_nested_item(&mut self, item: hir::ItemId) {
|
||||||
self.visit_item(self.tcx.map.expect_item(item.id))
|
self.visit_item(self.tcx.map.expect_item(item.id))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_item(&mut self, item: &hir::Item) {
|
fn visit_item(&mut self, item: &hir::Item) {
|
||||||
let orig_all_public = self.prev_public;
|
let inherited_item_level = match item.node {
|
||||||
let orig_all_exported = self.prev_exported;
|
// Impls inherit level from their types and traits
|
||||||
match item.node {
|
hir::ItemImpl(_, _, _, None, ref ty, _) => {
|
||||||
// impls/extern blocks do not break the "public chain" because they
|
self.ty_level(&ty)
|
||||||
// cannot have visibility qualifiers on them anyway. Impls are also not
|
}
|
||||||
// added to public/exported sets based on inherited publicity.
|
hir::ItemImpl(_, _, _, Some(ref trait_ref), ref ty, _) => {
|
||||||
hir::ItemImpl(..) | hir::ItemDefaultImpl(..) => {}
|
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(..) => {
|
hir::ItemForeignMod(..) => {
|
||||||
self.maybe_insert_id(item.id);
|
self.prev_level
|
||||||
}
|
}
|
||||||
|
// Other `pub` items inherit levels from parents
|
||||||
// Private by default, hence we only retain the "public chain" if
|
|
||||||
// `pub` is explicitly listed.
|
|
||||||
_ => {
|
_ => {
|
||||||
self.prev_public = self.prev_public && item.vis == hir::Public;
|
if item.vis == hir::Public { self.prev_level } else { None }
|
||||||
self.prev_exported = (self.prev_exported && item.vis == hir::Public) ||
|
|
||||||
self.exported_items.contains(&item.id);
|
|
||||||
|
|
||||||
self.maybe_insert_id(item.id);
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
// Update id of the item itself
|
||||||
|
let item_level = self.update(item.id, inherited_item_level);
|
||||||
|
|
||||||
|
// Update ids of nested things
|
||||||
match item.node {
|
match item.node {
|
||||||
// Enum variants inherit from their parent, so if the enum is
|
|
||||||
// public all variants are public
|
|
||||||
hir::ItemEnum(ref def, _) => {
|
hir::ItemEnum(ref def, _) => {
|
||||||
for variant in &def.variants {
|
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() {
|
for field in variant.node.data.fields() {
|
||||||
// Variant fields are always public
|
self.update(field.node.id, variant_level);
|
||||||
self.maybe_insert_id(field.node.id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
hir::ItemImpl(_, _, _, None, _, ref impl_items) => {
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
for impl_item in impl_items {
|
for impl_item in impl_items {
|
||||||
if impl_item.vis == hir::Public {
|
if impl_item.vis == hir::Public {
|
||||||
if public_ty {
|
self.update(impl_item.id, item_level);
|
||||||
self.public_items.insert(impl_item.id);
|
|
||||||
}
|
|
||||||
if exported_ty {
|
|
||||||
self.exported_items.insert(impl_item.id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
hir::ItemImpl(_, _, _, Some(_), _, ref impl_items) => {
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
for impl_item in impl_items {
|
for impl_item in impl_items {
|
||||||
if public_ty && public_trait {
|
self.update(impl_item.id, item_level);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default methods on traits are all public/exported so long as the trait
|
|
||||||
// is public/exported
|
|
||||||
hir::ItemTrait(_, _, _, ref trait_items) => {
|
hir::ItemTrait(_, _, _, ref trait_items) => {
|
||||||
for trait_item in 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, _) => {
|
hir::ItemStruct(ref def, _) => {
|
||||||
if !def.is_struct() {
|
if !def.is_struct() {
|
||||||
self.maybe_insert_id(def.id());
|
self.update(def.id(), item_level);
|
||||||
}
|
}
|
||||||
for field in def.fields() {
|
for field in def.fields() {
|
||||||
// Struct fields can be public or private, so lets check
|
|
||||||
if field.node.kind.visibility() == hir::Public {
|
if field.node.kind.visibility() == hir::Public {
|
||||||
self.maybe_insert_id(field.node.id);
|
self.update(field.node.id, item_level);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
hir::ItemForeignMod(ref foreign_mod) => {
|
||||||
hir::ItemTy(ref ty, _) if self.prev_exported => {
|
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 {
|
if let hir::TyPath(..) = ty.node {
|
||||||
match self.tcx.def_map.borrow().get(&ty.id).unwrap().full_def() {
|
match self.tcx.def_map.borrow().get(&ty.id).unwrap().full_def() {
|
||||||
def::DefPrimTy(..) | def::DefSelfTy(..) | def::DefTyParam(..) => {},
|
def::DefPrimTy(..) | def::DefSelfTy(..) | def::DefTyParam(..) => {},
|
||||||
def => {
|
def => {
|
||||||
if let Some(node_id) = self.tcx.map.as_local_node_id(def.def_id()) {
|
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);
|
intravisit::walk_item(self, item);
|
||||||
|
|
||||||
self.prev_public = orig_all_public;
|
self.prev_level = orig_level;
|
||||||
self.prev_exported = orig_all_exported;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_block(&mut self, b: &'v hir::Block) {
|
fn visit_block(&mut self, b: &'v hir::Block) {
|
||||||
let orig_all_public = replace(&mut self.prev_public, false);
|
let orig_level = replace(&mut self.prev_level, None);
|
||||||
let orig_all_exported = replace(&mut self.prev_exported, false);
|
|
||||||
|
|
||||||
// Blocks can have exported and public items, for example impls, but they always
|
// Blocks can have public items, for example impls, but they always
|
||||||
// start as non-public and non-exported regardless of publicity of a function,
|
// start as completely private regardless of publicity of a function,
|
||||||
// constant, type, field, etc. in which this block resides
|
// constant, type, field, etc. in which this block resides
|
||||||
intravisit::walk_block(self, b);
|
intravisit::walk_block(self, b);
|
||||||
|
|
||||||
self.prev_public = orig_all_public;
|
self.prev_level = orig_level;
|
||||||
self.prev_exported = orig_all_exported;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_mod(&mut self, m: &hir::Mod, _sp: Span, id: ast::NodeId) {
|
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
|
// This code is here instead of in visit_item so that the
|
||||||
// crate module gets processed as well.
|
// crate module gets processed as well.
|
||||||
if self.prev_exported {
|
if self.prev_level.is_some() {
|
||||||
assert!(self.export_map.contains_key(&id), "wut {}", id);
|
for export in self.export_map.get(&id).expect("module isn't found in export map") {
|
||||||
for export in self.export_map.get(&id).unwrap() {
|
|
||||||
if let Some(node_id) = self.tcx.map.as_local_node_id(export.def_id) {
|
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) {
|
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 @@ impl<'a, 'tcx> SanePrivacyVisitor<'a, 'tcx> {
|
|||||||
|
|
||||||
struct VisiblePrivateTypesVisitor<'a, 'tcx: 'a> {
|
struct VisiblePrivateTypesVisitor<'a, 'tcx: 'a> {
|
||||||
tcx: &'a ty::ctxt<'tcx>,
|
tcx: &'a ty::ctxt<'tcx>,
|
||||||
exported_items: &'a ExportedItems,
|
access_levels: &'a AccessLevels,
|
||||||
public_items: &'a PublicItems,
|
|
||||||
in_variant: bool,
|
in_variant: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1210,7 +1143,7 @@ impl<'a, 'tcx> VisiblePrivateTypesVisitor<'a, 'tcx> {
|
|||||||
fn trait_is_public(&self, trait_id: ast::NodeId) -> bool {
|
fn trait_is_public(&self, trait_id: ast::NodeId) -> bool {
|
||||||
// FIXME: this would preferably be using `exported_items`, but all
|
// FIXME: this would preferably be using `exported_items`, but all
|
||||||
// traits are exported currently (see `EmbargoVisitor.exported_trait`)
|
// 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,
|
fn check_ty_param_bound(&self,
|
||||||
@ -1226,7 +1159,7 @@ impl<'a, 'tcx> VisiblePrivateTypesVisitor<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn item_is_public(&self, id: &ast::NodeId, vis: hir::Visibility) -> bool {
|
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 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> {
|
|||||||
match impl_item.node {
|
match impl_item.node {
|
||||||
hir::ImplItemKind::Const(..) |
|
hir::ImplItemKind::Const(..) |
|
||||||
hir::ImplItemKind::Method(..) => {
|
hir::ImplItemKind::Method(..) => {
|
||||||
self.exported_items.contains(&impl_item.id)
|
self.access_levels.is_reachable(impl_item.id)
|
||||||
}
|
}
|
||||||
hir::ImplItemKind::Type(_) => false,
|
hir::ImplItemKind::Type(_) => false,
|
||||||
}
|
}
|
||||||
@ -1461,7 +1394,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn visit_foreign_item(&mut self, item: &hir::ForeignItem) {
|
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)
|
intravisit::walk_foreign_item(self, item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1479,7 +1412,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn visit_variant(&mut self, v: &hir::Variant, g: &hir::Generics, item_id: ast::NodeId) {
|
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;
|
self.in_variant = true;
|
||||||
intravisit::walk_variant(self, v, g, item_id);
|
intravisit::walk_variant(self, v, g, item_id);
|
||||||
self.in_variant = false;
|
self.in_variant = false;
|
||||||
@ -1509,7 +1442,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> {
|
|||||||
pub fn check_crate(tcx: &ty::ctxt,
|
pub fn check_crate(tcx: &ty::ctxt,
|
||||||
export_map: &def::ExportMap,
|
export_map: &def::ExportMap,
|
||||||
external_exports: ExternalExports)
|
external_exports: ExternalExports)
|
||||||
-> (ExportedItems, PublicItems) {
|
-> AccessLevels {
|
||||||
let krate = tcx.map.krate();
|
let krate = tcx.map.krate();
|
||||||
|
|
||||||
// Sanity check to make sure that all privacy usage and controls are
|
// 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.
|
// items which are reachable from external crates based on visibility.
|
||||||
let mut visitor = EmbargoVisitor {
|
let mut visitor = EmbargoVisitor {
|
||||||
tcx: tcx,
|
tcx: tcx,
|
||||||
exported_items: NodeSet(),
|
|
||||||
public_items: NodeSet(),
|
|
||||||
export_map: export_map,
|
export_map: export_map,
|
||||||
prev_exported: true,
|
access_levels: Default::default(),
|
||||||
prev_public: true,
|
prev_level: Some(AccessLevel::Public),
|
||||||
|
changed: false,
|
||||||
};
|
};
|
||||||
visitor.exported_items.insert(ast::CRATE_NODE_ID);
|
|
||||||
visitor.public_items.insert(ast::CRATE_NODE_ID);
|
|
||||||
loop {
|
loop {
|
||||||
let before = (visitor.exported_items.len(), visitor.public_items.len());
|
|
||||||
intravisit::walk_crate(&mut visitor, krate);
|
intravisit::walk_crate(&mut visitor, krate);
|
||||||
let after = (visitor.exported_items.len(), visitor.public_items.len());
|
if visitor.changed {
|
||||||
if after == before {
|
visitor.changed = false;
|
||||||
|
} else {
|
||||||
break
|
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 {
|
let mut visitor = VisiblePrivateTypesVisitor {
|
||||||
tcx: tcx,
|
tcx: tcx,
|
||||||
exported_items: &exported_items,
|
access_levels: &access_levels,
|
||||||
public_items: &public_items,
|
|
||||||
in_variant: false,
|
in_variant: false,
|
||||||
};
|
};
|
||||||
intravisit::walk_crate(&mut visitor, krate);
|
intravisit::walk_crate(&mut visitor, krate);
|
||||||
}
|
}
|
||||||
return (exported_items, public_items);
|
|
||||||
|
access_levels
|
||||||
}
|
}
|
||||||
|
@ -13,10 +13,10 @@ use rustc_lint;
|
|||||||
use rustc_driver::{driver, target_features};
|
use rustc_driver::{driver, target_features};
|
||||||
use rustc::session::{self, config};
|
use rustc::session::{self, config};
|
||||||
use rustc::middle::def_id::DefId;
|
use rustc::middle::def_id::DefId;
|
||||||
|
use rustc::middle::privacy::AccessLevels;
|
||||||
use rustc::middle::ty;
|
use rustc::middle::ty;
|
||||||
use rustc::front::map as hir_map;
|
use rustc::front::map as hir_map;
|
||||||
use rustc::lint;
|
use rustc::lint;
|
||||||
use rustc::util::nodemap::DefIdSet;
|
|
||||||
use rustc_trans::back::link;
|
use rustc_trans::back::link;
|
||||||
use rustc_resolve as resolve;
|
use rustc_resolve as resolve;
|
||||||
use rustc_front::lowering::{lower_crate, LoweringContext};
|
use rustc_front::lowering::{lower_crate, LoweringContext};
|
||||||
@ -77,8 +77,7 @@ impl<'b, 'tcx> DocContext<'b, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct CrateAnalysis {
|
pub struct CrateAnalysis {
|
||||||
pub exported_items: DefIdSet,
|
pub access_levels: AccessLevels<DefId>,
|
||||||
pub public_items: DefIdSet,
|
|
||||||
pub external_paths: ExternalPaths,
|
pub external_paths: ExternalPaths,
|
||||||
pub external_typarams: RefCell<Option<HashMap<DefId, String>>>,
|
pub external_typarams: RefCell<Option<HashMap<DefId, String>>>,
|
||||||
pub inlined: RefCell<Option<HashSet<DefId>>>,
|
pub inlined: RefCell<Option<HashSet<DefId>>>,
|
||||||
@ -147,18 +146,15 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec<String>, externs: Externs,
|
|||||||
&name,
|
&name,
|
||||||
resolve::MakeGlobMap::No,
|
resolve::MakeGlobMap::No,
|
||||||
|tcx, _, analysis| {
|
|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
|
// Convert from a NodeId set to a DefId set since we don't always have easy access
|
||||||
// to the map from defid -> nodeid
|
// to the map from defid -> nodeid
|
||||||
let exported_items: DefIdSet =
|
let access_levels = AccessLevels {
|
||||||
exported_items.into_iter()
|
map: access_levels.map.into_iter()
|
||||||
.map(|n| tcx.map.local_def_id(n))
|
.map(|(k, v)| (tcx.map.local_def_id(k), v))
|
||||||
.collect();
|
.collect()
|
||||||
let public_items: DefIdSet =
|
};
|
||||||
public_items.into_iter()
|
|
||||||
.map(|n| tcx.map.local_def_id(n))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let ctxt = DocContext {
|
let ctxt = DocContext {
|
||||||
map: &tcx.map,
|
map: &tcx.map,
|
||||||
@ -174,8 +170,7 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec<String>, externs: Externs,
|
|||||||
debug!("crate: {:?}", ctxt.map.krate());
|
debug!("crate: {:?}", ctxt.map.krate());
|
||||||
|
|
||||||
let mut analysis = CrateAnalysis {
|
let mut analysis = CrateAnalysis {
|
||||||
exported_items: exported_items,
|
access_levels: access_levels,
|
||||||
public_items: public_items,
|
|
||||||
external_paths: RefCell::new(None),
|
external_paths: RefCell::new(None),
|
||||||
external_typarams: RefCell::new(None),
|
external_typarams: RefCell::new(None),
|
||||||
inlined: RefCell::new(None),
|
inlined: RefCell::new(None),
|
||||||
|
@ -56,8 +56,8 @@ use serialize::json::{self, ToJson};
|
|||||||
use syntax::{abi, ast};
|
use syntax::{abi, ast};
|
||||||
use rustc::metadata::cstore::LOCAL_CRATE;
|
use rustc::metadata::cstore::LOCAL_CRATE;
|
||||||
use rustc::middle::def_id::{CRATE_DEF_INDEX, DefId};
|
use rustc::middle::def_id::{CRATE_DEF_INDEX, DefId};
|
||||||
|
use rustc::middle::privacy::AccessLevels;
|
||||||
use rustc::middle::stability;
|
use rustc::middle::stability;
|
||||||
use rustc::util::nodemap::DefIdSet;
|
|
||||||
use rustc_front::hir;
|
use rustc_front::hir;
|
||||||
|
|
||||||
use clean::{self, SelfTy};
|
use clean::{self, SelfTy};
|
||||||
@ -244,7 +244,7 @@ pub struct Cache {
|
|||||||
search_index: Vec<IndexItem>,
|
search_index: Vec<IndexItem>,
|
||||||
privmod: bool,
|
privmod: bool,
|
||||||
remove_priv: bool,
|
remove_priv: bool,
|
||||||
public_items: DefIdSet,
|
access_levels: AccessLevels<DefId>,
|
||||||
deref_trait_did: Option<DefId>,
|
deref_trait_did: Option<DefId>,
|
||||||
|
|
||||||
// In rare case where a structure is defined in one module but implemented
|
// 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
|
// Crawl the crate to build various caches used for the output
|
||||||
let analysis = ::ANALYSISKEY.with(|a| a.clone());
|
let analysis = ::ANALYSISKEY.with(|a| a.clone());
|
||||||
let analysis = analysis.borrow();
|
let analysis = analysis.borrow();
|
||||||
let public_items = analysis.as_ref().map(|a| a.public_items.clone());
|
let access_levels = analysis.as_ref().map(|a| a.access_levels.clone());
|
||||||
let public_items = public_items.unwrap_or(DefIdSet());
|
let access_levels = access_levels.unwrap_or(Default::default());
|
||||||
let paths: HashMap<DefId, (Vec<String>, ItemType)> =
|
let paths: HashMap<DefId, (Vec<String>, ItemType)> =
|
||||||
analysis.as_ref().map(|a| {
|
analysis.as_ref().map(|a| {
|
||||||
let paths = a.external_paths.borrow_mut().take().unwrap();
|
let paths = a.external_paths.borrow_mut().take().unwrap();
|
||||||
@ -435,7 +435,7 @@ pub fn run(mut krate: clean::Crate,
|
|||||||
primitive_locations: HashMap::new(),
|
primitive_locations: HashMap::new(),
|
||||||
remove_priv: cx.passes.contains("strip-private"),
|
remove_priv: cx.passes.contains("strip-private"),
|
||||||
privmod: false,
|
privmod: false,
|
||||||
public_items: public_items,
|
access_levels: access_levels,
|
||||||
orphan_methods: Vec::new(),
|
orphan_methods: Vec::new(),
|
||||||
traits: mem::replace(&mut krate.external_traits, HashMap::new()),
|
traits: mem::replace(&mut krate.external_traits, HashMap::new()),
|
||||||
deref_trait_did: analysis.as_ref().and_then(|a| a.deref_trait_did),
|
deref_trait_did: analysis.as_ref().and_then(|a| a.deref_trait_did),
|
||||||
@ -1053,7 +1053,7 @@ impl DocFolder for Cache {
|
|||||||
if
|
if
|
||||||
!self.paths.contains_key(&item.def_id) ||
|
!self.paths.contains_key(&item.def_id) ||
|
||||||
!item.def_id.is_local() ||
|
!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.paths.insert(item.def_id,
|
||||||
(self.stack.clone(), shortty(&item)));
|
(self.stack.clone(), shortty(&item)));
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
use rustc::middle::def_id::DefId;
|
||||||
|
use rustc::middle::privacy::AccessLevels;
|
||||||
use rustc::util::nodemap::DefIdSet;
|
use rustc::util::nodemap::DefIdSet;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::string::String;
|
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 = super::ANALYSISKEY.with(|a| a.clone());
|
||||||
let analysis = analysis.borrow();
|
let analysis = analysis.borrow();
|
||||||
let analysis = analysis.as_ref().unwrap();
|
let analysis = analysis.as_ref().unwrap();
|
||||||
let exported_items = analysis.exported_items.clone();
|
let access_levels = analysis.access_levels.clone();
|
||||||
|
|
||||||
// strip all private items
|
// strip all private items
|
||||||
{
|
{
|
||||||
let mut stripper = Stripper {
|
let mut stripper = Stripper {
|
||||||
retained: &mut retained,
|
retained: &mut retained,
|
||||||
exported_items: &exported_items,
|
access_levels: &access_levels,
|
||||||
};
|
};
|
||||||
krate = stripper.fold_crate(krate);
|
krate = stripper.fold_crate(krate);
|
||||||
}
|
}
|
||||||
@ -117,7 +119,7 @@ pub fn strip_private(mut krate: clean::Crate) -> plugins::PluginResult {
|
|||||||
|
|
||||||
struct Stripper<'a> {
|
struct Stripper<'a> {
|
||||||
retained: &'a mut DefIdSet,
|
retained: &'a mut DefIdSet,
|
||||||
exported_items: &'a DefIdSet,
|
access_levels: &'a AccessLevels<DefId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> fold::DocFolder for Stripper<'a> {
|
impl<'a> fold::DocFolder for Stripper<'a> {
|
||||||
@ -130,18 +132,14 @@ impl<'a> fold::DocFolder for Stripper<'a> {
|
|||||||
clean::VariantItem(..) | clean::MethodItem(..) |
|
clean::VariantItem(..) | clean::MethodItem(..) |
|
||||||
clean::ForeignFunctionItem(..) | clean::ForeignStaticItem(..) => {
|
clean::ForeignFunctionItem(..) | clean::ForeignStaticItem(..) => {
|
||||||
if i.def_id.is_local() {
|
if i.def_id.is_local() {
|
||||||
if !self.exported_items.contains(&i.def_id) {
|
if !self.access_levels.is_exported(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) {
|
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clean::ConstantItem(..) => {
|
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;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -168,7 +166,7 @@ impl<'a> fold::DocFolder for Stripper<'a> {
|
|||||||
clean::ImplItem(clean::Impl{
|
clean::ImplItem(clean::Impl{
|
||||||
for_: clean::ResolvedPath{ did, .. }, ..
|
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;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -214,7 +214,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
|||||||
let analysis = match self.analysis {
|
let analysis = match self.analysis {
|
||||||
Some(analysis) => analysis, None => return false
|
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
|
return false
|
||||||
}
|
}
|
||||||
if !self.view_item_stack.insert(def_node_id) { return false }
|
if !self.view_item_stack.insert(def_node_id) { return false }
|
||||||
|
Loading…
Reference in New Issue
Block a user