diff --git a/CHANGELOG.md b/CHANGELOG.md
index cff60a21c99..bc50ff3a44a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3520,6 +3520,7 @@ Released 2018-09-13
 [`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_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_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
diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs
index 696f0c6f6b3..b4edb8ea90e 100644
--- a/clippy_lints/src/lib.register_all.rs
+++ b/clippy_lints/src/lib.register_all.rs
@@ -119,6 +119,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(loops::FOR_KV_MAP),
     LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES),
     LintId::of(loops::ITER_NEXT_LOOP),
+    LintId::of(loops::MANUAL_FIND),
     LintId::of(loops::MANUAL_FLATTEN),
     LintId::of(loops::MANUAL_MEMCPY),
     LintId::of(loops::MISSING_SPIN_LOOP),
diff --git a/clippy_lints/src/lib.register_complexity.rs b/clippy_lints/src/lib.register_complexity.rs
index 6370264a12a..27de11bf1ae 100644
--- a/clippy_lints/src/lib.register_complexity.rs
+++ b/clippy_lints/src/lib.register_complexity.rs
@@ -21,6 +21,7 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec!
     LintId::of(lifetimes::EXTRA_UNUSED_LIFETIMES),
     LintId::of(lifetimes::NEEDLESS_LIFETIMES),
     LintId::of(loops::EXPLICIT_COUNTER_LOOP),
+    LintId::of(loops::MANUAL_FIND),
     LintId::of(loops::MANUAL_FLATTEN),
     LintId::of(loops::SINGLE_ELEMENT_LOOP),
     LintId::of(loops::WHILE_LET_LOOP),
diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs
index 15b9405be3c..29a5f368f23 100644
--- a/clippy_lints/src/lib.register_lints.rs
+++ b/clippy_lints/src/lib.register_lints.rs
@@ -237,6 +237,7 @@ store.register_lints(&[
     loops::FOR_KV_MAP,
     loops::FOR_LOOPS_OVER_FALLIBLES,
     loops::ITER_NEXT_LOOP,
+    loops::MANUAL_FIND,
     loops::MANUAL_FLATTEN,
     loops::MANUAL_MEMCPY,
     loops::MISSING_SPIN_LOOP,
diff --git a/clippy_lints/src/loops/manual_find.rs b/clippy_lints/src/loops/manual_find.rs
new file mode 100644
index 00000000000..33736d6d4e6
--- /dev/null
+++ b/clippy_lints/src/loops/manual_find.rs
@@ -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
+        }
+    }
+}
diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs
index fa7a8b10033..ed270bd490d 100644
--- a/clippy_lints/src/loops/mod.rs
+++ b/clippy_lints/src/loops/mod.rs
@@ -5,6 +5,7 @@ mod explicit_iter_loop;
 mod for_kv_map;
 mod for_loops_over_fallibles;
 mod iter_next_loop;
+mod manual_find;
 mod manual_flatten;
 mod manual_memcpy;
 mod missing_spin_loop;
@@ -609,6 +610,37 @@ declare_clippy_lint! {
     "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 => [
     MANUAL_MEMCPY,
     MANUAL_FLATTEN,
@@ -629,6 +661,7 @@ declare_lint_pass!(Loops => [
     SAME_ITEM_PUSH,
     SINGLE_ELEMENT_LOOP,
     MISSING_SPIN_LOOP,
+    MANUAL_FIND,
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Loops {
@@ -703,6 +736,7 @@ fn check_for_loop<'tcx>(
     single_element_loop::check(cx, pat, arg, body, expr);
     same_item_push::check(cx, pat, arg, body, expr);
     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<'_>) {
diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs
index 7f6b535c7b1..c93b4b2f205 100644
--- a/clippy_lints/src/non_expressive_names.rs
+++ b/clippy_lints/src/non_expressive_names.rs
@@ -159,12 +159,10 @@ impl<'a, 'tcx, 'b> Visitor<'tcx> for SimilarNamesNameVisitor<'a, 'tcx, 'b> {
 
 #[must_use]
 fn get_exemptions(interned_name: &str) -> Option<&'static [&'static str]> {
-    for &list in ALLOWED_TO_BE_SIMILAR {
-        if allowed_to_be_similar(interned_name, list) {
-            return Some(list);
-        }
-    }
-    None
+    ALLOWED_TO_BE_SIMILAR
+        .iter()
+        .find(|&&list| allowed_to_be_similar(interned_name, list))
+        .copied()
 }
 
 #[must_use]
diff --git a/tests/ui/manual_find.rs b/tests/ui/manual_find.rs
new file mode 100644
index 00000000000..257fe045f78
--- /dev/null
+++ b/tests/ui/manual_find.rs
@@ -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() {}
diff --git a/tests/ui/manual_find.stderr b/tests/ui/manual_find.stderr
new file mode 100644
index 00000000000..da0fd4aaef7
--- /dev/null
+++ b/tests/ui/manual_find.stderr
@@ -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
+
diff --git a/tests/ui/manual_find_fixable.fixed b/tests/ui/manual_find_fixable.fixed
new file mode 100644
index 00000000000..36d1644c22b
--- /dev/null
+++ b/tests/ui/manual_find_fixable.fixed
@@ -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() {}
diff --git a/tests/ui/manual_find_fixable.rs b/tests/ui/manual_find_fixable.rs
new file mode 100644
index 00000000000..ed277ddaa72
--- /dev/null
+++ b/tests/ui/manual_find_fixable.rs
@@ -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() {}
diff --git a/tests/ui/manual_find_fixable.stderr b/tests/ui/manual_find_fixable.stderr
new file mode 100644
index 00000000000..dbc4ff69a74
--- /dev/null
+++ b/tests/ui/manual_find_fixable.stderr
@@ -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
+
diff --git a/tests/ui/while_let_on_iterator.fixed b/tests/ui/while_let_on_iterator.fixed
index cb8892a3f00..e9ff64431e1 100644
--- a/tests/ui/while_let_on_iterator.fixed
+++ b/tests/ui/while_let_on_iterator.fixed
@@ -6,7 +6,8 @@
     unreachable_code,
     unused_mut,
     dead_code,
-    clippy::equatable_if_let
+    clippy::equatable_if_let,
+    clippy::manual_find
 )]
 
 fn base() {
diff --git a/tests/ui/while_let_on_iterator.rs b/tests/ui/while_let_on_iterator.rs
index d9157184495..03da39526b2 100644
--- a/tests/ui/while_let_on_iterator.rs
+++ b/tests/ui/while_let_on_iterator.rs
@@ -6,7 +6,8 @@
     unreachable_code,
     unused_mut,
     dead_code,
-    clippy::equatable_if_let
+    clippy::equatable_if_let,
+    clippy::manual_find
 )]
 
 fn base() {
diff --git a/tests/ui/while_let_on_iterator.stderr b/tests/ui/while_let_on_iterator.stderr
index fb2b0f2467c..42859243855 100644
--- a/tests/ui/while_let_on_iterator.stderr
+++ b/tests/ui/while_let_on_iterator.stderr
@@ -1,5 +1,5 @@
 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() {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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`
 
 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() {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in iter`
 
 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() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in iter`
 
 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() {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for [..] in it`
 
 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() {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for [_x] in it`
 
 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() {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x @ [_] in it`
 
 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() {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in y`
 
 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() {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it.by_ref()`
 
 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() {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for n in it`
 
 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() {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it`
 
 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() {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it`
 
 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() {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it.by_ref()`
 
 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() {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it.by_ref()`
 
 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() {
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for i in self.0.by_ref()`
 
 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 {
    |                    ^^^^^^^^^^^^^^ 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`
 
 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() {
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for i in self.0.0.0.by_ref()`
 
 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() {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for n in it.by_ref()`
 
 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() {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.by_ref()`
 
 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() {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.by_ref()`
 
 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() {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.0.by_ref()`
 
 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() {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in s.x.by_ref()`
 
 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() {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in x[0].by_ref()`
 
 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() {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in it`