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} ;
@@ -12,13 +12,20 @@ use rustc_hir::LangItem::{self, OptionNone, OptionSome, PollPending, PollReady,
1212use rustc_hir:: { Arm , Expr , ExprKind , Guard , Node , Pat , PatKind , QPath , UnOp } ;
1313use rustc_lint:: LateContext ;
1414use rustc_middle:: ty:: { self , GenericArgKind , Ty } ;
15- use rustc_span:: { sym, Symbol } ;
15+ use rustc_span:: { sym, Span , Symbol } ;
1616use 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) {
21- find_sugg_for_if_let ( cx, expr, let_pat, let_expr, "while" , false ) ;
20+ if let Some ( higher:: WhileLet {
21+ let_pat,
22+ let_expr,
23+ let_span,
24+ ..
25+ } ) = higher:: WhileLet :: hir ( expr)
26+ {
27+ 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
@@ -28,8 +35,73 @@ pub(super) fn check_if_let<'tcx>(
2835 pat : & ' tcx Pat < ' _ > ,
2936 scrutinee : & ' tcx Expr < ' _ > ,
3037 has_else : bool ,
38+ let_span : Span ,
3139) {
32- find_sugg_for_if_let ( cx, expr, pat, scrutinee, "if" , has_else) ;
40+ find_if_let_true ( cx, pat, scrutinee, let_span) ;
41+ find_method_sugg_for_if_let ( cx, expr, pat, scrutinee, "if" , has_else) ;
42+ }
43+
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 = ...`
65+ fn 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+ ) {
77+ if let PatKind :: Lit ( lit) = pat. kind
78+ && let ExprKind :: Lit ( lit) = lit. kind
79+ && let LitKind :: Bool ( pat_is_true) = lit. node
80+ {
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+ ) ;
90+
91+ if !pat_is_true {
92+ sugg = make_unop ( "!" , sugg) ;
93+ }
94+
95+ span_lint_and_sugg (
96+ cx,
97+ REDUNDANT_PATTERN_MATCHING ,
98+ span,
99+ message,
100+ "consider using the condition directly" ,
101+ sugg. to_string ( ) ,
102+ applicability,
103+ ) ;
104+ }
33105}
34106
35107// Extract the generic arguments out of a type
@@ -100,7 +172,7 @@ fn find_method_and_type<'tcx>(
100172 }
101173}
102174
103- fn find_sugg_for_if_let < ' tcx > (
175+ fn find_method_sugg_for_if_let < ' tcx > (
104176 cx : & LateContext < ' tcx > ,
105177 expr : & ' tcx Expr < ' _ > ,
106178 let_pat : & Pat < ' _ > ,
0 commit comments