mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-24 05:33:27 +00:00
Auto merge of #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
This commit is contained in:
commit
d5d8ef13d7
4 changed files with 175 additions and 35 deletions
|
@ -6,7 +6,7 @@ use clippy_utils::source::{snippet, snippet_with_applicability};
|
|||
use clippy_utils::sugg;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::visitors::is_local_used;
|
||||
use rustc_hir::{BindingAnnotation, Body, BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind};
|
||||
use rustc_hir::{BindingAnnotation, Body, BorrowKind, ByRef, Expr, ExprKind, Mutability, Pat, PatKind};
|
||||
use rustc_lint::{LateContext, LintContext};
|
||||
use rustc_middle::ty;
|
||||
use rustc_span::sym;
|
||||
|
@ -30,9 +30,9 @@ pub(super) fn check<'tcx>(
|
|||
if let Body {params: [p], value: body_expr, generator_kind: _ } = cx.tcx.hir().body(c.body);
|
||||
if let PatKind::Tuple([key_pat, val_pat], _) = p.pat.kind;
|
||||
|
||||
let (replacement_kind, binded_ident) = match (&key_pat.kind, &val_pat.kind) {
|
||||
(key, PatKind::Binding(_, _, value, _)) if pat_is_wild(cx, key, m_arg) => ("value", value),
|
||||
(PatKind::Binding(_, _, key, _), value) if pat_is_wild(cx, value, m_arg) => ("key", key),
|
||||
let (replacement_kind, annotation, bound_ident) = match (&key_pat.kind, &val_pat.kind) {
|
||||
(key, PatKind::Binding(ann, _, value, _)) if pat_is_wild(cx, key, m_arg) => ("value", ann, value),
|
||||
(PatKind::Binding(ann, _, key, _), value) if pat_is_wild(cx, value, m_arg) => ("key", ann, key),
|
||||
_ => return,
|
||||
};
|
||||
|
||||
|
@ -47,7 +47,7 @@ pub(super) fn check<'tcx>(
|
|||
if_chain! {
|
||||
if let ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = body_expr.kind;
|
||||
if let [local_ident] = path.segments;
|
||||
if local_ident.ident.as_str() == binded_ident.as_str();
|
||||
if local_ident.ident.as_str() == bound_ident.as_str();
|
||||
|
||||
then {
|
||||
span_lint_and_sugg(
|
||||
|
@ -60,13 +60,23 @@ pub(super) fn check<'tcx>(
|
|||
applicability,
|
||||
);
|
||||
} else {
|
||||
let ref_annotation = if annotation.0 == ByRef::Yes {
|
||||
"ref "
|
||||
} else {
|
||||
""
|
||||
};
|
||||
let mut_annotation = if annotation.1 == Mutability::Mut {
|
||||
"mut "
|
||||
} else {
|
||||
""
|
||||
};
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
ITER_KV_MAP,
|
||||
expr.span,
|
||||
&format!("iterating on a map's {replacement_kind}s"),
|
||||
"try",
|
||||
format!("{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{binded_ident}| {})",
|
||||
format!("{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{ref_annotation}{mut_annotation}{bound_ident}| {})",
|
||||
snippet_with_applicability(cx, body_expr.span, "/* body */", &mut applicability)),
|
||||
applicability,
|
||||
);
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
// run-rustfix
|
||||
|
||||
#![warn(clippy::iter_kv_map)]
|
||||
#![allow(clippy::redundant_clone)]
|
||||
#![allow(clippy::suspicious_map)]
|
||||
#![allow(clippy::map_identity)]
|
||||
#![allow(unused_mut, clippy::redundant_clone, clippy::suspicious_map, clippy::map_identity)]
|
||||
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
|
||||
fn main() {
|
||||
let get_key = |(key, _val)| key;
|
||||
fn ref_acceptor(v: &u32) -> u32 {
|
||||
*v
|
||||
}
|
||||
|
||||
let map: HashMap<u32, u32> = HashMap::new();
|
||||
|
||||
|
@ -36,6 +37,20 @@ fn main() {
|
|||
let _ = map.keys().map(|key| key * 9).count();
|
||||
let _ = map.values().map(|value| value * 17).count();
|
||||
|
||||
// Preserve the ref in the fix.
|
||||
let _ = map.clone().into_values().map(|ref val| ref_acceptor(val)).count();
|
||||
|
||||
// Preserve the mut in the fix.
|
||||
let _ = map
|
||||
.clone().into_values().map(|mut val| {
|
||||
val += 2;
|
||||
val
|
||||
})
|
||||
.count();
|
||||
|
||||
// Don't let a mut interfere.
|
||||
let _ = map.clone().into_values().count();
|
||||
|
||||
let map: BTreeMap<u32, u32> = BTreeMap::new();
|
||||
|
||||
let _ = map.keys().collect::<Vec<_>>();
|
||||
|
@ -61,4 +76,18 @@ fn main() {
|
|||
// Lint
|
||||
let _ = map.keys().map(|key| key * 9).count();
|
||||
let _ = map.values().map(|value| value * 17).count();
|
||||
|
||||
// Preserve the ref in the fix.
|
||||
let _ = map.clone().into_values().map(|ref val| ref_acceptor(val)).count();
|
||||
|
||||
// Preserve the mut in the fix.
|
||||
let _ = map
|
||||
.clone().into_values().map(|mut val| {
|
||||
val += 2;
|
||||
val
|
||||
})
|
||||
.count();
|
||||
|
||||
// Don't let a mut interfere.
|
||||
let _ = map.clone().into_values().count();
|
||||
}
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
// run-rustfix
|
||||
|
||||
#![warn(clippy::iter_kv_map)]
|
||||
#![allow(clippy::redundant_clone)]
|
||||
#![allow(clippy::suspicious_map)]
|
||||
#![allow(clippy::map_identity)]
|
||||
#![allow(unused_mut, clippy::redundant_clone, clippy::suspicious_map, clippy::map_identity)]
|
||||
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
|
||||
fn main() {
|
||||
let get_key = |(key, _val)| key;
|
||||
fn ref_acceptor(v: &u32) -> u32 {
|
||||
*v
|
||||
}
|
||||
|
||||
let map: HashMap<u32, u32> = HashMap::new();
|
||||
|
||||
|
@ -36,6 +37,22 @@ fn main() {
|
|||
let _ = map.iter().map(|(key, _value)| key * 9).count();
|
||||
let _ = map.iter().map(|(_key, value)| value * 17).count();
|
||||
|
||||
// Preserve the ref in the fix.
|
||||
let _ = map.clone().into_iter().map(|(_, ref val)| ref_acceptor(val)).count();
|
||||
|
||||
// Preserve the mut in the fix.
|
||||
let _ = map
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|(_, mut val)| {
|
||||
val += 2;
|
||||
val
|
||||
})
|
||||
.count();
|
||||
|
||||
// Don't let a mut interfere.
|
||||
let _ = map.clone().into_iter().map(|(_, mut val)| val).count();
|
||||
|
||||
let map: BTreeMap<u32, u32> = BTreeMap::new();
|
||||
|
||||
let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>();
|
||||
|
@ -61,4 +78,20 @@ fn main() {
|
|||
// Lint
|
||||
let _ = map.iter().map(|(key, _value)| key * 9).count();
|
||||
let _ = map.iter().map(|(_key, value)| value * 17).count();
|
||||
|
||||
// Preserve the ref in the fix.
|
||||
let _ = map.clone().into_iter().map(|(_, ref val)| ref_acceptor(val)).count();
|
||||
|
||||
// Preserve the mut in the fix.
|
||||
let _ = map
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|(_, mut val)| {
|
||||
val += 2;
|
||||
val
|
||||
})
|
||||
.count();
|
||||
|
||||
// Don't let a mut interfere.
|
||||
let _ = map.clone().into_iter().map(|(_, mut val)| val).count();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: iterating on a map's keys
|
||||
--> $DIR/iter_kv_map.rs:15:13
|
||||
--> $DIR/iter_kv_map.rs:16:13
|
||||
|
|
||||
LL | let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()`
|
||||
|
@ -7,130 +7,198 @@ LL | let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>();
|
|||
= note: `-D clippy::iter-kv-map` implied by `-D warnings`
|
||||
|
||||
error: iterating on a map's values
|
||||
--> $DIR/iter_kv_map.rs:16:13
|
||||
--> $DIR/iter_kv_map.rs:17:13
|
||||
|
|
||||
LL | let _ = map.iter().map(|(_, value)| value).collect::<Vec<_>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()`
|
||||
|
||||
error: iterating on a map's values
|
||||
--> $DIR/iter_kv_map.rs:17:13
|
||||
--> $DIR/iter_kv_map.rs:18:13
|
||||
|
|
||||
LL | let _ = map.iter().map(|(_, v)| v + 2).collect::<Vec<_>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)`
|
||||
|
||||
error: iterating on a map's keys
|
||||
--> $DIR/iter_kv_map.rs:19:13
|
||||
--> $DIR/iter_kv_map.rs:20:13
|
||||
|
|
||||
LL | let _ = map.clone().into_iter().map(|(key, _)| key).collect::<Vec<_>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys()`
|
||||
|
||||
error: iterating on a map's keys
|
||||
--> $DIR/iter_kv_map.rs:20:13
|
||||
--> $DIR/iter_kv_map.rs:21:13
|
||||
|
|
||||
LL | let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::<Vec<_>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys().map(|key| key + 2)`
|
||||
|
||||
error: iterating on a map's values
|
||||
--> $DIR/iter_kv_map.rs:22:13
|
||||
--> $DIR/iter_kv_map.rs:23:13
|
||||
|
|
||||
LL | let _ = map.clone().into_iter().map(|(_, val)| val).collect::<Vec<_>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()`
|
||||
|
||||
error: iterating on a map's values
|
||||
--> $DIR/iter_kv_map.rs:23:13
|
||||
--> $DIR/iter_kv_map.rs:24:13
|
||||
|
|
||||
LL | let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::<Vec<_>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|val| val + 2)`
|
||||
|
||||
error: iterating on a map's values
|
||||
--> $DIR/iter_kv_map.rs:25:13
|
||||
--> $DIR/iter_kv_map.rs:26:13
|
||||
|
|
||||
LL | let _ = map.clone().iter().map(|(_, val)| val).collect::<Vec<_>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().values()`
|
||||
|
||||
error: iterating on a map's keys
|
||||
--> $DIR/iter_kv_map.rs:26:13
|
||||
--> $DIR/iter_kv_map.rs:27:13
|
||||
|
|
||||
LL | let _ = map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()`
|
||||
|
||||
error: iterating on a map's keys
|
||||
--> $DIR/iter_kv_map.rs:36:13
|
||||
--> $DIR/iter_kv_map.rs:37:13
|
||||
|
|
||||
LL | let _ = map.iter().map(|(key, _value)| key * 9).count();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys().map(|key| key * 9)`
|
||||
|
||||
error: iterating on a map's values
|
||||
--> $DIR/iter_kv_map.rs:37:13
|
||||
--> $DIR/iter_kv_map.rs:38:13
|
||||
|
|
||||
LL | let _ = map.iter().map(|(_key, value)| value * 17).count();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|value| value * 17)`
|
||||
|
||||
error: iterating on a map's keys
|
||||
error: iterating on a map's values
|
||||
--> $DIR/iter_kv_map.rs:41:13
|
||||
|
|
||||
LL | let _ = map.clone().into_iter().map(|(_, ref val)| ref_acceptor(val)).count();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|ref val| ref_acceptor(val))`
|
||||
|
||||
error: iterating on a map's values
|
||||
--> $DIR/iter_kv_map.rs:44:13
|
||||
|
|
||||
LL | let _ = map
|
||||
| _____________^
|
||||
LL | | .clone()
|
||||
LL | | .into_iter()
|
||||
LL | | .map(|(_, mut val)| {
|
||||
LL | | val += 2;
|
||||
LL | | val
|
||||
LL | | })
|
||||
| |__________^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
LL ~ let _ = map
|
||||
LL + .clone().into_values().map(|mut val| {
|
||||
LL + val += 2;
|
||||
LL + val
|
||||
LL + })
|
||||
|
|
||||
|
||||
error: iterating on a map's values
|
||||
--> $DIR/iter_kv_map.rs:54:13
|
||||
|
|
||||
LL | let _ = map.clone().into_iter().map(|(_, mut val)| val).count();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()`
|
||||
|
||||
error: iterating on a map's keys
|
||||
--> $DIR/iter_kv_map.rs:58:13
|
||||
|
|
||||
LL | let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()`
|
||||
|
||||
error: iterating on a map's values
|
||||
--> $DIR/iter_kv_map.rs:42:13
|
||||
--> $DIR/iter_kv_map.rs:59:13
|
||||
|
|
||||
LL | let _ = map.iter().map(|(_, value)| value).collect::<Vec<_>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()`
|
||||
|
||||
error: iterating on a map's values
|
||||
--> $DIR/iter_kv_map.rs:43:13
|
||||
--> $DIR/iter_kv_map.rs:60:13
|
||||
|
|
||||
LL | let _ = map.iter().map(|(_, v)| v + 2).collect::<Vec<_>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)`
|
||||
|
||||
error: iterating on a map's keys
|
||||
--> $DIR/iter_kv_map.rs:45:13
|
||||
--> $DIR/iter_kv_map.rs:62:13
|
||||
|
|
||||
LL | let _ = map.clone().into_iter().map(|(key, _)| key).collect::<Vec<_>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys()`
|
||||
|
||||
error: iterating on a map's keys
|
||||
--> $DIR/iter_kv_map.rs:46:13
|
||||
--> $DIR/iter_kv_map.rs:63:13
|
||||
|
|
||||
LL | let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::<Vec<_>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys().map(|key| key + 2)`
|
||||
|
||||
error: iterating on a map's values
|
||||
--> $DIR/iter_kv_map.rs:48:13
|
||||
--> $DIR/iter_kv_map.rs:65:13
|
||||
|
|
||||
LL | let _ = map.clone().into_iter().map(|(_, val)| val).collect::<Vec<_>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()`
|
||||
|
||||
error: iterating on a map's values
|
||||
--> $DIR/iter_kv_map.rs:49:13
|
||||
--> $DIR/iter_kv_map.rs:66:13
|
||||
|
|
||||
LL | let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::<Vec<_>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|val| val + 2)`
|
||||
|
||||
error: iterating on a map's values
|
||||
--> $DIR/iter_kv_map.rs:51:13
|
||||
--> $DIR/iter_kv_map.rs:68:13
|
||||
|
|
||||
LL | let _ = map.clone().iter().map(|(_, val)| val).collect::<Vec<_>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().values()`
|
||||
|
||||
error: iterating on a map's keys
|
||||
--> $DIR/iter_kv_map.rs:52:13
|
||||
--> $DIR/iter_kv_map.rs:69:13
|
||||
|
|
||||
LL | let _ = map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()`
|
||||
|
||||
error: iterating on a map's keys
|
||||
--> $DIR/iter_kv_map.rs:62:13
|
||||
--> $DIR/iter_kv_map.rs:79:13
|
||||
|
|
||||
LL | let _ = map.iter().map(|(key, _value)| key * 9).count();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys().map(|key| key * 9)`
|
||||
|
||||
error: iterating on a map's values
|
||||
--> $DIR/iter_kv_map.rs:63:13
|
||||
--> $DIR/iter_kv_map.rs:80:13
|
||||
|
|
||||
LL | let _ = map.iter().map(|(_key, value)| value * 17).count();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|value| value * 17)`
|
||||
|
||||
error: aborting due to 22 previous errors
|
||||
error: iterating on a map's values
|
||||
--> $DIR/iter_kv_map.rs:83:13
|
||||
|
|
||||
LL | let _ = map.clone().into_iter().map(|(_, ref val)| ref_acceptor(val)).count();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|ref val| ref_acceptor(val))`
|
||||
|
||||
error: iterating on a map's values
|
||||
--> $DIR/iter_kv_map.rs:86:13
|
||||
|
|
||||
LL | let _ = map
|
||||
| _____________^
|
||||
LL | | .clone()
|
||||
LL | | .into_iter()
|
||||
LL | | .map(|(_, mut val)| {
|
||||
LL | | val += 2;
|
||||
LL | | val
|
||||
LL | | })
|
||||
| |__________^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
LL ~ let _ = map
|
||||
LL + .clone().into_values().map(|mut val| {
|
||||
LL + val += 2;
|
||||
LL + val
|
||||
LL + })
|
||||
|
|
||||
|
||||
error: iterating on a map's values
|
||||
--> $DIR/iter_kv_map.rs:96:13
|
||||
|
|
||||
LL | let _ = map.clone().into_iter().map(|(_, mut val)| val).count();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()`
|
||||
|
||||
error: aborting due to 28 previous errors
|
||||
|
||||
|
|
Loading…
Reference in a new issue