html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "https://doc.rust-lang.org/nightly/")]
-#![feature(nll)]
+#![deny(rust_2018_idioms)]
+
#![feature(rustc_diagnostic_macros)]
#![recursion_limit="256"]
-#[macro_use] extern crate rustc;
#[macro_use] extern crate syntax;
-extern crate rustc_typeck;
-extern crate syntax_pos;
-extern crate rustc_data_structures;
-use rustc::hir::{self, Node, PatKind};
+use rustc::bug;
+use rustc::hir::{self, Node, PatKind, AssociatedItemKind};
use rustc::hir::def::Def;
use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, CrateNum, DefId};
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
use rustc::util::nodemap::NodeSet;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::sync::Lrc;
-use syntax::ast::{self, CRATE_NODE_ID, Ident};
+use syntax::ast::{self, DUMMY_NODE_ID, Ident};
use syntax::attr;
use syntax::symbol::keywords;
use syntax_pos::Span;
let mut reach = self.reach(trait_item_ref.id.node_id, item_level);
reach.generics().predicates();
- if trait_item_ref.kind == hir::AssociatedItemKind::Type &&
+ if trait_item_ref.kind == AssociatedItemKind::Type &&
!trait_item_ref.defaultness.has_value() {
// No type to visit.
} else {
NestedVisitorMap::All(&self.tcx.hir())
}
+ fn visit_mod(&mut self, _m: &'tcx hir::Mod, _s: Span, _n: ast::NodeId) {
+ // Don't visit nested modules, since we run a separate visitor walk
+ // for each module in `privacy_access_levels`
+ }
+
fn visit_nested_body(&mut self, body: hir::BodyId) {
let orig_tables = mem::replace(&mut self.tables, self.tcx.body_tables(body));
let body = self.tcx.hir().body(body);
NestedVisitorMap::All(&self.tcx.hir())
}
+ fn visit_mod(&mut self, _m: &'tcx hir::Mod, _s: Span, _n: ast::NodeId) {
+ // Don't visit nested modules, since we run a separate visitor walk
+ // for each module in `privacy_access_levels`
+ }
+
fn visit_nested_body(&mut self, body: hir::BodyId) {
let orig_tables = mem::replace(&mut self.tables, self.tcx.body_tables(body));
let orig_in_body = mem::replace(&mut self.in_body, true);
if self.item_is_public(&impl_item_ref.id.node_id, &impl_item_ref.vis) {
let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
match impl_item_ref.kind {
- hir::AssociatedItemKind::Const => {
+ AssociatedItemKind::Const => {
found_pub_static = true;
intravisit::walk_impl_item(self, impl_item);
}
- hir::AssociatedItemKind::Method { has_self: false } => {
+ AssociatedItemKind::Method { has_self: false } => {
found_pub_static = true;
intravisit::walk_impl_item(self, impl_item);
}
struct SearchInterfaceForPrivateItemsVisitor<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ item_id: ast::NodeId,
item_def_id: DefId,
span: Span,
/// The visitor checks that each component type is at least this visible.
has_pub_restricted: bool,
has_old_errors: bool,
in_assoc_ty: bool,
+ private_crates: FxHashSet<CrateNum>
}
impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
}
fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {
+ if self.leaks_private_dep(def_id) {
+ self.tcx.lint_node(lint::builtin::EXPORTED_PRIVATE_DEPENDENCIES,
+ self.item_id,
+ self.span,
+ &format!("{} `{}` from private dependency '{}' in public \
+ interface", kind, descr,
+ self.tcx.crate_name(def_id.krate)));
+
+ }
+
let node_id = match self.tcx.hir().as_local_node_id(def_id) {
Some(node_id) => node_id,
None => return false,
self.tcx.lint_node(lint::builtin::PRIVATE_IN_PUBLIC, node_id, self.span,
&format!("{} (error {})", msg, err_code));
}
+
}
+
false
}
+
+ /// An item is 'leaked' from a private dependency if all
+ /// of the following are true:
+ /// 1. It's contained within a public type
+ /// 2. It comes from a private crate
+ fn leaks_private_dep(&self, item_id: DefId) -> bool {
+ let ret = self.required_visibility == ty::Visibility::Public &&
+ self.private_crates.contains(&item_id.krate);
+
+ log::debug!("leaks_private_dep(item_id={:?})={}", item_id, ret);
+ return ret;
+ }
}
impl<'a, 'tcx> DefIdVisitor<'a, 'tcx> for SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
has_pub_restricted: bool,
old_error_set: &'a NodeSet,
+ private_crates: FxHashSet<CrateNum>
}
impl<'a, 'tcx> PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
SearchInterfaceForPrivateItemsVisitor {
tcx: self.tcx,
+ item_id,
item_def_id: self.tcx.hir().local_def_id(item_id),
span: self.tcx.hir().span(item_id),
required_visibility,
has_pub_restricted: self.has_pub_restricted,
has_old_errors,
in_assoc_ty: false,
+ private_crates: self.private_crates.clone()
+ }
+ }
+
+ fn check_trait_or_impl_item(&self, node_id: ast::NodeId, assoc_item_kind: AssociatedItemKind,
+ defaultness: hir::Defaultness, vis: ty::Visibility) {
+ let mut check = self.check(node_id, vis);
+
+ let (check_ty, is_assoc_ty) = match assoc_item_kind {
+ AssociatedItemKind::Const | AssociatedItemKind::Method { .. } => (true, false),
+ AssociatedItemKind::Type => (defaultness.has_value(), true),
+ // `ty()` for existential types is the underlying type,
+ // it's not a part of interface, so we skip it.
+ AssociatedItemKind::Existential => (false, true),
+ };
+ check.in_assoc_ty = is_assoc_ty;
+ check.generics().predicates();
+ if check_ty {
+ check.ty();
}
}
}
self.check(item.id, item_visibility).generics().predicates();
for trait_item_ref in trait_item_refs {
- let mut check = self.check(trait_item_ref.id.node_id, item_visibility);
- check.in_assoc_ty = trait_item_ref.kind == hir::AssociatedItemKind::Type;
- check.generics().predicates();
-
- if trait_item_ref.kind == hir::AssociatedItemKind::Type &&
- !trait_item_ref.defaultness.has_value() {
- // No type to visit.
- } else {
- check.ty();
- }
+ self.check_trait_or_impl_item(trait_item_ref.id.node_id, trait_item_ref.kind,
+ trait_item_ref.defaultness, item_visibility);
}
}
hir::ItemKind::TraitAlias(..) => {
} else {
impl_vis
};
- let mut check = self.check(impl_item.id, impl_item_vis);
- check.in_assoc_ty = impl_item_ref.kind == hir::AssociatedItemKind::Type;
- check.generics().predicates().ty();
+ self.check_trait_or_impl_item(impl_item_ref.id.node_id, impl_item_ref.kind,
+ impl_item_ref.defaultness, impl_item_vis);
}
}
}
}
}
-pub fn provide(providers: &mut Providers) {
+pub fn provide(providers: &mut Providers<'_>) {
*providers = Providers {
privacy_access_levels,
+ check_mod_privacy,
..*providers
};
}
tcx.privacy_access_levels(LOCAL_CRATE)
}
-fn privacy_access_levels<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- krate: CrateNum)
- -> Lrc<AccessLevels> {
- assert_eq!(krate, LOCAL_CRATE);
-
- let krate = tcx.hir().krate();
+fn check_mod_privacy<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>, module_def_id: DefId) {
let empty_tables = ty::TypeckTables::empty(None);
+
// Check privacy of names not checked in previous compilation stages.
let mut visitor = NamePrivacyVisitor {
tcx,
tables: &empty_tables,
- current_item: CRATE_NODE_ID,
+ current_item: DUMMY_NODE_ID,
empty_tables: &empty_tables,
};
- intravisit::walk_crate(&mut visitor, krate);
+ let (module, span, node_id) = tcx.hir().get_module(module_def_id);
+ intravisit::walk_mod(&mut visitor, module, node_id);
// Check privacy of explicitly written types and traits as well as
// inferred types of expressions and patterns.
let mut visitor = TypePrivacyVisitor {
tcx,
tables: &empty_tables,
- current_item: DefId::local(CRATE_DEF_INDEX),
+ current_item: module_def_id,
in_body: false,
- span: krate.span,
+ span,
empty_tables: &empty_tables,
};
- intravisit::walk_crate(&mut visitor, krate);
+ intravisit::walk_mod(&mut visitor, module, node_id);
+}
+
+fn privacy_access_levels<'tcx>(
+ tcx: TyCtxt<'_, 'tcx, 'tcx>,
+ krate: CrateNum,
+) -> Lrc<AccessLevels> {
+ assert_eq!(krate, LOCAL_CRATE);
+
+ let krate = tcx.hir().krate();
+
+ for &module in krate.modules.keys() {
+ tcx.ensure().check_mod_privacy(tcx.hir().local_def_id(module));
+ }
+
+ let private_crates: FxHashSet<CrateNum> = tcx.sess.opts.extern_private.iter()
+ .flat_map(|c| {
+ tcx.crates().iter().find(|&&krate| &tcx.crate_name(krate) == c).cloned()
+ }).collect();
+
// Build up a set of all exported items in the AST. This is a set of all
// items which are reachable from external crates based on visibility.
tcx,
has_pub_restricted,
old_error_set: &visitor.old_error_set,
+ private_crates
};
krate.visit_all_item_likes(&mut DeepVisitor::new(&mut visitor));
}