about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--clippy_lints/src/methods/bind_instead_of_map.rs14
-rw-r--r--clippy_lints/src/methods/bytes_nth.rs11
-rw-r--r--clippy_lints/src/methods/expect_used.rs4
-rw-r--r--clippy_lints/src/methods/filetype_is_file.rs4
-rw-r--r--clippy_lints/src/methods/filter_map.rs50
-rw-r--r--clippy_lints/src/methods/filter_map_identity.rs15
-rw-r--r--clippy_lints/src/methods/filter_map_next.rs7
-rw-r--r--clippy_lints/src/methods/filter_next.rs11
-rw-r--r--clippy_lints/src/methods/flat_map_identity.rs4
-rw-r--r--clippy_lints/src/methods/get_unwrap.rs20
-rw-r--r--clippy_lints/src/methods/iter_cloned_collect.rs4
-rw-r--r--clippy_lints/src/methods/iter_count.rs8
-rw-r--r--clippy_lints/src/methods/iter_next_slice.rs4
-rw-r--r--clippy_lints/src/methods/iter_nth.rs14
-rw-r--r--clippy_lints/src/methods/iter_nth_zero.rs6
-rw-r--r--clippy_lints/src/methods/iter_skip_next.rs22
-rw-r--r--clippy_lints/src/methods/iterator_step_by_zero.rs4
-rw-r--r--clippy_lints/src/methods/manual_saturating_arithmetic.rs13
-rw-r--r--clippy_lints/src/methods/map_collect_result_unit.rs9
-rw-r--r--clippy_lints/src/methods/map_flatten.rs19
-rw-r--r--clippy_lints/src/methods/map_unwrap_or.rs21
-rw-r--r--clippy_lints/src/methods/mod.rs283
-rw-r--r--clippy_lints/src/methods/ok_expect.rs6
-rw-r--r--clippy_lints/src/methods/option_as_ref_deref.rs16
-rw-r--r--clippy_lints/src/methods/option_map_or_none.rs22
-rw-r--r--clippy_lints/src/methods/option_map_unwrap_or.rs22
-rw-r--r--clippy_lints/src/methods/search_is_some.rs88
-rw-r--r--clippy_lints/src/methods/skip_while_next.rs2
-rw-r--r--clippy_lints/src/methods/string_extend_chars.rs7
-rw-r--r--clippy_lints/src/methods/suspicious_map.rs9
-rw-r--r--clippy_lints/src/methods/uninit_assumed_init.rs8
-rw-r--r--clippy_lints/src/methods/unnecessary_filter_map.rs4
-rw-r--r--clippy_lints/src/methods/unnecessary_fold.rs33
-rw-r--r--clippy_lints/src/methods/unnecessary_lazy_eval.rs11
-rw-r--r--clippy_lints/src/methods/unwrap_used.rs4
-rw-r--r--clippy_lints/src/methods/useless_asref.rs3
-rw-r--r--clippy_lints/src/methods/zst_offset.rs5
37 files changed, 412 insertions, 375 deletions
diff --git a/clippy_lints/src/methods/bind_instead_of_map.rs b/clippy_lints/src/methods/bind_instead_of_map.rs
index 0ba8a98a018..8ccb8f4268c 100644
--- a/clippy_lints/src/methods/bind_instead_of_map.rs
+++ b/clippy_lints/src/methods/bind_instead_of_map.rs
@@ -80,7 +80,7 @@ pub(crate) trait BindInsteadOfMap {
     fn lint_closure_autofixable(
         cx: &LateContext<'_>,
         expr: &hir::Expr<'_>,
-        args: &[hir::Expr<'_>],
+        recv: &hir::Expr<'_>,
         closure_expr: &hir::Expr<'_>,
         closure_args_span: Span,
     ) -> bool {
@@ -103,7 +103,7 @@ pub(crate) trait BindInsteadOfMap {
                 };
 
                 let closure_args_snip = snippet(cx, closure_args_span, "..");
-                let option_snip = snippet(cx, args[0].span, "..");
+                let option_snip = snippet(cx, recv.span, "..");
                 let note = format!("{}.{}({} {})", option_snip, Self::GOOD_METHOD_NAME, closure_args_snip, some_inner_snip);
                 span_lint_and_sugg(
                     cx,
@@ -158,17 +158,17 @@ pub(crate) trait BindInsteadOfMap {
     }
 
     /// Lint use of `_.and_then(|x| Some(y))` for `Option`s
-    fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) -> bool {
-        if !match_type(cx, cx.typeck_results().expr_ty(&args[0]), Self::TYPE_QPATH) {
+    fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) -> bool {
+        if !match_type(cx, cx.typeck_results().expr_ty(recv), Self::TYPE_QPATH) {
             return false;
         }
 
-        match args[1].kind {
+        match arg.kind {
             hir::ExprKind::Closure(_, _, body_id, closure_args_span, _) => {
                 let closure_body = cx.tcx.hir().body(body_id);
                 let closure_expr = remove_blocks(&closure_body.value);
 
-                if Self::lint_closure_autofixable(cx, expr, args, closure_expr, closure_args_span) {
+                if Self::lint_closure_autofixable(cx, expr, recv, closure_expr, closure_args_span) {
                     true
                 } else {
                     Self::lint_closure(cx, expr, closure_expr)
@@ -182,7 +182,7 @@ pub(crate) trait BindInsteadOfMap {
                     expr.span,
                     Self::no_op_msg().as_ref(),
                     "use the expression directly",
-                    snippet(cx, args[0].span, "..").into(),
+                    snippet(cx, recv.span, "..").into(),
                     Applicability::MachineApplicable,
                 );
                 true
diff --git a/clippy_lints/src/methods/bytes_nth.rs b/clippy_lints/src/methods/bytes_nth.rs
index 4f88f80a304..77f140510b6 100644
--- a/clippy_lints/src/methods/bytes_nth.rs
+++ b/clippy_lints/src/methods/bytes_nth.rs
@@ -3,16 +3,15 @@ use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::is_type_diagnostic_item;
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind};
+use rustc_hir::Expr;
 use rustc_lint::LateContext;
 use rustc_span::sym;
 
 use super::BYTES_NTH;
 
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, iter_args: &'tcx [Expr<'tcx>]) {
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx Expr<'tcx>, n_arg: &'tcx Expr<'tcx>) {
     if_chain! {
-        if let ExprKind::MethodCall(_, _, ref args, _) = expr.kind;
-        let ty = cx.typeck_results().expr_ty(&iter_args[0]).peel_refs();
+        let ty = cx.typeck_results().expr_ty(recv).peel_refs();
         let caller_type = if is_type_diagnostic_item(cx, ty, sym::string_type) {
             Some("String")
         } else if ty.is_str() {
@@ -31,8 +30,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, iter_args: &'
                 "try",
                 format!(
                     "{}.as_bytes().get({})",
-                    snippet_with_applicability(cx, iter_args[0].span, "..", &mut applicability),
-                    snippet_with_applicability(cx, args[1].span, "..", &mut applicability)
+                    snippet_with_applicability(cx, recv.span, "..", &mut applicability),
+                    snippet_with_applicability(cx, n_arg.span, "..", &mut applicability)
                 ),
                 applicability,
             );
diff --git a/clippy_lints/src/methods/expect_used.rs b/clippy_lints/src/methods/expect_used.rs
index 64531b29ade..63a834fdce0 100644
--- a/clippy_lints/src/methods/expect_used.rs
+++ b/clippy_lints/src/methods/expect_used.rs
@@ -7,8 +7,8 @@ use rustc_span::sym;
 use super::EXPECT_USED;
 
 /// lint use of `expect()` for `Option`s and `Result`s
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, expect_args: &[hir::Expr<'_>]) {
-    let obj_ty = cx.typeck_results().expr_ty(&expect_args[0]).peel_refs();
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
+    let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
 
     let mess = if is_type_diagnostic_item(cx, obj_ty, sym::option_type) {
         Some((EXPECT_USED, "an Option", "None"))
diff --git a/clippy_lints/src/methods/filetype_is_file.rs b/clippy_lints/src/methods/filetype_is_file.rs
index 39d2f15dbc8..7b2967feb0f 100644
--- a/clippy_lints/src/methods/filetype_is_file.rs
+++ b/clippy_lints/src/methods/filetype_is_file.rs
@@ -8,8 +8,8 @@ use rustc_span::source_map::Span;
 
 use super::FILETYPE_IS_FILE;
 
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
-    let ty = cx.typeck_results().expr_ty(&args[0]);
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
+    let ty = cx.typeck_results().expr_ty(recv);
 
     if !match_type(cx, ty, &paths::FILE_TYPE) {
         return;
diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs
index 68f8480dc51..45d1ed953b4 100644
--- a/clippy_lints/src/methods/filter_map.rs
+++ b/clippy_lints/src/methods/filter_map.rs
@@ -46,21 +46,17 @@ fn is_method<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Sy
     }
 }
 
-fn is_option_filter_map<'tcx>(
-    cx: &LateContext<'tcx>,
-    filter_arg: &'tcx hir::Expr<'_>,
-    map_arg: &'tcx hir::Expr<'_>,
-) -> bool {
+fn is_option_filter_map<'tcx>(cx: &LateContext<'tcx>, filter_arg: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) -> bool {
     is_method(cx, map_arg, sym::unwrap) && is_method(cx, filter_arg, sym!(is_some))
 }
 
 /// lint use of `filter().map()` for `Iterators`
-fn lint_filter_some_map_unwrap<'tcx>(
-    cx: &LateContext<'tcx>,
-    expr: &'tcx hir::Expr<'_>,
-    filter_recv: &'tcx hir::Expr<'_>,
-    filter_arg: &'tcx hir::Expr<'_>,
-    map_arg: &'tcx hir::Expr<'_>,
+fn lint_filter_some_map_unwrap(
+    cx: &LateContext<'_>,
+    expr: &hir::Expr<'_>,
+    filter_recv: &hir::Expr<'_>,
+    filter_arg: &hir::Expr<'_>,
+    map_arg: &hir::Expr<'_>,
     target_span: Span,
     methods_span: Span,
 ) {
@@ -86,14 +82,28 @@ fn lint_filter_some_map_unwrap<'tcx>(
 }
 
 /// lint use of `filter().map()` or `find().map()` for `Iterators`
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, is_find: bool, target_span: Span) {
+#[allow(clippy::too_many_arguments)]
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &hir::Expr<'_>,
+    filter_recv: &hir::Expr<'_>,
+    filter_arg: &hir::Expr<'_>,
+    filter_span: Span,
+    map_recv: &hir::Expr<'_>,
+    map_arg: &hir::Expr<'_>,
+    map_span: Span,
+    is_find: bool,
+) {
+    lint_filter_some_map_unwrap(
+        cx,
+        expr,
+        filter_recv,
+        filter_arg,
+        map_arg,
+        map_span,
+        filter_span.with_hi(expr.span.hi()),
+    );
     if_chain! {
-            if let ExprKind::MethodCall(_, _, [map_recv, map_arg], map_span) = expr.kind;
-            if let ExprKind::MethodCall(_, _, [filter_recv, filter_arg], filter_span) = map_recv.kind;
-            then {
-              lint_filter_some_map_unwrap(cx, expr, filter_recv, filter_arg,
-                map_arg, target_span, filter_span.to(map_span));
-              if_chain! {
             if is_trait_method(cx, map_recv, sym::Iterator);
 
             // filter(|x| ...is_some())...
@@ -148,7 +158,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, is_
             };
             if SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(filter_arg, map_arg);
             then {
-                let span = filter_span.to(map_span);
+                let span = filter_span.with_hi(expr.span.hi());
                 let (filter_name, lint) = if is_find {
                     ("find", MANUAL_FIND_MAP)
                 } else {
@@ -160,7 +170,5 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, is_
                     snippet(cx, map_arg.span, ".."), to_opt);
                 span_lint_and_sugg(cx, lint, span, &msg, "try", sugg, Applicability::MachineApplicable);
             }
-        }
-        }
     }
 }
diff --git a/clippy_lints/src/methods/filter_map_identity.rs b/clippy_lints/src/methods/filter_map_identity.rs
index 80598d88508..3a61f4ccad7 100644
--- a/clippy_lints/src/methods/filter_map_identity.rs
+++ b/clippy_lints/src/methods/filter_map_identity.rs
@@ -8,15 +8,8 @@ use rustc_span::{source_map::Span, sym};
 
 use super::FILTER_MAP_IDENTITY;
 
-pub(super) fn check(
-    cx: &LateContext<'_>,
-    expr: &hir::Expr<'_>,
-    filter_map_args: &[hir::Expr<'_>],
-    filter_map_span: Span,
-) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_map_arg: &hir::Expr<'_>, filter_map_span: Span) {
     if is_trait_method(cx, expr, sym::Iterator) {
-        let arg_node = &filter_map_args[1].kind;
-
         let apply_lint = |message: &str| {
             span_lint_and_sugg(
                 cx,
@@ -30,8 +23,8 @@ pub(super) fn check(
         };
 
         if_chain! {
-            if let hir::ExprKind::Closure(_, _, body_id, _, _) = arg_node;
-            let body = cx.tcx.hir().body(*body_id);
+            if let hir::ExprKind::Closure(_, _, body_id, _, _) = filter_map_arg.kind;
+            let body = cx.tcx.hir().body(body_id);
 
             if let hir::PatKind::Binding(_, binding_id, ..) = body.params[0].pat.kind;
             if path_to_local_id(&body.value, binding_id);
@@ -41,7 +34,7 @@ pub(super) fn check(
         }
 
         if_chain! {
-            if let hir::ExprKind::Path(ref qpath) = arg_node;
+            if let hir::ExprKind::Path(ref qpath) = filter_map_arg.kind;
 
             if match_qpath(qpath, &paths::STD_CONVERT_IDENTITY);
 
diff --git a/clippy_lints/src/methods/filter_map_next.rs b/clippy_lints/src/methods/filter_map_next.rs
index ba57abd16c9..2b19e4ee8c0 100644
--- a/clippy_lints/src/methods/filter_map_next.rs
+++ b/clippy_lints/src/methods/filter_map_next.rs
@@ -14,7 +14,8 @@ const FILTER_MAP_NEXT_MSRV: RustcVersion = RustcVersion::new(1, 30, 0);
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &'tcx hir::Expr<'_>,
-    filter_args: &'tcx [hir::Expr<'_>],
+    recv: &'tcx hir::Expr<'_>,
+    arg: &'tcx hir::Expr<'_>,
     msrv: Option<&RustcVersion>,
 ) {
     if is_trait_method(cx, expr, sym::Iterator) {
@@ -24,9 +25,9 @@ pub(super) fn check<'tcx>(
 
         let msg = "called `filter_map(..).next()` on an `Iterator`. This is more succinctly expressed by calling \
                    `.find_map(..)` instead";
-        let filter_snippet = snippet(cx, filter_args[1].span, "..");
+        let filter_snippet = snippet(cx, arg.span, "..");
         if filter_snippet.lines().count() <= 1 {
-            let iter_snippet = snippet(cx, filter_args[0].span, "..");
+            let iter_snippet = snippet(cx, recv.span, "..");
             span_lint_and_sugg(
                 cx,
                 FILTER_MAP_NEXT,
diff --git a/clippy_lints/src/methods/filter_next.rs b/clippy_lints/src/methods/filter_next.rs
index 6cd24334414..172714f6b01 100644
--- a/clippy_lints/src/methods/filter_next.rs
+++ b/clippy_lints/src/methods/filter_next.rs
@@ -9,14 +9,19 @@ use rustc_span::sym;
 use super::FILTER_NEXT;
 
 /// lint use of `filter().next()` for `Iterators`
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, filter_args: &'tcx [hir::Expr<'_>]) {
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx hir::Expr<'_>,
+    recv: &'tcx hir::Expr<'_>,
+    filter_arg: &'tcx hir::Expr<'_>,
+) {
     // lint if caller of `.filter().next()` is an Iterator
     if is_trait_method(cx, expr, sym::Iterator) {
         let msg = "called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling \
                    `.find(..)` instead";
-        let filter_snippet = snippet(cx, filter_args[1].span, "..");
+        let filter_snippet = snippet(cx, filter_arg.span, "..");
         if filter_snippet.lines().count() <= 1 {
-            let iter_snippet = snippet(cx, filter_args[0].span, "..");
+            let iter_snippet = snippet(cx, recv.span, "..");
             // add note if not multi-line
             span_lint_and_sugg(
                 cx,
diff --git a/clippy_lints/src/methods/flat_map_identity.rs b/clippy_lints/src/methods/flat_map_identity.rs
index 034ea6c6562..664885a2f0e 100644
--- a/clippy_lints/src/methods/flat_map_identity.rs
+++ b/clippy_lints/src/methods/flat_map_identity.rs
@@ -12,11 +12,11 @@ use super::FLAT_MAP_IDENTITY;
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &'tcx hir::Expr<'_>,
-    flat_map_args: &'tcx [hir::Expr<'_>],
+    flat_map_arg: &'tcx hir::Expr<'_>,
     flat_map_span: Span,
 ) {
     if is_trait_method(cx, expr, sym::Iterator) {
-        let arg_node = &flat_map_args[1].kind;
+        let arg_node = &flat_map_arg.kind;
 
         let apply_lint = |message: &str| {
             span_lint_and_sugg(
diff --git a/clippy_lints/src/methods/get_unwrap.rs b/clippy_lints/src/methods/get_unwrap.rs
index b3a9743c614..54f28064384 100644
--- a/clippy_lints/src/methods/get_unwrap.rs
+++ b/clippy_lints/src/methods/get_unwrap.rs
@@ -11,18 +11,20 @@ use rustc_span::sym;
 
 use super::GET_UNWRAP;
 
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, get_args: &'tcx [hir::Expr<'_>], is_mut: bool) {
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &hir::Expr<'_>,
+    recv: &'tcx hir::Expr<'tcx>,
+    get_arg: &'tcx hir::Expr<'_>,
+    is_mut: bool,
+) {
     // Note: we don't want to lint `get_mut().unwrap` for `HashMap` or `BTreeMap`,
     // because they do not implement `IndexMut`
     let mut applicability = Applicability::MachineApplicable;
-    let expr_ty = cx.typeck_results().expr_ty(&get_args[0]);
-    let get_args_str = if get_args.len() > 1 {
-        snippet_with_applicability(cx, get_args[1].span, "..", &mut applicability)
-    } else {
-        return; // not linting on a .get().unwrap() chain or variant
-    };
+    let expr_ty = cx.typeck_results().expr_ty(recv);
+    let get_args_str = snippet_with_applicability(cx, get_arg.span, "..", &mut applicability);
     let mut needs_ref;
-    let caller_type = if derefs_to_slice(cx, &get_args[0], expr_ty).is_some() {
+    let caller_type = if derefs_to_slice(cx, recv, expr_ty).is_some() {
         needs_ref = get_args_str.parse::<usize>().is_ok();
         "slice"
     } else if is_type_diagnostic_item(cx, expr_ty, sym::vec_type) {
@@ -77,7 +79,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, get_args
         format!(
             "{}{}[{}]",
             borrow_str,
-            snippet_with_applicability(cx, get_args[0].span, "..", &mut applicability),
+            snippet_with_applicability(cx, recv.span, "..", &mut applicability),
             get_args_str
         ),
         applicability,
diff --git a/clippy_lints/src/methods/iter_cloned_collect.rs b/clippy_lints/src/methods/iter_cloned_collect.rs
index 848f47e39f6..739f313716e 100644
--- a/clippy_lints/src/methods/iter_cloned_collect.rs
+++ b/clippy_lints/src/methods/iter_cloned_collect.rs
@@ -9,10 +9,10 @@ use rustc_span::sym;
 
 use super::ITER_CLONED_COLLECT;
 
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, iter_args: &'tcx [hir::Expr<'_>]) {
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, recv: &'tcx hir::Expr<'_>) {
     if_chain! {
         if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::vec_type);
-        if let Some(slice) = derefs_to_slice(cx, &iter_args[0], cx.typeck_results().expr_ty(&iter_args[0]));
+        if let Some(slice) = derefs_to_slice(cx, recv, cx.typeck_results().expr_ty(recv));
         if let Some(to_replace) = expr.span.trim_start(slice.span.source_callsite());
 
         then {
diff --git a/clippy_lints/src/methods/iter_count.rs b/clippy_lints/src/methods/iter_count.rs
index e394a8fe819..c6b7c7cd179 100644
--- a/clippy_lints/src/methods/iter_count.rs
+++ b/clippy_lints/src/methods/iter_count.rs
@@ -10,9 +10,9 @@ use rustc_span::sym;
 
 use super::ITER_COUNT;
 
-pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, iter_args: &'tcx [Expr<'tcx>], iter_method: &str) {
-    let ty = cx.typeck_results().expr_ty(&iter_args[0]);
-    let caller_type = if derefs_to_slice(cx, &iter_args[0], ty).is_some() {
+pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx Expr<'tcx>, iter_method: &str) {
+    let ty = cx.typeck_results().expr_ty(recv);
+    let caller_type = if derefs_to_slice(cx, recv, ty).is_some() {
         "slice"
     } else if is_type_diagnostic_item(cx, ty, sym::vec_type) {
         "Vec"
@@ -42,7 +42,7 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, iter_args: &'
         "try",
         format!(
             "{}.len()",
-            snippet_with_applicability(cx, iter_args[0].span, "..", &mut applicability),
+            snippet_with_applicability(cx, recv.span, "..", &mut applicability),
         ),
         applicability,
     );
diff --git a/clippy_lints/src/methods/iter_next_slice.rs b/clippy_lints/src/methods/iter_next_slice.rs
index e9b37b6f2bd..dab0a43a096 100644
--- a/clippy_lints/src/methods/iter_next_slice.rs
+++ b/clippy_lints/src/methods/iter_next_slice.rs
@@ -13,9 +13,7 @@ use rustc_span::symbol::sym;
 
 use super::ITER_NEXT_SLICE;
 
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, iter_args: &'tcx [hir::Expr<'_>]) {
-    let caller_expr = &iter_args[0];
-
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, caller_expr: &'tcx hir::Expr<'_>) {
     // Skip lint if the `iter().next()` expression is a for loop argument,
     // since it is already covered by `&loops::ITER_NEXT_LOOP`
     let mut parent_expr_opt = get_parent_expr(cx, expr);
diff --git a/clippy_lints/src/methods/iter_nth.rs b/clippy_lints/src/methods/iter_nth.rs
index c46af427b3c..c2232239fe4 100644
--- a/clippy_lints/src/methods/iter_nth.rs
+++ b/clippy_lints/src/methods/iter_nth.rs
@@ -11,20 +11,20 @@ use super::ITER_NTH;
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &hir::Expr<'_>,
-    nth_and_iter_args: &[&'tcx [hir::Expr<'tcx>]],
+    iter_recv: &'tcx hir::Expr<'tcx>,
+    nth_recv: &hir::Expr<'_>,
+    nth_arg: &hir::Expr<'_>,
     is_mut: bool,
 ) {
-    let iter_args = nth_and_iter_args[1];
     let mut_str = if is_mut { "_mut" } else { "" };
-    let caller_type = if derefs_to_slice(cx, &iter_args[0], cx.typeck_results().expr_ty(&iter_args[0])).is_some() {
+    let caller_type = if derefs_to_slice(cx, iter_recv, cx.typeck_results().expr_ty(iter_recv)).is_some() {
         "slice"
-    } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&iter_args[0]), sym::vec_type) {
+    } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(iter_recv), sym::vec_type) {
         "Vec"
-    } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&iter_args[0]), sym::vecdeque_type) {
+    } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(iter_recv), sym::vecdeque_type) {
         "VecDeque"
     } else {
-        let nth_args = nth_and_iter_args[0];
-        iter_nth_zero::check(cx, expr, &nth_args);
+        iter_nth_zero::check(cx, expr, nth_recv, nth_arg);
         return; // caller is not a type that we want to lint
     };
 
diff --git a/clippy_lints/src/methods/iter_nth_zero.rs b/clippy_lints/src/methods/iter_nth_zero.rs
index a12f672739c..52d7c15332e 100644
--- a/clippy_lints/src/methods/iter_nth_zero.rs
+++ b/clippy_lints/src/methods/iter_nth_zero.rs
@@ -10,10 +10,10 @@ use rustc_span::sym;
 
 use super::ITER_NTH_ZERO;
 
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, nth_args: &'tcx [hir::Expr<'_>]) {
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) {
     if_chain! {
         if is_trait_method(cx, expr, sym::Iterator);
-        if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), &nth_args[1]);
+        if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), arg);
         then {
             let mut applicability = Applicability::MachineApplicable;
             span_lint_and_sugg(
@@ -22,7 +22,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, nth_args
                 expr.span,
                 "called `.nth(0)` on a `std::iter::Iterator`, when `.next()` is equivalent",
                 "try calling `.next()` instead of `.nth(0)`",
-                format!("{}.next()", snippet_with_applicability(cx, nth_args[0].span, "..", &mut applicability)),
+                format!("{}.next()", snippet_with_applicability(cx, recv.span, "..", &mut applicability)),
                 applicability,
             );
         }
diff --git a/clippy_lints/src/methods/iter_skip_next.rs b/clippy_lints/src/methods/iter_skip_next.rs
index b1d398876d3..e32594757d0 100644
--- a/clippy_lints/src/methods/iter_skip_next.rs
+++ b/clippy_lints/src/methods/iter_skip_next.rs
@@ -8,19 +8,17 @@ use rustc_span::sym;
 
 use super::ITER_SKIP_NEXT;
 
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, skip_args: &[hir::Expr<'_>]) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) {
     // lint if caller of skip is an Iterator
     if is_trait_method(cx, expr, sym::Iterator) {
-        if let [caller, n] = skip_args {
-            span_lint_and_sugg(
-                cx,
-                ITER_SKIP_NEXT,
-                expr.span.trim_start(caller.span).unwrap(),
-                "called `skip(..).next()` on an iterator",
-                "use `nth` instead",
-                format!(".nth({})", snippet(cx, n.span, "..")),
-                Applicability::MachineApplicable,
-            );
-        }
+        span_lint_and_sugg(
+            cx,
+            ITER_SKIP_NEXT,
+            expr.span.trim_start(recv.span).unwrap(),
+            "called `skip(..).next()` on an iterator",
+            "use `nth` instead",
+            format!(".nth({})", snippet(cx, arg.span, "..")),
+            Applicability::MachineApplicable,
+        );
     }
 }
diff --git a/clippy_lints/src/methods/iterator_step_by_zero.rs b/clippy_lints/src/methods/iterator_step_by_zero.rs
index 3baa580314f..06b12998b1a 100644
--- a/clippy_lints/src/methods/iterator_step_by_zero.rs
+++ b/clippy_lints/src/methods/iterator_step_by_zero.rs
@@ -7,9 +7,9 @@ use rustc_span::sym;
 
 use super::ITERATOR_STEP_BY_ZERO;
 
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, args: &'tcx [hir::Expr<'_>]) {
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, arg: &'tcx hir::Expr<'_>) {
     if is_trait_method(cx, expr, sym::Iterator) {
-        if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), &args[1]) {
+        if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), arg) {
             span_lint(
                 cx,
                 ITERATOR_STEP_BY_ZERO,
diff --git a/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/clippy_lints/src/methods/manual_saturating_arithmetic.rs
index f16699322d1..6c5a842a912 100644
--- a/clippy_lints/src/methods/manual_saturating_arithmetic.rs
+++ b/clippy_lints/src/methods/manual_saturating_arithmetic.rs
@@ -8,11 +8,14 @@ use rustc_hir as hir;
 use rustc_lint::LateContext;
 use rustc_target::abi::LayoutOf;
 
-pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[&[hir::Expr<'_>]], arith: &str) {
-    let unwrap_arg = &args[0][1];
-    let arith_lhs = &args[1][0];
-    let arith_rhs = &args[1][1];
-
+pub fn check(
+    cx: &LateContext<'_>,
+    expr: &hir::Expr<'_>,
+    arith_lhs: &hir::Expr<'_>,
+    arith_rhs: &hir::Expr<'_>,
+    unwrap_arg: &hir::Expr<'_>,
+    arith: &str,
+) {
     let ty = cx.typeck_results().expr_ty(arith_lhs);
     if !ty.is_integral() {
         return;
diff --git a/clippy_lints/src/methods/map_collect_result_unit.rs b/clippy_lints/src/methods/map_collect_result_unit.rs
index e4402b2da21..82063ad70b5 100644
--- a/clippy_lints/src/methods/map_collect_result_unit.rs
+++ b/clippy_lints/src/methods/map_collect_result_unit.rs
@@ -14,13 +14,13 @@ use super::MAP_COLLECT_RESULT_UNIT;
 pub(super) fn check(
     cx: &LateContext<'_>,
     expr: &hir::Expr<'_>,
-    map_args: &[hir::Expr<'_>],
-    collect_args: &[hir::Expr<'_>],
+    iter: &hir::Expr<'_>,
+    map_fn: &hir::Expr<'_>,
+    collect_recv: &hir::Expr<'_>,
 ) {
     if_chain! {
         // called on Iterator
-        if let [map_expr] = collect_args;
-        if is_trait_method(cx, map_expr, sym::Iterator);
+        if is_trait_method(cx, collect_recv, sym::Iterator);
         // return of collect `Result<(),_>`
         let collect_ret_ty = cx.typeck_results().expr_ty(expr);
         if is_type_diagnostic_item(cx, collect_ret_ty, sym::result_type);
@@ -28,7 +28,6 @@ pub(super) fn check(
         if let Some(result_t) = substs.types().next();
         if result_t.is_unit();
         // get parts for snippet
-        if let [iter, map_fn] = map_args;
         then {
             span_lint_and_sugg(
                 cx,
diff --git a/clippy_lints/src/methods/map_flatten.rs b/clippy_lints/src/methods/map_flatten.rs
index 4bc52b036a8..e8ad16bc0de 100644
--- a/clippy_lints/src/methods/map_flatten.rs
+++ b/clippy_lints/src/methods/map_flatten.rs
@@ -11,10 +11,15 @@ use rustc_span::symbol::sym;
 use super::MAP_FLATTEN;
 
 /// lint use of `map().flatten()` for `Iterators` and 'Options'
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map_args: &'tcx [hir::Expr<'_>]) {
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx hir::Expr<'_>,
+    recv: &'tcx hir::Expr<'_>,
+    map_arg: &'tcx hir::Expr<'_>,
+) {
     // lint if caller of `.map().flatten()` is an Iterator
     if is_trait_method(cx, expr, sym::Iterator) {
-        let map_closure_ty = cx.typeck_results().expr_ty(&map_args[1]);
+        let map_closure_ty = cx.typeck_results().expr_ty(map_arg);
         let is_map_to_option = match map_closure_ty.kind() {
             ty::Closure(_, _) | ty::FnDef(_, _) | ty::FnPtr(_) => {
                 let map_closure_sig = match map_closure_ty.kind() {
@@ -34,12 +39,12 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map
             // `(...).map(...)` has type `impl Iterator<Item=impl Iterator<...>>
             "flat_map"
         };
-        let func_snippet = snippet(cx, map_args[1].span, "..");
+        let func_snippet = snippet(cx, map_arg.span, "..");
         let hint = format!(".{0}({1})", method_to_use, func_snippet);
         span_lint_and_sugg(
             cx,
             MAP_FLATTEN,
-            expr.span.with_lo(map_args[0].span.hi()),
+            expr.span.with_lo(recv.span.hi()),
             "called `map(..).flatten()` on an `Iterator`",
             &format!("try using `{}` instead", method_to_use),
             hint,
@@ -48,13 +53,13 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map
     }
 
     // lint if caller of `.map().flatten()` is an Option
-    if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym::option_type) {
-        let func_snippet = snippet(cx, map_args[1].span, "..");
+    if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::option_type) {
+        let func_snippet = snippet(cx, map_arg.span, "..");
         let hint = format!(".and_then({})", func_snippet);
         span_lint_and_sugg(
             cx,
             MAP_FLATTEN,
-            expr.span.with_lo(map_args[0].span.hi()),
+            expr.span.with_lo(recv.span.hi()),
             "called `map(..).flatten()` on an `Option`",
             "try using `and_then` instead",
             hint,
diff --git a/clippy_lints/src/methods/map_unwrap_or.rs b/clippy_lints/src/methods/map_unwrap_or.rs
index deb4b4492b5..4330fea727b 100644
--- a/clippy_lints/src/methods/map_unwrap_or.rs
+++ b/clippy_lints/src/methods/map_unwrap_or.rs
@@ -18,22 +18,23 @@ const MAP_UNWRAP_OR_MSRV: RustcVersion = RustcVersion::new(1, 41, 0);
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &'tcx hir::Expr<'_>,
-    map_args: &'tcx [hir::Expr<'_>],
-    unwrap_args: &'tcx [hir::Expr<'_>],
+    recv: &'tcx hir::Expr<'_>,
+    map_arg: &'tcx hir::Expr<'_>,
+    unwrap_arg: &'tcx hir::Expr<'_>,
     msrv: Option<&RustcVersion>,
 ) -> bool {
     if !meets_msrv(msrv, &MAP_UNWRAP_OR_MSRV) {
         return false;
     }
     // lint if the caller of `map()` is an `Option`
-    let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym::option_type);
-    let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym::result_type);
+    let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::option_type);
+    let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::result_type);
 
     if is_option || is_result {
         // Don't make a suggestion that may fail to compile due to mutably borrowing
         // the same variable twice.
-        let map_mutated_vars = mutated_variables(&map_args[0], cx);
-        let unwrap_mutated_vars = mutated_variables(&unwrap_args[1], cx);
+        let map_mutated_vars = mutated_variables(recv, cx);
+        let unwrap_mutated_vars = mutated_variables(unwrap_arg, cx);
         if let (Some(map_mutated_vars), Some(unwrap_mutated_vars)) = (map_mutated_vars, unwrap_mutated_vars) {
             if map_mutated_vars.intersection(&unwrap_mutated_vars).next().is_some() {
                 return false;
@@ -51,14 +52,14 @@ pub(super) fn check<'tcx>(
             `.map_or_else(<g>, <f>)` instead"
         };
         // get snippets for args to map() and unwrap_or_else()
-        let map_snippet = snippet(cx, map_args[1].span, "..");
-        let unwrap_snippet = snippet(cx, unwrap_args[1].span, "..");
+        let map_snippet = snippet(cx, map_arg.span, "..");
+        let unwrap_snippet = snippet(cx, unwrap_arg.span, "..");
         // lint, with note if neither arg is > 1 line and both map() and
         // unwrap_or_else() have the same span
         let multiline = map_snippet.lines().count() > 1 || unwrap_snippet.lines().count() > 1;
-        let same_span = map_args[1].span.ctxt() == unwrap_args[1].span.ctxt();
+        let same_span = map_arg.span.ctxt() == unwrap_arg.span.ctxt();
         if same_span && !multiline {
-            let var_snippet = snippet(cx, map_args[0].span, "..");
+            let var_snippet = snippet(cx, recv.span, "..");
             span_lint_and_sugg(
                 cx,
                 MAP_UNWRAP_OR,
diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs
index 8a04fd0060d..9a95354db7a 100644
--- a/clippy_lints/src/methods/mod.rs
+++ b/clippy_lints/src/methods/mod.rs
@@ -62,17 +62,18 @@ mod zst_offset;
 use bind_instead_of_map::BindInsteadOfMap;
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 use clippy_utils::ty::{contains_adt_constructor, contains_ty, implements_trait, is_copy, is_type_diagnostic_item};
-use clippy_utils::{contains_return, get_trait_def_id, in_macro, iter_input_pats, method_calls, paths, return_ty};
+use clippy_utils::{contains_return, get_trait_def_id, in_macro, iter_input_pats, paths, return_ty};
 use if_chain::if_chain;
 use rustc_hir as hir;
 use rustc_hir::def::Res;
-use rustc_hir::{PrimTy, QPath, TraitItem, TraitItemKind};
+use rustc_hir::{Expr, ExprKind, PrimTy, QPath, TraitItem, TraitItemKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, TraitRef, Ty, TyS};
 use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::symbol::{sym, SymbolStr};
+use rustc_span::symbol::SymbolStr;
+use rustc_span::{sym, Span};
 use rustc_typeck::hir_ty_to_ty;
 
 declare_clippy_lint! {
@@ -1704,134 +1705,32 @@ impl_lint_pass!(Methods => [
     IMPLICIT_CLONE
 ]);
 
+/// Extracts a method call name, args, and `Span` of the method name.
+fn method_call<'tcx>(recv: &'tcx hir::Expr<'tcx>) -> Option<(SymbolStr, &'tcx [hir::Expr<'tcx>], Span)> {
+    if let ExprKind::MethodCall(path, span, args, _) = recv.kind {
+        if !args.iter().any(|e| e.span.from_expansion()) {
+            return Some((path.ident.name.as_str(), args, span));
+        }
+    }
+    None
+}
+
+/// Same as `method_call` but the `SymbolStr` is dereferenced into a temporary `&str`
+macro_rules! method_call {
+    ($expr:expr) => {
+        method_call($expr)
+            .as_ref()
+            .map(|&(ref name, args, span)| (&**name, args, span))
+    };
+}
+
 impl<'tcx> LateLintPass<'tcx> for Methods {
-    #[allow(clippy::too_many_lines)]
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
         if in_macro(expr.span) {
             return;
         }
 
-        let (method_names, arg_lists, method_spans) = method_calls(expr, 2);
-        let method_names: Vec<SymbolStr> = method_names.iter().map(|s| s.as_str()).collect();
-        let method_names: Vec<&str> = method_names.iter().map(|s| &**s).collect();
-
-        match method_names.as_slice() {
-            ["unwrap", "get"] => get_unwrap::check(cx, expr, arg_lists[1], false),
-            ["unwrap", "get_mut"] => get_unwrap::check(cx, expr, arg_lists[1], true),
-            ["unwrap", ..] => unwrap_used::check(cx, expr, arg_lists[0]),
-            ["expect", "ok"] => ok_expect::check(cx, expr, arg_lists[1]),
-            ["expect", ..] => expect_used::check(cx, expr, arg_lists[0]),
-            ["unwrap_or", "map"] => option_map_unwrap_or::check(cx, expr, arg_lists[1], arg_lists[0], method_spans[1]),
-            ["unwrap_or_else", "map"] => {
-                if !map_unwrap_or::check(cx, expr, arg_lists[1], arg_lists[0], self.msrv.as_ref()) {
-                    unnecessary_lazy_eval::check(cx, expr, arg_lists[0], "unwrap_or");
-                }
-            },
-            ["map_or", ..] => option_map_or_none::check(cx, expr, arg_lists[0]),
-            ["and_then", ..] => {
-                let biom_option_linted = bind_instead_of_map::OptionAndThenSome::check(cx, expr, arg_lists[0]);
-                let biom_result_linted = bind_instead_of_map::ResultAndThenOk::check(cx, expr, arg_lists[0]);
-                if !biom_option_linted && !biom_result_linted {
-                    unnecessary_lazy_eval::check(cx, expr, arg_lists[0], "and");
-                }
-            },
-            ["or_else", ..] => {
-                if !bind_instead_of_map::ResultOrElseErrInfo::check(cx, expr, arg_lists[0]) {
-                    unnecessary_lazy_eval::check(cx, expr, arg_lists[0], "or");
-                }
-            },
-            ["next", "filter"] => filter_next::check(cx, expr, arg_lists[1]),
-            ["next", "skip_while"] => skip_while_next::check(cx, expr, arg_lists[1]),
-            ["next", "iter"] => iter_next_slice::check(cx, expr, arg_lists[1]),
-            ["map", "filter"] => filter_map::check(cx, expr, false, method_spans[0]),
-            ["map", "filter_map"] => filter_map_map::check(cx, expr),
-            ["next", "filter_map"] => filter_map_next::check(cx, expr, arg_lists[1], self.msrv.as_ref()),
-            ["map", "find"] => filter_map::check(cx, expr, true, method_spans[0]),
-            ["flat_map", "filter"] => filter_flat_map::check(cx, expr),
-            ["flat_map", "filter_map"] => filter_map_flat_map::check(cx, expr),
-            ["flat_map", ..] => flat_map_identity::check(cx, expr, arg_lists[0], method_spans[0]),
-            ["flatten", "map"] => map_flatten::check(cx, expr, arg_lists[1]),
-            [option_check_method, "find"] if "is_some" == *option_check_method || "is_none" == *option_check_method => {
-                search_is_some::check(
-                    cx,
-                    expr,
-                    "find",
-                    option_check_method,
-                    arg_lists[1],
-                    arg_lists[0],
-                    method_spans[1],
-                )
-            },
-            [option_check_method, "position"]
-                if "is_some" == *option_check_method || "is_none" == *option_check_method =>
-            {
-                search_is_some::check(
-                    cx,
-                    expr,
-                    "position",
-                    option_check_method,
-                    arg_lists[1],
-                    arg_lists[0],
-                    method_spans[1],
-                )
-            },
-            [option_check_method, "rposition"]
-                if "is_some" == *option_check_method || "is_none" == *option_check_method =>
-            {
-                search_is_some::check(
-                    cx,
-                    expr,
-                    "rposition",
-                    option_check_method,
-                    arg_lists[1],
-                    arg_lists[0],
-                    method_spans[1],
-                )
-            },
-            ["extend", ..] => string_extend_chars::check(cx, expr, arg_lists[0]),
-            ["count", "into_iter"] => iter_count::check(cx, expr, &arg_lists[1], "into_iter"),
-            ["count", "iter"] => iter_count::check(cx, expr, &arg_lists[1], "iter"),
-            ["count", "iter_mut"] => iter_count::check(cx, expr, &arg_lists[1], "iter_mut"),
-            ["nth", "iter"] => iter_nth::check(cx, expr, &arg_lists, false),
-            ["nth", "iter_mut"] => iter_nth::check(cx, expr, &arg_lists, true),
-            ["nth", "bytes"] => bytes_nth::check(cx, expr, &arg_lists[1]),
-            ["nth", ..] => iter_nth_zero::check(cx, expr, arg_lists[0]),
-            ["step_by", ..] => iterator_step_by_zero::check(cx, expr, arg_lists[0]),
-            ["next", "skip"] => iter_skip_next::check(cx, expr, arg_lists[1]),
-            ["collect", "cloned"] => iter_cloned_collect::check(cx, expr, arg_lists[1]),
-            ["as_ref"] => useless_asref::check(cx, expr, "as_ref", arg_lists[0]),
-            ["as_mut"] => useless_asref::check(cx, expr, "as_mut", arg_lists[0]),
-            ["fold", ..] => unnecessary_fold::check(cx, expr, arg_lists[0], method_spans[0]),
-            ["filter_map", ..] => {
-                unnecessary_filter_map::check(cx, expr, arg_lists[0]);
-                filter_map_identity::check(cx, expr, arg_lists[0], method_spans[0]);
-            },
-            ["count", "map"] => suspicious_map::check(cx, expr, arg_lists[1], arg_lists[0]),
-            ["assume_init"] => uninit_assumed_init::check(cx, &arg_lists[0][0], expr),
-            ["unwrap_or", arith @ ("checked_add" | "checked_sub" | "checked_mul")] => {
-                manual_saturating_arithmetic::check(cx, expr, &arg_lists, &arith["checked_".len()..])
-            },
-            ["add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub"] => {
-                zst_offset::check(cx, expr, arg_lists[0])
-            },
-            ["is_file", ..] => filetype_is_file::check(cx, expr, arg_lists[0]),
-            ["map", "as_ref"] => {
-                option_as_ref_deref::check(cx, expr, arg_lists[1], arg_lists[0], false, self.msrv.as_ref())
-            },
-            ["map", "as_mut"] => {
-                option_as_ref_deref::check(cx, expr, arg_lists[1], arg_lists[0], true, self.msrv.as_ref())
-            },
-            ["unwrap_or_else", ..] => unnecessary_lazy_eval::check(cx, expr, arg_lists[0], "unwrap_or"),
-            ["get_or_insert_with", ..] => unnecessary_lazy_eval::check(cx, expr, arg_lists[0], "get_or_insert"),
-            ["ok_or_else", ..] => unnecessary_lazy_eval::check(cx, expr, arg_lists[0], "ok_or"),
-            ["collect", "map"] => map_collect_result_unit::check(cx, expr, arg_lists[1], arg_lists[0]),
-            ["for_each", "inspect"] => inspect_for_each::check(cx, expr, method_spans[1]),
-            ["to_owned", ..] => implicit_clone::check(cx, expr, sym::ToOwned),
-            ["to_os_string", ..] => implicit_clone::check(cx, expr, sym::OsStr),
-            ["to_path_buf", ..] => implicit_clone::check(cx, expr, sym::Path),
-            ["to_vec", ..] => implicit_clone::check(cx, expr, sym::slice),
-            _ => {},
-        }
+        check_methods(cx, expr, self.msrv.as_ref());
 
         match expr.kind {
             hir::ExprKind::Call(ref func, ref args) => {
@@ -2020,6 +1919,140 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
 
     extract_msrv_attr!(LateContext);
 }
+
+#[allow(clippy::too_many_lines)]
+fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Option<&RustcVersion>) {
+    if let Some((name, [recv, args @ ..], span)) = method_call!(expr) {
+        match (name, args) {
+            ("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [recv, _]) => {
+                zst_offset::check(cx, expr, recv)
+            },
+            ("and_then", [arg]) => {
+                let biom_option_linted = bind_instead_of_map::OptionAndThenSome::check(cx, expr, recv, arg);
+                let biom_result_linted = bind_instead_of_map::ResultAndThenOk::check(cx, expr, recv, arg);
+                if !biom_option_linted && !biom_result_linted {
+                    unnecessary_lazy_eval::check(cx, expr, recv, arg, "and");
+                }
+            },
+            ("as_mut", []) => useless_asref::check(cx, expr, "as_mut", recv),
+            ("as_ref", []) => useless_asref::check(cx, expr, "as_ref", recv),
+            ("assume_init", []) => uninit_assumed_init::check(cx, expr, recv),
+            ("collect", []) => match method_call!(recv) {
+                Some(("cloned", [recv2], _)) => iter_cloned_collect::check(cx, expr, recv2),
+                Some(("map", [m_recv, m_arg], _)) => {
+                    map_collect_result_unit::check(cx, expr, m_recv, m_arg, recv);
+                },
+                _ => {},
+            },
+            ("count", []) => match method_call!(recv) {
+                Some((name @ ("into_iter" | "iter" | "iter_mut"), [recv2], _)) => {
+                    iter_count::check(cx, expr, recv2, name);
+                },
+                Some(("map", [_, arg], _)) => suspicious_map::check(cx, expr, recv, arg),
+                _ => {},
+            },
+            ("expect", [_]) => match method_call!(recv) {
+                Some(("ok", [recv], _)) => ok_expect::check(cx, expr, recv),
+                _ => expect_used::check(cx, expr, recv),
+            },
+            ("extend", [arg]) => string_extend_chars::check(cx, expr, recv, arg),
+            ("filter_map", [arg]) => {
+                unnecessary_filter_map::check(cx, expr, arg);
+                filter_map_identity::check(cx, expr, arg, span);
+            },
+            ("flat_map", [flm_arg]) => match method_call!(recv) {
+                Some(("filter", [_, _], _)) => filter_flat_map::check(cx, expr),
+                Some(("filter_map", [_, _], _)) => filter_map_flat_map::check(cx, expr),
+                _ => flat_map_identity::check(cx, expr, flm_arg, span),
+            },
+            ("flatten", []) => {
+                if let Some(("map", [recv, map_arg], _)) = method_call!(recv) {
+                    map_flatten::check(cx, expr, recv, map_arg);
+                }
+            },
+            ("fold", [init, acc]) => unnecessary_fold::check(cx, expr, init, acc, span),
+            ("for_each", [_]) => {
+                if let Some(("inspect", [_, _], span2)) = method_call!(recv) {
+                    inspect_for_each::check(cx, expr, span2);
+                }
+            },
+            ("get_or_insert_with", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert"),
+            ("is_file", []) => filetype_is_file::check(cx, expr, recv),
+            ("is_none", []) => check_is_some_is_none(cx, expr, recv, false),
+            ("is_some", []) => check_is_some_is_none(cx, expr, recv, true),
+            ("map", [m_arg]) => {
+                if let Some((name, [recv2, args @ ..], span2)) = method_call!(recv) {
+                    match (name, args) {
+                        ("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, msrv),
+                        ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, msrv),
+                        ("filter", [f_arg]) => {
+                            filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false)
+                        },
+                        ("filter_map", [_]) => filter_map_map::check(cx, expr),
+                        ("find", [f_arg]) => filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, true),
+                        _ => {},
+                    }
+                }
+            },
+            ("map_or", [def, map]) => option_map_or_none::check(cx, expr, recv, def, map),
+            ("next", []) => {
+                if let Some((name, [recv, args @ ..], _)) = method_call!(recv) {
+                    match (name, args) {
+                        ("filter", [arg]) => filter_next::check(cx, expr, recv, arg),
+                        ("filter_map", [arg]) => filter_map_next::check(cx, expr, recv, arg, msrv),
+                        ("iter", []) => iter_next_slice::check(cx, expr, recv),
+                        ("skip", [arg]) => iter_skip_next::check(cx, expr, recv, arg),
+                        ("skip_while", [_]) => skip_while_next::check(cx, expr),
+                        _ => {},
+                    }
+                }
+            },
+            ("nth", [n_arg]) => match method_call!(recv) {
+                Some(("bytes", [recv2], _)) => bytes_nth::check(cx, expr, recv2, n_arg),
+                Some(("iter", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false),
+                Some(("iter_mut", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true),
+                _ => iter_nth_zero::check(cx, expr, recv, n_arg),
+            },
+            ("ok_or_else", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"),
+            ("or_else", [arg]) => {
+                if !bind_instead_of_map::ResultOrElseErrInfo::check(cx, expr, recv, arg) {
+                    unnecessary_lazy_eval::check(cx, expr, recv, arg, "or");
+                }
+            },
+            ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg),
+            ("to_os_string", []) => implicit_clone::check(cx, expr, sym::OsStr),
+            ("to_owned", []) => implicit_clone::check(cx, expr, sym::ToOwned),
+            ("to_path_buf", []) => implicit_clone::check(cx, expr, sym::Path),
+            ("to_vec", []) => implicit_clone::check(cx, expr, sym::slice),
+            ("unwrap", []) => match method_call!(recv) {
+                Some(("get", [recv, get_arg], _)) => get_unwrap::check(cx, expr, recv, get_arg, false),
+                Some(("get_mut", [recv, get_arg], _)) => get_unwrap::check(cx, expr, recv, get_arg, true),
+                _ => unwrap_used::check(cx, expr, recv),
+            },
+            ("unwrap_or", [u_arg]) => match method_call!(recv) {
+                Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), [lhs, rhs], _)) => {
+                    manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]);
+                },
+                Some(("map", [m_recv, m_arg], span)) => {
+                    option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span)
+                },
+                _ => {},
+            },
+            ("unwrap_or_else", [u_arg]) => match method_call!(recv) {
+                Some(("map", [recv, map_arg], _)) if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, msrv) => {},
+                _ => unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or"),
+            },
+            _ => {},
+        }
+    }
+}
+
+fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, is_some: bool) {
+    if let Some((name @ ("find" | "position" | "rposition"), [f_recv, arg], span)) = method_call!(recv) {
+        search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span)
+    }
+}
+
 /// Used for `lint_binary_expr_with_method_call`.
 #[derive(Copy, Clone)]
 struct BinaryExprInfo<'a> {
diff --git a/clippy_lints/src/methods/ok_expect.rs b/clippy_lints/src/methods/ok_expect.rs
index e6ce9cac397..d0b1b4b84be 100644
--- a/clippy_lints/src/methods/ok_expect.rs
+++ b/clippy_lints/src/methods/ok_expect.rs
@@ -9,11 +9,11 @@ use rustc_span::sym;
 use super::OK_EXPECT;
 
 /// lint use of `ok().expect()` for `Result`s
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ok_args: &[hir::Expr<'_>]) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
     if_chain! {
         // lint if the caller of `ok()` is a `Result`
-        if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&ok_args[0]), sym::result_type);
-        let result_type = cx.typeck_results().expr_ty(&ok_args[0]);
+        if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::result_type);
+        let result_type = cx.typeck_results().expr_ty(recv);
         if let Some(error_type) = get_error_type(cx, result_type);
         if has_debug_impl(error_type, cx);
 
diff --git a/clippy_lints/src/methods/option_as_ref_deref.rs b/clippy_lints/src/methods/option_as_ref_deref.rs
index d11ede080dc..1367a0c21d8 100644
--- a/clippy_lints/src/methods/option_as_ref_deref.rs
+++ b/clippy_lints/src/methods/option_as_ref_deref.rs
@@ -18,8 +18,8 @@ const OPTION_AS_REF_DEREF_MSRV: RustcVersion = RustcVersion::new(1, 40, 0);
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &hir::Expr<'_>,
-    as_ref_args: &[hir::Expr<'_>],
-    map_args: &[hir::Expr<'_>],
+    as_ref_recv: &hir::Expr<'_>,
+    map_arg: &hir::Expr<'_>,
     is_mut: bool,
     msrv: Option<&RustcVersion>,
 ) {
@@ -29,7 +29,7 @@ pub(super) fn check<'tcx>(
 
     let same_mutability = |m| (is_mut && m == &hir::Mutability::Mut) || (!is_mut && m == &hir::Mutability::Not);
 
-    let option_ty = cx.typeck_results().expr_ty(&as_ref_args[0]);
+    let option_ty = cx.typeck_results().expr_ty(as_ref_recv);
     if !is_type_diagnostic_item(cx, option_ty, sym::option_type) {
         return;
     }
@@ -46,9 +46,9 @@ pub(super) fn check<'tcx>(
         &paths::VEC_AS_MUT_SLICE,
     ];
 
-    let is_deref = match map_args[1].kind {
+    let is_deref = match map_arg.kind {
         hir::ExprKind::Path(ref expr_qpath) => cx
-            .qpath_res(expr_qpath, map_args[1].hir_id)
+            .qpath_res(expr_qpath, map_arg.hir_id)
             .opt_def_id()
             .map_or(false, |fun_def_id| {
                 deref_aliases.iter().any(|path| match_def_path(cx, fun_def_id, path))
@@ -96,12 +96,12 @@ pub(super) fn check<'tcx>(
 
     if is_deref {
         let current_method = if is_mut {
-            format!(".as_mut().map({})", snippet(cx, map_args[1].span, ".."))
+            format!(".as_mut().map({})", snippet(cx, map_arg.span, ".."))
         } else {
-            format!(".as_ref().map({})", snippet(cx, map_args[1].span, ".."))
+            format!(".as_ref().map({})", snippet(cx, map_arg.span, ".."))
         };
         let method_hint = if is_mut { "as_deref_mut" } else { "as_deref" };
-        let hint = format!("{}.{}()", snippet(cx, as_ref_args[0].span, ".."), method_hint);
+        let hint = format!("{}.{}()", snippet(cx, as_ref_recv.span, ".."), method_hint);
         let suggestion = format!("try using {} instead", method_hint);
 
         let msg = format!(
diff --git a/clippy_lints/src/methods/option_map_or_none.rs b/clippy_lints/src/methods/option_map_or_none.rs
index d93db2c22e4..013a6f90ac9 100644
--- a/clippy_lints/src/methods/option_map_or_none.rs
+++ b/clippy_lints/src/methods/option_map_or_none.rs
@@ -11,9 +11,15 @@ use super::OPTION_MAP_OR_NONE;
 use super::RESULT_MAP_OR_INTO_OPTION;
 
 /// lint use of `_.map_or(None, _)` for `Option`s and `Result`s
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map_or_args: &'tcx [hir::Expr<'_>]) {
-    let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_or_args[0]), sym::option_type);
-    let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_or_args[0]), sym::result_type);
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx hir::Expr<'_>,
+    recv: &'tcx hir::Expr<'_>,
+    def_arg: &'tcx hir::Expr<'_>,
+    map_arg: &'tcx hir::Expr<'_>,
+) {
+    let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::option_type);
+    let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::result_type);
 
     // There are two variants of this `map_or` lint:
     // (1) using `map_or` as an adapter from `Result<T,E>` to `Option<T>`
@@ -25,7 +31,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map
     }
 
     let (lint_name, msg, instead, hint) = {
-        let default_arg_is_none = if let hir::ExprKind::Path(ref qpath) = map_or_args[1].kind {
+        let default_arg_is_none = if let hir::ExprKind::Path(ref qpath) = def_arg.kind {
             match_qpath(qpath, &paths::OPTION_NONE)
         } else {
             return;
@@ -36,15 +42,15 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map
             return;
         }
 
-        let f_arg_is_some = if let hir::ExprKind::Path(ref qpath) = map_or_args[2].kind {
+        let f_arg_is_some = if let hir::ExprKind::Path(ref qpath) = map_arg.kind {
             match_qpath(qpath, &paths::OPTION_SOME)
         } else {
             false
         };
 
         if is_option {
-            let self_snippet = snippet(cx, map_or_args[0].span, "..");
-            let func_snippet = snippet(cx, map_or_args[2].span, "..");
+            let self_snippet = snippet(cx, recv.span, "..");
+            let func_snippet = snippet(cx, map_arg.span, "..");
             let msg = "called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling \
                        `and_then(..)` instead";
             (
@@ -56,7 +62,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map
         } else if f_arg_is_some {
             let msg = "called `map_or(None, Some)` on a `Result` value. This can be done more directly by calling \
                        `ok()` instead";
-            let self_snippet = snippet(cx, map_or_args[0].span, "..");
+            let self_snippet = snippet(cx, recv.span, "..");
             (
                 RESULT_MAP_OR_INTO_OPTION,
                 msg,
diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs
index e252abc177a..5bca49dec24 100644
--- a/clippy_lints/src/methods/option_map_unwrap_or.rs
+++ b/clippy_lints/src/methods/option_map_unwrap_or.rs
@@ -18,13 +18,15 @@ use super::MAP_UNWRAP_OR;
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &rustc_hir::Expr<'_>,
-    map_args: &'tcx [rustc_hir::Expr<'_>],
-    unwrap_args: &'tcx [rustc_hir::Expr<'_>],
+    recv: &rustc_hir::Expr<'_>,
+    map_arg: &'tcx rustc_hir::Expr<'_>,
+    unwrap_recv: &rustc_hir::Expr<'_>,
+    unwrap_arg: &'tcx rustc_hir::Expr<'_>,
     map_span: Span,
 ) {
     // lint if the caller of `map()` is an `Option`
-    if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym::option_type) {
-        if !is_copy(cx, cx.typeck_results().expr_ty(&unwrap_args[1])) {
+    if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::option_type) {
+        if !is_copy(cx, cx.typeck_results().expr_ty(unwrap_arg)) {
             // Do not lint if the `map` argument uses identifiers in the `map`
             // argument that are also used in the `unwrap_or` argument
 
@@ -32,27 +34,27 @@ pub(super) fn check<'tcx>(
                 cx,
                 identifiers: FxHashSet::default(),
             };
-            unwrap_visitor.visit_expr(&unwrap_args[1]);
+            unwrap_visitor.visit_expr(unwrap_arg);
 
             let mut map_expr_visitor = MapExprVisitor {
                 cx,
                 identifiers: unwrap_visitor.identifiers,
                 found_identifier: false,
             };
-            map_expr_visitor.visit_expr(&map_args[1]);
+            map_expr_visitor.visit_expr(map_arg);
 
             if map_expr_visitor.found_identifier {
                 return;
             }
         }
 
-        if differing_macro_contexts(unwrap_args[1].span, map_span) {
+        if differing_macro_contexts(unwrap_arg.span, map_span) {
             return;
         }
 
         let mut applicability = Applicability::MachineApplicable;
         // get snippet for unwrap_or()
-        let unwrap_snippet = snippet_with_applicability(cx, unwrap_args[1].span, "..", &mut applicability);
+        let unwrap_snippet = snippet_with_applicability(cx, unwrap_arg.span, "..", &mut applicability);
         // lint message
         // comparing the snippet from source to raw text ("None") below is safe
         // because we already have checked the type.
@@ -70,14 +72,14 @@ pub(super) fn check<'tcx>(
         );
 
         span_lint_and_then(cx, MAP_UNWRAP_OR, expr.span, msg, |diag| {
-            let map_arg_span = map_args[1].span;
+            let map_arg_span = map_arg.span;
 
             let mut suggestion = vec![
                 (
                     map_span,
                     String::from(if unwrap_snippet_none { "and_then" } else { "map_or" }),
                 ),
-                (expr.span.with_lo(unwrap_args[0].span.hi()), String::from("")),
+                (expr.span.with_lo(unwrap_recv.span.hi()), String::from("")),
             ];
 
             if !unwrap_snippet_none {
diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs
index de7d168295f..8a94d7f4155 100644
--- a/clippy_lints/src/methods/search_is_some.rs
+++ b/clippy_lints/src/methods/search_is_some.rs
@@ -15,29 +15,31 @@ use super::SEARCH_IS_SOME;
 
 /// lint searching an Iterator followed by `is_some()`
 /// or calling `find()` on a string followed by `is_some()` or `is_none()`
-#[allow(clippy::too_many_lines)]
+#[allow(clippy::too_many_arguments, clippy::too_many_lines)]
 pub(super) fn check<'tcx>(
-    cx: &LateContext<'tcx>,
+    cx: &LateContext<'_>,
     expr: &'tcx hir::Expr<'_>,
     search_method: &str,
-    option_check_method: &str,
-    search_args: &'tcx [hir::Expr<'_>],
-    is_some_args: &'tcx [hir::Expr<'_>],
+    is_some: bool,
+    search_recv: &hir::Expr<'_>,
+    search_arg: &'tcx hir::Expr<'_>,
+    is_some_recv: &hir::Expr<'_>,
     method_span: Span,
 ) {
+    let option_check_method = if is_some { "is_some" } else { "is_none" };
     // lint if caller of search is an Iterator
-    if is_trait_method(cx, &is_some_args[0], sym::Iterator) {
+    if is_trait_method(cx, is_some_recv, sym::Iterator) {
         let msg = format!(
             "called `{}()` after searching an `Iterator` with `{}`",
             option_check_method, search_method
         );
-        let search_snippet = snippet(cx, search_args[1].span, "..");
+        let search_snippet = snippet(cx, search_arg.span, "..");
         if search_snippet.lines().count() <= 1 {
             // suggest `any(|x| ..)` instead of `any(|&x| ..)` for `find(|&x| ..).is_some()`
             // suggest `any(|..| *..)` instead of `any(|..| **..)` for `find(|..| **..).is_some()`
             let any_search_snippet = if_chain! {
                 if search_method == "find";
-                if let hir::ExprKind::Closure(_, _, body_id, ..) = search_args[1].kind;
+                if let hir::ExprKind::Closure(_, _, body_id, ..) = search_arg.kind;
                 let closure_body = cx.tcx.hir().body(body_id);
                 if let Some(closure_arg) = closure_body.params.get(0);
                 then {
@@ -54,38 +56,34 @@ pub(super) fn check<'tcx>(
                 }
             };
             // add note if not multi-line
-            match option_check_method {
-                "is_some" => {
-                    span_lint_and_sugg(
-                        cx,
-                        SEARCH_IS_SOME,
-                        method_span.with_hi(expr.span.hi()),
-                        &msg,
-                        "use `any()` instead",
-                        format!(
-                            "any({})",
-                            any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str)
-                        ),
-                        Applicability::MachineApplicable,
-                    );
-                },
-                "is_none" => {
-                    let iter = snippet(cx, search_args[0].span, "..");
-                    span_lint_and_sugg(
-                        cx,
-                        SEARCH_IS_SOME,
-                        expr.span,
-                        &msg,
-                        "use `!_.any()` instead",
-                        format!(
-                            "!{}.any({})",
-                            iter,
-                            any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str)
-                        ),
-                        Applicability::MachineApplicable,
-                    );
-                },
-                _ => (),
+            if is_some {
+                span_lint_and_sugg(
+                    cx,
+                    SEARCH_IS_SOME,
+                    method_span.with_hi(expr.span.hi()),
+                    &msg,
+                    "use `any()` instead",
+                    format!(
+                        "any({})",
+                        any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str)
+                    ),
+                    Applicability::MachineApplicable,
+                );
+            } else {
+                let iter = snippet(cx, search_recv.span, "..");
+                span_lint_and_sugg(
+                    cx,
+                    SEARCH_IS_SOME,
+                    expr.span,
+                    &msg,
+                    "use `!_.any()` instead",
+                    format!(
+                        "!{}.any({})",
+                        iter,
+                        any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str)
+                    ),
+                    Applicability::MachineApplicable,
+                );
             }
         } else {
             let hint = format!(
@@ -110,14 +108,14 @@ pub(super) fn check<'tcx>(
             }
         };
         if_chain! {
-            if is_string_or_str_slice(&search_args[0]);
-            if is_string_or_str_slice(&search_args[1]);
+            if is_string_or_str_slice(&search_recv);
+            if is_string_or_str_slice(&search_arg);
             then {
                 let msg = format!("called `{}()` after calling `find()` on a string", option_check_method);
                 match option_check_method {
                     "is_some" => {
                         let mut applicability = Applicability::MachineApplicable;
-                        let find_arg = snippet_with_applicability(cx, search_args[1].span, "..", &mut applicability);
+                        let find_arg = snippet_with_applicability(cx, search_arg.span, "..", &mut applicability);
                         span_lint_and_sugg(
                             cx,
                             SEARCH_IS_SOME,
@@ -129,9 +127,9 @@ pub(super) fn check<'tcx>(
                         );
                     },
                     "is_none" => {
-                        let string = snippet(cx, search_args[0].span, "..");
+                        let string = snippet(cx, search_recv.span, "..");
                         let mut applicability = Applicability::MachineApplicable;
-                        let find_arg = snippet_with_applicability(cx, search_args[1].span, "..", &mut applicability);
+                        let find_arg = snippet_with_applicability(cx, search_arg.span, "..", &mut applicability);
                         span_lint_and_sugg(
                             cx,
                             SEARCH_IS_SOME,
diff --git a/clippy_lints/src/methods/skip_while_next.rs b/clippy_lints/src/methods/skip_while_next.rs
index 3db83785b59..9f0b6c34ea2 100644
--- a/clippy_lints/src/methods/skip_while_next.rs
+++ b/clippy_lints/src/methods/skip_while_next.rs
@@ -7,7 +7,7 @@ use rustc_span::sym;
 use super::SKIP_WHILE_NEXT;
 
 /// lint use of `skip_while().next()` for `Iterators`
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, _skip_while_args: &'tcx [hir::Expr<'_>]) {
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
     // lint if caller of `.skip_while().next()` is an Iterator
     if is_trait_method(cx, expr, sym::Iterator) {
         span_lint_and_help(
diff --git a/clippy_lints/src/methods/string_extend_chars.rs b/clippy_lints/src/methods/string_extend_chars.rs
index 5c688ac5621..6e7890a3080 100644
--- a/clippy_lints/src/methods/string_extend_chars.rs
+++ b/clippy_lints/src/methods/string_extend_chars.rs
@@ -10,12 +10,11 @@ use rustc_span::symbol::sym;
 
 use super::STRING_EXTEND_CHARS;
 
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
-    let obj_ty = cx.typeck_results().expr_ty(&args[0]).peel_refs();
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) {
+    let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
     if !is_type_diagnostic_item(cx, obj_ty, sym::string_type) {
         return;
     }
-    let arg = &args[1];
     if let Some(arglists) = method_chain_args(arg, &["chars"]) {
         let target = &arglists[0][0];
         let self_ty = cx.typeck_results().expr_ty(target).peel_refs();
@@ -36,7 +35,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Exp
             "try this",
             format!(
                 "{}.push_str({}{})",
-                snippet_with_applicability(cx, args[0].span, "..", &mut applicability),
+                snippet_with_applicability(cx, recv.span, "..", &mut applicability),
                 ref_str,
                 snippet_with_applicability(cx, target.span, "..", &mut applicability)
             ),
diff --git a/clippy_lints/src/methods/suspicious_map.rs b/clippy_lints/src/methods/suspicious_map.rs
index 7015bd54c35..0fd0668c734 100644
--- a/clippy_lints/src/methods/suspicious_map.rs
+++ b/clippy_lints/src/methods/suspicious_map.rs
@@ -8,15 +8,8 @@ use rustc_span::sym;
 
 use super::SUSPICIOUS_MAP;
 
-pub fn check<'tcx>(
-    cx: &LateContext<'tcx>,
-    expr: &hir::Expr<'_>,
-    map_args: &[hir::Expr<'_>],
-    count_args: &[hir::Expr<'_>],
-) {
+pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, count_recv: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) {
     if_chain! {
-        if let [count_recv] = count_args;
-        if let [_, map_arg] = map_args;
         if is_trait_method(cx, count_recv, sym::Iterator);
         let closure = expr_or_init(cx, map_arg);
         if let Some(body_id) = cx.tcx.hir().maybe_body_owned_by(closure.hir_id);
diff --git a/clippy_lints/src/methods/uninit_assumed_init.rs b/clippy_lints/src/methods/uninit_assumed_init.rs
index f2f6ef4be6c..3cc1912b15a 100644
--- a/clippy_lints/src/methods/uninit_assumed_init.rs
+++ b/clippy_lints/src/methods/uninit_assumed_init.rs
@@ -8,18 +8,18 @@ use rustc_middle::ty::{self, Ty};
 use super::UNINIT_ASSUMED_INIT;
 
 /// lint for `MaybeUninit::uninit().assume_init()` (we already have the latter)
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, outer: &hir::Expr<'_>) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
     if_chain! {
-        if let hir::ExprKind::Call(ref callee, ref args) = expr.kind;
+        if let hir::ExprKind::Call(ref callee, ref args) = recv.kind;
         if args.is_empty();
         if let hir::ExprKind::Path(ref path) = callee.kind;
         if match_qpath(path, &paths::MEM_MAYBEUNINIT_UNINIT);
-        if !is_maybe_uninit_ty_valid(cx, cx.typeck_results().expr_ty_adjusted(outer));
+        if !is_maybe_uninit_ty_valid(cx, cx.typeck_results().expr_ty_adjusted(expr));
         then {
             span_lint(
                 cx,
                 UNINIT_ASSUMED_INIT,
-                outer.span,
+                expr.span,
                 "this call for this type may be undefined behavior"
             );
         }
diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs
index 48d905ab833..dac7e039e37 100644
--- a/clippy_lints/src/methods/unnecessary_filter_map.rs
+++ b/clippy_lints/src/methods/unnecessary_filter_map.rs
@@ -10,12 +10,12 @@ use rustc_span::sym;
 
 use super::UNNECESSARY_FILTER_MAP;
 
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>) {
     if !is_trait_method(cx, expr, sym::Iterator) {
         return;
     }
 
-    if let hir::ExprKind::Closure(_, _, body_id, ..) = args[1].kind {
+    if let hir::ExprKind::Closure(_, _, body_id, ..) = arg.kind {
         let body = cx.tcx.hir().body(body_id);
         let arg_id = body.params[0].pat.hir_id;
         let mutates_arg =
diff --git a/clippy_lints/src/methods/unnecessary_fold.rs b/clippy_lints/src/methods/unnecessary_fold.rs
index 1268fd4bda9..7c16470348f 100644
--- a/clippy_lints/src/methods/unnecessary_fold.rs
+++ b/clippy_lints/src/methods/unnecessary_fold.rs
@@ -11,11 +11,17 @@ use rustc_span::{source_map::Span, sym};
 
 use super::UNNECESSARY_FOLD;
 
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, fold_args: &[hir::Expr<'_>], fold_span: Span) {
+pub(super) fn check(
+    cx: &LateContext<'_>,
+    expr: &hir::Expr<'_>,
+    init: &hir::Expr<'_>,
+    acc: &hir::Expr<'_>,
+    fold_span: Span,
+) {
     fn check_fold_with_op(
         cx: &LateContext<'_>,
         expr: &hir::Expr<'_>,
-        fold_args: &[hir::Expr<'_>],
+        acc: &hir::Expr<'_>,
         fold_span: Span,
         op: hir::BinOpKind,
         replacement_method_name: &str,
@@ -23,7 +29,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, fold_args: &[hir
     ) {
         if_chain! {
             // Extract the body of the closure passed to fold
-            if let hir::ExprKind::Closure(_, _, body_id, _, _) = fold_args[2].kind;
+            if let hir::ExprKind::Closure(_, _, body_id, _, _) = acc.kind;
             let closure_body = cx.tcx.hir().body(body_id);
             let closure_expr = remove_blocks(&closure_body.value);
 
@@ -74,25 +80,14 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, fold_args: &[hir
         return;
     }
 
-    assert!(
-        fold_args.len() == 3,
-        "Expected fold_args to have three entries - the receiver, the initial value and the closure"
-    );
-
     // Check if the first argument to .fold is a suitable literal
-    if let hir::ExprKind::Lit(ref lit) = fold_args[1].kind {
+    if let hir::ExprKind::Lit(ref lit) = init.kind {
         match lit.node {
-            ast::LitKind::Bool(false) => {
-                check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::Or, "any", true)
-            },
-            ast::LitKind::Bool(true) => {
-                check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::And, "all", true)
-            },
-            ast::LitKind::Int(0, _) => {
-                check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::Add, "sum", false)
-            },
+            ast::LitKind::Bool(false) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Or, "any", true),
+            ast::LitKind::Bool(true) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::And, "all", true),
+            ast::LitKind::Int(0, _) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Add, "sum", false),
             ast::LitKind::Int(1, _) => {
-                check_fold_with_op(cx, expr, fold_args, fold_span, hir::BinOpKind::Mul, "product", false)
+                check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Mul, "product", false)
             },
             _ => (),
         }
diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs
index a86185bf0a6..b7380883a5e 100644
--- a/clippy_lints/src/methods/unnecessary_lazy_eval.rs
+++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs
@@ -14,14 +14,15 @@ use super::UNNECESSARY_LAZY_EVALUATIONS;
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &'tcx hir::Expr<'_>,
-    args: &'tcx [hir::Expr<'_>],
+    recv: &'tcx hir::Expr<'_>,
+    arg: &'tcx hir::Expr<'_>,
     simplify_using: &str,
 ) {
-    let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]), sym::option_type);
-    let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]), sym::result_type);
+    let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::option_type);
+    let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::result_type);
 
     if is_option || is_result {
-        if let hir::ExprKind::Closure(_, _, eid, _, _) = args[1].kind {
+        if let hir::ExprKind::Closure(_, _, eid, _, _) = arg.kind {
             let body = cx.tcx.hir().body(eid);
             let body_expr = &body.value;
 
@@ -55,7 +56,7 @@ pub(super) fn check<'tcx>(
                     &format!("use `{}` instead", simplify_using),
                     format!(
                         "{0}.{1}({2})",
-                        snippet(cx, args[0].span, ".."),
+                        snippet(cx, recv.span, ".."),
                         simplify_using,
                         snippet(cx, body_expr.span, ".."),
                     ),
diff --git a/clippy_lints/src/methods/unwrap_used.rs b/clippy_lints/src/methods/unwrap_used.rs
index 2f5806115bd..7fd1948594d 100644
--- a/clippy_lints/src/methods/unwrap_used.rs
+++ b/clippy_lints/src/methods/unwrap_used.rs
@@ -7,8 +7,8 @@ use rustc_span::sym;
 use super::UNWRAP_USED;
 
 /// lint use of `unwrap()` for `Option`s and `Result`s
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, unwrap_args: &[hir::Expr<'_>]) {
-    let obj_ty = cx.typeck_results().expr_ty(&unwrap_args[0]).peel_refs();
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
+    let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
 
     let mess = if is_type_diagnostic_item(cx, obj_ty, sym::option_type) {
         Some((UNWRAP_USED, "an Option", "None"))
diff --git a/clippy_lints/src/methods/useless_asref.rs b/clippy_lints/src/methods/useless_asref.rs
index b5505af0f7e..e0b1de68b37 100644
--- a/clippy_lints/src/methods/useless_asref.rs
+++ b/clippy_lints/src/methods/useless_asref.rs
@@ -10,12 +10,11 @@ use rustc_lint::LateContext;
 use super::USELESS_ASREF;
 
 /// Checks for the `USELESS_ASREF` lint.
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, as_ref_args: &[hir::Expr<'_>]) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, recvr: &hir::Expr<'_>) {
     // when we get here, we've already checked that the call name is "as_ref" or "as_mut"
     // check if the call is to the actual `AsRef` or `AsMut` trait
     if match_trait_method(cx, expr, &paths::ASREF_TRAIT) || match_trait_method(cx, expr, &paths::ASMUT_TRAIT) {
         // check if the type after `as_ref` or `as_mut` is the same as before
-        let recvr = &as_ref_args[0];
         let rcv_ty = cx.typeck_results().expr_ty(recvr);
         let res_ty = cx.typeck_results().expr_ty(expr);
         let (base_res_ty, res_depth) = walk_ptrs_ty_depth(res_ty);
diff --git a/clippy_lints/src/methods/zst_offset.rs b/clippy_lints/src/methods/zst_offset.rs
index 9f6a7c4db17..0489d0f6fcf 100644
--- a/clippy_lints/src/methods/zst_offset.rs
+++ b/clippy_lints/src/methods/zst_offset.rs
@@ -6,10 +6,9 @@ use rustc_middle::ty;
 
 use super::ZST_OFFSET;
 
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
     if_chain! {
-        if args.len() == 2;
-        if let ty::RawPtr(ty::TypeAndMut { ref ty, .. }) = cx.typeck_results().expr_ty(&args[0]).kind();
+        if let ty::RawPtr(ty::TypeAndMut { ref ty, .. }) = cx.typeck_results().expr_ty(recv).kind();
         if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty));
         if layout.is_zst();
         then {