Skip to content

Commit 26d1500

Browse files
committed
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.
1 parent 4df5288 commit 26d1500

File tree

9 files changed

+181
-182
lines changed

9 files changed

+181
-182
lines changed

src/librustc/hir/intravisit.rs

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ use syntax::ast::{NodeId, CRATE_NODE_ID, Name, Attribute};
3838
use syntax::codemap::Spanned;
3939
use syntax_pos::Span;
4040
use hir::*;
41+
use hir::map::Map;
4142
use super::itemlikevisit::DeepVisitor;
4243

4344
use std::cmp;
@@ -85,23 +86,52 @@ pub trait Visitor<'v> : Sized {
8586
///////////////////////////////////////////////////////////////////////////
8687
// Nested items.
8788

88-
/// Invoked when a nested item is encountered. By default, does
89-
/// nothing. If you want a deep walk, you need to override to
90-
/// fetch the item contents. But most of the time, it is easier to
91-
/// use either the "shallow" or "deep" visit patterns described on
92-
/// `itemlikevisit::ItemLikeVisitor`.
89+
/// The default versions of the `visit_nested_XXX` routines invoke
90+
/// this method to get a map to use; if they get back `None`, they
91+
/// just skip nested things. Otherwise, they will lookup the
92+
/// nested item-like things in the map and visit it. So the best
93+
/// way to implement a nested visitor is to override this method
94+
/// to return a `Map`; one advantage of this is that if we add
95+
/// more types of nested things in the future, they will
96+
/// automatically work.
97+
///
98+
/// **If for some reason you want the nested behavior, but don't
99+
/// have a `Map` are your disposal:** then you should override the
100+
/// `visit_nested_XXX` methods, and override this method to
101+
/// `panic!()`. This way, if a new `visit_nested_XXX` variant is
102+
/// added in the future, we will see the panic in your code and
103+
/// fix it appropriately.
104+
fn nested_visit_map(&mut self) -> Option<&Map<'v>> {
105+
None
106+
}
107+
108+
/// Invoked when a nested item is encountered. By default does
109+
/// nothing unless you override `nested_visit_map` to return
110+
/// `Some(_)`, in which case it will walk the item. **You probably
111+
/// don't want to override this method** -- instead, override
112+
/// `nested_visit_map` or use the "shallow" or "deep" visit
113+
/// patterns described on `itemlikevisit::ItemLikeVisitor`. The only
114+
/// reason to override this method is if you want a nested pattern
115+
/// but cannot supply a `Map`; see `nested_visit_map` for advice.
93116
#[allow(unused_variables)]
94117
fn visit_nested_item(&mut self, id: ItemId) {
118+
let opt_item = self.nested_visit_map()
119+
.map(|map| map.expect_item(id.id));
120+
if let Some(item) = opt_item {
121+
self.visit_item(item);
122+
}
95123
}
96124

97-
/// Invoked when a nested impl item is encountered. By default, does
98-
/// nothing. If you want a deep walk, you need to override to
99-
/// fetch the item contents. But most of the time, it is easier
100-
/// (and better) to invoke `Crate::visit_all_item_likes`, which visits
101-
/// all items in the crate in some order (but doesn't respect
102-
/// nesting).
125+
/// Like `visit_nested_item()`, but for impl items. See
126+
/// `visit_nested_item()` for advice on when to override this
127+
/// method.
103128
#[allow(unused_variables)]
104129
fn visit_nested_impl_item(&mut self, id: ImplItemId) {
130+
let opt_item = self.nested_visit_map()
131+
.map(|map| map.impl_item(id));
132+
if let Some(item) = opt_item {
133+
self.visit_impl_item(item);
134+
}
105135
}
106136

107137
/// Visit the top-level item and (optionally) nested items / impl items. See

src/librustc/hir/map/collector.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,11 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
9292
/// Because we want to track parent items and so forth, enable
9393
/// deep walking so that we walk nested items in the context of
9494
/// their outer items.
95+
96+
fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'v>> {
97+
panic!("visit_nested_xxx must be manually implemented in this visitor")
98+
}
99+
95100
fn visit_nested_item(&mut self, item: ItemId) {
96101
debug!("visit_nested_item: {:?}", item);
97102
if !self.ignore_nested_items {

src/librustc/lint/context.rs

Lines changed: 31 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -792,21 +792,15 @@ impl<'a> LintContext for EarlyContext<'a> {
792792
}
793793
}
794794

795-
impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
795+
impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
796796
/// Because lints are scoped lexically, we want to walk nested
797797
/// items in the context of the outer item, so enable
798798
/// deep-walking.
799-
fn visit_nested_item(&mut self, item: hir::ItemId) {
800-
let item = self.tcx.map.expect_item(item.id);
801-
self.visit_item(item)
799+
fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> {
800+
Some(&self.tcx.map)
802801
}
803802

804-
fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) {
805-
let impl_item = self.tcx.map.impl_item(item_id);
806-
self.visit_impl_item(impl_item)
807-
}
808-
809-
fn visit_item(&mut self, it: &hir::Item) {
803+
fn visit_item(&mut self, it: &'tcx hir::Item) {
810804
self.with_lint_attrs(&it.attrs, |cx| {
811805
run_lints!(cx, check_item, late_passes, it);
812806
cx.visit_ids(|v| v.visit_item(it));
@@ -815,27 +809,27 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
815809
})
816810
}
817811

818-
fn visit_foreign_item(&mut self, it: &hir::ForeignItem) {
812+
fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem) {
819813
self.with_lint_attrs(&it.attrs, |cx| {
820814
run_lints!(cx, check_foreign_item, late_passes, it);
821815
hir_visit::walk_foreign_item(cx, it);
822816
run_lints!(cx, check_foreign_item_post, late_passes, it);
823817
})
824818
}
825819

826-
fn visit_pat(&mut self, p: &hir::Pat) {
820+
fn visit_pat(&mut self, p: &'tcx hir::Pat) {
827821
run_lints!(self, check_pat, late_passes, p);
828822
hir_visit::walk_pat(self, p);
829823
}
830824

831-
fn visit_expr(&mut self, e: &hir::Expr) {
825+
fn visit_expr(&mut self, e: &'tcx hir::Expr) {
832826
self.with_lint_attrs(&e.attrs, |cx| {
833827
run_lints!(cx, check_expr, late_passes, e);
834828
hir_visit::walk_expr(cx, e);
835829
})
836830
}
837831

838-
fn visit_stmt(&mut self, s: &hir::Stmt) {
832+
fn visit_stmt(&mut self, s: &'tcx hir::Stmt) {
839833
// statement attributes are actually just attributes on one of
840834
// - item
841835
// - local
@@ -845,40 +839,43 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
845839
hir_visit::walk_stmt(self, s);
846840
}
847841

848-
fn visit_fn(&mut self, fk: hir_visit::FnKind<'v>, decl: &'v hir::FnDecl,
849-
body: &'v hir::Expr, span: Span, id: ast::NodeId) {
842+
fn visit_fn(&mut self, fk: hir_visit::FnKind<'tcx>, decl: &'tcx hir::FnDecl,
843+
body: &'tcx hir::Expr, span: Span, id: ast::NodeId) {
850844
run_lints!(self, check_fn, late_passes, fk, decl, body, span, id);
851845
hir_visit::walk_fn(self, fk, decl, body, span, id);
852846
run_lints!(self, check_fn_post, late_passes, fk, decl, body, span, id);
853847
}
854848

855849
fn visit_variant_data(&mut self,
856-
s: &hir::VariantData,
850+
s: &'tcx hir::VariantData,
857851
name: ast::Name,
858-
g: &hir::Generics,
852+
g: &'tcx hir::Generics,
859853
item_id: ast::NodeId,
860854
_: Span) {
861855
run_lints!(self, check_struct_def, late_passes, s, name, g, item_id);
862856
hir_visit::walk_struct_def(self, s);
863857
run_lints!(self, check_struct_def_post, late_passes, s, name, g, item_id);
864858
}
865859

866-
fn visit_struct_field(&mut self, s: &hir::StructField) {
860+
fn visit_struct_field(&mut self, s: &'tcx hir::StructField) {
867861
self.with_lint_attrs(&s.attrs, |cx| {
868862
run_lints!(cx, check_struct_field, late_passes, s);
869863
hir_visit::walk_struct_field(cx, s);
870864
})
871865
}
872866

873-
fn visit_variant(&mut self, v: &hir::Variant, g: &hir::Generics, item_id: ast::NodeId) {
867+
fn visit_variant(&mut self,
868+
v: &'tcx hir::Variant,
869+
g: &'tcx hir::Generics,
870+
item_id: ast::NodeId) {
874871
self.with_lint_attrs(&v.node.attrs, |cx| {
875872
run_lints!(cx, check_variant, late_passes, v, g);
876873
hir_visit::walk_variant(cx, v, g, item_id);
877874
run_lints!(cx, check_variant_post, late_passes, v, g);
878875
})
879876
}
880877

881-
fn visit_ty(&mut self, t: &hir::Ty) {
878+
fn visit_ty(&mut self, t: &'tcx hir::Ty) {
882879
run_lints!(self, check_ty, late_passes, t);
883880
hir_visit::walk_ty(self, t);
884881
}
@@ -887,45 +884,45 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
887884
run_lints!(self, check_name, late_passes, sp, name);
888885
}
889886

890-
fn visit_mod(&mut self, m: &hir::Mod, s: Span, n: ast::NodeId) {
887+
fn visit_mod(&mut self, m: &'tcx hir::Mod, s: Span, n: ast::NodeId) {
891888
run_lints!(self, check_mod, late_passes, m, s, n);
892889
hir_visit::walk_mod(self, m, n);
893890
run_lints!(self, check_mod_post, late_passes, m, s, n);
894891
}
895892

896-
fn visit_local(&mut self, l: &hir::Local) {
893+
fn visit_local(&mut self, l: &'tcx hir::Local) {
897894
self.with_lint_attrs(&l.attrs, |cx| {
898895
run_lints!(cx, check_local, late_passes, l);
899896
hir_visit::walk_local(cx, l);
900897
})
901898
}
902899

903-
fn visit_block(&mut self, b: &hir::Block) {
900+
fn visit_block(&mut self, b: &'tcx hir::Block) {
904901
run_lints!(self, check_block, late_passes, b);
905902
hir_visit::walk_block(self, b);
906903
run_lints!(self, check_block_post, late_passes, b);
907904
}
908905

909-
fn visit_arm(&mut self, a: &hir::Arm) {
906+
fn visit_arm(&mut self, a: &'tcx hir::Arm) {
910907
run_lints!(self, check_arm, late_passes, a);
911908
hir_visit::walk_arm(self, a);
912909
}
913910

914-
fn visit_decl(&mut self, d: &hir::Decl) {
911+
fn visit_decl(&mut self, d: &'tcx hir::Decl) {
915912
run_lints!(self, check_decl, late_passes, d);
916913
hir_visit::walk_decl(self, d);
917914
}
918915

919-
fn visit_expr_post(&mut self, e: &hir::Expr) {
916+
fn visit_expr_post(&mut self, e: &'tcx hir::Expr) {
920917
run_lints!(self, check_expr_post, late_passes, e);
921918
}
922919

923-
fn visit_generics(&mut self, g: &hir::Generics) {
920+
fn visit_generics(&mut self, g: &'tcx hir::Generics) {
924921
run_lints!(self, check_generics, late_passes, g);
925922
hir_visit::walk_generics(self, g);
926923
}
927924

928-
fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) {
925+
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
929926
self.with_lint_attrs(&trait_item.attrs, |cx| {
930927
run_lints!(cx, check_trait_item, late_passes, trait_item);
931928
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> {
934931
});
935932
}
936933

937-
fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) {
934+
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
938935
self.with_lint_attrs(&impl_item.attrs, |cx| {
939936
run_lints!(cx, check_impl_item, late_passes, impl_item);
940937
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> {
943940
});
944941
}
945942

946-
fn visit_lifetime(&mut self, lt: &hir::Lifetime) {
943+
fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) {
947944
run_lints!(self, check_lifetime, late_passes, lt);
948945
}
949946

950-
fn visit_lifetime_def(&mut self, lt: &hir::LifetimeDef) {
947+
fn visit_lifetime_def(&mut self, lt: &'tcx hir::LifetimeDef) {
951948
run_lints!(self, check_lifetime_def, late_passes, lt);
952949
}
953950

954-
fn visit_path(&mut self, p: &hir::Path, id: ast::NodeId) {
951+
fn visit_path(&mut self, p: &'tcx hir::Path, id: ast::NodeId) {
955952
run_lints!(self, check_path, late_passes, p, id);
956953
hir_visit::walk_path(self, p);
957954
}
958955

959-
fn visit_path_list_item(&mut self, prefix: &hir::Path, item: &hir::PathListItem) {
956+
fn visit_path_list_item(&mut self, prefix: &'tcx hir::Path, item: &'tcx hir::PathListItem) {
960957
run_lints!(self, check_path_list_item, late_passes, item);
961958
hir_visit::walk_path_list_item(self, prefix, item);
962959
}
@@ -1121,7 +1118,6 @@ struct IdVisitor<'a, 'b: 'a, 'tcx: 'a+'b> {
11211118

11221119
// Output any lints that were previously added to the session.
11231120
impl<'a, 'b, 'tcx, 'v> hir_visit::Visitor<'v> for IdVisitor<'a, 'b, 'tcx> {
1124-
11251121
fn visit_id(&mut self, id: ast::NodeId) {
11261122
if let Some(lints) = self.cx.sess().lints.borrow_mut().remove(&id) {
11271123
debug!("LateContext::visit_id: id={:?} lints={:?}", id, lints);

src/librustc/middle/dead.rs

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -511,22 +511,16 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> {
511511
}
512512
}
513513

514-
impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> {
514+
impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> {
515515
/// Walk nested items in place so that we don't report dead-code
516516
/// on inner functions when the outer function is already getting
517517
/// an error. We could do this also by checking the parents, but
518518
/// this is how the code is setup and it seems harmless enough.
519-
fn visit_nested_item(&mut self, item: hir::ItemId) {
520-
let item = self.tcx.map.expect_item(item.id);
521-
self.visit_item(item)
519+
fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> {
520+
Some(&self.tcx.map)
522521
}
523522

524-
fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) {
525-
let impl_item = self.tcx.map.impl_item(item_id);
526-
self.visit_impl_item(impl_item)
527-
}
528-
529-
fn visit_item(&mut self, item: &hir::Item) {
523+
fn visit_item(&mut self, item: &'tcx hir::Item) {
530524
if self.should_warn_about_item(item) {
531525
self.warn_dead_code(
532526
item.id,
@@ -540,7 +534,10 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> {
540534
}
541535
}
542536

543-
fn visit_variant(&mut self, variant: &hir::Variant, g: &hir::Generics, id: ast::NodeId) {
537+
fn visit_variant(&mut self,
538+
variant: &'tcx hir::Variant,
539+
g: &'tcx hir::Generics,
540+
id: ast::NodeId) {
544541
if self.should_warn_about_variant(&variant.node) {
545542
self.warn_dead_code(variant.node.data.id(), variant.span,
546543
variant.node.name, "variant");
@@ -549,14 +546,14 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> {
549546
}
550547
}
551548

552-
fn visit_foreign_item(&mut self, fi: &hir::ForeignItem) {
549+
fn visit_foreign_item(&mut self, fi: &'tcx hir::ForeignItem) {
553550
if !self.symbol_is_live(fi.id, None) {
554551
self.warn_dead_code(fi.id, fi.span, fi.name, fi.node.descriptive_variant());
555552
}
556553
intravisit::walk_foreign_item(self, fi);
557554
}
558555

559-
fn visit_struct_field(&mut self, field: &hir::StructField) {
556+
fn visit_struct_field(&mut self, field: &'tcx hir::StructField) {
560557
if self.should_warn_about_field(&field) {
561558
self.warn_dead_code(field.id, field.span,
562559
field.name, "field");
@@ -565,7 +562,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> {
565562
intravisit::walk_struct_field(self, field);
566563
}
567564

568-
fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) {
565+
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
569566
match impl_item.node {
570567
hir::ImplItemKind::Const(_, ref expr) => {
571568
if !self.symbol_is_live(impl_item.id, None) {
@@ -586,7 +583,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> {
586583
}
587584

588585
// Overwrite so that we don't warn the trait item itself.
589-
fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) {
586+
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
590587
match trait_item.node {
591588
hir::ConstTraitItem(_, Some(ref body))|
592589
hir::MethodTraitItem(_, Some(ref body)) => {

0 commit comments

Comments
 (0)