11use clippy_config:: msrvs:: { self , Msrv } ;
22use clippy_utils:: diagnostics:: span_lint_and_sugg;
33use clippy_utils:: eager_or_lazy:: switch_to_eager_eval;
4- use clippy_utils:: source:: snippet;
4+ use clippy_utils:: source:: { snippet, snippet_opt } ;
55use clippy_utils:: ty:: is_type_diagnostic_item;
66use clippy_utils:: visitors:: is_local_used;
77use clippy_utils:: { get_parent_expr, path_to_local_id} ;
@@ -14,6 +14,26 @@ use rustc_span::sym;
1414
1515use super :: UNNECESSARY_MAP_OR ;
1616
17+ pub ( super ) enum Variant {
18+ Ok ,
19+ Some ,
20+ }
21+ impl Variant {
22+ pub fn variant_name ( & self ) -> & ' static str {
23+ match self {
24+ Variant :: Ok => "Ok" ,
25+ Variant :: Some => "Some" ,
26+ }
27+ }
28+
29+ pub fn method_name ( & self ) -> & ' static str {
30+ match self {
31+ Variant :: Ok => "is_ok_and" ,
32+ Variant :: Some => "is_some_and" ,
33+ }
34+ }
35+ }
36+
1737// Only checking map_or for now
1838pub ( super ) fn check (
1939 cx : & LateContext < ' _ > ,
@@ -29,14 +49,23 @@ pub(super) fn check(
2949 && ( is_type_diagnostic_item ( cx, recv_ty, sym:: Option ) || is_type_diagnostic_item ( cx, recv_ty, sym:: Result ) )
3050 && let Bool ( def_bool) = def_kind. node
3151 {
52+ let variant = if is_type_diagnostic_item ( cx, recv_ty, sym:: Option ) {
53+ Variant :: Some
54+ } else {
55+ Variant :: Ok
56+ } ;
57+
3258 let ( sugg, method) = if let ExprKind :: Closure ( map_closure) = map. kind
3359 && let closure_body = cx. tcx . hir ( ) . body ( map_closure. body )
3460 && let closure_body_value = closure_body. value . peel_blocks ( )
3561 && let ExprKind :: Binary ( op, l, r) = closure_body_value. kind
3662 && let Some ( param) = closure_body. params . first ( )
3763 && let PatKind :: Binding ( _, hir_id, _, _) = param. pat . kind
38- // checking that map_or is either:
39- // .map_or(false, |x| x == y) OR .map_or(true, |x| x != y)
64+ // checking that map_or is one of the following:
65+ // .map_or(false, |x| x == y)
66+ // .map_or(false, |x| y == x) - swapped comparison
67+ // .map_or(true, |x| x != y)
68+ // .map_or(true, |x| y != x) - swapped comparison
4069 && ( ( BinOpKind :: Eq == op. node && !def_bool) || ( BinOpKind :: Ne == op. node && def_bool) )
4170 && let non_binding_location = if path_to_local_id ( l, hir_id) { r } else { l }
4271 && switch_to_eager_eval ( cx, non_binding_location)
@@ -46,12 +75,8 @@ pub(super) fn check(
4675 && !is_local_used ( cx, non_binding_location, hir_id)
4776 && typeck_results. expr_ty ( l) == typeck_results. expr_ty ( r)
4877 {
49- let wrap = if is_type_diagnostic_item ( cx, recv_ty, sym:: Option ) {
50- "Some"
51- } else {
52- "Ok"
53- } ;
54- let comparator = if BinOpKind :: Eq == op. node { "==" } else { "!=" } ;
78+ let wrap = variant. variant_name ( ) ;
79+ let comparator = op. node . as_str ( ) ;
5580
5681 // we may need to add parens around the suggestion
5782 // in case the parent expression has additional method calls,
@@ -62,32 +87,21 @@ pub(super) fn check(
6287 . is_some_and ( |expr| expr. precedence ( ) . order ( ) > i8:: try_from ( AssocOp :: Equal . precedence ( ) ) . unwrap_or ( 0 ) ) ;
6388 (
6489 format ! (
65- "{}{} {} {}({}){}" ,
90+ "{}{} {comparator } {wrap }({}){}" ,
6691 if should_add_parens { "(" } else { "" } ,
6792 snippet( cx, recv. span, ".." ) ,
68- comparator,
69- wrap,
7093 snippet( cx, non_binding_location. span. source_callsite( ) , ".." ) ,
7194 if should_add_parens { ")" } else { "" }
7295 ) ,
7396 "standard comparison" ,
7497 )
75- } else if !def_bool && msrv. meets ( msrvs:: OPTION_RESULT_IS_VARIANT_AND ) {
76- let sugg = if is_type_diagnostic_item ( cx, recv_ty, sym:: Option ) {
77- "is_some_and"
78- } else {
79- "is_ok_and"
80- } ;
81-
82- (
83- format ! (
84- "{}.{}({})" ,
85- snippet( cx, recv. span. source_callsite( ) , ".." ) ,
86- sugg,
87- snippet( cx, map. span. source_callsite( ) , ".." )
88- ) ,
89- sugg,
90- )
98+ } else if !def_bool
99+ && msrv. meets ( msrvs:: OPTION_RESULT_IS_VARIANT_AND )
100+ && let Some ( recv_callsite) = snippet_opt ( cx, recv. span . source_callsite ( ) )
101+ && let Some ( span_callsite) = snippet_opt ( cx, map. span . source_callsite ( ) )
102+ {
103+ let sugg = variant. method_name ( ) ;
104+ ( format ! ( "{recv_callsite}.{sugg}({span_callsite})" , ) , sugg)
91105 } else {
92106 return ;
93107 } ;
0 commit comments