about summary refs log tree commit diff
diff options
context:
space:
mode:
authorlapla-cogito <me@lapla.dev>2025-02-11 15:16:32 +0900
committerlapla-cogito <me@lapla.dev>2025-02-16 06:21:57 +0900
commitfd17bfe57d615673f94e1c4a5686222ad03a1056 (patch)
treece36e97177563db41601b2ed3f7d2a55384bedca
parenta8b17827c60caa55872c06737bb242c615ab8f13 (diff)
downloadrust-fd17bfe57d615673f94e1c4a5686222ad03a1056.tar.gz
rust-fd17bfe57d615673f94e1c4a5686222ad03a1056.zip
add `manual_contains` lint
-rw-r--r--CHANGELOG.md1
-rw-r--r--clippy_lints/src/declared_lints.rs1
-rw-r--r--clippy_lints/src/methods/manual_contains.rs113
-rw-r--r--clippy_lints/src/methods/mod.rs30
-rw-r--r--tests/ui/manual_contains.fixed98
-rw-r--r--tests/ui/manual_contains.rs98
-rw-r--r--tests/ui/manual_contains.stderr77
-rw-r--r--tests/ui/needless_collect.fixed8
-rw-r--r--tests/ui/needless_collect.rs8
-rw-r--r--tests/ui/needless_collect.stderr38
-rw-r--r--tests/ui/search_is_some_fixable_none.fixed2
-rw-r--r--tests/ui/search_is_some_fixable_none.rs2
-rw-r--r--tests/ui/search_is_some_fixable_some.fixed2
-rw-r--r--tests/ui/search_is_some_fixable_some.rs2
14 files changed, 455 insertions, 25 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a1ea3ce8f79..2b8695f6627 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5743,6 +5743,7 @@ Released 2018-09-13
 [`manual_bits`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_bits
 [`manual_c_str_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_c_str_literals
 [`manual_clamp`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_clamp
+[`manual_contains`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_contains
 [`manual_div_ceil`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_div_ceil
 [`manual_filter`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter
 [`manual_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter_map
diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs
index 1f00fb82c6d..4b439d3a7a2 100644
--- a/clippy_lints/src/declared_lints.rs
+++ b/clippy_lints/src/declared_lints.rs
@@ -418,6 +418,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
     crate::methods::ITER_SKIP_ZERO_INFO,
     crate::methods::ITER_WITH_DRAIN_INFO,
     crate::methods::JOIN_ABSOLUTE_PATHS_INFO,
+    crate::methods::MANUAL_CONTAINS_INFO,
     crate::methods::MANUAL_C_STR_LITERALS_INFO,
     crate::methods::MANUAL_FILTER_MAP_INFO,
     crate::methods::MANUAL_FIND_MAP_INFO,
diff --git a/clippy_lints/src/methods/manual_contains.rs b/clippy_lints/src/methods/manual_contains.rs
new file mode 100644
index 00000000000..61bf32cc19b
--- /dev/null
+++ b/clippy_lints/src/methods/manual_contains.rs
@@ -0,0 +1,113 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::eager_or_lazy::switch_to_eager_eval;
+use clippy_utils::peel_hir_pat_refs;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::sugg::Sugg;
+use rustc_ast::UnOp;
+use rustc_errors::Applicability;
+use rustc_hir::def::Res;
+use rustc_hir::{BinOpKind, Body, Expr, ExprKind, HirId, QPath};
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self};
+use rustc_span::source_map::Spanned;
+
+use super::MANUAL_CONTAINS;
+
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, closure_arg: &Expr<'_>) {
+    let mut app = Applicability::MachineApplicable;
+
+    if !expr.span.from_expansion()
+        // check if `iter().any()` can be replaced with `contains()`
+        && let ExprKind::Closure(closure) = closure_arg.kind
+        && let Body{params: [param],value} = cx.tcx.hir().body(closure.body)
+        && let ExprKind::Binary(op, lhs, rhs) = value.kind
+        && let (peeled_ref_pat, _) = peel_hir_pat_refs(param.pat)
+        && let Some((snip,snip_expr)) = can_replace_with_contains(cx, op, lhs, rhs, peeled_ref_pat.hir_id, &mut app)
+        && let ref_type = cx.typeck_results().expr_ty_adjusted(recv)
+        && let ty::Ref(_, inner_type, _) = ref_type.kind()
+        && let ty::Slice(slice_type) = inner_type.kind()
+        && *slice_type == cx.typeck_results().expr_ty(snip_expr)
+    {
+        span_lint_and_sugg(
+            cx,
+            MANUAL_CONTAINS,
+            expr.span,
+            "using `contains()` instead of `iter().any()` is more efficient",
+            "try",
+            format!(
+                "{}.contains({})",
+                snippet_with_applicability(cx, recv.span, "_", &mut app),
+                snip
+            ),
+            app,
+        );
+    }
+}
+
+enum EligibleArg {
+    IsClosureArg,
+    ContainsArg(String),
+}
+
+fn try_get_eligible_arg<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'tcx>,
+    closure_arg_id: HirId,
+    applicability: &mut Applicability,
+) -> Option<(EligibleArg, &'tcx Expr<'tcx>)> {
+    let mut get_snippet = |expr: &Expr<'_>, needs_borrow: bool| {
+        let sugg = Sugg::hir_with_applicability(cx, expr, "_", applicability);
+        EligibleArg::ContainsArg((if needs_borrow { sugg.addr() } else { sugg }).to_string())
+    };
+
+    match expr.kind {
+        ExprKind::Path(QPath::Resolved(_, path)) => {
+            if path.res == Res::Local(closure_arg_id) {
+                Some((EligibleArg::IsClosureArg, expr))
+            } else {
+                Some((get_snippet(expr, true), expr))
+            }
+        },
+        ExprKind::Unary(UnOp::Deref, inner) => {
+            if let ExprKind::Path(QPath::Resolved(_, path)) = inner.kind {
+                if path.res == Res::Local(closure_arg_id) {
+                    Some((EligibleArg::IsClosureArg, expr))
+                } else {
+                    Some((get_snippet(inner, false), expr))
+                }
+            } else {
+                None
+            }
+        },
+        _ => {
+            if switch_to_eager_eval(cx, expr) {
+                Some((get_snippet(expr, true), expr))
+            } else {
+                None
+            }
+        },
+    }
+}
+
+fn can_replace_with_contains<'tcx>(
+    cx: &LateContext<'tcx>,
+    bin_op: Spanned<BinOpKind>,
+    left_expr: &'tcx Expr<'tcx>,
+    right_expr: &'tcx Expr<'tcx>,
+    closure_arg_id: HirId,
+    applicability: &mut Applicability,
+) -> Option<(String, &'tcx Expr<'tcx>)> {
+    if bin_op.node != BinOpKind::Eq {
+        return None;
+    }
+
+    let left_candidate = try_get_eligible_arg(cx, left_expr, closure_arg_id, applicability)?;
+    let right_candidate = try_get_eligible_arg(cx, right_expr, closure_arg_id, applicability)?;
+    match (left_candidate, right_candidate) {
+        ((EligibleArg::IsClosureArg, _), (EligibleArg::ContainsArg(snip), candidate_expr))
+        | ((EligibleArg::ContainsArg(snip), candidate_expr), (EligibleArg::IsClosureArg, _)) => {
+            Some((snip, candidate_expr))
+        },
+        _ => None,
+    }
+}
diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs
index 7e9db66ff86..7e66016b89d 100644
--- a/clippy_lints/src/methods/mod.rs
+++ b/clippy_lints/src/methods/mod.rs
@@ -54,6 +54,7 @@ mod iter_with_drain;
 mod iterator_step_by_zero;
 mod join_absolute_paths;
 mod manual_c_str_literals;
+mod manual_contains;
 mod manual_inspect;
 mod manual_is_variant_and;
 mod manual_next_back;
@@ -4434,6 +4435,31 @@ declare_clippy_lint! {
     "calling .bytes() is very inefficient when data is not in memory"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for usage of `iter().any()` on slices when it can be replaced with `contains()` and suggests doing so.
+    ///
+    /// ### Why is this bad?
+    /// `contains()` is more concise and idiomatic, sometimes more fast.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// fn foo(values: &[u8]) -> bool {
+    ///    values.iter().any(|&v| v == 10)
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// fn foo(values: &[u8]) -> bool {
+    ///    values.contains(&10)
+    /// }
+    /// ```
+    #[clippy::version = "1.86.0"]
+    pub MANUAL_CONTAINS,
+    perf,
+    "unnecessary `iter().any()` on slices that can be replaced with `contains()`"
+}
+
 #[expect(clippy::struct_excessive_bools)]
 pub struct Methods {
     avoid_breaking_exported_api: bool,
@@ -4609,6 +4635,7 @@ impl_lint_pass!(Methods => [
     SLICED_STRING_AS_BYTES,
     RETURN_AND_THEN,
     UNBUFFERED_BYTES,
+    MANUAL_CONTAINS,
 ]);
 
 /// Extracts a method call name, args, and `Span` of the method name.
@@ -4866,6 +4893,9 @@ impl Methods {
                         Some(("map", _, [map_arg], _, map_call_span)) => {
                             map_all_any_identity::check(cx, expr, recv, map_call_span, map_arg, call_span, arg, "any");
                         },
+                        Some(("iter", iter_recv, ..)) => {
+                            manual_contains::check(cx, expr, iter_recv, arg);
+                        },
                         _ => {},
                     }
                 },
diff --git a/tests/ui/manual_contains.fixed b/tests/ui/manual_contains.fixed
new file mode 100644
index 00000000000..d26c948a781
--- /dev/null
+++ b/tests/ui/manual_contains.fixed
@@ -0,0 +1,98 @@
+#![warn(clippy::manual_contains)]
+#![allow(clippy::eq_op, clippy::useless_vec)]
+
+fn should_lint() {
+    let vec: Vec<u8> = vec![1, 2, 3, 4, 5, 6];
+    let values = &vec[..];
+    let _ = values.contains(&4);
+    //~^ manual_contains
+
+    let vec: Vec<u32> = vec![1, 2, 3, 4, 5, 6];
+    let values = &vec[..];
+    let _ = values.contains(&4);
+    //~^ manual_contains
+
+    let values: [u8; 6] = [3, 14, 15, 92, 6, 5];
+    let _ = values.contains(&10);
+    //~^ manual_contains
+
+    let num = 14;
+    let values: [u8; 6] = [3, 14, 15, 92, 6, 5];
+    let _ = values.contains(&num);
+    //~^ manual_contains
+
+    let num = 14;
+    let values: [u8; 6] = [3, 14, 15, 92, 6, 5];
+    let _ = values.contains(&num);
+    //~^ manual_contains
+
+    let values: [u8; 6] = [3, 14, 15, 92, 6, 5];
+    let _ = values.contains(&4);
+    //~^ manual_contains
+
+    let vec: Vec<u8> = vec![1, 2, 3, 4, 5, 6];
+    let values = &vec[..];
+    let _ = values.contains(&4);
+    //~^ manual_contains
+
+    let vec: Vec<u8> = vec![1, 2, 3, 4, 5, 6];
+    let values = &vec[..];
+    let a = &4;
+    let _ = values.contains(a);
+    //~^ manual_contains
+
+    let vec = vec!["1", "2", "3", "4", "5", "6"];
+    let values = &vec[..];
+    let _ = values.contains(&"4");
+    //~^ manual_contains
+
+    let vec: Vec<u32> = vec![1, 2, 3, 4, 5, 6];
+    let values = &vec[..];
+    let _ = values.contains(&(4 + 1));
+    //~^ manual_contains
+}
+
+fn should_not_lint() {
+    let values: [u8; 6] = [3, 14, 15, 92, 6, 5];
+    let _ = values.iter().any(|&v| v > 10);
+
+    let vec: Vec<u32> = vec![1, 2, 3, 4, 5, 6];
+    let values = &vec[..];
+    let _ = values.iter().any(|&v| v % 2 == 0);
+    let _ = values.iter().any(|&v| v * 2 == 6);
+    let _ = values.iter().any(|&v| v == v);
+    let _ = values.iter().any(|&v| 4 == 4);
+    let _ = values.contains(&4);
+
+    let a = 1;
+    let b = 2;
+    let _ = values.iter().any(|&v| a == b);
+    let _ = values.iter().any(|&v| a == 4);
+
+    let vec: Vec<String> = vec!["1", "2", "3", "4", "5", "6"]
+        .iter()
+        .map(|&x| x.to_string())
+        .collect();
+    let values = &vec[..];
+    let _ = values.iter().any(|v| v == "4");
+
+    let vec: Vec<u32> = vec![1, 2, 3, 4, 5, 6];
+    let values = &vec[..];
+    let mut counter = 0;
+    let mut count = || {
+        counter += 1;
+        counter
+    };
+    let _ = values.iter().any(|&v| v == count());
+    let _ = values.iter().any(|&v| v == v * 2);
+}
+
+fn foo(values: &[u8]) -> bool {
+    values.contains(&10)
+    //~^ manual_contains
+}
+
+fn bar(values: [u8; 3]) -> bool {
+    values.contains(&10)
+    //~^ manual_contains
+}
diff --git a/tests/ui/manual_contains.rs b/tests/ui/manual_contains.rs
new file mode 100644
index 00000000000..fe67d2ee5d5
--- /dev/null
+++ b/tests/ui/manual_contains.rs
@@ -0,0 +1,98 @@
+#![warn(clippy::manual_contains)]
+#![allow(clippy::eq_op, clippy::useless_vec)]
+
+fn should_lint() {
+    let vec: Vec<u8> = vec![1, 2, 3, 4, 5, 6];
+    let values = &vec[..];
+    let _ = values.iter().any(|&v| v == 4);
+    //~^ manual_contains
+
+    let vec: Vec<u32> = vec![1, 2, 3, 4, 5, 6];
+    let values = &vec[..];
+    let _ = values.iter().any(|&v| v == 4);
+    //~^ manual_contains
+
+    let values: [u8; 6] = [3, 14, 15, 92, 6, 5];
+    let _ = values.iter().any(|&v| v == 10);
+    //~^ manual_contains
+
+    let num = 14;
+    let values: [u8; 6] = [3, 14, 15, 92, 6, 5];
+    let _ = values.iter().any(|&v| v == num);
+    //~^ manual_contains
+
+    let num = 14;
+    let values: [u8; 6] = [3, 14, 15, 92, 6, 5];
+    let _ = values.iter().any(|&v| num == v);
+    //~^ manual_contains
+
+    let values: [u8; 6] = [3, 14, 15, 92, 6, 5];
+    let _ = values.iter().any(|v| *v == 4);
+    //~^ manual_contains
+
+    let vec: Vec<u8> = vec![1, 2, 3, 4, 5, 6];
+    let values = &vec[..];
+    let _ = values.iter().any(|&v| 4 == v);
+    //~^ manual_contains
+
+    let vec: Vec<u8> = vec![1, 2, 3, 4, 5, 6];
+    let values = &vec[..];
+    let a = &4;
+    let _ = values.iter().any(|v| *v == *a);
+    //~^ manual_contains
+
+    let vec = vec!["1", "2", "3", "4", "5", "6"];
+    let values = &vec[..];
+    let _ = values.iter().any(|&v| v == "4");
+    //~^ manual_contains
+
+    let vec: Vec<u32> = vec![1, 2, 3, 4, 5, 6];
+    let values = &vec[..];
+    let _ = values.iter().any(|&v| v == 4 + 1);
+    //~^ manual_contains
+}
+
+fn should_not_lint() {
+    let values: [u8; 6] = [3, 14, 15, 92, 6, 5];
+    let _ = values.iter().any(|&v| v > 10);
+
+    let vec: Vec<u32> = vec![1, 2, 3, 4, 5, 6];
+    let values = &vec[..];
+    let _ = values.iter().any(|&v| v % 2 == 0);
+    let _ = values.iter().any(|&v| v * 2 == 6);
+    let _ = values.iter().any(|&v| v == v);
+    let _ = values.iter().any(|&v| 4 == 4);
+    let _ = values.contains(&4);
+
+    let a = 1;
+    let b = 2;
+    let _ = values.iter().any(|&v| a == b);
+    let _ = values.iter().any(|&v| a == 4);
+
+    let vec: Vec<String> = vec!["1", "2", "3", "4", "5", "6"]
+        .iter()
+        .map(|&x| x.to_string())
+        .collect();
+    let values = &vec[..];
+    let _ = values.iter().any(|v| v == "4");
+
+    let vec: Vec<u32> = vec![1, 2, 3, 4, 5, 6];
+    let values = &vec[..];
+    let mut counter = 0;
+    let mut count = || {
+        counter += 1;
+        counter
+    };
+    let _ = values.iter().any(|&v| v == count());
+    let _ = values.iter().any(|&v| v == v * 2);
+}
+
+fn foo(values: &[u8]) -> bool {
+    values.iter().any(|&v| v == 10)
+    //~^ manual_contains
+}
+
+fn bar(values: [u8; 3]) -> bool {
+    values.iter().any(|&v| v == 10)
+    //~^ manual_contains
+}
diff --git a/tests/ui/manual_contains.stderr b/tests/ui/manual_contains.stderr
new file mode 100644
index 00000000000..e6e2dea560c
--- /dev/null
+++ b/tests/ui/manual_contains.stderr
@@ -0,0 +1,77 @@
+error: using `contains()` instead of `iter().any()` is more efficient
+  --> tests/ui/manual_contains.rs:7:13
+   |
+LL |     let _ = values.iter().any(|&v| v == 4);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `values.contains(&4)`
+   |
+   = note: `-D clippy::manual-contains` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::manual_contains)]`
+
+error: using `contains()` instead of `iter().any()` is more efficient
+  --> tests/ui/manual_contains.rs:12:13
+   |
+LL |     let _ = values.iter().any(|&v| v == 4);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `values.contains(&4)`
+
+error: using `contains()` instead of `iter().any()` is more efficient
+  --> tests/ui/manual_contains.rs:16:13
+   |
+LL |     let _ = values.iter().any(|&v| v == 10);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `values.contains(&10)`
+
+error: using `contains()` instead of `iter().any()` is more efficient
+  --> tests/ui/manual_contains.rs:21:13
+   |
+LL |     let _ = values.iter().any(|&v| v == num);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `values.contains(&num)`
+
+error: using `contains()` instead of `iter().any()` is more efficient
+  --> tests/ui/manual_contains.rs:26:13
+   |
+LL |     let _ = values.iter().any(|&v| num == v);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `values.contains(&num)`
+
+error: using `contains()` instead of `iter().any()` is more efficient
+  --> tests/ui/manual_contains.rs:30:13
+   |
+LL |     let _ = values.iter().any(|v| *v == 4);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `values.contains(&4)`
+
+error: using `contains()` instead of `iter().any()` is more efficient
+  --> tests/ui/manual_contains.rs:35:13
+   |
+LL |     let _ = values.iter().any(|&v| 4 == v);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `values.contains(&4)`
+
+error: using `contains()` instead of `iter().any()` is more efficient
+  --> tests/ui/manual_contains.rs:41:13
+   |
+LL |     let _ = values.iter().any(|v| *v == *a);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `values.contains(a)`
+
+error: using `contains()` instead of `iter().any()` is more efficient
+  --> tests/ui/manual_contains.rs:46:13
+   |
+LL |     let _ = values.iter().any(|&v| v == "4");
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `values.contains(&"4")`
+
+error: using `contains()` instead of `iter().any()` is more efficient
+  --> tests/ui/manual_contains.rs:51:13
+   |
+LL |     let _ = values.iter().any(|&v| v == 4 + 1);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `values.contains(&(4 + 1))`
+
+error: using `contains()` instead of `iter().any()` is more efficient
+  --> tests/ui/manual_contains.rs:91:5
+   |
+LL |     values.iter().any(|&v| v == 10)
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `values.contains(&10)`
+
+error: using `contains()` instead of `iter().any()` is more efficient
+  --> tests/ui/manual_contains.rs:96:5
+   |
+LL |     values.iter().any(|&v| v == 10)
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `values.contains(&10)`
+
+error: aborting due to 12 previous errors
+
diff --git a/tests/ui/needless_collect.fixed b/tests/ui/needless_collect.fixed
index 104941dc993..bad8c307586 100644
--- a/tests/ui/needless_collect.fixed
+++ b/tests/ui/needless_collect.fixed
@@ -1,4 +1,10 @@
-#![allow(unused, clippy::needless_if, clippy::suspicious_map, clippy::iter_count)]
+#![allow(
+    unused,
+    clippy::needless_if,
+    clippy::suspicious_map,
+    clippy::iter_count,
+    clippy::manual_contains
+)]
 
 use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList};
 
diff --git a/tests/ui/needless_collect.rs b/tests/ui/needless_collect.rs
index 7f05f51b82e..3dfb5194f40 100644
--- a/tests/ui/needless_collect.rs
+++ b/tests/ui/needless_collect.rs
@@ -1,4 +1,10 @@
-#![allow(unused, clippy::needless_if, clippy::suspicious_map, clippy::iter_count)]
+#![allow(
+    unused,
+    clippy::needless_if,
+    clippy::suspicious_map,
+    clippy::iter_count,
+    clippy::manual_contains
+)]
 
 use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList};
 
diff --git a/tests/ui/needless_collect.stderr b/tests/ui/needless_collect.stderr
index cba54f0af6b..00745eb2923 100644
--- a/tests/ui/needless_collect.stderr
+++ b/tests/ui/needless_collect.stderr
@@ -1,5 +1,5 @@
 error: avoid using `collect()` when not needed
-  --> tests/ui/needless_collect.rs:9:29
+  --> tests/ui/needless_collect.rs:15:29
    |
 LL |     let len = sample.iter().collect::<Vec<_>>().len();
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `count()`
@@ -8,109 +8,109 @@ LL |     let len = sample.iter().collect::<Vec<_>>().len();
    = help: to override `-D warnings` add `#[allow(clippy::needless_collect)]`
 
 error: avoid using `collect()` when not needed
-  --> tests/ui/needless_collect.rs:11:22
+  --> tests/ui/needless_collect.rs:17:22
    |
 LL |     if sample.iter().collect::<Vec<_>>().is_empty() {
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `next().is_none()`
 
 error: avoid using `collect()` when not needed
-  --> tests/ui/needless_collect.rs:15:28
+  --> tests/ui/needless_collect.rs:21:28
    |
 LL |     sample.iter().cloned().collect::<Vec<_>>().contains(&1);
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `any(|x| x == 1)`
 
 error: avoid using `collect()` when not needed
-  --> tests/ui/needless_collect.rs:21:35
+  --> tests/ui/needless_collect.rs:27:35
    |
 LL |     sample.iter().map(|x| (x, x)).collect::<HashMap<_, _>>().is_empty();
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `next().is_none()`
 
 error: avoid using `collect()` when not needed
-  --> tests/ui/needless_collect.rs:23:35
+  --> tests/ui/needless_collect.rs:29:35
    |
 LL |     sample.iter().map(|x| (x, x)).collect::<BTreeMap<_, _>>().is_empty();
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `next().is_none()`
 
 error: avoid using `collect()` when not needed
-  --> tests/ui/needless_collect.rs:31:19
+  --> tests/ui/needless_collect.rs:37:19
    |
 LL |     sample.iter().collect::<LinkedList<_>>().len();
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `count()`
 
 error: avoid using `collect()` when not needed
-  --> tests/ui/needless_collect.rs:33:19
+  --> tests/ui/needless_collect.rs:39:19
    |
 LL |     sample.iter().collect::<LinkedList<_>>().is_empty();
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `next().is_none()`
 
 error: avoid using `collect()` when not needed
-  --> tests/ui/needless_collect.rs:35:28
+  --> tests/ui/needless_collect.rs:41:28
    |
 LL |     sample.iter().cloned().collect::<LinkedList<_>>().contains(&1);
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `any(|x| x == 1)`
 
 error: avoid using `collect()` when not needed
-  --> tests/ui/needless_collect.rs:37:19
+  --> tests/ui/needless_collect.rs:43:19
    |
 LL |     sample.iter().collect::<LinkedList<_>>().contains(&&1);
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `any(|x| x == &1)`
 
 error: avoid using `collect()` when not needed
-  --> tests/ui/needless_collect.rs:41:19
+  --> tests/ui/needless_collect.rs:47:19
    |
 LL |     sample.iter().collect::<BinaryHeap<_>>().len();
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `count()`
 
 error: avoid using `collect()` when not needed
-  --> tests/ui/needless_collect.rs:43:19
+  --> tests/ui/needless_collect.rs:49:19
    |
 LL |     sample.iter().collect::<BinaryHeap<_>>().is_empty();
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `next().is_none()`
 
 error: avoid using `collect()` when not needed
-  --> tests/ui/needless_collect.rs:49:27
+  --> tests/ui/needless_collect.rs:55:27
    |
 LL |     let _ = sample.iter().collect::<HashSet<_>>().is_empty();
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `next().is_none()`
 
 error: avoid using `collect()` when not needed
-  --> tests/ui/needless_collect.rs:51:27
+  --> tests/ui/needless_collect.rs:57:27
    |
 LL |     let _ = sample.iter().collect::<HashSet<_>>().contains(&&0);
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `any(|x| x == &0)`
 
 error: avoid using `collect()` when not needed
-  --> tests/ui/needless_collect.rs:74:27
+  --> tests/ui/needless_collect.rs:80:27
    |
 LL |     let _ = sample.iter().collect::<VecWrapper<_>>().is_empty();
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `next().is_none()`
 
 error: avoid using `collect()` when not needed
-  --> tests/ui/needless_collect.rs:76:27
+  --> tests/ui/needless_collect.rs:82:27
    |
 LL |     let _ = sample.iter().collect::<VecWrapper<_>>().contains(&&0);
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `any(|x| x == &0)`
 
 error: avoid using `collect()` when not needed
-  --> tests/ui/needless_collect.rs:81:40
+  --> tests/ui/needless_collect.rs:87:40
    |
 LL |         Vec::<u8>::new().extend((0..10).collect::<Vec<_>>());
    |                                        ^^^^^^^^^^^^^^^^^^^^ help: remove this call
 
 error: avoid using `collect()` when not needed
-  --> tests/ui/needless_collect.rs:83:20
+  --> tests/ui/needless_collect.rs:89:20
    |
 LL |         foo((0..10).collect::<Vec<_>>());
    |                    ^^^^^^^^^^^^^^^^^^^^ help: remove this call
 
 error: avoid using `collect()` when not needed
-  --> tests/ui/needless_collect.rs:85:49
+  --> tests/ui/needless_collect.rs:91:49
    |
 LL |         bar((0..10).collect::<Vec<_>>(), (0..10).collect::<Vec<_>>());
    |                                                 ^^^^^^^^^^^^^^^^^^^^ help: remove this call
 
 error: avoid using `collect()` when not needed
-  --> tests/ui/needless_collect.rs:87:37
+  --> tests/ui/needless_collect.rs:93:37
    |
 LL |         baz((0..10), (), ('a'..='z').collect::<Vec<_>>())
    |                                     ^^^^^^^^^^^^^^^^^^^^ help: remove this call
diff --git a/tests/ui/search_is_some_fixable_none.fixed b/tests/ui/search_is_some_fixable_none.fixed
index e6355bdf792..847e5140d3e 100644
--- a/tests/ui/search_is_some_fixable_none.fixed
+++ b/tests/ui/search_is_some_fixable_none.fixed
@@ -1,4 +1,4 @@
-#![allow(dead_code, clippy::explicit_auto_deref, clippy::useless_vec)]
+#![allow(dead_code, clippy::explicit_auto_deref, clippy::useless_vec, clippy::manual_contains)]
 #![warn(clippy::search_is_some)]
 
 fn main() {
diff --git a/tests/ui/search_is_some_fixable_none.rs b/tests/ui/search_is_some_fixable_none.rs
index 8cc80f122f0..e976d12600c 100644
--- a/tests/ui/search_is_some_fixable_none.rs
+++ b/tests/ui/search_is_some_fixable_none.rs
@@ -1,4 +1,4 @@
-#![allow(dead_code, clippy::explicit_auto_deref, clippy::useless_vec)]
+#![allow(dead_code, clippy::explicit_auto_deref, clippy::useless_vec, clippy::manual_contains)]
 #![warn(clippy::search_is_some)]
 
 fn main() {
diff --git a/tests/ui/search_is_some_fixable_some.fixed b/tests/ui/search_is_some_fixable_some.fixed
index 6ab0593eecd..05e88b8528f 100644
--- a/tests/ui/search_is_some_fixable_some.fixed
+++ b/tests/ui/search_is_some_fixable_some.fixed
@@ -1,4 +1,4 @@
-#![allow(dead_code, clippy::explicit_auto_deref, clippy::useless_vec)]
+#![allow(dead_code, clippy::explicit_auto_deref, clippy::useless_vec, clippy::manual_contains)]
 #![warn(clippy::search_is_some)]
 
 fn main() {
diff --git a/tests/ui/search_is_some_fixable_some.rs b/tests/ui/search_is_some_fixable_some.rs
index 35094cdf2c0..caab816f243 100644
--- a/tests/ui/search_is_some_fixable_some.rs
+++ b/tests/ui/search_is_some_fixable_some.rs
@@ -1,4 +1,4 @@
-#![allow(dead_code, clippy::explicit_auto_deref, clippy::useless_vec)]
+#![allow(dead_code, clippy::explicit_auto_deref, clippy::useless_vec, clippy::manual_contains)]
 #![warn(clippy::search_is_some)]
 
 fn main() {