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, declare_tool_lint}
;
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(_
, _
, _
) | PatKind
::Range(_
, _
, _
) | PatKind
::Binding(..) | PatKind
::Wild
| PatKind
::Or(_
) => {
52 PatKind
::Struct(_
, a
, etc
) => !etc
&& a
.iter().all(|x
| unary_pattern(x
.pat
)),
53 PatKind
::Tuple(a
, etc
) | PatKind
::TupleStruct(_
, a
, etc
) => etc
.as_opt_usize().is_none() && array_rec(a
),
54 PatKind
::Ref(x
, _
) | PatKind
::Box(x
) => unary_pattern(x
),
55 PatKind
::Path(_
) | PatKind
::Lit(_
) => true,
59 fn is_structural_partial_eq
<'tcx
>(cx
: &LateContext
<'tcx
>, ty
: Ty
<'tcx
>, other
: Ty
<'tcx
>) -> bool
{
60 if let Some(def_id
) = cx
.tcx
.lang_items().eq_trait() {
61 implements_trait(cx
, ty
, def_id
, &[other
.into()])
67 impl<'tcx
> LateLintPass
<'tcx
> for PatternEquality
{
68 fn check_expr(&mut self, cx
: &LateContext
<'tcx
>, expr
: &'tcx Expr
<'tcx
>) {
69 if !in_external_macro(cx
.sess(), expr
.span
)
70 && let ExprKind
::Let(let_expr
) = expr
.kind
71 && unary_pattern(let_expr
.pat
)
73 let exp_ty
= cx
.typeck_results().expr_ty(let_expr
.init
);
74 let pat_ty
= cx
.typeck_results().pat_ty(let_expr
.pat
);
75 let mut applicability
= Applicability
::MachineApplicable
;
77 if is_structural_partial_eq(cx
, exp_ty
, pat_ty
) {
78 let pat_str
= match let_expr
.pat
.kind
{
79 PatKind
::Struct(..) => format
!(
81 snippet_with_context(cx
, let_expr
.pat
.span
, expr
.span
.ctxt(), "..", &mut applicability
).0,
83 _
=> snippet_with_context(cx
, let_expr
.pat
.span
, expr
.span
.ctxt(), "..", &mut applicability
)
91 "this pattern matching can be expressed using equality",
95 snippet_with_context(cx
, let_expr
.init
.span
, expr
.span
.ctxt(), "..", &mut applicability
).0,
104 "this pattern matching can be expressed using `matches!`",
108 snippet_with_context(cx
, let_expr
.init
.span
, expr
.span
.ctxt(), "..", &mut applicability
).0,
109 snippet_with_context(cx
, let_expr
.pat
.span
, expr
.span
.ctxt(), "..", &mut applicability
).0,