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