]>
Commit | Line | Data |
---|---|---|
abe05a73 XL |
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}; | |
ff7c6d11 | 16 | use std::slice; |
abe05a73 XL |
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() { | |
ff7c6d11 | 29 | cx.check_unused_mut_pat(slice::from_ref(&arg.pat)); |
abe05a73 XL |
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 { | |
94b46f34 | 49 | p.each_binding(|_, hir_id, span, path1| { |
abe05a73 XL |
50 | let name = path1.node; |
51 | ||
52 | // Skip anything that looks like `_foo` | |
53 | if name.as_str().starts_with("_") { | |
94b46f34 | 54 | return; |
abe05a73 XL |
55 | } |
56 | ||
57 | // Skip anything that looks like `&foo` or `&mut foo`, only look | |
58 | // for by-value bindings | |
abe05a73 XL |
59 | let bm = match self.bccx.tables.pat_binding_modes().get(hir_id) { |
60 | Some(&bm) => bm, | |
61 | None => span_bug!(span, "missing binding mode"), | |
62 | }; | |
63 | match bm { | |
64 | ty::BindByValue(hir::MutMutable) => {} | |
65 | _ => return, | |
66 | } | |
67 | ||
94b46f34 | 68 | mutables.entry(name).or_insert(Vec::new()).push((hir_id, span)); |
abe05a73 XL |
69 | }); |
70 | } | |
71 | ||
72 | for (_name, ids) in mutables { | |
73 | // If any id for this name was used mutably then consider them all | |
74 | // ok, so move on to the next | |
94b46f34 XL |
75 | if ids.iter().any(|&(ref hir_id, _)| self.used_mut.contains(hir_id)) { |
76 | continue; | |
abe05a73 XL |
77 | } |
78 | ||
94b46f34 XL |
79 | let (hir_id, span) = ids[0]; |
80 | let mut_span = tcx.sess.codemap().span_until_non_whitespace(span); | |
abe05a73 XL |
81 | |
82 | // Ok, every name wasn't used mutably, so issue a warning that this | |
83 | // didn't need to be mutable. | |
94b46f34 XL |
84 | tcx.struct_span_lint_hir(UNUSED_MUT, |
85 | hir_id, | |
86 | span, | |
87 | "variable does not need to be mutable") | |
abe05a73 XL |
88 | .span_suggestion_short(mut_span, "remove this `mut`", "".to_owned()) |
89 | .emit(); | |
90 | } | |
91 | } | |
92 | } | |
93 | ||
94 | impl<'a, 'tcx> Visitor<'tcx> for UnusedMutCx<'a, 'tcx> { | |
95 | fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { | |
96 | NestedVisitorMap::OnlyBodies(&self.bccx.tcx.hir) | |
97 | } | |
98 | ||
99 | fn visit_arm(&mut self, arm: &hir::Arm) { | |
100 | self.check_unused_mut_pat(&arm.pats) | |
101 | } | |
102 | ||
103 | fn visit_local(&mut self, local: &hir::Local) { | |
ff7c6d11 | 104 | self.check_unused_mut_pat(slice::from_ref(&local.pat)); |
abe05a73 XL |
105 | } |
106 | } | |
107 | ||
108 | impl<'a, 'tcx> Visitor<'tcx> for UsedMutFinder<'a, 'tcx> { | |
109 | fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { | |
110 | NestedVisitorMap::OnlyBodies(&self.bccx.tcx.hir) | |
111 | } | |
112 | ||
113 | fn visit_nested_body(&mut self, id: hir::BodyId) { | |
114 | let def_id = self.bccx.tcx.hir.body_owner_def_id(id); | |
115 | self.set.extend(self.bccx.tcx.borrowck(def_id).used_mut_nodes.iter().cloned()); | |
116 | self.visit_body(self.bccx.tcx.hir.body(id)); | |
117 | } | |
118 | } |