add a `nested_visit_map` method

This allows you to enable *all* nested visits in a future-compatible
sort of way. Moreover, if you choose to override the `visit_nested`
methods yourself, you can "future-proof" against omissions by overriding
`nested_visit_map` to panic.
This commit is contained in:
Niko Matsakis 2016-11-09 16:45:26 -05:00
parent 4df5288971
commit 26d1500e13
9 changed files with 183 additions and 184 deletions

View File

@ -38,6 +38,7 @@ use syntax::ast::{NodeId, CRATE_NODE_ID, Name, Attribute};
use syntax::codemap::Spanned;
use syntax_pos::Span;
use hir::*;
use hir::map::Map;
use super::itemlikevisit::DeepVisitor;
use std::cmp;
@ -85,23 +86,52 @@ pub trait Visitor<'v> : Sized {
///////////////////////////////////////////////////////////////////////////
// Nested items.
/// Invoked when a nested item is encountered. By default, does
/// nothing. If you want a deep walk, you need to override to
/// fetch the item contents. But most of the time, it is easier to
/// use either the "shallow" or "deep" visit patterns described on
/// `itemlikevisit::ItemLikeVisitor`.
#[allow(unused_variables)]
fn visit_nested_item(&mut self, id: ItemId) {
/// The default versions of the `visit_nested_XXX` routines invoke
/// this method to get a map to use; if they get back `None`, they
/// just skip nested things. Otherwise, they will lookup the
/// nested item-like things in the map and visit it. So the best
/// way to implement a nested visitor is to override this method
/// to return a `Map`; one advantage of this is that if we add
/// more types of nested things in the future, they will
/// automatically work.
///
/// **If for some reason you want the nested behavior, but don't
/// have a `Map` are your disposal:** then you should override the
/// `visit_nested_XXX` methods, and override this method to
/// `panic!()`. This way, if a new `visit_nested_XXX` variant is
/// added in the future, we will see the panic in your code and
/// fix it appropriately.
fn nested_visit_map(&mut self) -> Option<&Map<'v>> {
None
}
/// Invoked when a nested impl item is encountered. By default, does
/// nothing. If you want a deep walk, you need to override to
/// fetch the item contents. But most of the time, it is easier
/// (and better) to invoke `Crate::visit_all_item_likes`, which visits
/// all items in the crate in some order (but doesn't respect
/// nesting).
/// Invoked when a nested item is encountered. By default does
/// nothing unless you override `nested_visit_map` to return
/// `Some(_)`, in which case it will walk the item. **You probably
/// don't want to override this method** -- instead, override
/// `nested_visit_map` or use the "shallow" or "deep" visit
/// patterns described on `itemlikevisit::ItemLikeVisitor`. The only
/// reason to override this method is if you want a nested pattern
/// but cannot supply a `Map`; see `nested_visit_map` for advice.
#[allow(unused_variables)]
fn visit_nested_item(&mut self, id: ItemId) {
let opt_item = self.nested_visit_map()
.map(|map| map.expect_item(id.id));
if let Some(item) = opt_item {
self.visit_item(item);
}
}
/// Like `visit_nested_item()`, but for impl items. See
/// `visit_nested_item()` for advice on when to override this
/// method.
#[allow(unused_variables)]
fn visit_nested_impl_item(&mut self, id: ImplItemId) {
let opt_item = self.nested_visit_map()
.map(|map| map.impl_item(id));
if let Some(item) = opt_item {
self.visit_impl_item(item);
}
}
/// Visit the top-level item and (optionally) nested items / impl items. See

View File

@ -92,6 +92,11 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
/// Because we want to track parent items and so forth, enable
/// deep walking so that we walk nested items in the context of
/// their outer items.
fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'v>> {
panic!("visit_nested_xxx must be manually implemented in this visitor")
}
fn visit_nested_item(&mut self, item: ItemId) {
debug!("visit_nested_item: {:?}", item);
if !self.ignore_nested_items {

View File

@ -792,21 +792,15 @@ impl<'a> LintContext for EarlyContext<'a> {
}
}
impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
/// Because lints are scoped lexically, we want to walk nested
/// items in the context of the outer item, so enable
/// deep-walking.
fn visit_nested_item(&mut self, item: hir::ItemId) {
let item = self.tcx.map.expect_item(item.id);
self.visit_item(item)
fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> {
Some(&self.tcx.map)
}
fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) {
let impl_item = self.tcx.map.impl_item(item_id);
self.visit_impl_item(impl_item)
}
fn visit_item(&mut self, it: &hir::Item) {
fn visit_item(&mut self, it: &'tcx hir::Item) {
self.with_lint_attrs(&it.attrs, |cx| {
run_lints!(cx, check_item, late_passes, it);
cx.visit_ids(|v| v.visit_item(it));
@ -815,7 +809,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
})
}
fn visit_foreign_item(&mut self, it: &hir::ForeignItem) {
fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem) {
self.with_lint_attrs(&it.attrs, |cx| {
run_lints!(cx, check_foreign_item, late_passes, it);
hir_visit::walk_foreign_item(cx, it);
@ -823,19 +817,19 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
})
}
fn visit_pat(&mut self, p: &hir::Pat) {
fn visit_pat(&mut self, p: &'tcx hir::Pat) {
run_lints!(self, check_pat, late_passes, p);
hir_visit::walk_pat(self, p);
}
fn visit_expr(&mut self, e: &hir::Expr) {
fn visit_expr(&mut self, e: &'tcx hir::Expr) {
self.with_lint_attrs(&e.attrs, |cx| {
run_lints!(cx, check_expr, late_passes, e);
hir_visit::walk_expr(cx, e);
})
}
fn visit_stmt(&mut self, s: &hir::Stmt) {
fn visit_stmt(&mut self, s: &'tcx hir::Stmt) {
// statement attributes are actually just attributes on one of
// - item
// - local
@ -845,17 +839,17 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
hir_visit::walk_stmt(self, s);
}
fn visit_fn(&mut self, fk: hir_visit::FnKind<'v>, decl: &'v hir::FnDecl,
body: &'v hir::Expr, span: Span, id: ast::NodeId) {
fn visit_fn(&mut self, fk: hir_visit::FnKind<'tcx>, decl: &'tcx hir::FnDecl,
body: &'tcx hir::Expr, span: Span, id: ast::NodeId) {
run_lints!(self, check_fn, late_passes, fk, decl, body, span, id);
hir_visit::walk_fn(self, fk, decl, body, span, id);
run_lints!(self, check_fn_post, late_passes, fk, decl, body, span, id);
}
fn visit_variant_data(&mut self,
s: &hir::VariantData,
s: &'tcx hir::VariantData,
name: ast::Name,
g: &hir::Generics,
g: &'tcx hir::Generics,
item_id: ast::NodeId,
_: Span) {
run_lints!(self, check_struct_def, late_passes, s, name, g, item_id);
@ -863,14 +857,17 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
run_lints!(self, check_struct_def_post, late_passes, s, name, g, item_id);
}
fn visit_struct_field(&mut self, s: &hir::StructField) {
fn visit_struct_field(&mut self, s: &'tcx hir::StructField) {
self.with_lint_attrs(&s.attrs, |cx| {
run_lints!(cx, check_struct_field, late_passes, s);
hir_visit::walk_struct_field(cx, s);
})
}
fn visit_variant(&mut self, v: &hir::Variant, g: &hir::Generics, item_id: ast::NodeId) {
fn visit_variant(&mut self,
v: &'tcx hir::Variant,
g: &'tcx hir::Generics,
item_id: ast::NodeId) {
self.with_lint_attrs(&v.node.attrs, |cx| {
run_lints!(cx, check_variant, late_passes, v, g);
hir_visit::walk_variant(cx, v, g, item_id);
@ -878,7 +875,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
})
}
fn visit_ty(&mut self, t: &hir::Ty) {
fn visit_ty(&mut self, t: &'tcx hir::Ty) {
run_lints!(self, check_ty, late_passes, t);
hir_visit::walk_ty(self, t);
}
@ -887,45 +884,45 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
run_lints!(self, check_name, late_passes, sp, name);
}
fn visit_mod(&mut self, m: &hir::Mod, s: Span, n: ast::NodeId) {
fn visit_mod(&mut self, m: &'tcx hir::Mod, s: Span, n: ast::NodeId) {
run_lints!(self, check_mod, late_passes, m, s, n);
hir_visit::walk_mod(self, m, n);
run_lints!(self, check_mod_post, late_passes, m, s, n);
}
fn visit_local(&mut self, l: &hir::Local) {
fn visit_local(&mut self, l: &'tcx hir::Local) {
self.with_lint_attrs(&l.attrs, |cx| {
run_lints!(cx, check_local, late_passes, l);
hir_visit::walk_local(cx, l);
})
}
fn visit_block(&mut self, b: &hir::Block) {
fn visit_block(&mut self, b: &'tcx hir::Block) {
run_lints!(self, check_block, late_passes, b);
hir_visit::walk_block(self, b);
run_lints!(self, check_block_post, late_passes, b);
}
fn visit_arm(&mut self, a: &hir::Arm) {
fn visit_arm(&mut self, a: &'tcx hir::Arm) {
run_lints!(self, check_arm, late_passes, a);
hir_visit::walk_arm(self, a);
}
fn visit_decl(&mut self, d: &hir::Decl) {
fn visit_decl(&mut self, d: &'tcx hir::Decl) {
run_lints!(self, check_decl, late_passes, d);
hir_visit::walk_decl(self, d);
}
fn visit_expr_post(&mut self, e: &hir::Expr) {
fn visit_expr_post(&mut self, e: &'tcx hir::Expr) {
run_lints!(self, check_expr_post, late_passes, e);
}
fn visit_generics(&mut self, g: &hir::Generics) {
fn visit_generics(&mut self, g: &'tcx hir::Generics) {
run_lints!(self, check_generics, late_passes, g);
hir_visit::walk_generics(self, g);
}
fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) {
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
self.with_lint_attrs(&trait_item.attrs, |cx| {
run_lints!(cx, check_trait_item, late_passes, trait_item);
cx.visit_ids(|v| hir_visit::walk_trait_item(v, trait_item));
@ -934,7 +931,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
});
}
fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) {
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
self.with_lint_attrs(&impl_item.attrs, |cx| {
run_lints!(cx, check_impl_item, late_passes, impl_item);
cx.visit_ids(|v| hir_visit::walk_impl_item(v, impl_item));
@ -943,20 +940,20 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
});
}
fn visit_lifetime(&mut self, lt: &hir::Lifetime) {
fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) {
run_lints!(self, check_lifetime, late_passes, lt);
}
fn visit_lifetime_def(&mut self, lt: &hir::LifetimeDef) {
fn visit_lifetime_def(&mut self, lt: &'tcx hir::LifetimeDef) {
run_lints!(self, check_lifetime_def, late_passes, lt);
}
fn visit_path(&mut self, p: &hir::Path, id: ast::NodeId) {
fn visit_path(&mut self, p: &'tcx hir::Path, id: ast::NodeId) {
run_lints!(self, check_path, late_passes, p, id);
hir_visit::walk_path(self, p);
}
fn visit_path_list_item(&mut self, prefix: &hir::Path, item: &hir::PathListItem) {
fn visit_path_list_item(&mut self, prefix: &'tcx hir::Path, item: &'tcx hir::PathListItem) {
run_lints!(self, check_path_list_item, late_passes, item);
hir_visit::walk_path_list_item(self, prefix, item);
}
@ -1121,7 +1118,6 @@ struct IdVisitor<'a, 'b: 'a, 'tcx: 'a+'b> {
// Output any lints that were previously added to the session.
impl<'a, 'b, 'tcx, 'v> hir_visit::Visitor<'v> for IdVisitor<'a, 'b, 'tcx> {
fn visit_id(&mut self, id: ast::NodeId) {
if let Some(lints) = self.cx.sess().lints.borrow_mut().remove(&id) {
debug!("LateContext::visit_id: id={:?} lints={:?}", id, lints);

View File

@ -511,22 +511,16 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> {
}
}
impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> {
impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> {
/// Walk nested items in place so that we don't report dead-code
/// on inner functions when the outer function is already getting
/// an error. We could do this also by checking the parents, but
/// this is how the code is setup and it seems harmless enough.
fn visit_nested_item(&mut self, item: hir::ItemId) {
let item = self.tcx.map.expect_item(item.id);
self.visit_item(item)
fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> {
Some(&self.tcx.map)
}
fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) {
let impl_item = self.tcx.map.impl_item(item_id);
self.visit_impl_item(impl_item)
}
fn visit_item(&mut self, item: &hir::Item) {
fn visit_item(&mut self, item: &'tcx hir::Item) {
if self.should_warn_about_item(item) {
self.warn_dead_code(
item.id,
@ -540,7 +534,10 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> {
}
}
fn visit_variant(&mut self, variant: &hir::Variant, g: &hir::Generics, id: ast::NodeId) {
fn visit_variant(&mut self,
variant: &'tcx hir::Variant,
g: &'tcx hir::Generics,
id: ast::NodeId) {
if self.should_warn_about_variant(&variant.node) {
self.warn_dead_code(variant.node.data.id(), variant.span,
variant.node.name, "variant");
@ -549,14 +546,14 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> {
}
}
fn visit_foreign_item(&mut self, fi: &hir::ForeignItem) {
fn visit_foreign_item(&mut self, fi: &'tcx hir::ForeignItem) {
if !self.symbol_is_live(fi.id, None) {
self.warn_dead_code(fi.id, fi.span, fi.name, fi.node.descriptive_variant());
}
intravisit::walk_foreign_item(self, fi);
}
fn visit_struct_field(&mut self, field: &hir::StructField) {
fn visit_struct_field(&mut self, field: &'tcx hir::StructField) {
if self.should_warn_about_field(&field) {
self.warn_dead_code(field.id, field.span,
field.name, "field");
@ -565,7 +562,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> {
intravisit::walk_struct_field(self, field);
}
fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) {
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
match impl_item.node {
hir::ImplItemKind::Const(_, ref expr) => {
if !self.symbol_is_live(impl_item.id, None) {
@ -586,7 +583,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> {
}
// Overwrite so that we don't warn the trait item itself.
fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) {
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
match trait_item.node {
hir::ConstTraitItem(_, Some(ref body))|
hir::MethodTraitItem(_, Some(ref body)) => {

View File

@ -132,21 +132,14 @@ pub fn krate(sess: &Session,
Ok(map)
}
impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> {
impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
// Override the nested functions -- lifetimes follow lexical scope,
// so it's convenient to walk the tree in lexical order.
fn visit_nested_item(&mut self, id: hir::ItemId) {
let item = self.hir_map.expect_item(id.id);
self.visit_item(item)
fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> {
Some(&self.hir_map)
}
fn visit_nested_impl_item(&mut self, id: hir::ImplItemId) {
let impl_item = self.hir_map.impl_item(id);
self.visit_impl_item(impl_item)
}
fn visit_item(&mut self, item: &hir::Item) {
fn visit_item(&mut self, item: &'tcx hir::Item) {
// Save labels for nested items.
let saved_labels_in_fn = replace(&mut self.labels_in_fn, vec![]);
@ -192,7 +185,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> {
self.labels_in_fn = saved_labels_in_fn;
}
fn visit_foreign_item(&mut self, item: &hir::ForeignItem) {
fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem) {
// Items save/restore the set of labels. This way inner items
// can freely reuse names, be they loop labels or lifetimes.
let saved = replace(&mut self.labels_in_fn, vec![]);
@ -215,8 +208,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> {
replace(&mut self.labels_in_fn, saved);
}
fn visit_fn(&mut self, fk: FnKind<'v>, decl: &'v hir::FnDecl,
b: &'v hir::Expr, s: Span, fn_id: ast::NodeId) {
fn visit_fn(&mut self, fk: FnKind<'tcx>, decl: &'tcx hir::FnDecl,
b: &'tcx hir::Expr, s: Span, fn_id: ast::NodeId) {
match fk {
FnKind::ItemFn(_, generics, ..) => {
self.visit_early_late(fn_id,decl, generics, |this| {
@ -241,7 +234,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> {
}
}
fn visit_ty(&mut self, ty: &hir::Ty) {
fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
match ty.node {
hir::TyBareFn(ref c) => {
self.with(LateScope(&c.lifetimes, self.scope), |old_scope, this| {
@ -271,7 +264,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> {
}
}
fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) {
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
// We reset the labels on every trait item, so that different
// methods in an impl can reuse label names.
let saved = replace(&mut self.labels_in_fn, vec![]);
@ -288,7 +281,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> {
replace(&mut self.labels_in_fn, saved);
}
fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) {
fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
if lifetime_ref.name == keywords::StaticLifetime.name() {
self.insert_lifetime(lifetime_ref, DefStaticRegion);
return;
@ -296,7 +289,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> {
self.resolve_lifetime_ref(lifetime_ref);
}
fn visit_generics(&mut self, generics: &hir::Generics) {
fn visit_generics(&mut self, generics: &'tcx hir::Generics) {
for ty_param in generics.ty_params.iter() {
walk_list!(self, visit_ty_param_bound, &ty_param.bounds);
if let Some(ref ty) = ty_param.default {
@ -345,8 +338,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> {
}
fn visit_poly_trait_ref(&mut self,
trait_ref: &hir::PolyTraitRef,
_modifier: &hir::TraitBoundModifier) {
trait_ref: &'tcx hir::PolyTraitRef,
_modifier: &'tcx hir::TraitBoundModifier) {
debug!("visit_poly_trait_ref trait_ref={:?}", trait_ref);
if !self.trait_ref_hack || !trait_ref.bound_lifetimes.is_empty() {
@ -504,13 +497,12 @@ fn extract_labels(ctxt: &mut LifetimeContext, b: &hir::Expr) {
}
impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
fn add_scope_and_walk_fn<'b>(&mut self,
fk: FnKind,
fd: &hir::FnDecl,
fb: &'b hir::Expr,
_span: Span,
fn_id: ast::NodeId) {
fn add_scope_and_walk_fn(&mut self,
fk: FnKind<'tcx>,
fd: &'tcx hir::FnDecl,
fb: &'tcx hir::Expr,
_span: Span,
fn_id: ast::NodeId) {
match fk {
FnKind::ItemFn(_, generics, ..) => {
intravisit::walk_fn_decl(self, fd);
@ -533,8 +525,15 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|_old_scope, this| this.visit_expr(fb))
}
// FIXME(#37666) this works around a limitation in the region inferencer
fn hack<F>(&mut self, f: F) where
F: for<'b> FnOnce(&mut LifetimeContext<'b, 'tcx>),
{
f(self)
}
fn with<F>(&mut self, wrap_scope: ScopeChain, f: F) where
F: FnOnce(Scope, &mut LifetimeContext),
F: for<'b> FnOnce(Scope, &mut LifetimeContext<'b, 'tcx>),
{
let LifetimeContext {sess, hir_map, ref mut map, ..} = *self;
let mut this = LifetimeContext {
@ -571,10 +570,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
/// ordering is not important there.
fn visit_early_late<F>(&mut self,
fn_id: ast::NodeId,
decl: &hir::FnDecl,
generics: &hir::Generics,
decl: &'tcx hir::FnDecl,
generics: &'tcx hir::Generics,
walk: F) where
F: FnOnce(&mut LifetimeContext),
F: for<'b, 'c> FnOnce(&'b mut LifetimeContext<'c, 'tcx>),
{
let fn_def_id = self.hir_map.local_def_id(fn_id);
insert_late_bound_lifetimes(self.map,
@ -604,11 +603,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
}
}
let this = self;
this.with(EarlyScope(&early, start as u32, this.scope), move |old_scope, this| {
self.with(EarlyScope(&early, start as u32, self.scope), move |old_scope, this| {
this.with(LateScope(&late, this.scope), move |_, this| {
this.check_lifetime_defs(old_scope, &generics.lifetimes);
walk(this);
this.hack(walk); // FIXME(#37666) workaround in place of `walk(this)`
});
});
}

View File

@ -120,7 +120,7 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> {
// stability. The stability is recorded in the index and used as the parent.
fn annotate<F>(&mut self, id: NodeId, attrs: &[Attribute],
item_sp: Span, kind: AnnotationKind, visit_children: F)
where F: FnOnce(&mut Annotator)
where F: FnOnce(&mut Self)
{
if self.index.staged_api[&LOCAL_CRATE] && self.tcx.sess.features.borrow().staged_api {
debug!("annotate(id = {:?}, attrs = {:?})", id, attrs);
@ -234,21 +234,15 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> {
}
}
impl<'a, 'tcx, 'v> Visitor<'v> for Annotator<'a, 'tcx> {
impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
/// Because stability levels are scoped lexically, we want to walk
/// nested items in the context of the outer item, so enable
/// deep-walking.
fn visit_nested_item(&mut self, item: hir::ItemId) {
let item = self.tcx.map.expect_item(item.id);
self.visit_item(item)
fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> {
Some(&self.tcx.map)
}
fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) {
let impl_item = self.tcx.map.impl_item(item_id);
self.visit_impl_item(impl_item)
}
fn visit_item(&mut self, i: &Item) {
fn visit_item(&mut self, i: &'tcx Item) {
let orig_in_trait_impl = self.in_trait_impl;
let mut kind = AnnotationKind::Required;
match i.node {
@ -277,13 +271,13 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Annotator<'a, 'tcx> {
self.in_trait_impl = orig_in_trait_impl;
}
fn visit_trait_item(&mut self, ti: &hir::TraitItem) {
fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem) {
self.annotate(ti.id, &ti.attrs, ti.span, AnnotationKind::Required, |v| {
intravisit::walk_trait_item(v, ti);
});
}
fn visit_impl_item(&mut self, ii: &hir::ImplItem) {
fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem) {
let kind = if self.in_trait_impl {
AnnotationKind::Prohibited
} else {
@ -294,25 +288,25 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Annotator<'a, 'tcx> {
});
}
fn visit_variant(&mut self, var: &Variant, g: &'v Generics, item_id: NodeId) {
fn visit_variant(&mut self, var: &'tcx Variant, g: &'tcx Generics, item_id: NodeId) {
self.annotate(var.node.data.id(), &var.node.attrs, var.span, AnnotationKind::Required, |v| {
intravisit::walk_variant(v, var, g, item_id);
})
}
fn visit_struct_field(&mut self, s: &StructField) {
fn visit_struct_field(&mut self, s: &'tcx StructField) {
self.annotate(s.id, &s.attrs, s.span, AnnotationKind::Required, |v| {
intravisit::walk_struct_field(v, s);
});
}
fn visit_foreign_item(&mut self, i: &hir::ForeignItem) {
fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem) {
self.annotate(i.id, &i.attrs, i.span, AnnotationKind::Required, |v| {
intravisit::walk_foreign_item(v, i);
});
}
fn visit_macro_def(&mut self, md: &'v hir::MacroDef) {
fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef) {
if md.imported_from.is_none() {
self.annotate(md.id, &md.attrs, md.span, AnnotationKind::Required, |_| {});
}
@ -449,21 +443,15 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
}
}
impl<'a, 'v, 'tcx> Visitor<'v> for Checker<'a, 'tcx> {
impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
/// Because stability levels are scoped lexically, we want to walk
/// nested items in the context of the outer item, so enable
/// deep-walking.
fn visit_nested_item(&mut self, item: hir::ItemId) {
let item = self.tcx.map.expect_item(item.id);
self.visit_item(item)
fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> {
Some(&self.tcx.map)
}
fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) {
let impl_item = self.tcx.map.impl_item(item_id);
self.visit_impl_item(impl_item)
}
fn visit_item(&mut self, item: &hir::Item) {
fn visit_item(&mut self, item: &'tcx hir::Item) {
// When compiling with --test we don't enforce stability on the
// compiler-generated test module, demarcated with `DUMMY_SP` plus the
// name `__test`
@ -474,31 +462,31 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Checker<'a, 'tcx> {
intravisit::walk_item(self, item);
}
fn visit_expr(&mut self, ex: &hir::Expr) {
fn visit_expr(&mut self, ex: &'tcx hir::Expr) {
check_expr(self.tcx, ex,
&mut |id, sp, stab, depr| self.check(id, sp, stab, depr));
intravisit::walk_expr(self, ex);
}
fn visit_path(&mut self, path: &hir::Path, id: ast::NodeId) {
fn visit_path(&mut self, path: &'tcx hir::Path, id: ast::NodeId) {
check_path(self.tcx, path, id,
&mut |id, sp, stab, depr| self.check(id, sp, stab, depr));
intravisit::walk_path(self, path)
}
fn visit_path_list_item(&mut self, prefix: &hir::Path, item: &hir::PathListItem) {
fn visit_path_list_item(&mut self, prefix: &'tcx hir::Path, item: &'tcx hir::PathListItem) {
check_path_list_item(self.tcx, item,
&mut |id, sp, stab, depr| self.check(id, sp, stab, depr));
intravisit::walk_path_list_item(self, prefix, item)
}
fn visit_pat(&mut self, pat: &hir::Pat) {
fn visit_pat(&mut self, pat: &'tcx hir::Pat) {
check_pat(self.tcx, pat,
&mut |id, sp, stab, depr| self.check(id, sp, stab, depr));
intravisit::walk_pat(self, pat)
}
fn visit_block(&mut self, b: &hir::Block) {
fn visit_block(&mut self, b: &'tcx hir::Block) {
let old_skip_count = self.in_skip_block;
match b.rules {
hir::BlockCheckMode::PushUnstableBlock => {

View File

@ -499,14 +499,6 @@ macro_rules! hash_span {
}
impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'hash, 'tcx> {
fn visit_nested_item(&mut self, _: ItemId) {
// Each item is hashed independently; ignore nested items.
}
fn visit_nested_impl_item(&mut self, _: ImplItemId) {
// Impl items are hashed independently; ignore nested impl items.
}
fn visit_variant_data(&mut self,
s: &'tcx VariantData,
name: Name,

View File

@ -106,12 +106,20 @@ impl<'k> StatCollector<'k> {
}
impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'v>> {
panic!("visit_nested_xxx must be manually implemented in this visitor")
}
fn visit_nested_item(&mut self, id: hir::ItemId) {
let nested_item = self.krate.unwrap().item(id.id);
self.visit_item(nested_item)
}
fn visit_nested_impl_item(&mut self, impl_item_id: hir::ImplItemId) {
let nested_impl_item = self.krate.unwrap().impl_item(impl_item_id);
self.visit_impl_item(nested_impl_item)
}
fn visit_item(&mut self, i: &'v hir::Item) {
self.record("Item", Id::Node(i.id), i);
hir_visit::walk_item(self, i)

View File

@ -116,20 +116,14 @@ impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> {
}
}
impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> {
/// We want to visit items in the context of their containing
/// module and so forth, so supply a crate for doing a deep walk.
fn visit_nested_item(&mut self, item: hir::ItemId) {
let tcx = self.tcx;
self.visit_item(tcx.map.expect_item(item.id))
fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> {
Some(&self.tcx.map)
}
fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) {
let impl_item = self.tcx.map.impl_item(item_id);
self.visit_impl_item(impl_item)
}
fn visit_item(&mut self, item: &hir::Item) {
fn visit_item(&mut self, item: &'tcx hir::Item) {
let inherited_item_level = match item.node {
// Impls inherit level from their types and traits
hir::ItemImpl(.., None, ref ty, _) => {
@ -278,7 +272,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
self.prev_level = orig_level;
}
fn visit_block(&mut self, b: &'v hir::Block) {
fn visit_block(&mut self, b: &'tcx hir::Block) {
let orig_level = replace(&mut self.prev_level, None);
// Blocks can have public items, for example impls, but they always
@ -289,7 +283,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
self.prev_level = orig_level;
}
fn visit_mod(&mut self, m: &hir::Mod, _sp: Span, id: ast::NodeId) {
fn visit_mod(&mut self, m: &'tcx 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_level.is_some() {
@ -305,14 +299,14 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
intravisit::walk_mod(self, m, id);
}
fn visit_macro_def(&mut self, md: &'v hir::MacroDef) {
fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef) {
self.update(md.id, Some(AccessLevel::Public));
}
}
impl<'b, 'a, 'tcx: 'a> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
// Make the type hidden under a type alias reachable
fn reach_aliased_type(&mut self, item: &hir::Item, path: &hir::Path) {
fn reach_aliased_type(&mut self, item: &'tcx hir::Item, path: &'tcx hir::Path) {
if let hir::ItemTy(ref ty, ref generics) = item.node {
// See `fn is_public_type_alias` for details
self.visit_ty(ty);
@ -326,14 +320,14 @@ impl<'b, 'a, 'tcx: 'a> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
}
}
impl<'b, 'a, 'tcx: 'a, 'v> Visitor<'v> for ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
impl<'b, 'a, 'tcx: 'a> Visitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) {
// when we visit an impl, its methods and items are part of its "interface"
let impl_item = self.ev.tcx.map.impl_item(item_id);
self.visit_impl_item(impl_item)
}
fn visit_ty(&mut self, ty: &hir::Ty) {
fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
if let hir::TyPath(_, ref path) = ty.node {
let def = self.ev.tcx.expect_def(ty.id);
match def {
@ -365,7 +359,7 @@ impl<'b, 'a, 'tcx: 'a, 'v> Visitor<'v> for ReachEverythingInTheInterfaceVisitor<
intravisit::walk_ty(self, ty);
}
fn visit_trait_ref(&mut self, trait_ref: &hir::TraitRef) {
fn visit_trait_ref(&mut self, trait_ref: &'tcx hir::TraitRef) {
let def_id = self.ev.tcx.expect_def(trait_ref.ref_id).def_id();
if let Some(node_id) = self.ev.tcx.map.as_local_node_id(def_id) {
let item = self.ev.tcx.map.expect_item(node_id);
@ -427,26 +421,20 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
}
}
impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
impl<'a, 'tcx> Visitor<'tcx> for PrivacyVisitor<'a, 'tcx> {
/// We want to visit items in the context of their containing
/// module and so forth, so supply a crate for doing a deep walk.
fn visit_nested_item(&mut self, item: hir::ItemId) {
let tcx = self.tcx;
self.visit_item(tcx.map.expect_item(item.id))
fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> {
Some(&self.tcx.map)
}
fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) {
let impl_item = self.tcx.map.impl_item(item_id);
self.visit_impl_item(impl_item)
}
fn visit_item(&mut self, item: &hir::Item) {
fn visit_item(&mut self, item: &'tcx hir::Item) {
let orig_curitem = replace(&mut self.curitem, item.id);
intravisit::walk_item(self, item);
self.curitem = orig_curitem;
}
fn visit_expr(&mut self, expr: &hir::Expr) {
fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
match expr.node {
hir::ExprMethodCall(..) => {
let method_call = ty::MethodCall::expr(expr.id);
@ -506,7 +494,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
intravisit::walk_expr(self, expr);
}
fn visit_pat(&mut self, pattern: &hir::Pat) {
fn visit_pat(&mut self, pattern: &'tcx hir::Pat) {
// Foreign functions do not have their patterns mapped in the def_map,
// and there's nothing really relevant there anyway, so don't bother
// checking privacy. If you can name the type then you can pass it to an
@ -542,7 +530,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
intravisit::walk_pat(self, pattern);
}
fn visit_foreign_item(&mut self, fi: &hir::ForeignItem) {
fn visit_foreign_item(&mut self, fi: &'tcx hir::ForeignItem) {
self.in_foreign = true;
intravisit::walk_foreign_item(self, fi);
self.in_foreign = false;
@ -636,20 +624,14 @@ impl<'a, 'b, 'tcx, 'v> Visitor<'v> for ObsoleteCheckTypeForPrivatenessVisitor<'a
fn visit_expr(&mut self, _: &hir::Expr) {}
}
impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
/// We want to visit items in the context of their containing
/// module and so forth, so supply a crate for doing a deep walk.
fn visit_nested_item(&mut self, item: hir::ItemId) {
let tcx = self.tcx;
self.visit_item(tcx.map.expect_item(item.id))
fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> {
Some(&self.tcx.map)
}
fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) {
let impl_item = self.tcx.map.impl_item(item_id);
self.visit_impl_item(impl_item)
}
fn visit_item(&mut self, item: &hir::Item) {
fn visit_item(&mut self, item: &'tcx hir::Item) {
match item.node {
// contents of a private mod can be reexported, so we need
// to check internals.
@ -834,7 +816,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx>
intravisit::walk_item(self, item);
}
fn visit_generics(&mut self, generics: &hir::Generics) {
fn visit_generics(&mut self, generics: &'tcx hir::Generics) {
for ty_param in generics.ty_params.iter() {
for bound in ty_param.bounds.iter() {
self.check_ty_param_bound(bound)
@ -855,13 +837,13 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx>
}
}
fn visit_foreign_item(&mut self, item: &hir::ForeignItem) {
fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem) {
if self.access_levels.is_reachable(item.id) {
intravisit::walk_foreign_item(self, item)
}
}
fn visit_ty(&mut self, t: &hir::Ty) {
fn visit_ty(&mut self, t: &'tcx hir::Ty) {
if let hir::TyPath(..) = t.node {
if self.path_is_private_type(t.id) {
self.old_error_set.insert(t.id);
@ -870,7 +852,10 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx>
intravisit::walk_ty(self, t)
}
fn visit_variant(&mut self, v: &hir::Variant, g: &hir::Generics, item_id: ast::NodeId) {
fn visit_variant(&mut self,
v: &'tcx hir::Variant,
g: &'tcx hir::Generics,
item_id: ast::NodeId) {
if self.access_levels.is_reachable(v.node.data.id()) {
self.in_variant = true;
intravisit::walk_variant(self, v, g, item_id);
@ -878,7 +863,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx>
}
}
fn visit_struct_field(&mut self, s: &hir::StructField) {
fn visit_struct_field(&mut self, s: &'tcx hir::StructField) {
if s.vis == hir::Public || self.in_variant {
intravisit::walk_struct_field(self, s);
}
@ -888,8 +873,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx>
// expression/block context can't possibly contain exported things.
// (Making them no-ops stops us from traversing the whole AST without
// having to be super careful about our `walk_...` calls above.)
fn visit_block(&mut self, _: &hir::Block) {}
fn visit_expr(&mut self, _: &hir::Expr) {}
fn visit_block(&mut self, _: &'tcx hir::Block) {}
fn visit_expr(&mut self, _: &'tcx hir::Expr) {}
}
///////////////////////////////////////////////////////////////////////////////