Skip to content

Commit d5d8ef1

Browse files
committed
Auto merge of rust-lang#10159 - khuey:iter_kv_map_ref_mut, r=llogiq
Make the iter_kv_map lint handle ref/mut annotations. For the degenerate (`map(|(k, _)| k)`/`map(|(_, v)| v)`) cases a mut annotation is superfluous and a ref annotation won't compile, so no additional handling is required. For cases where the `map` call must be preserved ref/mut annotations should also be presereved so that the map body continues to work as expected. *Please write a short comment explaining your change (or "none" for internal only changes)* changelog: [`iter_kv_map`]: handle ref/mut annotations
2 parents d39dd86 + 755ae3f commit d5d8ef1

File tree

4 files changed

+175
-35
lines changed

4 files changed

+175
-35
lines changed

clippy_lints/src/methods/iter_kv_map.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use clippy_utils::source::{snippet, snippet_with_applicability};
66
use clippy_utils::sugg;
77
use clippy_utils::ty::is_type_diagnostic_item;
88
use clippy_utils::visitors::is_local_used;
9-
use rustc_hir::{BindingAnnotation, Body, BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind};
9+
use rustc_hir::{BindingAnnotation, Body, BorrowKind, ByRef, Expr, ExprKind, Mutability, Pat, PatKind};
1010
use rustc_lint::{LateContext, LintContext};
1111
use rustc_middle::ty;
1212
use rustc_span::sym;
@@ -30,9 +30,9 @@ pub(super) fn check<'tcx>(
3030
if let Body {params: [p], value: body_expr, generator_kind: _ } = cx.tcx.hir().body(c.body);
3131
if let PatKind::Tuple([key_pat, val_pat], _) = p.pat.kind;
3232

33-
let (replacement_kind, binded_ident) = match (&key_pat.kind, &val_pat.kind) {
34-
(key, PatKind::Binding(_, _, value, _)) if pat_is_wild(cx, key, m_arg) => ("value", value),
35-
(PatKind::Binding(_, _, key, _), value) if pat_is_wild(cx, value, m_arg) => ("key", key),
33+
let (replacement_kind, annotation, bound_ident) = match (&key_pat.kind, &val_pat.kind) {
34+
(key, PatKind::Binding(ann, _, value, _)) if pat_is_wild(cx, key, m_arg) => ("value", ann, value),
35+
(PatKind::Binding(ann, _, key, _), value) if pat_is_wild(cx, value, m_arg) => ("key", ann, key),
3636
_ => return,
3737
};
3838

@@ -47,7 +47,7 @@ pub(super) fn check<'tcx>(
4747
if_chain! {
4848
if let ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = body_expr.kind;
4949
if let [local_ident] = path.segments;
50-
if local_ident.ident.as_str() == binded_ident.as_str();
50+
if local_ident.ident.as_str() == bound_ident.as_str();
5151

5252
then {
5353
span_lint_and_sugg(
@@ -60,13 +60,23 @@ pub(super) fn check<'tcx>(
6060
applicability,
6161
);
6262
} else {
63+
let ref_annotation = if annotation.0 == ByRef::Yes {
64+
"ref "
65+
} else {
66+
""
67+
};
68+
let mut_annotation = if annotation.1 == Mutability::Mut {
69+
"mut "
70+
} else {
71+
""
72+
};
6373
span_lint_and_sugg(
6474
cx,
6575
ITER_KV_MAP,
6676
expr.span,
6777
&format!("iterating on a map's {replacement_kind}s"),
6878
"try",
69-
format!("{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{binded_ident}| {})",
79+
format!("{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{ref_annotation}{mut_annotation}{bound_ident}| {})",
7080
snippet_with_applicability(cx, body_expr.span, "/* body */", &mut applicability)),
7181
applicability,
7282
);

tests/ui/iter_kv_map.fixed

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
// run-rustfix
22

33
#![warn(clippy::iter_kv_map)]
4-
#![allow(clippy::redundant_clone)]
5-
#![allow(clippy::suspicious_map)]
6-
#![allow(clippy::map_identity)]
4+
#![allow(unused_mut, clippy::redundant_clone, clippy::suspicious_map, clippy::map_identity)]
75

86
use std::collections::{BTreeMap, HashMap};
97

108
fn main() {
119
let get_key = |(key, _val)| key;
10+
fn ref_acceptor(v: &u32) -> u32 {
11+
*v
12+
}
1213

1314
let map: HashMap<u32, u32> = HashMap::new();
1415

@@ -36,6 +37,20 @@ fn main() {
3637
let _ = map.keys().map(|key| key * 9).count();
3738
let _ = map.values().map(|value| value * 17).count();
3839

40+
// Preserve the ref in the fix.
41+
let _ = map.clone().into_values().map(|ref val| ref_acceptor(val)).count();
42+
43+
// Preserve the mut in the fix.
44+
let _ = map
45+
.clone().into_values().map(|mut val| {
46+
val += 2;
47+
val
48+
})
49+
.count();
50+
51+
// Don't let a mut interfere.
52+
let _ = map.clone().into_values().count();
53+
3954
let map: BTreeMap<u32, u32> = BTreeMap::new();
4055

4156
let _ = map.keys().collect::<Vec<_>>();
@@ -61,4 +76,18 @@ fn main() {
6176
// Lint
6277
let _ = map.keys().map(|key| key * 9).count();
6378
let _ = map.values().map(|value| value * 17).count();
79+
80+
// Preserve the ref in the fix.
81+
let _ = map.clone().into_values().map(|ref val| ref_acceptor(val)).count();
82+
83+
// Preserve the mut in the fix.
84+
let _ = map
85+
.clone().into_values().map(|mut val| {
86+
val += 2;
87+
val
88+
})
89+
.count();
90+
91+
// Don't let a mut interfere.
92+
let _ = map.clone().into_values().count();
6493
}

tests/ui/iter_kv_map.rs

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
// run-rustfix
22

33
#![warn(clippy::iter_kv_map)]
4-
#![allow(clippy::redundant_clone)]
5-
#![allow(clippy::suspicious_map)]
6-
#![allow(clippy::map_identity)]
4+
#![allow(unused_mut, clippy::redundant_clone, clippy::suspicious_map, clippy::map_identity)]
75

86
use std::collections::{BTreeMap, HashMap};
97

108
fn main() {
119
let get_key = |(key, _val)| key;
10+
fn ref_acceptor(v: &u32) -> u32 {
11+
*v
12+
}
1213

1314
let map: HashMap<u32, u32> = HashMap::new();
1415

@@ -36,6 +37,22 @@ fn main() {
3637
let _ = map.iter().map(|(key, _value)| key * 9).count();
3738
let _ = map.iter().map(|(_key, value)| value * 17).count();
3839

40+
// Preserve the ref in the fix.
41+
let _ = map.clone().into_iter().map(|(_, ref val)| ref_acceptor(val)).count();
42+
43+
// Preserve the mut in the fix.
44+
let _ = map
45+
.clone()
46+
.into_iter()
47+
.map(|(_, mut val)| {
48+
val += 2;
49+
val
50+
})
51+
.count();
52+
53+
// Don't let a mut interfere.
54+
let _ = map.clone().into_iter().map(|(_, mut val)| val).count();
55+
3956
let map: BTreeMap<u32, u32> = BTreeMap::new();
4057

4158
let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>();
@@ -61,4 +78,20 @@ fn main() {
6178
// Lint
6279
let _ = map.iter().map(|(key, _value)| key * 9).count();
6380
let _ = map.iter().map(|(_key, value)| value * 17).count();
81+
82+
// Preserve the ref in the fix.
83+
let _ = map.clone().into_iter().map(|(_, ref val)| ref_acceptor(val)).count();
84+
85+
// Preserve the mut in the fix.
86+
let _ = map
87+
.clone()
88+
.into_iter()
89+
.map(|(_, mut val)| {
90+
val += 2;
91+
val
92+
})
93+
.count();
94+
95+
// Don't let a mut interfere.
96+
let _ = map.clone().into_iter().map(|(_, mut val)| val).count();
6497
}

0 commit comments

Comments
 (0)