add manual_find lint for function return case

This commit is contained in:
Elliot Bobrow 2022-04-06 09:28:49 -07:00
parent 6206086dd5
commit 430575b61a
15 changed files with 844 additions and 31 deletions

View file

@ -3384,6 +3384,7 @@ Released 2018-09-13
[`manual_async_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn [`manual_async_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn
[`manual_bits`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_bits [`manual_bits`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_bits
[`manual_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter_map [`manual_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter_map
[`manual_find`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find
[`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map [`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map
[`manual_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten [`manual_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten
[`manual_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_map [`manual_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_map

View file

@ -109,6 +109,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
LintId::of(loops::FOR_KV_MAP), LintId::of(loops::FOR_KV_MAP),
LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES), LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES),
LintId::of(loops::ITER_NEXT_LOOP), LintId::of(loops::ITER_NEXT_LOOP),
LintId::of(loops::MANUAL_FIND),
LintId::of(loops::MANUAL_FLATTEN), LintId::of(loops::MANUAL_FLATTEN),
LintId::of(loops::MANUAL_MEMCPY), LintId::of(loops::MANUAL_MEMCPY),
LintId::of(loops::MISSING_SPIN_LOOP), LintId::of(loops::MISSING_SPIN_LOOP),

View file

@ -21,6 +21,7 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec!
LintId::of(lifetimes::EXTRA_UNUSED_LIFETIMES), LintId::of(lifetimes::EXTRA_UNUSED_LIFETIMES),
LintId::of(lifetimes::NEEDLESS_LIFETIMES), LintId::of(lifetimes::NEEDLESS_LIFETIMES),
LintId::of(loops::EXPLICIT_COUNTER_LOOP), LintId::of(loops::EXPLICIT_COUNTER_LOOP),
LintId::of(loops::MANUAL_FIND),
LintId::of(loops::MANUAL_FLATTEN), LintId::of(loops::MANUAL_FLATTEN),
LintId::of(loops::SINGLE_ELEMENT_LOOP), LintId::of(loops::SINGLE_ELEMENT_LOOP),
LintId::of(loops::WHILE_LET_LOOP), LintId::of(loops::WHILE_LET_LOOP),

View file

@ -222,6 +222,7 @@ store.register_lints(&[
loops::FOR_KV_MAP, loops::FOR_KV_MAP,
loops::FOR_LOOPS_OVER_FALLIBLES, loops::FOR_LOOPS_OVER_FALLIBLES,
loops::ITER_NEXT_LOOP, loops::ITER_NEXT_LOOP,
loops::MANUAL_FIND,
loops::MANUAL_FLATTEN, loops::MANUAL_FLATTEN,
loops::MANUAL_MEMCPY, loops::MANUAL_MEMCPY,
loops::MISSING_SPIN_LOOP, loops::MISSING_SPIN_LOOP,

View file

@ -0,0 +1,158 @@
use super::utils::make_iterator_snippet;
use super::MANUAL_FIND;
use clippy_utils::{
diagnostics::span_lint_and_then, higher, is_lang_ctor, path_res, peel_blocks_with_stmt,
source::snippet_with_applicability, ty::implements_trait,
};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{
def::Res, lang_items::LangItem, BindingAnnotation, Block, Expr, ExprKind, HirId, Node, Pat, PatKind, Stmt, StmtKind,
};
use rustc_lint::LateContext;
use rustc_span::source_map::Span;
pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>,
pat: &'tcx Pat<'_>,
arg: &'tcx Expr<'_>,
body: &'tcx Expr<'_>,
span: Span,
expr: &'tcx Expr<'_>,
) {
let inner_expr = peel_blocks_with_stmt(body);
// Check for the specific case that the result is returned and optimize suggestion for that (more
// cases can be added later)
if_chain! {
if let Some(higher::If { cond, then, r#else: None, }) = higher::If::hir(inner_expr);
if let Some(binding_id) = get_binding(pat);
if let ExprKind::Block(block, _) = then.kind;
if let [stmt] = block.stmts;
if let StmtKind::Semi(semi) = stmt.kind;
if let ExprKind::Ret(Some(ret_value)) = semi.kind;
if let ExprKind::Call(Expr { kind: ExprKind::Path(ctor), .. }, [inner_ret]) = ret_value.kind;
if is_lang_ctor(cx, ctor, LangItem::OptionSome);
if path_res(cx, inner_ret) == Res::Local(binding_id);
if let Some((last_stmt, last_ret)) = last_stmt_and_ret(cx, expr);
then {
let mut applicability = Applicability::MachineApplicable;
let mut snippet = make_iterator_snippet(cx, arg, &mut applicability);
// Checks if `pat` is a single reference to a binding (`&x`)
let is_ref_to_binding =
matches!(pat.kind, PatKind::Ref(inner, _) if matches!(inner.kind, PatKind::Binding(..)));
// If `pat` is not a binding or a reference to a binding (`x` or `&x`)
// we need to map it to the binding returned by the function (i.e. `.map(|(x, _)| x)`)
if !(matches!(pat.kind, PatKind::Binding(..)) || is_ref_to_binding) {
snippet.push_str(
&format!(
".map(|{}| {})",
snippet_with_applicability(cx, pat.span, "..", &mut applicability),
snippet_with_applicability(cx, inner_ret.span, "..", &mut applicability),
)[..],
);
}
let ty = cx.typeck_results().expr_ty(inner_ret);
if cx.tcx.lang_items().copy_trait().map_or(false, |id| implements_trait(cx, ty, id, &[])) {
snippet.push_str(
&format!(
".find(|{}{}| {})",
"&".repeat(1 + usize::from(is_ref_to_binding)),
snippet_with_applicability(cx, inner_ret.span, "..", &mut applicability),
snippet_with_applicability(cx, cond.span, "..", &mut applicability),
)[..],
);
if is_ref_to_binding {
snippet.push_str(".copied()");
}
} else {
applicability = Applicability::MaybeIncorrect;
snippet.push_str(
&format!(
".find(|{}| {})",
snippet_with_applicability(cx, inner_ret.span, "..", &mut applicability),
snippet_with_applicability(cx, cond.span, "..", &mut applicability),
)[..],
);
}
// Extends to `last_stmt` to include semicolon in case of `return None;`
let lint_span = span.to(last_stmt.span).to(last_ret.span);
span_lint_and_then(
cx,
MANUAL_FIND,
lint_span,
"manual implementation of `Iterator::find`",
|diag| {
if applicability == Applicability::MaybeIncorrect {
diag.note("you may need to dereference some variables");
}
diag.span_suggestion(
lint_span,
"replace with an iterator",
snippet,
applicability,
);
},
);
}
}
}
fn get_binding(pat: &Pat<'_>) -> Option<HirId> {
let mut hir_id = None;
let mut count = 0;
pat.each_binding(|annotation, id, _, _| {
count += 1;
if count > 1 {
hir_id = None;
return;
}
if let BindingAnnotation::Unannotated = annotation {
hir_id = Some(id);
}
});
hir_id
}
// Returns the last statement and last return if function fits format for lint
fn last_stmt_and_ret<'tcx>(
cx: &LateContext<'tcx>,
expr: &'tcx Expr<'_>,
) -> Option<(&'tcx Stmt<'tcx>, &'tcx Expr<'tcx>)> {
// Returns last non-return statement and the last return
fn extract<'tcx>(block: &Block<'tcx>) -> Option<(&'tcx Stmt<'tcx>, &'tcx Expr<'tcx>)> {
if let [.., last_stmt] = block.stmts {
if let Some(ret) = block.expr {
return Some((last_stmt, ret));
}
if_chain! {
if let [.., snd_last, _] = block.stmts;
if let StmtKind::Semi(last_expr) = last_stmt.kind;
if let ExprKind::Ret(Some(ret)) = last_expr.kind;
then {
return Some((snd_last, ret));
}
}
}
None
}
let mut parent_iter = cx.tcx.hir().parent_iter(expr.hir_id);
if_chain! {
// This should be the loop
if let Some((node_hir, Node::Stmt(..))) = parent_iter.next();
// This should be the funciton body
if let Some((_, Node::Block(block))) = parent_iter.next();
if let Some((last_stmt, last_ret)) = extract(block);
if last_stmt.hir_id == node_hir;
if let ExprKind::Path(path) = &last_ret.kind;
if is_lang_ctor(cx, path, LangItem::OptionNone);
if let Some((_, Node::Expr(_block))) = parent_iter.next();
// This includes the function header
if let Some((_, func)) = parent_iter.next();
if func.fn_kind().is_some();
then {
Some((block.stmts.last().unwrap(), last_ret))
} else {
None
}
}
}

View file

@ -5,6 +5,7 @@ mod explicit_iter_loop;
mod for_kv_map; mod for_kv_map;
mod for_loops_over_fallibles; mod for_loops_over_fallibles;
mod iter_next_loop; mod iter_next_loop;
mod manual_find;
mod manual_flatten; mod manual_flatten;
mod manual_memcpy; mod manual_memcpy;
mod missing_spin_loop; mod missing_spin_loop;
@ -597,6 +598,37 @@ declare_clippy_lint! {
"An empty busy waiting loop" "An empty busy waiting loop"
} }
declare_clippy_lint! {
/// ### What it does
/// Check for manual implementations of Iterator::find
///
/// ### Why is this bad?
/// It doesn't affect performance, but using `find` is shorter and easier to read.
///
/// ### Example
///
/// ```rust
/// fn example(arr: Vec<i32>) -> Option<i32> {
/// for el in arr {
/// if el == 1 {
/// return Some(el);
/// }
/// }
/// None
/// }
/// ```
/// Use instead:
/// ```rust
/// fn example(arr: Vec<i32>) -> Option<i32> {
/// arr.into_iter().find(|&el| el == 1)
/// }
/// ```
#[clippy::version = "1.61.0"]
pub MANUAL_FIND,
complexity,
"manual implementation of `Iterator::find`"
}
declare_lint_pass!(Loops => [ declare_lint_pass!(Loops => [
MANUAL_MEMCPY, MANUAL_MEMCPY,
MANUAL_FLATTEN, MANUAL_FLATTEN,
@ -617,6 +649,7 @@ declare_lint_pass!(Loops => [
SAME_ITEM_PUSH, SAME_ITEM_PUSH,
SINGLE_ELEMENT_LOOP, SINGLE_ELEMENT_LOOP,
MISSING_SPIN_LOOP, MISSING_SPIN_LOOP,
MANUAL_FIND,
]); ]);
impl<'tcx> LateLintPass<'tcx> for Loops { impl<'tcx> LateLintPass<'tcx> for Loops {
@ -692,6 +725,7 @@ fn check_for_loop<'tcx>(
single_element_loop::check(cx, pat, arg, body, expr); single_element_loop::check(cx, pat, arg, body, expr);
same_item_push::check(cx, pat, arg, body, expr); same_item_push::check(cx, pat, arg, body, expr);
manual_flatten::check(cx, pat, arg, body, span); manual_flatten::check(cx, pat, arg, body, span);
manual_find::check(cx, pat, arg, body, span, expr);
} }
fn check_for_loop_arg(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>) { fn check_for_loop_arg(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>) {

View file

@ -159,12 +159,10 @@ impl<'a, 'tcx, 'b> Visitor<'tcx> for SimilarNamesNameVisitor<'a, 'tcx, 'b> {
#[must_use] #[must_use]
fn get_exemptions(interned_name: &str) -> Option<&'static [&'static str]> { fn get_exemptions(interned_name: &str) -> Option<&'static [&'static str]> {
for &list in ALLOWED_TO_BE_SIMILAR { ALLOWED_TO_BE_SIMILAR
if allowed_to_be_similar(interned_name, list) { .iter()
return Some(list); .find(|&&list| allowed_to_be_similar(interned_name, list))
} .copied()
}
None
} }
#[must_use] #[must_use]

22
tests/ui/manual_find.rs Normal file
View file

@ -0,0 +1,22 @@
#![allow(unused)]
#![warn(clippy::manual_find)]
fn vec_string(strings: Vec<String>) -> Option<String> {
for s in strings {
if s == String::new() {
return Some(s);
}
}
None
}
fn tuple(arr: Vec<(String, i32)>) -> Option<String> {
for (s, _) in arr {
if s == String::new() {
return Some(s);
}
}
None
}
fn main() {}

View file

@ -0,0 +1,29 @@
error: manual implementation of `Iterator::find`
--> $DIR/manual_find.rs:5:5
|
LL | / for s in strings {
LL | | if s == String::new() {
LL | | return Some(s);
LL | | }
LL | | }
LL | | None
| |________^ help: replace with an iterator: `strings.into_iter().find(|s| s == String::new())`
|
= note: `-D clippy::manual-find` implied by `-D warnings`
= note: you may need to dereference some variables
error: manual implementation of `Iterator::find`
--> $DIR/manual_find.rs:14:5
|
LL | / for (s, _) in arr {
LL | | if s == String::new() {
LL | | return Some(s);
LL | | }
LL | | }
LL | | None
| |________^ help: replace with an iterator: `arr.into_iter().map(|(s, _)| s).find(|s| s == String::new())`
|
= note: you may need to dereference some variables
error: aborting due to 2 previous errors

View file

@ -0,0 +1,182 @@
// run-rustfix
#![allow(unused, clippy::needless_return)]
#![warn(clippy::manual_find)]
use std::collections::HashMap;
const ARRAY: &[u32; 5] = &[2, 7, 1, 9, 3];
fn lookup(n: u32) -> Option<u32> {
ARRAY.iter().find(|&&v| v == n).copied()
}
fn with_pat(arr: Vec<(u32, u32)>) -> Option<u32> {
arr.into_iter().map(|(a, _)| a).find(|&a| a % 2 == 0)
}
struct Data {
name: String,
is_true: bool,
}
fn with_struct(arr: Vec<Data>) -> Option<Data> {
arr.into_iter().find(|el| el.name.len() == 10)
}
struct Tuple(usize, usize);
fn with_tuple_struct(arr: Vec<Tuple>) -> Option<usize> {
arr.into_iter().map(|Tuple(a, _)| a).find(|&a| a >= 3)
}
struct A;
impl A {
fn should_keep(&self) -> bool {
true
}
}
fn with_method_call(arr: Vec<A>) -> Option<A> {
arr.into_iter().find(|el| el.should_keep())
}
fn with_closure(arr: Vec<u32>) -> Option<u32> {
let f = |el: u32| -> u32 { el + 10 };
arr.into_iter().find(|&el| f(el) == 20)
}
fn with_closure2(arr: HashMap<String, i32>) -> Option<i32> {
let f = |el: i32| -> bool { el == 10 };
arr.values().find(|&&el| f(el)).copied()
}
fn with_bool(arr: Vec<Data>) -> Option<Data> {
arr.into_iter().find(|el| el.is_true)
}
fn with_side_effects(arr: Vec<u32>) -> Option<u32> {
for v in arr {
if v == 1 {
println!("side effect");
return Some(v);
}
}
None
}
fn with_else(arr: Vec<u32>) -> Option<u32> {
for el in arr {
if el % 2 == 0 {
return Some(el);
} else {
println!("{}", el);
}
}
None
}
fn tuple_with_ref(v: [(u8, &u8); 3]) -> Option<u8> {
v.into_iter().map(|(_, &x)| x).find(|&x| x > 10)
}
fn ref_to_tuple_with_ref(v: &[(u8, &u8)]) -> Option<u8> {
v.iter().map(|&(_, &x)| x).find(|&x| x > 10)
}
fn explicit_ret(arr: Vec<i32>) -> Option<i32> {
arr.into_iter().find(|&x| x >= 5)
}
fn plus_one(a: i32) -> Option<i32> {
Some(a + 1)
}
fn fn_instead_of_some(a: &[i32]) -> Option<i32> {
for &x in a {
if x == 1 {
return plus_one(x);
}
}
None
}
fn for_in_condition(a: &[i32], b: bool) -> Option<i32> {
if b {
for &x in a {
if x == 1 {
return Some(x);
}
}
}
None
}
fn intermediate_statements(a: &[i32]) -> Option<i32> {
for &x in a {
if x == 1 {
return Some(x);
}
}
println!("side effect");
None
}
fn mixed_binding_modes(arr: Vec<(i32, String)>) -> Option<i32> {
for (x, mut s) in arr {
if x == 1 && s.as_mut_str().len() == 2 {
return Some(x);
}
}
None
}
fn as_closure() {
#[rustfmt::skip]
let f = |arr: Vec<i32>| -> Option<i32> {
arr.into_iter().find(|&x| x < 1)
};
}
fn in_block(a: &[i32]) -> Option<i32> {
let should_be_none = {
for &x in a {
if x == 1 {
return Some(x);
}
}
None
};
assert!(should_be_none.is_none());
should_be_none
}
// Not handled yet
fn mut_binding(v: Vec<String>) -> Option<String> {
for mut s in v {
if s.as_mut_str().len() > 1 {
return Some(s);
}
}
None
}
fn subpattern(v: Vec<[u32; 32]>) -> Option<[u32; 32]> {
for a @ [first, ..] in v {
if a[12] == first {
return Some(a);
}
}
None
}
fn two_bindings(v: Vec<(u8, u8)>) -> Option<u8> {
for (a, n) in v {
if a == n {
return Some(a);
}
}
None
}
fn main() {}

View file

@ -0,0 +1,242 @@
// run-rustfix
#![allow(unused, clippy::needless_return)]
#![warn(clippy::manual_find)]
use std::collections::HashMap;
const ARRAY: &[u32; 5] = &[2, 7, 1, 9, 3];
fn lookup(n: u32) -> Option<u32> {
for &v in ARRAY {
if v == n {
return Some(v);
}
}
None
}
fn with_pat(arr: Vec<(u32, u32)>) -> Option<u32> {
for (a, _) in arr {
if a % 2 == 0 {
return Some(a);
}
}
None
}
struct Data {
name: String,
is_true: bool,
}
fn with_struct(arr: Vec<Data>) -> Option<Data> {
for el in arr {
if el.name.len() == 10 {
return Some(el);
}
}
None
}
struct Tuple(usize, usize);
fn with_tuple_struct(arr: Vec<Tuple>) -> Option<usize> {
for Tuple(a, _) in arr {
if a >= 3 {
return Some(a);
}
}
None
}
struct A;
impl A {
fn should_keep(&self) -> bool {
true
}
}
fn with_method_call(arr: Vec<A>) -> Option<A> {
for el in arr {
if el.should_keep() {
return Some(el);
}
}
None
}
fn with_closure(arr: Vec<u32>) -> Option<u32> {
let f = |el: u32| -> u32 { el + 10 };
for el in arr {
if f(el) == 20 {
return Some(el);
}
}
None
}
fn with_closure2(arr: HashMap<String, i32>) -> Option<i32> {
let f = |el: i32| -> bool { el == 10 };
for &el in arr.values() {
if f(el) {
return Some(el);
}
}
None
}
fn with_bool(arr: Vec<Data>) -> Option<Data> {
for el in arr {
if el.is_true {
return Some(el);
}
}
None
}
fn with_side_effects(arr: Vec<u32>) -> Option<u32> {
for v in arr {
if v == 1 {
println!("side effect");
return Some(v);
}
}
None
}
fn with_else(arr: Vec<u32>) -> Option<u32> {
for el in arr {
if el % 2 == 0 {
return Some(el);
} else {
println!("{}", el);
}
}
None
}
fn tuple_with_ref(v: [(u8, &u8); 3]) -> Option<u8> {
for (_, &x) in v {
if x > 10 {
return Some(x);
}
}
None
}
fn ref_to_tuple_with_ref(v: &[(u8, &u8)]) -> Option<u8> {
for &(_, &x) in v {
if x > 10 {
return Some(x);
}
}
None
}
fn explicit_ret(arr: Vec<i32>) -> Option<i32> {
for x in arr {
if x >= 5 {
return Some(x);
}
}
return None;
}
fn plus_one(a: i32) -> Option<i32> {
Some(a + 1)
}
fn fn_instead_of_some(a: &[i32]) -> Option<i32> {
for &x in a {
if x == 1 {
return plus_one(x);
}
}
None
}
fn for_in_condition(a: &[i32], b: bool) -> Option<i32> {
if b {
for &x in a {
if x == 1 {
return Some(x);
}
}
}
None
}
fn intermediate_statements(a: &[i32]) -> Option<i32> {
for &x in a {
if x == 1 {
return Some(x);
}
}
println!("side effect");
None
}
fn mixed_binding_modes(arr: Vec<(i32, String)>) -> Option<i32> {
for (x, mut s) in arr {
if x == 1 && s.as_mut_str().len() == 2 {
return Some(x);
}
}
None
}
fn as_closure() {
#[rustfmt::skip]
let f = |arr: Vec<i32>| -> Option<i32> {
for x in arr {
if x < 1 {
return Some(x);
}
}
None
};
}
fn in_block(a: &[i32]) -> Option<i32> {
let should_be_none = {
for &x in a {
if x == 1 {
return Some(x);
}
}
None
};
assert!(should_be_none.is_none());
should_be_none
}
// Not handled yet
fn mut_binding(v: Vec<String>) -> Option<String> {
for mut s in v {
if s.as_mut_str().len() > 1 {
return Some(s);
}
}
None
}
fn subpattern(v: Vec<[u32; 32]>) -> Option<[u32; 32]> {
for a @ [first, ..] in v {
if a[12] == first {
return Some(a);
}
}
None
}
fn two_bindings(v: Vec<(u8, u8)>) -> Option<u8> {
for (a, n) in v {
if a == n {
return Some(a);
}
}
None
}
fn main() {}

View file

@ -0,0 +1,142 @@
error: manual implementation of `Iterator::find`
--> $DIR/manual_find_fixable.rs:11:5
|
LL | / for &v in ARRAY {
LL | | if v == n {
LL | | return Some(v);
LL | | }
LL | | }
LL | | None
| |________^ help: replace with an iterator: `ARRAY.iter().find(|&&v| v == n).copied()`
|
= note: `-D clippy::manual-find` implied by `-D warnings`
error: manual implementation of `Iterator::find`
--> $DIR/manual_find_fixable.rs:20:5
|
LL | / for (a, _) in arr {
LL | | if a % 2 == 0 {
LL | | return Some(a);
LL | | }
LL | | }
LL | | None
| |________^ help: replace with an iterator: `arr.into_iter().map(|(a, _)| a).find(|&a| a % 2 == 0)`
error: manual implementation of `Iterator::find`
--> $DIR/manual_find_fixable.rs:33:5
|
LL | / for el in arr {
LL | | if el.name.len() == 10 {
LL | | return Some(el);
LL | | }
LL | | }
LL | | None
| |________^ help: replace with an iterator: `arr.into_iter().find(|el| el.name.len() == 10)`
|
= note: you may need to dereference some variables
error: manual implementation of `Iterator::find`
--> $DIR/manual_find_fixable.rs:43:5
|
LL | / for Tuple(a, _) in arr {
LL | | if a >= 3 {
LL | | return Some(a);
LL | | }
LL | | }
LL | | None
| |________^ help: replace with an iterator: `arr.into_iter().map(|Tuple(a, _)| a).find(|&a| a >= 3)`
error: manual implementation of `Iterator::find`
--> $DIR/manual_find_fixable.rs:58:5
|
LL | / for el in arr {
LL | | if el.should_keep() {
LL | | return Some(el);
LL | | }
LL | | }
LL | | None
| |________^ help: replace with an iterator: `arr.into_iter().find(|el| el.should_keep())`
|
= note: you may need to dereference some variables
error: manual implementation of `Iterator::find`
--> $DIR/manual_find_fixable.rs:68:5
|
LL | / for el in arr {
LL | | if f(el) == 20 {
LL | | return Some(el);
LL | | }
LL | | }
LL | | None
| |________^ help: replace with an iterator: `arr.into_iter().find(|&el| f(el) == 20)`
error: manual implementation of `Iterator::find`
--> $DIR/manual_find_fixable.rs:78:5
|
LL | / for &el in arr.values() {
LL | | if f(el) {
LL | | return Some(el);
LL | | }
LL | | }
LL | | None
| |________^ help: replace with an iterator: `arr.values().find(|&&el| f(el)).copied()`
error: manual implementation of `Iterator::find`
--> $DIR/manual_find_fixable.rs:87:5
|
LL | / for el in arr {
LL | | if el.is_true {
LL | | return Some(el);
LL | | }
LL | | }
LL | | None
| |________^ help: replace with an iterator: `arr.into_iter().find(|el| el.is_true)`
|
= note: you may need to dereference some variables
error: manual implementation of `Iterator::find`
--> $DIR/manual_find_fixable.rs:117:5
|
LL | / for (_, &x) in v {
LL | | if x > 10 {
LL | | return Some(x);
LL | | }
LL | | }
LL | | None
| |________^ help: replace with an iterator: `v.into_iter().map(|(_, &x)| x).find(|&x| x > 10)`
error: manual implementation of `Iterator::find`
--> $DIR/manual_find_fixable.rs:126:5
|
LL | / for &(_, &x) in v {
LL | | if x > 10 {
LL | | return Some(x);
LL | | }
LL | | }
LL | | None
| |________^ help: replace with an iterator: `v.iter().map(|&(_, &x)| x).find(|&x| x > 10)`
error: manual implementation of `Iterator::find`
--> $DIR/manual_find_fixable.rs:135:5
|
LL | / for x in arr {
LL | | if x >= 5 {
LL | | return Some(x);
LL | | }
LL | | }
LL | | return None;
| |________________^ help: replace with an iterator: `arr.into_iter().find(|&x| x >= 5)`
error: manual implementation of `Iterator::find`
--> $DIR/manual_find_fixable.rs:190:9
|
LL | / for x in arr {
LL | | if x < 1 {
LL | | return Some(x);
LL | | }
LL | | }
LL | | None
| |____________^ help: replace with an iterator: `arr.into_iter().find(|&x| x < 1)`
error: aborting due to 12 previous errors

View file

@ -6,7 +6,8 @@
unreachable_code, unreachable_code,
unused_mut, unused_mut,
dead_code, dead_code,
clippy::equatable_if_let clippy::equatable_if_let,
clippy::manual_find
)] )]
fn base() { fn base() {

View file

@ -6,7 +6,8 @@
unreachable_code, unreachable_code,
unused_mut, unused_mut,
dead_code, dead_code,
clippy::equatable_if_let clippy::equatable_if_let,
clippy::manual_find
)] )]
fn base() { fn base() {

View file

@ -1,5 +1,5 @@
error: this loop could be written as a `for` loop error: this loop could be written as a `for` loop
--> $DIR/while_let_on_iterator.rs:14:5 --> $DIR/while_let_on_iterator.rs:15:5
| |
LL | while let Option::Some(x) = iter.next() { LL | while let Option::Some(x) = iter.next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in iter` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in iter`
@ -7,85 +7,85 @@ LL | while let Option::Some(x) = iter.next() {
= note: `-D clippy::while-let-on-iterator` implied by `-D warnings` = note: `-D clippy::while-let-on-iterator` implied by `-D warnings`
error: this loop could be written as a `for` loop error: this loop could be written as a `for` loop
--> $DIR/while_let_on_iterator.rs:19:5 --> $DIR/while_let_on_iterator.rs:20:5
| |
LL | while let Some(x) = iter.next() { LL | while let Some(x) = iter.next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in iter` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in iter`
error: this loop could be written as a `for` loop error: this loop could be written as a `for` loop
--> $DIR/while_let_on_iterator.rs:24:5 --> $DIR/while_let_on_iterator.rs:25:5
| |
LL | while let Some(_) = iter.next() {} LL | while let Some(_) = iter.next() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in iter` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in iter`
error: this loop could be written as a `for` loop error: this loop could be written as a `for` loop
--> $DIR/while_let_on_iterator.rs:100:9 --> $DIR/while_let_on_iterator.rs:101:9
| |
LL | while let Some([..]) = it.next() {} LL | while let Some([..]) = it.next() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for [..] in it` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for [..] in it`
error: this loop could be written as a `for` loop error: this loop could be written as a `for` loop
--> $DIR/while_let_on_iterator.rs:107:9 --> $DIR/while_let_on_iterator.rs:108:9
| |
LL | while let Some([_x]) = it.next() {} LL | while let Some([_x]) = it.next() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for [_x] in it` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for [_x] in it`
error: this loop could be written as a `for` loop error: this loop could be written as a `for` loop
--> $DIR/while_let_on_iterator.rs:120:9 --> $DIR/while_let_on_iterator.rs:121:9
| |
LL | while let Some(x @ [_]) = it.next() { LL | while let Some(x @ [_]) = it.next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x @ [_] in it` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x @ [_] in it`
error: this loop could be written as a `for` loop error: this loop could be written as a `for` loop
--> $DIR/while_let_on_iterator.rs:140:9 --> $DIR/while_let_on_iterator.rs:141:9
| |
LL | while let Some(_) = y.next() { LL | while let Some(_) = y.next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in y` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in y`
error: this loop could be written as a `for` loop error: this loop could be written as a `for` loop
--> $DIR/while_let_on_iterator.rs:197:9 --> $DIR/while_let_on_iterator.rs:198:9
| |
LL | while let Some(m) = it.next() { LL | while let Some(m) = it.next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it.by_ref()` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it.by_ref()`
error: this loop could be written as a `for` loop error: this loop could be written as a `for` loop
--> $DIR/while_let_on_iterator.rs:208:5 --> $DIR/while_let_on_iterator.rs:209:5
| |
LL | while let Some(n) = it.next() { LL | while let Some(n) = it.next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for n in it` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for n in it`
error: this loop could be written as a `for` loop error: this loop could be written as a `for` loop
--> $DIR/while_let_on_iterator.rs:210:9 --> $DIR/while_let_on_iterator.rs:211:9
| |
LL | while let Some(m) = it.next() { LL | while let Some(m) = it.next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it`
error: this loop could be written as a `for` loop error: this loop could be written as a `for` loop
--> $DIR/while_let_on_iterator.rs:219:9 --> $DIR/while_let_on_iterator.rs:220:9
| |
LL | while let Some(m) = it.next() { LL | while let Some(m) = it.next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it`
error: this loop could be written as a `for` loop error: this loop could be written as a `for` loop
--> $DIR/while_let_on_iterator.rs:228:9 --> $DIR/while_let_on_iterator.rs:229:9
| |
LL | while let Some(m) = it.next() { LL | while let Some(m) = it.next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it.by_ref()` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it.by_ref()`
error: this loop could be written as a `for` loop error: this loop could be written as a `for` loop
--> $DIR/while_let_on_iterator.rs:245:9 --> $DIR/while_let_on_iterator.rs:246:9
| |
LL | while let Some(m) = it.next() { LL | while let Some(m) = it.next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it.by_ref()` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it.by_ref()`
error: this loop could be written as a `for` loop error: this loop could be written as a `for` loop
--> $DIR/while_let_on_iterator.rs:260:13 --> $DIR/while_let_on_iterator.rs:261:13
| |
LL | while let Some(i) = self.0.next() { LL | while let Some(i) = self.0.next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for i in self.0.by_ref()` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for i in self.0.by_ref()`
error: manual `!RangeInclusive::contains` implementation error: manual `!RangeInclusive::contains` implementation
--> $DIR/while_let_on_iterator.rs:261:20 --> $DIR/while_let_on_iterator.rs:262:20
| |
LL | if i < 3 || i > 7 { LL | if i < 3 || i > 7 {
| ^^^^^^^^^^^^^^ help: use: `!(3..=7).contains(&i)` | ^^^^^^^^^^^^^^ help: use: `!(3..=7).contains(&i)`
@ -93,49 +93,49 @@ LL | if i < 3 || i > 7 {
= note: `-D clippy::manual-range-contains` implied by `-D warnings` = note: `-D clippy::manual-range-contains` implied by `-D warnings`
error: this loop could be written as a `for` loop error: this loop could be written as a `for` loop
--> $DIR/while_let_on_iterator.rs:292:13 --> $DIR/while_let_on_iterator.rs:293:13
| |
LL | while let Some(i) = self.0.0.0.next() { LL | while let Some(i) = self.0.0.0.next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for i in self.0.0.0.by_ref()` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for i in self.0.0.0.by_ref()`
error: this loop could be written as a `for` loop error: this loop could be written as a `for` loop
--> $DIR/while_let_on_iterator.rs:321:5 --> $DIR/while_let_on_iterator.rs:322:5
| |
LL | while let Some(n) = it.next() { LL | while let Some(n) = it.next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for n in it.by_ref()` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for n in it.by_ref()`
error: this loop could be written as a `for` loop error: this loop could be written as a `for` loop
--> $DIR/while_let_on_iterator.rs:333:9 --> $DIR/while_let_on_iterator.rs:334:9
| |
LL | while let Some(x) = it.next() { LL | while let Some(x) = it.next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.by_ref()` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.by_ref()`
error: this loop could be written as a `for` loop error: this loop could be written as a `for` loop
--> $DIR/while_let_on_iterator.rs:347:5 --> $DIR/while_let_on_iterator.rs:348:5
| |
LL | while let Some(x) = it.next() { LL | while let Some(x) = it.next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.by_ref()` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.by_ref()`
error: this loop could be written as a `for` loop error: this loop could be written as a `for` loop
--> $DIR/while_let_on_iterator.rs:358:5 --> $DIR/while_let_on_iterator.rs:359:5
| |
LL | while let Some(x) = it.0.next() { LL | while let Some(x) = it.0.next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.0.by_ref()` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.0.by_ref()`
error: this loop could be written as a `for` loop error: this loop could be written as a `for` loop
--> $DIR/while_let_on_iterator.rs:393:5 --> $DIR/while_let_on_iterator.rs:394:5
| |
LL | while let Some(x) = s.x.next() { LL | while let Some(x) = s.x.next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in s.x.by_ref()` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in s.x.by_ref()`
error: this loop could be written as a `for` loop error: this loop could be written as a `for` loop
--> $DIR/while_let_on_iterator.rs:400:5 --> $DIR/while_let_on_iterator.rs:401:5
| |
LL | while let Some(x) = x[0].next() { LL | while let Some(x) = x[0].next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in x[0].by_ref()` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in x[0].by_ref()`
error: this loop could be written as a `for` loop error: this loop could be written as a `for` loop
--> $DIR/while_let_on_iterator.rs:407:5 --> $DIR/while_let_on_iterator.rs:408:5
| |
LL | while let Some(..) = it.next() { LL | while let Some(..) = it.next() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in it` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in it`