]> git.lizzy.rs Git - rust.git/blob - src/librustc_borrowck/borrowck/unused.rs
475ff0b744349abfb01cd4ef6f959705fe0f864f
[rust.git] / src / librustc_borrowck / borrowck / unused.rs
1 // Copyright 2017 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 use rustc::hir::intravisit::{Visitor, NestedVisitorMap};
12 use rustc::hir::{self, HirId};
13 use rustc::lint::builtin::UNUSED_MUT;
14 use rustc::ty;
15 use rustc::util::nodemap::{FxHashMap, FxHashSet};
16 use std::slice;
17 use syntax::ptr::P;
18
19 use borrowck::BorrowckCtxt;
20
21 pub fn check<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, body: &'tcx hir::Body) {
22     let mut used_mut = bccx.used_mut_nodes.borrow().clone();
23     UsedMutFinder {
24         bccx,
25         set: &mut used_mut,
26     }.visit_expr(&body.value);
27     let mut cx = UnusedMutCx { bccx, used_mut };
28     for arg in body.arguments.iter() {
29         cx.check_unused_mut_pat(slice::from_ref(&arg.pat));
30     }
31     cx.visit_expr(&body.value);
32 }
33
34 struct UsedMutFinder<'a, 'tcx: 'a> {
35     bccx: &'a BorrowckCtxt<'a, 'tcx>,
36     set: &'a mut FxHashSet<HirId>,
37 }
38
39 struct UnusedMutCx<'a, 'tcx: 'a> {
40     bccx: &'a BorrowckCtxt<'a, 'tcx>,
41     used_mut: FxHashSet<HirId>,
42 }
43
44 impl<'a, 'tcx> UnusedMutCx<'a, 'tcx> {
45     fn check_unused_mut_pat(&self, pats: &[P<hir::Pat>]) {
46         let tcx = self.bccx.tcx;
47         let mut mutables = FxHashMap();
48         for p in pats {
49             p.each_binding(|_, hir_id, span, ident| {
50                 // Skip anything that looks like `_foo`
51                 if ident.as_str().starts_with("_") {
52                     return;
53                 }
54
55                 // Skip anything that looks like `&foo` or `&mut foo`, only look
56                 // for by-value bindings
57                 if let Some(&bm) = self.bccx.tables.pat_binding_modes().get(hir_id) {
58                     match bm {
59                         ty::BindByValue(hir::MutMutable) => {}
60                         _ => return,
61                     }
62
63                     mutables.entry(ident.name).or_insert(Vec::new()).push((hir_id, span));
64                 } else {
65                     tcx.sess.delay_span_bug(span, "missing binding mode");
66                 }
67             });
68         }
69
70         for (_name, ids) in mutables {
71             // If any id for this name was used mutably then consider them all
72             // ok, so move on to the next
73             if ids.iter().any(|&(ref hir_id, _)| self.used_mut.contains(hir_id)) {
74                 continue;
75             }
76
77             let (hir_id, span) = ids[0];
78             let mut_span = tcx.sess.codemap().span_until_non_whitespace(span);
79
80             // Ok, every name wasn't used mutably, so issue a warning that this
81             // didn't need to be mutable.
82             tcx.struct_span_lint_hir(UNUSED_MUT,
83                                      hir_id,
84                                      span,
85                                      "variable does not need to be mutable")
86                 .span_suggestion_short(mut_span, "remove this `mut`", "".to_owned())
87                 .emit();
88         }
89     }
90 }
91
92 impl<'a, 'tcx> Visitor<'tcx> for UnusedMutCx<'a, 'tcx> {
93     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
94         NestedVisitorMap::OnlyBodies(&self.bccx.tcx.hir)
95     }
96
97     fn visit_arm(&mut self, arm: &hir::Arm) {
98         self.check_unused_mut_pat(&arm.pats)
99     }
100
101     fn visit_local(&mut self, local: &hir::Local) {
102         self.check_unused_mut_pat(slice::from_ref(&local.pat));
103     }
104 }
105
106 impl<'a, 'tcx> Visitor<'tcx> for UsedMutFinder<'a, 'tcx> {
107     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
108         NestedVisitorMap::OnlyBodies(&self.bccx.tcx.hir)
109     }
110
111     fn visit_nested_body(&mut self, id: hir::BodyId) {
112         let def_id = self.bccx.tcx.hir.body_owner_def_id(id);
113         self.set.extend(self.bccx.tcx.borrowck(def_id).used_mut_nodes.iter().cloned());
114         self.visit_body(self.bccx.tcx.hir.body(id));
115     }
116 }