11use super :: REDUNDANT_PATTERN_MATCHING ;
22use clippy_utils:: diagnostics:: { span_lint_and_sugg, span_lint_and_then} ;
33use clippy_utils:: source:: { snippet, walk_span_to_context} ;
4- use clippy_utils:: sugg:: Sugg ;
4+ use clippy_utils:: sugg:: { make_unop , Sugg } ;
55use clippy_utils:: ty:: { is_type_diagnostic_item, needs_ordered_drop} ;
66use clippy_utils:: visitors:: { any_temporaries_need_ordered_drop, for_each_expr} ;
77use clippy_utils:: { higher, is_expn_of, is_trait_method} ;
@@ -17,8 +17,15 @@ use std::fmt::Write;
1717use std:: ops:: ControlFlow ;
1818
1919pub ( super ) fn check < ' tcx > ( cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' _ > ) {
20- if let Some ( higher:: WhileLet { let_pat, let_expr, .. } ) = higher:: WhileLet :: hir ( expr) {
20+ if let Some ( higher:: WhileLet {
21+ let_pat,
22+ let_expr,
23+ let_span,
24+ ..
25+ } ) = higher:: WhileLet :: hir ( expr)
26+ {
2127 find_method_sugg_for_if_let ( cx, expr, let_pat, let_expr, "while" , false ) ;
28+ find_if_let_true ( cx, let_pat, let_expr, let_span) ;
2229 }
2330}
2431
@@ -34,26 +41,65 @@ pub(super) fn check_if_let<'tcx>(
3441 find_method_sugg_for_if_let ( cx, expr, pat, scrutinee, "if" , has_else) ;
3542}
3643
44+ /// Looks for:
45+ /// * `matches!(expr, true)`
46+ pub fn check_matches_true < ' tcx > (
47+ cx : & LateContext < ' tcx > ,
48+ expr : & ' tcx Expr < ' _ > ,
49+ arm : & ' tcx Arm < ' _ > ,
50+ scrutinee : & ' tcx Expr < ' _ > ,
51+ ) {
52+ find_match_true (
53+ cx,
54+ arm. pat ,
55+ scrutinee,
56+ expr. span . source_callsite ( ) ,
57+ "using `matches!` to pattern match a bool" ,
58+ ) ;
59+ }
60+
61+ /// Looks for any of:
62+ /// * `if let true = ...`
63+ /// * `if let false = ...`
64+ /// * `while let true = ...`
3765fn find_if_let_true < ' tcx > ( cx : & LateContext < ' tcx > , pat : & ' tcx Pat < ' _ > , scrutinee : & ' tcx Expr < ' _ > , let_span : Span ) {
66+ find_match_true ( cx, pat, scrutinee, let_span, "using `if let` to pattern match a bool" ) ;
67+ }
68+
69+ /// Common logic between `find_if_let_true` and `check_matches_true`
70+ fn find_match_true < ' tcx > (
71+ cx : & LateContext < ' tcx > ,
72+ pat : & ' tcx Pat < ' _ > ,
73+ scrutinee : & ' tcx Expr < ' _ > ,
74+ span : Span ,
75+ message : & str ,
76+ ) {
3877 if let PatKind :: Lit ( lit) = pat. kind
3978 && let ExprKind :: Lit ( lit) = lit. kind
40- && let LitKind :: Bool ( is_true ) = lit. node
79+ && let LitKind :: Bool ( pat_is_true ) = lit. node
4180 {
42- let mut snip = snippet ( cx, scrutinee. span , ".." ) . into_owned ( ) ;
81+ let mut applicability = Applicability :: MachineApplicable ;
82+
83+ let mut sugg = Sugg :: hir_with_context (
84+ cx,
85+ scrutinee,
86+ scrutinee. span . source_callsite ( ) . ctxt ( ) ,
87+ ".." ,
88+ & mut applicability,
89+ ) ;
4390
44- if !is_true {
45- // Invert condition for `if let false = ...`
46- snip. insert ( 0 , '!' ) ;
91+ if !pat_is_true {
92+ sugg = make_unop ( "!" , sugg) ;
4793 }
4894
4995 span_lint_and_sugg (
5096 cx,
5197 REDUNDANT_PATTERN_MATCHING ,
52- let_span ,
53- "using `if let` to pattern match a boolean" ,
54- "consider using a regular `if` expression " ,
55- snip ,
56- Applicability :: MachineApplicable ,
98+ span ,
99+ message ,
100+ "consider using the condition directly " ,
101+ sugg . to_string ( ) ,
102+ applicability ,
57103 ) ;
58104 }
59105}
0 commit comments