Merge pull request #711 from mcarton/hashmap

Fix false positive in `FOR_KV_MAP` and `&mut` refs
This commit is contained in:
Martin Carton 2016-02-26 12:54:31 +01:00
commit 14d2afbf03
2 changed files with 16 additions and 10 deletions

View File

@ -588,24 +588,23 @@ fn check_for_loop_explicit_counter(cx: &LateContext, arg: &Expr, body: &Expr, ex
} }
} }
// Check for the FOR_KV_MAP lint. /// Check for the FOR_KV_MAP lint.
fn check_for_loop_over_map_kv(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, expr: &Expr) { fn check_for_loop_over_map_kv(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, expr: &Expr) {
if let PatKind::Tup(ref pat) = pat.node { if let PatKind::Tup(ref pat) = pat.node {
if pat.len() == 2 { if pat.len() == 2 {
let (pat_span, kind) = match (&pat[0].node, &pat[1].node) { let (pat_span, kind) = match (&pat[0].node, &pat[1].node) {
(key, _) if pat_is_wild(key, body) => (&pat[1].span, "values"), (key, _) if pat_is_wild(key, body) => (&pat[1].span, "values"),
(_, value) if pat_is_wild(value, body) => (&pat[0].span, "keys"), (_, value) if pat_is_wild(value, body) => (&pat[0].span, "keys"),
_ => return, _ => return,
}; };
let ty = walk_ptrs_ty(cx.tcx.expr_ty(arg)); let arg_span = match arg.node {
let arg_span = if let ExprAddrOf(_, ref expr) = arg.node { ExprAddrOf(MutImmutable, ref expr) => expr.span,
expr.span ExprAddrOf(MutMutable, _) => return, // for _ in &mut _, there is no {values,keys}_mut method
} else { _ => arg.span,
arg.span
}; };
let ty = walk_ptrs_ty(cx.tcx.expr_ty(arg));
if match_type(cx, ty, &HASHMAP_PATH) || match_type(cx, ty, &BTREEMAP_PATH) { if match_type(cx, ty, &HASHMAP_PATH) || match_type(cx, ty, &BTREEMAP_PATH) {
span_lint_and_then(cx, span_lint_and_then(cx,
FOR_KV_MAP, FOR_KV_MAP,
@ -625,7 +624,7 @@ fn check_for_loop_over_map_kv(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Ex
} }
// Return true if the pattern is a `PatWild` or an ident prefixed with '_'. /// Return true if the pattern is a `PatWild` or an ident prefixed with '_'.
fn pat_is_wild(pat: &PatKind, body: &Expr) -> bool { fn pat_is_wild(pat: &PatKind, body: &Expr) -> bool {
match *pat { match *pat {
PatKind::Wild => true, PatKind::Wild => true,
@ -845,7 +844,7 @@ enum VarState {
DontWarn, DontWarn,
} }
// Scan a for loop for variables that are incremented exactly once. /// Scan a for loop for variables that are incremented exactly once.
struct IncrementVisitor<'v, 't: 'v> { struct IncrementVisitor<'v, 't: 'v> {
cx: &'v LateContext<'v, 't>, // context reference cx: &'v LateContext<'v, 't>, // context reference
states: HashMap<NodeId, VarState>, // incremented variables states: HashMap<NodeId, VarState>, // incremented variables
@ -897,7 +896,7 @@ impl<'v, 't> Visitor<'v> for IncrementVisitor<'v, 't> {
} }
} }
// Check whether a variable is initialized to zero at the start of a loop. /// Check whether a variable is initialized to zero at the start of a loop.
struct InitializeVisitor<'v, 't: 'v> { struct InitializeVisitor<'v, 't: 'v> {
cx: &'v LateContext<'v, 't>, // context reference cx: &'v LateContext<'v, 't>, // context reference
end_expr: &'v Expr, // the for loop. Stop scanning here. end_expr: &'v Expr, // the for loop. Stop scanning here.

View File

@ -311,6 +311,13 @@ fn main() {
let _v = v; let _v = v;
} }
let mut m : HashMap<u64, u64> = HashMap::new();
for (_, v) in &mut m {
// Ok, there is no values_mut method or equivalent
let _v = v;
}
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