about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJason Newcomb <jsnewcomb@pm.me>2024-06-13 19:20:21 -0400
committerJason Newcomb <jsnewcomb@pm.me>2024-07-07 22:13:05 -0400
commitc22608823f5831f068f027deec09899d6971489a (patch)
tree9f3416881973e7ef234406ebd9965d1fb6787a00
parent58aa804ada9c13e8e5e89e6f25594d52ba835816 (diff)
downloadrust-c22608823f5831f068f027deec09899d6971489a.tar.gz
rust-c22608823f5831f068f027deec09899d6971489a.zip
`needless_borrowed_ref`: Check HIR tree first.
-rw-r--r--clippy_lints/src/needless_borrowed_ref.rs142
1 files changed, 67 insertions, 75 deletions
diff --git a/clippy_lints/src/needless_borrowed_ref.rs b/clippy_lints/src/needless_borrowed_ref.rs
index fb02f24c9dc..098098718af 100644
--- a/clippy_lints/src/needless_borrowed_ref.rs
+++ b/clippy_lints/src/needless_borrowed_ref.rs
@@ -37,83 +37,75 @@ declare_lint_pass!(NeedlessBorrowedRef => [NEEDLESS_BORROWED_REFERENCE]);
 
 impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowedRef {
     fn check_pat(&mut self, cx: &LateContext<'tcx>, ref_pat: &'tcx Pat<'_>) {
-        if ref_pat.span.from_expansion() {
-            // OK, simple enough, lints doesn't check in macro.
-            return;
-        }
-
-        // Do not lint patterns that are part of an OR `|` pattern, the binding mode must match in all arms
-        for (_, node) in cx.tcx.hir().parent_iter(ref_pat.hir_id) {
-            let Node::Pat(pat) = node else { break };
-
-            if matches!(pat.kind, PatKind::Or(_)) {
-                return;
+        if let PatKind::Ref(pat, Mutability::Not) = ref_pat.kind
+            && !ref_pat.span.from_expansion()
+            && cx
+                .tcx
+                .hir()
+                .parent_iter(ref_pat.hir_id)
+                .map_while(|(_, parent)| if let Node::Pat(pat) = parent { Some(pat) } else { None })
+                // Do not lint patterns that are part of an OR `|` pattern, the binding mode must match in all arms
+                .all(|pat| !matches!(pat.kind, PatKind::Or(_)))
+        {
+            match pat.kind {
+                // Check sub_pat got a `ref` keyword (excluding `ref mut`).
+                PatKind::Binding(BindingMode::REF, _, ident, None) => {
+                    span_lint_and_then(
+                        cx,
+                        NEEDLESS_BORROWED_REFERENCE,
+                        ref_pat.span,
+                        "this pattern takes a reference on something that is being dereferenced",
+                        |diag| {
+                            // `&ref ident`
+                            //  ^^^^^
+                            let span = ref_pat.span.until(ident.span);
+                            diag.span_suggestion_verbose(
+                                span,
+                                "try removing the `&ref` part",
+                                String::new(),
+                                Applicability::MachineApplicable,
+                            );
+                        },
+                    );
+                },
+                // Slices where each element is `ref`: `&[ref a, ref b, ..., ref z]`
+                PatKind::Slice(
+                    before,
+                    None
+                    | Some(Pat {
+                        kind: PatKind::Wild, ..
+                    }),
+                    after,
+                ) => {
+                    check_subpatterns(
+                        cx,
+                        "dereferencing a slice pattern where every element takes a reference",
+                        ref_pat,
+                        pat,
+                        itertools::chain(before, after),
+                    );
+                },
+                PatKind::Tuple(subpatterns, _) | PatKind::TupleStruct(_, subpatterns, _) => {
+                    check_subpatterns(
+                        cx,
+                        "dereferencing a tuple pattern where every element takes a reference",
+                        ref_pat,
+                        pat,
+                        subpatterns,
+                    );
+                },
+                PatKind::Struct(_, fields, _) => {
+                    check_subpatterns(
+                        cx,
+                        "dereferencing a struct pattern where every field's pattern takes a reference",
+                        ref_pat,
+                        pat,
+                        fields.iter().map(|field| field.pat),
+                    );
+                },
+                _ => {},
             }
         }
-
-        // Only lint immutable refs, because `&mut ref T` may be useful.
-        let PatKind::Ref(pat, Mutability::Not) = ref_pat.kind else {
-            return;
-        };
-
-        match pat.kind {
-            // Check sub_pat got a `ref` keyword (excluding `ref mut`).
-            PatKind::Binding(BindingMode::REF, _, ident, None) => {
-                span_lint_and_then(
-                    cx,
-                    NEEDLESS_BORROWED_REFERENCE,
-                    ref_pat.span,
-                    "this pattern takes a reference on something that is being dereferenced",
-                    |diag| {
-                        // `&ref ident`
-                        //  ^^^^^
-                        let span = ref_pat.span.until(ident.span);
-                        diag.span_suggestion_verbose(
-                            span,
-                            "try removing the `&ref` part",
-                            String::new(),
-                            Applicability::MachineApplicable,
-                        );
-                    },
-                );
-            },
-            // Slices where each element is `ref`: `&[ref a, ref b, ..., ref z]`
-            PatKind::Slice(
-                before,
-                None
-                | Some(Pat {
-                    kind: PatKind::Wild, ..
-                }),
-                after,
-            ) => {
-                check_subpatterns(
-                    cx,
-                    "dereferencing a slice pattern where every element takes a reference",
-                    ref_pat,
-                    pat,
-                    itertools::chain(before, after),
-                );
-            },
-            PatKind::Tuple(subpatterns, _) | PatKind::TupleStruct(_, subpatterns, _) => {
-                check_subpatterns(
-                    cx,
-                    "dereferencing a tuple pattern where every element takes a reference",
-                    ref_pat,
-                    pat,
-                    subpatterns,
-                );
-            },
-            PatKind::Struct(_, fields, _) => {
-                check_subpatterns(
-                    cx,
-                    "dereferencing a struct pattern where every field's pattern takes a reference",
-                    ref_pat,
-                    pat,
-                    fields.iter().map(|field| field.pat),
-                );
-            },
-            _ => {},
-        }
     }
 }