From fb6fad20c87d8562c60ef1ad28f6cf471b76d3c2 Mon Sep 17 00:00:00 2001 From: lengyijun Date: Sun, 20 Aug 2023 09:14:52 +0800 Subject: [PATCH] [`iter_overeager_cloned`]: detect .cloned().all() and .cloned().any() --- .../src/methods/iter_overeager_cloned.rs | 2 +- clippy_lints/src/methods/mod.rs | 22 ++++++++++++++----- tests/ui/iter_overeager_cloned.fixed | 6 ++--- tests/ui/iter_overeager_cloned.rs | 2 -- tests/ui/iter_overeager_cloned.stderr | 18 ++++++++++++++- 5 files changed, 36 insertions(+), 14 deletions(-) diff --git a/clippy_lints/src/methods/iter_overeager_cloned.rs b/clippy_lints/src/methods/iter_overeager_cloned.rs index ee405a3e30c..a49dd98db87 100644 --- a/clippy_lints/src/methods/iter_overeager_cloned.rs +++ b/clippy_lints/src/methods/iter_overeager_cloned.rs @@ -21,7 +21,7 @@ pub(super) enum Op<'a> { RmCloned, // rm `.cloned()` - // e.g. `map` `for_each` + // e.g. `map` `for_each` `all` `any` NeedlessMove(&'a str, &'a Expr<'a>), // later `.cloned()` diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 5075137caa0..5fb0d9f0a57 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3873,6 +3873,12 @@ impl Methods { ("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => { zst_offset::check(cx, expr, recv); }, + ("all", [arg]) => { + if let Some(("cloned", recv2, [], _, _)) = method_call(recv) { + iter_overeager_cloned::check(cx, expr, recv, recv2, + iter_overeager_cloned::Op::NeedlessMove(name, arg), false); + } + } ("and_then", [arg]) => { let biom_option_linted = bind_instead_of_map::OptionAndThenSome::check(cx, expr, recv, arg); let biom_result_linted = bind_instead_of_map::ResultAndThenOk::check(cx, expr, recv, arg); @@ -3880,12 +3886,16 @@ impl Methods { unnecessary_lazy_eval::check(cx, expr, recv, arg, "and"); } }, - ("any", [arg]) if let ExprKind::Closure(arg) = arg.kind - && let body = cx.tcx.hir().body(arg.body) - && let [param] = body.params - && let Some(("chars", recv, _, _, _)) = method_call(recv) => - { - string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), &self.msrv); + ("any", [arg]) => { + match method_call(recv) { + Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::NeedlessMove(name, arg), false), + Some(("chars", recv, _, _, _)) if let ExprKind::Closure(arg) = arg.kind + && let body = cx.tcx.hir().body(arg.body) + && let [param] = body.params => { + string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), &self.msrv); + } + _ => {} + } } ("arg", [arg]) => { suspicious_command_arg_space::check(cx, recv, arg, span); diff --git a/tests/ui/iter_overeager_cloned.fixed b/tests/ui/iter_overeager_cloned.fixed index 9dd046fec1f..7d8a584b022 100644 --- a/tests/ui/iter_overeager_cloned.fixed +++ b/tests/ui/iter_overeager_cloned.fixed @@ -63,11 +63,9 @@ fn main() { let _ = vec.iter().for_each(|x| assert!(!x.is_empty())); - // Not implemented yet - let _ = vec.iter().cloned().all(|x| x.len() == 1); + let _ = vec.iter().all(|x| x.len() == 1); - // Not implemented yet - let _ = vec.iter().cloned().any(|x| x.len() == 1); + let _ = vec.iter().any(|x| x.len() == 1); // Should probably stay as it is. let _ = [0, 1, 2, 3, 4].iter().cloned().take(10); diff --git a/tests/ui/iter_overeager_cloned.rs b/tests/ui/iter_overeager_cloned.rs index 3cab3669554..58c374ab8cd 100644 --- a/tests/ui/iter_overeager_cloned.rs +++ b/tests/ui/iter_overeager_cloned.rs @@ -64,10 +64,8 @@ fn main() { let _ = vec.iter().cloned().for_each(|x| assert!(!x.is_empty())); - // Not implemented yet let _ = vec.iter().cloned().all(|x| x.len() == 1); - // Not implemented yet let _ = vec.iter().cloned().any(|x| x.len() == 1); // Should probably stay as it is. diff --git a/tests/ui/iter_overeager_cloned.stderr b/tests/ui/iter_overeager_cloned.stderr index 4417a40a63b..1f4c9040f77 100644 --- a/tests/ui/iter_overeager_cloned.stderr +++ b/tests/ui/iter_overeager_cloned.stderr @@ -146,5 +146,21 @@ LL | let _ = vec.iter().cloned().for_each(|x| assert!(!x.is_empty())); | | | help: try: `.for_each(|x| assert!(!x.is_empty()))` -error: aborting due to 17 previous errors +error: unneeded cloning of iterator items + --> $DIR/iter_overeager_cloned.rs:67:13 + | +LL | let _ = vec.iter().cloned().all(|x| x.len() == 1); + | ^^^^^^^^^^------------------------------- + | | + | help: try: `.all(|x| x.len() == 1)` + +error: unneeded cloning of iterator items + --> $DIR/iter_overeager_cloned.rs:69:13 + | +LL | let _ = vec.iter().cloned().any(|x| x.len() == 1); + | ^^^^^^^^^^------------------------------- + | | + | help: try: `.any(|x| x.len() == 1)` + +error: aborting due to 19 previous errors