1
1
use clippy_config:: msrvs:: { self , Msrv } ;
2
2
use clippy_utils:: diagnostics:: span_lint_and_sugg;
3
3
use clippy_utils:: eager_or_lazy:: switch_to_eager_eval;
4
- use clippy_utils:: source:: snippet;
4
+ use clippy_utils:: source:: { snippet, snippet_opt } ;
5
5
use clippy_utils:: ty:: is_type_diagnostic_item;
6
6
use clippy_utils:: visitors:: is_local_used;
7
7
use clippy_utils:: { get_parent_expr, path_to_local_id} ;
@@ -14,6 +14,26 @@ use rustc_span::sym;
14
14
15
15
use super :: UNNECESSARY_MAP_OR ;
16
16
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
+
17
37
// Only checking map_or for now
18
38
pub ( super ) fn check (
19
39
cx : & LateContext < ' _ > ,
@@ -29,14 +49,23 @@ pub(super) fn check(
29
49
&& ( is_type_diagnostic_item ( cx, recv_ty, sym:: Option ) || is_type_diagnostic_item ( cx, recv_ty, sym:: Result ) )
30
50
&& let Bool ( def_bool) = def_kind. node
31
51
{
52
+ let variant = if is_type_diagnostic_item ( cx, recv_ty, sym:: Option ) {
53
+ Variant :: Some
54
+ } else {
55
+ Variant :: Ok
56
+ } ;
57
+
32
58
let ( sugg, method) = if let ExprKind :: Closure ( map_closure) = map. kind
33
59
&& let closure_body = cx. tcx . hir ( ) . body ( map_closure. body )
34
60
&& let closure_body_value = closure_body. value . peel_blocks ( )
35
61
&& let ExprKind :: Binary ( op, l, r) = closure_body_value. kind
36
62
&& let Some ( param) = closure_body. params . first ( )
37
63
&& 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
40
69
&& ( ( BinOpKind :: Eq == op. node && !def_bool) || ( BinOpKind :: Ne == op. node && def_bool) )
41
70
&& let non_binding_location = if path_to_local_id ( l, hir_id) { r } else { l }
42
71
&& switch_to_eager_eval ( cx, non_binding_location)
@@ -46,12 +75,8 @@ pub(super) fn check(
46
75
&& !is_local_used ( cx, non_binding_location, hir_id)
47
76
&& typeck_results. expr_ty ( l) == typeck_results. expr_ty ( r)
48
77
{
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 ( ) ;
55
80
56
81
// we may need to add parens around the suggestion
57
82
// in case the parent expression has additional method calls,
@@ -62,32 +87,21 @@ pub(super) fn check(
62
87
. is_some_and ( |expr| expr. precedence ( ) . order ( ) > i8:: try_from ( AssocOp :: Equal . precedence ( ) ) . unwrap_or ( 0 ) ) ;
63
88
(
64
89
format ! (
65
- "{}{} {} {}({}){}" ,
90
+ "{}{} {comparator } {wrap }({}){}" ,
66
91
if should_add_parens { "(" } else { "" } ,
67
92
snippet( cx, recv. span, ".." ) ,
68
- comparator,
69
- wrap,
70
93
snippet( cx, non_binding_location. span. source_callsite( ) , ".." ) ,
71
94
if should_add_parens { ")" } else { "" }
72
95
) ,
73
96
"standard comparison" ,
74
97
)
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)
91
105
} else {
92
106
return ;
93
107
} ;
0 commit comments