FOR_KV_MAP can now lint on mutable maps due to values_mut()

This commit is contained in:
Oliver Schneider 2017-01-10 08:33:20 +01:00
parent 3a18a48856
commit e066997046
No known key found for this signature in database
GPG key ID: 56D6EEA0FC67AC46
2 changed files with 30 additions and 13 deletions

View file

@ -16,7 +16,7 @@ use utils::sugg;
use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, multispan_sugg, in_external_macro, use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, multispan_sugg, in_external_macro,
is_refutable, span_help_and_lint, is_integer_literal, get_enclosing_block, span_lint_and_then, higher, is_refutable, span_help_and_lint, is_integer_literal, get_enclosing_block, span_lint_and_then, higher,
walk_ptrs_ty, last_path_segment}; last_path_segment};
use utils::paths; use utils::paths;
/// **What it does:** Checks for looping over the range of `0..len` of some /// **What it does:** Checks for looping over the range of `0..len` of some
@ -712,19 +712,24 @@ fn check_for_loop_over_map_kv<'a, 'tcx>(
if let PatKind::Tuple(ref pat, _) = pat.node { if let PatKind::Tuple(ref pat, _) = pat.node {
if pat.len() == 2 { if pat.len() == 2 {
let (new_pat_span, kind) = match (&pat[0].node, &pat[1].node) { let arg_span = arg.span;
(key, _) if pat_is_wild(cx, key, body) => (pat[1].span, "value"), let (new_pat_span, kind, ty, mutbl) = match cx.tcx.tables().expr_ty(arg).sty {
(_, value) if pat_is_wild(cx, value, body) => (pat[0].span, "key"), ty::TyRef(_, ref tam) => match (&pat[0].node, &pat[1].node) {
(key, _) if pat_is_wild(cx, key, body) => (pat[1].span, "value", tam.ty, tam.mutbl),
(_, value) if pat_is_wild(cx, value, body) => (pat[0].span, "key", tam.ty, MutImmutable),
_ => return,
},
_ => return, _ => return,
}; };
let mutbl = match mutbl {
let (arg_span, arg) = match arg.node { MutImmutable => "",
ExprAddrOf(MutImmutable, ref expr) => (arg.span, &**expr), MutMutable => "_mut",
ExprAddrOf(MutMutable, _) => return, // for _ in &mut _, there is no {values,keys}_mut method };
_ => (arg.span, arg), let arg = match arg.node {
ExprAddrOf(_, ref expr) => &**expr,
_ => arg,
}; };
let ty = walk_ptrs_ty(cx.tcx.tables().expr_ty(arg));
if match_type(cx, ty, &paths::HASHMAP) || match_type(cx, ty, &paths::BTREEMAP) { if match_type(cx, ty, &paths::HASHMAP) || match_type(cx, ty, &paths::BTREEMAP) {
span_lint_and_then(cx, span_lint_and_then(cx,
FOR_KV_MAP, FOR_KV_MAP,
@ -735,7 +740,7 @@ fn check_for_loop_over_map_kv<'a, 'tcx>(
multispan_sugg(db, multispan_sugg(db,
"use the corresponding method".into(), "use the corresponding method".into(),
&[(pat_span, &snippet(cx, new_pat_span, kind)), &[(pat_span, &snippet(cx, new_pat_span, kind)),
(arg_span, &format!("{}.{}s()", map.maybe_par(), kind))]); (arg_span, &format!("{}.{}s{}()", map.maybe_par(), kind, mutbl))]);
}); });
} }
} }

View file

@ -87,7 +87,7 @@ impl Unrelated {
} }
} }
#[deny(needless_range_loop, explicit_iter_loop, explicit_into_iter_loop, iter_next_loop, reverse_range_loop, explicit_counter_loop)] #[deny(needless_range_loop, explicit_iter_loop, explicit_into_iter_loop, iter_next_loop, reverse_range_loop, explicit_counter_loop, for_kv_map)]
#[deny(unused_collect)] #[deny(unused_collect)]
#[allow(linkedlist, shadow_unrelated, unnecessary_mut_passed, cyclomatic_complexity, similar_names)] #[allow(linkedlist, shadow_unrelated, unnecessary_mut_passed, cyclomatic_complexity, similar_names)]
#[allow(many_single_char_names)] #[allow(many_single_char_names)]
@ -417,11 +417,23 @@ fn main() {
let mut m : HashMap<u64, u64> = HashMap::new(); let mut m : HashMap<u64, u64> = HashMap::new();
for (_, v) in &mut m { for (_, v) in &mut m {
// Ok, there is no values_mut method or equivalent //~^ you seem to want to iterate on a map's values
//~| HELP use the corresponding method
//~| HELP use the corresponding method
//~| SUGGESTION for v in m.values_mut()
let _v = v; let _v = v;
} }
let m: &mut HashMap<u64, u64> = &mut HashMap::new();
for (_, v) in &mut *m {
//~^ you seem to want to iterate on a map's values
//~| HELP use the corresponding method
//~| HELP use the corresponding method
//~| SUGGESTION for v in (*m).values_mut()
let _v = v;
}
let m : HashMap<u64, u64> = HashMap::new();
let rm = &m; let rm = &m;
for (k, _value) in rm { for (k, _value) in rm {
//~^ you seem to want to iterate on a map's keys //~^ you seem to want to iterate on a map's keys