]> git.proxmox.com Git - rustc.git/blob - src/librustc_borrowck/borrowck/unused.rs
New upstream version 1.34.2+dfsg1
[rustc.git] / src / librustc_borrowck / borrowck / unused.rs
1 use rustc::hir::intravisit::{Visitor, NestedVisitorMap};
2 use rustc::hir::{self, HirId};
3 use rustc::lint::builtin::UNUSED_MUT;
4 use rustc::ty;
5 use rustc::util::nodemap::{FxHashMap, FxHashSet};
6 use errors::Applicability;
7 use std::slice;
8 use syntax::ptr::P;
9
10 use crate::borrowck::BorrowckCtxt;
11
12 pub fn check<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, body: &'tcx hir::Body) {
13 let mut used_mut = bccx.used_mut_nodes.borrow().clone();
14 UsedMutFinder {
15 bccx,
16 set: &mut used_mut,
17 }.visit_expr(&body.value);
18 let mut cx = UnusedMutCx { bccx, used_mut };
19 for arg in body.arguments.iter() {
20 cx.check_unused_mut_pat(slice::from_ref(&arg.pat));
21 }
22 cx.visit_expr(&body.value);
23 }
24
25 struct UsedMutFinder<'a, 'tcx: 'a> {
26 bccx: &'a BorrowckCtxt<'a, 'tcx>,
27 set: &'a mut FxHashSet<HirId>,
28 }
29
30 struct UnusedMutCx<'a, 'tcx: 'a> {
31 bccx: &'a BorrowckCtxt<'a, 'tcx>,
32 used_mut: FxHashSet<HirId>,
33 }
34
35 impl<'a, 'tcx> UnusedMutCx<'a, 'tcx> {
36 fn check_unused_mut_pat(&self, pats: &[P<hir::Pat>]) {
37 let tcx = self.bccx.tcx;
38 let mut mutables: FxHashMap<_, Vec<_>> = Default::default();
39 for p in pats {
40 p.each_binding(|_, hir_id, span, ident| {
41 // Skip anything that looks like `_foo`
42 if ident.as_str().starts_with("_") {
43 return;
44 }
45
46 // Skip anything that looks like `&foo` or `&mut foo`, only look
47 // for by-value bindings
48 if let Some(&bm) = self.bccx.tables.pat_binding_modes().get(hir_id) {
49 match bm {
50 ty::BindByValue(hir::MutMutable) => {}
51 _ => return,
52 }
53
54 mutables.entry(ident.name).or_default().push((hir_id, span));
55 } else {
56 tcx.sess.delay_span_bug(span, "missing binding mode");
57 }
58 });
59 }
60
61 for (_name, ids) in mutables {
62 // If any id for this name was used mutably then consider them all
63 // ok, so move on to the next
64 if ids.iter().any(|&(ref hir_id, _)| self.used_mut.contains(hir_id)) {
65 continue;
66 }
67
68 let (hir_id, span) = ids[0];
69 if span.compiler_desugaring_kind().is_some() {
70 // If the `mut` arises as part of a desugaring, we should ignore it.
71 continue;
72 }
73
74 // Ok, every name wasn't used mutably, so issue a warning that this
75 // didn't need to be mutable.
76 let mut_span = tcx.sess.source_map().span_until_non_whitespace(span);
77 tcx.struct_span_lint_hir(UNUSED_MUT,
78 hir_id,
79 span,
80 "variable does not need to be mutable")
81 .span_suggestion_short(
82 mut_span,
83 "remove this `mut`",
84 String::new(),
85 Applicability::MachineApplicable,
86 )
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 }