Skip to content

Commit 90d0085

Browse files
authored
match_as_ref: do not lint if other arm is not None => None (#15693)
Fixes #15691 changelog: [`match_as_ref`]: do not lint if other arm is not `None => None`
2 parents d457260 + c1f7829 commit 90d0085

File tree

4 files changed

+73
-9
lines changed

4 files changed

+73
-9
lines changed

clippy_lints/src/manual_option_as_slice.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use clippy_config::Conf;
22
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
33
use clippy_utils::msrvs::Msrv;
4-
use clippy_utils::{is_none_arm, msrvs, peel_hir_expr_refs, sym};
4+
use clippy_utils::{is_none_pattern, msrvs, peel_hir_expr_refs, sym};
55
use rustc_errors::Applicability;
66
use rustc_hir::def::{DefKind, Res};
77
use rustc_hir::{Arm, Expr, ExprKind, LangItem, Pat, PatKind, QPath, is_range_literal};
@@ -60,8 +60,8 @@ impl LateLintPass<'_> for ManualOptionAsSlice {
6060
}
6161
match expr.kind {
6262
ExprKind::Match(scrutinee, [arm1, arm2], _) => {
63-
if is_none_arm(cx, arm2) && check_arms(cx, arm2, arm1)
64-
|| is_none_arm(cx, arm1) && check_arms(cx, arm1, arm2)
63+
if is_none_pattern(cx, arm2.pat) && check_arms(cx, arm2, arm1)
64+
|| is_none_pattern(cx, arm1.pat) && check_arms(cx, arm1, arm2)
6565
{
6666
check_as_ref(cx, scrutinee, span, self.msrv);
6767
}

clippy_utils/src/lib.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -329,13 +329,17 @@ pub fn is_wild(pat: &Pat<'_>) -> bool {
329329
matches!(pat.kind, PatKind::Wild)
330330
}
331331

332-
// Checks if arm has the form `None => None`
333-
pub fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
334-
matches!(
335-
arm.pat.kind,
332+
/// Checks if the `pat` is `None`.
333+
pub fn is_none_pattern(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
334+
matches!(pat.kind,
336335
PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), .. })
337-
if is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), OptionNone)
338-
)
336+
if is_res_lang_ctor(cx, cx.qpath_res(qpath, pat.hir_id), OptionNone))
337+
}
338+
339+
/// Checks if `arm` has the form `None => None`.
340+
pub fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
341+
is_none_pattern(cx, arm.pat)
342+
&& matches!(peel_blocks(arm.body).kind, ExprKind::Path(qpath) if is_res_lang_ctor(cx, cx.qpath_res(&qpath, arm.body.hir_id), OptionNone))
339343
}
340344

341345
/// Checks if the given `QPath` belongs to a type alias.

tests/ui/match_as_ref.fixed

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,33 @@ fn main() {
4141
None => None,
4242
};
4343
}
44+
45+
mod issue15691 {
46+
use std::ops::{Deref, DerefMut};
47+
48+
struct A(B);
49+
struct B;
50+
51+
impl Deref for A {
52+
type Target = B;
53+
fn deref(&self) -> &Self::Target {
54+
&self.0
55+
}
56+
}
57+
58+
impl DerefMut for A {
59+
fn deref_mut(&mut self) -> &mut Self::Target {
60+
&mut self.0
61+
}
62+
}
63+
64+
fn func() {
65+
let mut a = Some(A(B));
66+
let mut b = Some(B);
67+
// Do not lint, we don't have `None => None`
68+
let _ = match b {
69+
Some(ref mut x) => Some(x),
70+
None => a.as_deref_mut(),
71+
};
72+
}
73+
}

tests/ui/match_as_ref.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,33 @@ fn main() {
5353
None => None,
5454
};
5555
}
56+
57+
mod issue15691 {
58+
use std::ops::{Deref, DerefMut};
59+
60+
struct A(B);
61+
struct B;
62+
63+
impl Deref for A {
64+
type Target = B;
65+
fn deref(&self) -> &Self::Target {
66+
&self.0
67+
}
68+
}
69+
70+
impl DerefMut for A {
71+
fn deref_mut(&mut self) -> &mut Self::Target {
72+
&mut self.0
73+
}
74+
}
75+
76+
fn func() {
77+
let mut a = Some(A(B));
78+
let mut b = Some(B);
79+
// Do not lint, we don't have `None => None`
80+
let _ = match b {
81+
Some(ref mut x) => Some(x),
82+
None => a.as_deref_mut(),
83+
};
84+
}
85+
}

0 commit comments

Comments
 (0)