1 use clippy_utils
::diagnostics
::span_lint_and_sugg
;
2 use clippy_utils
::source
::snippet_with_context
;
3 use clippy_utils
::ty
::implements_trait
;
4 use rustc_errors
::Applicability
;
5 use rustc_hir
::{Expr, ExprKind, Pat, PatKind}
;
6 use rustc_lint
::{LateContext, LateLintPass, LintContext}
;
7 use rustc_middle
::lint
::in_external_macro
;
8 use rustc_middle
::ty
::Ty
;
9 use rustc_session
::declare_lint_pass
;
11 declare_clippy_lint
! {
13 /// Checks for pattern matchings that can be expressed using equality.
15 /// ### Why is this bad?
17 /// * It reads better and has less cognitive load because equality won't cause binding.
18 /// * It is a [Yoda condition](https://en.wikipedia.org/wiki/Yoda_conditions). Yoda conditions are widely
19 /// criticized for increasing the cognitive load of reading the code.
20 /// * Equality is a simple bool expression and can be merged with `&&` and `||` and
25 /// if let Some(2) = x {
35 #[clippy::version = "1.57.0"]
38 "using pattern matching instead of equality"
41 declare_lint_pass
!(PatternEquality
=> [EQUATABLE_IF_LET
]);
43 /// detects if pattern matches just one thing
44 fn unary_pattern(pat
: &Pat
<'_
>) -> bool
{
45 fn array_rec(pats
: &[Pat
<'_
>]) -> bool
{
46 pats
.iter().all(unary_pattern
)
49 PatKind
::Slice(_
, _
, _
)
50 | PatKind
::Range(_
, _
, _
)
51 | PatKind
::Binding(..)
55 | PatKind
::Err(_
) => false,
56 PatKind
::Struct(_
, a
, etc
) => !etc
&& a
.iter().all(|x
| unary_pattern(x
.pat
)),
57 PatKind
::Tuple(a
, etc
) | PatKind
::TupleStruct(_
, a
, etc
) => etc
.as_opt_usize().is_none() && array_rec(a
),
58 PatKind
::Ref(x
, _
) | PatKind
::Box(x
) => unary_pattern(x
),
59 PatKind
::Path(_
) | PatKind
::Lit(_
) => true,
63 fn is_structural_partial_eq
<'tcx
>(cx
: &LateContext
<'tcx
>, ty
: Ty
<'tcx
>, other
: Ty
<'tcx
>) -> bool
{
64 if let Some(def_id
) = cx
.tcx
.lang_items().eq_trait() {
65 implements_trait(cx
, ty
, def_id
, &[other
.into()])
71 impl<'tcx
> LateLintPass
<'tcx
> for PatternEquality
{
72 fn check_expr(&mut self, cx
: &LateContext
<'tcx
>, expr
: &'tcx Expr
<'tcx
>) {
73 if !in_external_macro(cx
.sess(), expr
.span
)
74 && let ExprKind
::Let(let_expr
) = expr
.kind
75 && unary_pattern(let_expr
.pat
)
77 let exp_ty
= cx
.typeck_results().expr_ty(let_expr
.init
);
78 let pat_ty
= cx
.typeck_results().pat_ty(let_expr
.pat
);
79 let mut applicability
= Applicability
::MachineApplicable
;
81 if is_structural_partial_eq(cx
, exp_ty
, pat_ty
) {
82 let pat_str
= match let_expr
.pat
.kind
{
83 PatKind
::Struct(..) => format
!(
85 snippet_with_context(cx
, let_expr
.pat
.span
, expr
.span
.ctxt(), "..", &mut applicability
).0,
87 _
=> snippet_with_context(cx
, let_expr
.pat
.span
, expr
.span
.ctxt(), "..", &mut applicability
)
95 "this pattern matching can be expressed using equality",
99 snippet_with_context(cx
, let_expr
.init
.span
, expr
.span
.ctxt(), "..", &mut applicability
).0,
108 "this pattern matching can be expressed using `matches!`",
112 snippet_with_context(cx
, let_expr
.init
.span
, expr
.span
.ctxt(), "..", &mut applicability
).0,
113 snippet_with_context(cx
, let_expr
.pat
.span
, expr
.span
.ctxt(), "..", &mut applicability
).0,