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.
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.
11 use rustc
::hir
::intravisit
::{Visitor, NestedVisitorMap}
;
12 use rustc
::hir
::{self, HirId}
;
13 use rustc
::lint
::builtin
::UNUSED_MUT
;
15 use rustc
::util
::nodemap
::{FxHashMap, FxHashSet}
;
16 use errors
::Applicability
;
20 use borrowck
::BorrowckCtxt
;
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();
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
));
32 cx
.visit_expr(&body
.value
);
35 struct UsedMutFinder
<'a
, 'tcx
: 'a
> {
36 bccx
: &'a BorrowckCtxt
<'a
, 'tcx
>,
37 set
: &'a
mut FxHashSet
<HirId
>,
40 struct UnusedMutCx
<'a
, 'tcx
: 'a
> {
41 bccx
: &'a BorrowckCtxt
<'a
, 'tcx
>,
42 used_mut
: FxHashSet
<HirId
>,
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();
50 p
.each_binding(|_
, hir_id
, span
, ident
| {
51 // Skip anything that looks like `_foo`
52 if ident
.as_str().starts_with("_") {
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
) {
60 ty
::BindByValue(hir
::MutMutable
) => {}
64 mutables
.entry(ident
.name
).or_default().push((hir_id
, span
));
66 tcx
.sess
.delay_span_bug(span
, "missing binding mode");
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
)) {
78 let (hir_id
, span
) = ids
[0];
79 let mut_span
= tcx
.sess
.source_map().span_until_non_whitespace(span
);
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
,
86 "variable does not need to be mutable")
87 .span_suggestion_short_with_applicability(
91 Applicability
::MachineApplicable
)
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
)
102 fn visit_arm(&mut self, arm
: &hir
::Arm
) {
103 self.check_unused_mut_pat(&arm
.pats
)
106 fn visit_local(&mut self, local
: &hir
::Local
) {
107 self.check_unused_mut_pat(slice
::from_ref(&local
.pat
));
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
)
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
));