about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSamuel Tardieu <sam@rfc1149.net>2025-09-17 19:23:28 +0200
committerSamuel Tardieu <sam@rfc1149.net>2025-09-17 19:35:05 +0200
commitc1f782919bac1071a514eafb87e2463be25fc99e (patch)
treea81c9e7f7fc002da8005d63493264609d4ce7623
parent55570c9b257c8f2ae710d701ad03f924aed78cca (diff)
downloadrust-c1f782919bac1071a514eafb87e2463be25fc99e.tar.gz
rust-c1f782919bac1071a514eafb87e2463be25fc99e.zip
`match_as_ref`: do not lint if other arm is not `None => None`
-rw-r--r--clippy_lints/src/manual_option_as_slice.rs6
-rw-r--r--clippy_utils/src/lib.rs16
-rw-r--r--tests/ui/match_as_ref.fixed30
-rw-r--r--tests/ui/match_as_ref.rs30
4 files changed, 73 insertions, 9 deletions
diff --git a/clippy_lints/src/manual_option_as_slice.rs b/clippy_lints/src/manual_option_as_slice.rs
index 922db174e3d..b036e78cded 100644
--- a/clippy_lints/src/manual_option_as_slice.rs
+++ b/clippy_lints/src/manual_option_as_slice.rs
@@ -1,7 +1,7 @@
 use clippy_config::Conf;
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
 use clippy_utils::msrvs::Msrv;
-use clippy_utils::{is_none_arm, msrvs, peel_hir_expr_refs, sym};
+use clippy_utils::{is_none_pattern, msrvs, peel_hir_expr_refs, sym};
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Arm, Expr, ExprKind, LangItem, Pat, PatKind, QPath, is_range_literal};
@@ -60,8 +60,8 @@ impl LateLintPass<'_> for ManualOptionAsSlice {
         }
         match expr.kind {
             ExprKind::Match(scrutinee, [arm1, arm2], _) => {
-                if is_none_arm(cx, arm2) && check_arms(cx, arm2, arm1)
-                    || is_none_arm(cx, arm1) && check_arms(cx, arm1, arm2)
+                if is_none_pattern(cx, arm2.pat) && check_arms(cx, arm2, arm1)
+                    || is_none_pattern(cx, arm1.pat) && check_arms(cx, arm1, arm2)
                 {
                     check_as_ref(cx, scrutinee, span, self.msrv);
                 }
diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs
index 5223cd872a6..3e48397fbed 100644
--- a/clippy_utils/src/lib.rs
+++ b/clippy_utils/src/lib.rs
@@ -329,13 +329,17 @@ pub fn is_wild(pat: &Pat<'_>) -> bool {
     matches!(pat.kind, PatKind::Wild)
 }
 
-// Checks if arm has the form `None => None`
-pub fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
-    matches!(
-        arm.pat.kind,
+/// Checks if the `pat` is `None`.
+pub fn is_none_pattern(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
+    matches!(pat.kind,
         PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), .. })
-            if is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), OptionNone)
-    )
+            if is_res_lang_ctor(cx, cx.qpath_res(qpath, pat.hir_id), OptionNone))
+}
+
+/// Checks if `arm` has the form `None => None`.
+pub fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
+    is_none_pattern(cx, arm.pat)
+        && matches!(peel_blocks(arm.body).kind, ExprKind::Path(qpath) if is_res_lang_ctor(cx, cx.qpath_res(&qpath, arm.body.hir_id), OptionNone))
 }
 
 /// Checks if the given `QPath` belongs to a type alias.
diff --git a/tests/ui/match_as_ref.fixed b/tests/ui/match_as_ref.fixed
index 8c07076af4a..a39f0c9299b 100644
--- a/tests/ui/match_as_ref.fixed
+++ b/tests/ui/match_as_ref.fixed
@@ -41,3 +41,33 @@ fn main() {
         None => None,
     };
 }
+
+mod issue15691 {
+    use std::ops::{Deref, DerefMut};
+
+    struct A(B);
+    struct B;
+
+    impl Deref for A {
+        type Target = B;
+        fn deref(&self) -> &Self::Target {
+            &self.0
+        }
+    }
+
+    impl DerefMut for A {
+        fn deref_mut(&mut self) -> &mut Self::Target {
+            &mut self.0
+        }
+    }
+
+    fn func() {
+        let mut a = Some(A(B));
+        let mut b = Some(B);
+        // Do not lint, we don't have `None => None`
+        let _ = match b {
+            Some(ref mut x) => Some(x),
+            None => a.as_deref_mut(),
+        };
+    }
+}
diff --git a/tests/ui/match_as_ref.rs b/tests/ui/match_as_ref.rs
index 3a5b1227331..04992816790 100644
--- a/tests/ui/match_as_ref.rs
+++ b/tests/ui/match_as_ref.rs
@@ -53,3 +53,33 @@ fn main() {
         None => None,
     };
 }
+
+mod issue15691 {
+    use std::ops::{Deref, DerefMut};
+
+    struct A(B);
+    struct B;
+
+    impl Deref for A {
+        type Target = B;
+        fn deref(&self) -> &Self::Target {
+            &self.0
+        }
+    }
+
+    impl DerefMut for A {
+        fn deref_mut(&mut self) -> &mut Self::Target {
+            &mut self.0
+        }
+    }
+
+    fn func() {
+        let mut a = Some(A(B));
+        let mut b = Some(B);
+        // Do not lint, we don't have `None => None`
+        let _ = match b {
+            Some(ref mut x) => Some(x),
+            None => a.as_deref_mut(),
+        };
+    }
+}