]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/dead.rs
Various minor/cosmetic improvements to code
[rust.git] / src / librustc / middle / dead.rs
1 // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 // This implements the dead-code warning pass. It follows middle::reachable
12 // closely. The idea is that all reachable symbols are live, codes called
13 // from live codes are live, and everything else is dead.
14
15 use hir::Node;
16 use hir::{self, PatKind};
17 use hir::intravisit::{self, Visitor, NestedVisitorMap};
18 use hir::itemlikevisit::ItemLikeVisitor;
19
20 use hir::def::Def;
21 use hir::CodegenFnAttrFlags;
22 use hir::def_id::{DefId, LOCAL_CRATE};
23 use lint;
24 use middle::privacy;
25 use ty::{self, TyCtxt};
26 use util::nodemap::FxHashSet;
27
28 use syntax::{ast, source_map};
29 use syntax::attr;
30 use syntax_pos;
31
32 // Any local node that may call something in its body block should be
33 // explored. For example, if it's a live Node::Item that is a
34 // function, then we should explore its block to check for codes that
35 // may need to be marked as live.
36 fn should_explore<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
37                             node_id: ast::NodeId) -> bool {
38     match tcx.hir().find(node_id) {
39         Some(Node::Item(..)) |
40         Some(Node::ImplItem(..)) |
41         Some(Node::ForeignItem(..)) |
42         Some(Node::TraitItem(..)) =>
43             true,
44         _ =>
45             false
46     }
47 }
48
49 struct MarkSymbolVisitor<'a, 'tcx: 'a> {
50     worklist: Vec<ast::NodeId>,
51     tcx: TyCtxt<'a, 'tcx, 'tcx>,
52     tables: &'a ty::TypeckTables<'tcx>,
53     live_symbols: FxHashSet<ast::NodeId>,
54     repr_has_repr_c: bool,
55     in_pat: bool,
56     inherited_pub_visibility: bool,
57     ignore_variant_stack: Vec<DefId>,
58 }
59
60 impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
61     fn check_def_id(&mut self, def_id: DefId) {
62         if let Some(node_id) = self.tcx.hir().as_local_node_id(def_id) {
63             if should_explore(self.tcx, node_id) {
64                 self.worklist.push(node_id);
65             }
66             self.live_symbols.insert(node_id);
67         }
68     }
69
70     fn insert_def_id(&mut self, def_id: DefId) {
71         if let Some(node_id) = self.tcx.hir().as_local_node_id(def_id) {
72             debug_assert!(!should_explore(self.tcx, node_id));
73             self.live_symbols.insert(node_id);
74         }
75     }
76
77     fn handle_definition(&mut self, def: Def) {
78         match def {
79             Def::Const(_) | Def::AssociatedConst(..) | Def::TyAlias(_) => {
80                 self.check_def_id(def.def_id());
81             }
82             _ if self.in_pat => (),
83             Def::PrimTy(..) | Def::SelfTy(..) | Def::SelfCtor(..) |
84             Def::Local(..) | Def::Upvar(..) => {}
85             Def::Variant(variant_id) | Def::VariantCtor(variant_id, ..) => {
86                 if let Some(enum_id) = self.tcx.parent_def_id(variant_id) {
87                     self.check_def_id(enum_id);
88                 }
89                 if !self.ignore_variant_stack.contains(&variant_id) {
90                     self.check_def_id(variant_id);
91                 }
92             }
93             _ => {
94                 self.check_def_id(def.def_id());
95             }
96         }
97     }
98
99     fn lookup_and_handle_method(&mut self, id: hir::HirId) {
100         if let Some(def) = self.tables.type_dependent_defs().get(id) {
101             self.check_def_id(def.def_id());
102         } else {
103             bug!("no type-dependent def for method");
104         }
105     }
106
107     fn handle_field_access(&mut self, lhs: &hir::Expr, node_id: ast::NodeId) {
108         match self.tables.expr_ty_adjusted(lhs).sty {
109             ty::Adt(def, _) => {
110                 let index = self.tcx.field_index(node_id, self.tables);
111                 self.insert_def_id(def.non_enum_variant().fields[index].did);
112             }
113             ty::Tuple(..) => {}
114             _ => span_bug!(lhs.span, "named field access on non-ADT"),
115         }
116     }
117
118     fn handle_field_pattern_match(&mut self, lhs: &hir::Pat, def: Def,
119                                   pats: &[source_map::Spanned<hir::FieldPat>]) {
120         let variant = match self.tables.node_id_to_type(lhs.hir_id).sty {
121             ty::Adt(adt, _) => adt.variant_of_def(def),
122             _ => span_bug!(lhs.span, "non-ADT in struct pattern")
123         };
124         for pat in pats {
125             if let PatKind::Wild = pat.node.pat.node {
126                 continue;
127             }
128             let index = self.tcx.field_index(pat.node.id, self.tables);
129             self.insert_def_id(variant.fields[index].did);
130         }
131     }
132
133     fn mark_live_symbols(&mut self) {
134         let mut scanned = FxHashSet::default();
135         while let Some(id) = self.worklist.pop() {
136             if !scanned.insert(id) {
137                 continue
138             }
139
140             if let Some(ref node) = self.tcx.hir().find(id) {
141                 self.live_symbols.insert(id);
142                 self.visit_node(node);
143             }
144         }
145     }
146
147     fn visit_node(&mut self, node: &Node<'tcx>) {
148         let had_repr_c = self.repr_has_repr_c;
149         self.repr_has_repr_c = false;
150         let had_inherited_pub_visibility = self.inherited_pub_visibility;
151         self.inherited_pub_visibility = false;
152         match *node {
153             Node::Item(item) => {
154                 match item.node {
155                     hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => {
156                         let def_id = self.tcx.hir().local_def_id(item.id);
157                         let def = self.tcx.adt_def(def_id);
158                         self.repr_has_repr_c = def.repr.c();
159
160                         intravisit::walk_item(self, &item);
161                     }
162                     hir::ItemKind::Enum(..) => {
163                         self.inherited_pub_visibility = item.vis.node.is_pub();
164                         intravisit::walk_item(self, &item);
165                     }
166                     hir::ItemKind::Fn(..)
167                     | hir::ItemKind::Ty(..)
168                     | hir::ItemKind::Static(..)
169                     | hir::ItemKind::Existential(..)
170                     | hir::ItemKind::Const(..) => {
171                         intravisit::walk_item(self, &item);
172                     }
173                     _ => ()
174                 }
175             }
176             Node::TraitItem(trait_item) => {
177                 intravisit::walk_trait_item(self, trait_item);
178             }
179             Node::ImplItem(impl_item) => {
180                 intravisit::walk_impl_item(self, impl_item);
181             }
182             Node::ForeignItem(foreign_item) => {
183                 intravisit::walk_foreign_item(self, &foreign_item);
184             }
185             _ => ()
186         }
187         self.repr_has_repr_c = had_repr_c;
188         self.inherited_pub_visibility = had_inherited_pub_visibility;
189     }
190
191     fn mark_as_used_if_union(&mut self, adt: &ty::AdtDef, fields: &hir::HirVec<hir::Field>) {
192         if adt.is_union() && adt.non_enum_variant().fields.len() > 1 && adt.did.is_local() {
193             for field in fields {
194                 let index = self.tcx.field_index(field.id, self.tables);
195                 self.insert_def_id(adt.non_enum_variant().fields[index].did);
196             }
197         }
198     }
199 }
200
201 impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> {
202     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
203         NestedVisitorMap::None
204     }
205
206     fn visit_nested_body(&mut self, body: hir::BodyId) {
207         let old_tables = self.tables;
208         self.tables = self.tcx.body_tables(body);
209         let body = self.tcx.hir().body(body);
210         self.visit_body(body);
211         self.tables = old_tables;
212     }
213
214     fn visit_variant_data(&mut self, def: &'tcx hir::VariantData, _: ast::Name,
215                           _: &hir::Generics, _: ast::NodeId, _: syntax_pos::Span) {
216         let has_repr_c = self.repr_has_repr_c;
217         let inherited_pub_visibility = self.inherited_pub_visibility;
218         let live_fields = def.fields().iter().filter(|f| {
219             has_repr_c || inherited_pub_visibility || f.vis.node.is_pub()
220         });
221         self.live_symbols.extend(live_fields.map(|f| f.id));
222
223         intravisit::walk_struct_def(self, def);
224     }
225
226     fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
227         match expr.node {
228             hir::ExprKind::Path(ref qpath @ hir::QPath::TypeRelative(..)) => {
229                 let def = self.tables.qpath_def(qpath, expr.hir_id);
230                 self.handle_definition(def);
231             }
232             hir::ExprKind::MethodCall(..) => {
233                 self.lookup_and_handle_method(expr.hir_id);
234             }
235             hir::ExprKind::Field(ref lhs, ..) => {
236                 self.handle_field_access(&lhs, expr.id);
237             }
238             hir::ExprKind::Struct(_, ref fields, _) => {
239                 if let ty::Adt(ref adt, _) = self.tables.expr_ty(expr).sty {
240                     self.mark_as_used_if_union(adt, fields);
241                 }
242             }
243             _ => ()
244         }
245
246         intravisit::walk_expr(self, expr);
247     }
248
249     fn visit_arm(&mut self, arm: &'tcx hir::Arm) {
250         if arm.pats.len() == 1 {
251             let variants = arm.pats[0].necessary_variants();
252
253             // Inside the body, ignore constructions of variants
254             // necessary for the pattern to match. Those construction sites
255             // can't be reached unless the variant is constructed elsewhere.
256             let len = self.ignore_variant_stack.len();
257             self.ignore_variant_stack.extend_from_slice(&variants);
258             intravisit::walk_arm(self, arm);
259             self.ignore_variant_stack.truncate(len);
260         } else {
261             intravisit::walk_arm(self, arm);
262         }
263     }
264
265     fn visit_pat(&mut self, pat: &'tcx hir::Pat) {
266         match pat.node {
267             PatKind::Struct(hir::QPath::Resolved(_, ref path), ref fields, _) => {
268                 self.handle_field_pattern_match(pat, path.def, fields);
269             }
270             PatKind::Path(ref qpath @ hir::QPath::TypeRelative(..)) => {
271                 let def = self.tables.qpath_def(qpath, pat.hir_id);
272                 self.handle_definition(def);
273             }
274             _ => ()
275         }
276
277         self.in_pat = true;
278         intravisit::walk_pat(self, pat);
279         self.in_pat = false;
280     }
281
282     fn visit_path(&mut self, path: &'tcx hir::Path, _: hir::HirId) {
283         self.handle_definition(path.def);
284         intravisit::walk_path(self, path);
285     }
286 }
287
288 fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_, '_, '_>,
289                                     id: ast::NodeId,
290                                     attrs: &[ast::Attribute]) -> bool {
291     if attr::contains_name(attrs, "lang") {
292         return true;
293     }
294
295     // Stable attribute for #[lang = "panic_impl"]
296     if attr::contains_name(attrs, "panic_handler") {
297         return true;
298     }
299
300     // (To be) stable attribute for #[lang = "oom"]
301     if attr::contains_name(attrs, "alloc_error_handler") {
302         return true;
303     }
304
305     // Don't lint about global allocators
306     if attr::contains_name(attrs, "global_allocator") {
307         return true;
308     }
309
310     let def_id = tcx.hir().local_def_id(id);
311     let cg_attrs = tcx.codegen_fn_attrs(def_id);
312
313     // #[used], #[no_mangle], #[export_name], etc also keeps the item alive
314     // forcefully, e.g., for placing it in a specific section.
315     if cg_attrs.contains_extern_indicator() ||
316         cg_attrs.flags.contains(CodegenFnAttrFlags::USED) {
317         return true;
318     }
319
320     tcx.lint_level_at_node(lint::builtin::DEAD_CODE, id).0 == lint::Allow
321 }
322
323 // This visitor seeds items that
324 //   1) We want to explicitly consider as live:
325 //     * Item annotated with #[allow(dead_code)]
326 //         - This is done so that if we want to suppress warnings for a
327 //           group of dead functions, we only have to annotate the "root".
328 //           For example, if both `f` and `g` are dead and `f` calls `g`,
329 //           then annotating `f` with `#[allow(dead_code)]` will suppress
330 //           warning for both `f` and `g`.
331 //     * Item annotated with #[lang=".."]
332 //         - This is because lang items are always callable from elsewhere.
333 //   or
334 //   2) We are not sure to be live or not
335 //     * Implementation of a trait method
336 struct LifeSeeder<'k, 'tcx: 'k> {
337     worklist: Vec<ast::NodeId>,
338     krate: &'k hir::Crate,
339     tcx: TyCtxt<'k, 'tcx, 'tcx>,
340 }
341
342 impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> {
343     fn visit_item(&mut self, item: &hir::Item) {
344         let allow_dead_code = has_allow_dead_code_or_lang_attr(self.tcx,
345                                                                item.id,
346                                                                &item.attrs);
347         if allow_dead_code {
348             self.worklist.push(item.id);
349         }
350         match item.node {
351             hir::ItemKind::Enum(ref enum_def, _) if allow_dead_code => {
352                 self.worklist.extend(enum_def.variants.iter()
353                                                       .map(|variant| variant.node.data.id()));
354             }
355             hir::ItemKind::Trait(.., ref trait_item_refs) => {
356                 for trait_item_ref in trait_item_refs {
357                     let trait_item = self.krate.trait_item(trait_item_ref.id);
358                     match trait_item.node {
359                         hir::TraitItemKind::Const(_, Some(_)) |
360                         hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(_)) => {
361                             if has_allow_dead_code_or_lang_attr(self.tcx,
362                                                                 trait_item.id,
363                                                                 &trait_item.attrs) {
364                                 self.worklist.push(trait_item.id);
365                             }
366                         }
367                         _ => {}
368                     }
369                 }
370             }
371             hir::ItemKind::Impl(.., ref opt_trait, _, ref impl_item_refs) => {
372                 for impl_item_ref in impl_item_refs {
373                     let impl_item = self.krate.impl_item(impl_item_ref.id);
374                     if opt_trait.is_some() ||
375                             has_allow_dead_code_or_lang_attr(self.tcx,
376                                                              impl_item.id,
377                                                              &impl_item.attrs) {
378                         self.worklist.push(impl_item_ref.id.node_id);
379                     }
380                 }
381             }
382             _ => ()
383         }
384     }
385
386     fn visit_trait_item(&mut self, _item: &hir::TraitItem) {
387         // ignore: we are handling this in `visit_item` above
388     }
389
390     fn visit_impl_item(&mut self, _item: &hir::ImplItem) {
391         // ignore: we are handling this in `visit_item` above
392     }
393 }
394
395 fn create_and_seed_worklist<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
396                                       access_levels: &privacy::AccessLevels,
397                                       krate: &hir::Crate)
398                                       -> Vec<ast::NodeId>
399 {
400     let worklist = access_levels.map.iter().filter_map(|(&id, level)| {
401         if level >= &privacy::AccessLevel::Reachable {
402             Some(id)
403         } else {
404             None
405         }
406     }).chain(
407         // Seed entry point
408         tcx.sess.entry_fn.borrow().map(|(id, _, _)| id)
409     ).collect::<Vec<_>>();
410
411     // Seed implemented trait items
412     let mut life_seeder = LifeSeeder {
413         worklist,
414         krate,
415         tcx,
416     };
417     krate.visit_all_item_likes(&mut life_seeder);
418
419     return life_seeder.worklist;
420 }
421
422 fn find_live<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
423                        access_levels: &privacy::AccessLevels,
424                        krate: &hir::Crate)
425                        -> FxHashSet<ast::NodeId> {
426     let worklist = create_and_seed_worklist(tcx, access_levels, krate);
427     let mut symbol_visitor = MarkSymbolVisitor {
428         worklist,
429         tcx,
430         tables: &ty::TypeckTables::empty(None),
431         live_symbols: Default::default(),
432         repr_has_repr_c: false,
433         in_pat: false,
434         inherited_pub_visibility: false,
435         ignore_variant_stack: vec![],
436     };
437     symbol_visitor.mark_live_symbols();
438     symbol_visitor.live_symbols
439 }
440
441 fn get_struct_ctor_id(item: &hir::Item) -> Option<ast::NodeId> {
442     match item.node {
443         hir::ItemKind::Struct(ref struct_def, _) if !struct_def.is_struct() => {
444             Some(struct_def.id())
445         }
446         _ => None
447     }
448 }
449
450 struct DeadVisitor<'a, 'tcx: 'a> {
451     tcx: TyCtxt<'a, 'tcx, 'tcx>,
452     live_symbols: FxHashSet<ast::NodeId>,
453 }
454
455 impl<'a, 'tcx> DeadVisitor<'a, 'tcx> {
456     fn should_warn_about_item(&mut self, item: &hir::Item) -> bool {
457         let should_warn = match item.node {
458             hir::ItemKind::Static(..)
459             | hir::ItemKind::Const(..)
460             | hir::ItemKind::Fn(..)
461             | hir::ItemKind::Ty(..)
462             | hir::ItemKind::Enum(..)
463             | hir::ItemKind::Struct(..)
464             | hir::ItemKind::Union(..) => true,
465             _ => false
466         };
467         let ctor_id = get_struct_ctor_id(item);
468         should_warn && !self.symbol_is_live(item.id, ctor_id)
469     }
470
471     fn should_warn_about_field(&mut self, field: &hir::StructField) -> bool {
472         let field_type = self.tcx.type_of(self.tcx.hir().local_def_id(field.id));
473         !field.is_positional()
474             && !self.symbol_is_live(field.id, None)
475             && !field_type.is_phantom_data()
476             && !has_allow_dead_code_or_lang_attr(self.tcx, field.id, &field.attrs)
477     }
478
479     fn should_warn_about_variant(&mut self, variant: &hir::VariantKind) -> bool {
480         !self.symbol_is_live(variant.data.id(), None)
481             && !has_allow_dead_code_or_lang_attr(self.tcx,
482                                                  variant.data.id(),
483                                                  &variant.attrs)
484     }
485
486     fn should_warn_about_foreign_item(&mut self, fi: &hir::ForeignItem) -> bool {
487         !self.symbol_is_live(fi.id, None)
488             && !has_allow_dead_code_or_lang_attr(self.tcx, fi.id, &fi.attrs)
489     }
490
491     // id := node id of an item's definition.
492     // ctor_id := `Some` if the item is a struct_ctor (tuple struct),
493     //            `None` otherwise.
494     // If the item is a struct_ctor, then either its `id` or
495     // `ctor_id` (unwrapped) is in the live_symbols set. More specifically,
496     // DefMap maps the ExprKind::Path of a struct_ctor to the node referred by
497     // `ctor_id`. On the other hand, in a statement like
498     // `type <ident> <generics> = <ty>;` where <ty> refers to a struct_ctor,
499     // DefMap maps <ty> to `id` instead.
500     fn symbol_is_live(&mut self,
501                       id: ast::NodeId,
502                       ctor_id: Option<ast::NodeId>)
503                       -> bool {
504         if self.live_symbols.contains(&id)
505            || ctor_id.map_or(false, |ctor| self.live_symbols.contains(&ctor))
506         {
507             return true;
508         }
509         // If it's a type whose items are live, then it's live, too.
510         // This is done to handle the case where, for example, the static
511         // method of a private type is used, but the type itself is never
512         // called directly.
513         let def_id = self.tcx.hir().local_def_id(id);
514         let inherent_impls = self.tcx.inherent_impls(def_id);
515         for &impl_did in inherent_impls.iter() {
516             for &item_did in &self.tcx.associated_item_def_ids(impl_did)[..] {
517                 if let Some(item_node_id) = self.tcx.hir().as_local_node_id(item_did) {
518                     if self.live_symbols.contains(&item_node_id) {
519                         return true;
520                     }
521                 }
522             }
523         }
524         false
525     }
526
527     fn warn_dead_code(&mut self,
528                       id: ast::NodeId,
529                       span: syntax_pos::Span,
530                       name: ast::Name,
531                       node_type: &str,
532                       participle: &str) {
533         if !name.as_str().starts_with("_") {
534             self.tcx
535                 .lint_node(lint::builtin::DEAD_CODE,
536                            id,
537                            span,
538                            &format!("{} is never {}: `{}`",
539                                     node_type, participle, name));
540         }
541     }
542 }
543
544 impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> {
545     /// Walk nested items in place so that we don't report dead-code
546     /// on inner functions when the outer function is already getting
547     /// an error. We could do this also by checking the parents, but
548     /// this is how the code is setup and it seems harmless enough.
549     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
550         NestedVisitorMap::All(&self.tcx.hir())
551     }
552
553     fn visit_item(&mut self, item: &'tcx hir::Item) {
554         if self.should_warn_about_item(item) {
555             // For items that have a definition with a signature followed by a
556             // block, point only at the signature.
557             let span = match item.node {
558                 hir::ItemKind::Fn(..) |
559                 hir::ItemKind::Mod(..) |
560                 hir::ItemKind::Enum(..) |
561                 hir::ItemKind::Struct(..) |
562                 hir::ItemKind::Union(..) |
563                 hir::ItemKind::Trait(..) |
564                 hir::ItemKind::Impl(..) => self.tcx.sess.source_map().def_span(item.span),
565                 _ => item.span,
566             };
567             let participle = match item.node {
568                 hir::ItemKind::Struct(..) => "constructed", // Issue #52325
569                 _ => "used"
570             };
571             self.warn_dead_code(
572                 item.id,
573                 span,
574                 item.name,
575                 item.node.descriptive_variant(),
576                 participle,
577             );
578         } else {
579             // Only continue if we didn't warn
580             intravisit::walk_item(self, item);
581         }
582     }
583
584     fn visit_variant(&mut self,
585                      variant: &'tcx hir::Variant,
586                      g: &'tcx hir::Generics,
587                      id: ast::NodeId) {
588         if self.should_warn_about_variant(&variant.node) {
589             self.warn_dead_code(variant.node.data.id(), variant.span, variant.node.name,
590                                 "variant", "constructed");
591         } else {
592             intravisit::walk_variant(self, variant, g, id);
593         }
594     }
595
596     fn visit_foreign_item(&mut self, fi: &'tcx hir::ForeignItem) {
597         if self.should_warn_about_foreign_item(fi) {
598             self.warn_dead_code(fi.id, fi.span, fi.name,
599                                 fi.node.descriptive_variant(), "used");
600         }
601         intravisit::walk_foreign_item(self, fi);
602     }
603
604     fn visit_struct_field(&mut self, field: &'tcx hir::StructField) {
605         if self.should_warn_about_field(&field) {
606             self.warn_dead_code(field.id, field.span, field.ident.name, "field", "used");
607         }
608         intravisit::walk_struct_field(self, field);
609     }
610
611     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
612         match impl_item.node {
613             hir::ImplItemKind::Const(_, body_id) => {
614                 if !self.symbol_is_live(impl_item.id, None) {
615                     self.warn_dead_code(impl_item.id,
616                                         impl_item.span,
617                                         impl_item.ident.name,
618                                         "associated const",
619                                         "used");
620                 }
621                 self.visit_nested_body(body_id)
622             }
623             hir::ImplItemKind::Method(_, body_id) => {
624                 if !self.symbol_is_live(impl_item.id, None) {
625                     let span = self.tcx.sess.source_map().def_span(impl_item.span);
626                     self.warn_dead_code(impl_item.id, span, impl_item.ident.name, "method", "used");
627                 }
628                 self.visit_nested_body(body_id)
629             }
630             hir::ImplItemKind::Existential(..) |
631             hir::ImplItemKind::Type(..) => {}
632         }
633     }
634
635     // Overwrite so that we don't warn the trait item itself.
636     fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
637         match trait_item.node {
638             hir::TraitItemKind::Const(_, Some(body_id)) |
639             hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(body_id)) => {
640                 self.visit_nested_body(body_id)
641             }
642             hir::TraitItemKind::Const(_, None) |
643             hir::TraitItemKind::Method(_, hir::TraitMethod::Required(_)) |
644             hir::TraitItemKind::Type(..) => {}
645         }
646     }
647 }
648
649 pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
650     let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE);
651     let krate = tcx.hir().krate();
652     let live_symbols = find_live(tcx, access_levels, krate);
653     let mut visitor = DeadVisitor {
654         tcx,
655         live_symbols,
656     };
657     intravisit::walk_crate(&mut visitor, krate);
658 }