@@ -30,12 +30,12 @@ fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) ->
30
30
match closure_expr. kind {
31
31
hir:: ExprKind :: MethodCall ( hir:: PathSegment { ident, .. } , receiver, ..) => {
32
32
if_chain ! {
33
- if ident. name == method_name;
34
- if let hir:: ExprKind :: Path ( path) = & receiver. kind;
35
- if let Res :: Local ( ref local) = cx. qpath_res( path, receiver. hir_id) ;
36
- then {
37
- return arg_id == * local
38
- }
33
+ if ident. name == method_name;
34
+ if let hir:: ExprKind :: Path ( path) = & receiver. kind;
35
+ if let Res :: Local ( ref local) = cx. qpath_res( path, receiver. hir_id) ;
36
+ then {
37
+ return arg_id == * local
38
+ }
39
39
}
40
40
false
41
41
} ,
@@ -92,92 +92,92 @@ pub(super) fn check(
92
92
}
93
93
94
94
if_chain ! {
95
- if is_trait_method( cx, map_recv, sym:: Iterator ) ;
96
-
97
- // filter(|x| ...is_some())...
98
- if let ExprKind :: Closure ( & Closure { body: filter_body_id, .. } ) = filter_arg. kind;
99
- let filter_body = cx. tcx. hir( ) . body( filter_body_id) ;
100
- if let [ filter_param] = filter_body. params;
101
- // optional ref pattern: `filter(|&x| ..)`
102
- let ( filter_pat, is_filter_param_ref) = if let PatKind :: Ref ( ref_pat, _) = filter_param. pat. kind {
103
- ( ref_pat, true )
104
- } else {
105
- ( filter_param. pat, false )
95
+ if is_trait_method( cx, map_recv, sym:: Iterator ) ;
96
+
97
+ // filter(|x| ...is_some())...
98
+ if let ExprKind :: Closure ( & Closure { body: filter_body_id, .. } ) = filter_arg. kind;
99
+ let filter_body = cx. tcx. hir( ) . body( filter_body_id) ;
100
+ if let [ filter_param] = filter_body. params;
101
+ // optional ref pattern: `filter(|&x| ..)`
102
+ let ( filter_pat, is_filter_param_ref) = if let PatKind :: Ref ( ref_pat, _) = filter_param. pat. kind {
103
+ ( ref_pat, true )
104
+ } else {
105
+ ( filter_param. pat, false )
106
+ } ;
107
+ // closure ends with is_some() or is_ok()
108
+ if let PatKind :: Binding ( _, filter_param_id, _, None ) = filter_pat. kind;
109
+ if let ExprKind :: MethodCall ( path, filter_arg, [ ] , _) = filter_body. value. kind;
110
+ if let Some ( opt_ty) = cx. typeck_results( ) . expr_ty( filter_arg) . peel_refs( ) . ty_adt_def( ) ;
111
+ if let Some ( is_result) = if cx. tcx. is_diagnostic_item( sym:: Option , opt_ty. did( ) ) {
112
+ Some ( false )
113
+ } else if cx. tcx. is_diagnostic_item( sym:: Result , opt_ty. did( ) ) {
114
+ Some ( true )
115
+ } else {
116
+ None
117
+ } ;
118
+ if path. ident. name. as_str( ) == if is_result { "is_ok" } else { "is_some" } ;
119
+
120
+ // ...map(|x| ...unwrap())
121
+ if let ExprKind :: Closure ( & Closure { body: map_body_id, .. } ) = map_arg. kind;
122
+ let map_body = cx. tcx. hir( ) . body( map_body_id) ;
123
+ if let [ map_param] = map_body. params;
124
+ if let PatKind :: Binding ( _, map_param_id, map_param_ident, None ) = map_param. pat. kind;
125
+ // closure ends with expect() or unwrap()
126
+ if let ExprKind :: MethodCall ( seg, map_arg, ..) = map_body. value. kind;
127
+ if matches!( seg. ident. name, sym:: expect | sym:: unwrap | sym:: unwrap_or) ;
128
+
129
+ // .filter(..).map(|y| f(y).copied().unwrap())
130
+ // ~~~~
131
+ let map_arg_peeled = match map_arg. kind {
132
+ ExprKind :: MethodCall ( method, original_arg, [ ] , _) if acceptable_methods( method) => {
133
+ original_arg
134
+ } ,
135
+ _ => map_arg,
136
+ } ;
137
+
138
+ // .filter(|x| x.is_some()).map(|y| y[.acceptable_method()].unwrap())
139
+ let simple_equal = path_to_local_id( filter_arg, filter_param_id)
140
+ && path_to_local_id( map_arg_peeled, map_param_id) ;
141
+
142
+ let eq_fallback = |a: & Expr <' _>, b: & Expr <' _>| {
143
+ // in `filter(|x| ..)`, replace `*x` with `x`
144
+ let a_path = if_chain! {
145
+ if !is_filter_param_ref;
146
+ if let ExprKind :: Unary ( UnOp :: Deref , expr_path) = a. kind;
147
+ then { expr_path } else { a }
106
148
} ;
107
- // closure ends with is_some() or is_ok()
108
- if let PatKind :: Binding ( _, filter_param_id, _, None ) = filter_pat. kind;
109
- if let ExprKind :: MethodCall ( path, filter_arg, [ ] , _) = filter_body. value. kind;
110
- if let Some ( opt_ty) = cx. typeck_results( ) . expr_ty( filter_arg) . peel_refs( ) . ty_adt_def( ) ;
111
- if let Some ( is_result) = if cx. tcx. is_diagnostic_item( sym:: Option , opt_ty. did( ) ) {
112
- Some ( false )
113
- } else if cx. tcx. is_diagnostic_item( sym:: Result , opt_ty. did( ) ) {
114
- Some ( true )
149
+ // let the filter closure arg and the map closure arg be equal
150
+ path_to_local_id( a_path, filter_param_id)
151
+ && path_to_local_id( b, map_param_id)
152
+ && cx. typeck_results( ) . expr_ty_adjusted( a) == cx. typeck_results( ) . expr_ty_adjusted( b)
153
+ } ;
154
+
155
+ if simple_equal || SpanlessEq :: new( cx) . expr_fallback( eq_fallback) . eq_expr( filter_arg, map_arg_peeled) ;
156
+ then {
157
+ let span = filter_span. with_hi( expr. span. hi( ) ) ;
158
+ let ( filter_name, lint) = if is_find {
159
+ ( "find" , MANUAL_FIND_MAP )
115
160
} else {
116
- None
117
- } ;
118
- if path. ident. name. as_str( ) == if is_result { "is_ok" } else { "is_some" } ;
119
-
120
- // ...map(|x| ...unwrap())
121
- if let ExprKind :: Closure ( & Closure { body: map_body_id, .. } ) = map_arg. kind;
122
- let map_body = cx. tcx. hir( ) . body( map_body_id) ;
123
- if let [ map_param] = map_body. params;
124
- if let PatKind :: Binding ( _, map_param_id, map_param_ident, None ) = map_param. pat. kind;
125
- // closure ends with expect() or unwrap()
126
- if let ExprKind :: MethodCall ( seg, map_arg, ..) = map_body. value. kind;
127
- if matches!( seg. ident. name, sym:: expect | sym:: unwrap | sym:: unwrap_or) ;
128
-
129
- // .filter(..).map(|y| f(y).copied().unwrap())
130
- // ~~~~
131
- let map_arg_peeled = match map_arg. kind {
132
- ExprKind :: MethodCall ( method, original_arg, [ ] , _) if acceptable_methods( method) => {
133
- original_arg
134
- } ,
135
- _ => map_arg,
161
+ ( "filter" , MANUAL_FILTER_MAP )
136
162
} ;
163
+ let msg = format!( "`{filter_name}(..).map(..)` can be simplified as `{filter_name}_map(..)`" ) ;
164
+ let ( to_opt, deref) = if is_result {
165
+ ( ".ok()" , String :: new( ) )
166
+ } else {
167
+ let derefs = cx. typeck_results( )
168
+ . expr_adjustments( map_arg)
169
+ . iter( )
170
+ . filter( |adj| matches!( adj. kind, Adjust :: Deref ( _) ) )
171
+ . count( ) ;
137
172
138
- // .filter(|x| x.is_some()).map(|y| y[.acceptable_method()].unwrap())
139
- let simple_equal = path_to_local_id( filter_arg, filter_param_id)
140
- && path_to_local_id( map_arg_peeled, map_param_id) ;
141
-
142
- let eq_fallback = |a: & Expr <' _>, b: & Expr <' _>| {
143
- // in `filter(|x| ..)`, replace `*x` with `x`
144
- let a_path = if_chain! {
145
- if !is_filter_param_ref;
146
- if let ExprKind :: Unary ( UnOp :: Deref , expr_path) = a. kind;
147
- then { expr_path } else { a }
148
- } ;
149
- // let the filter closure arg and the map closure arg be equal
150
- path_to_local_id( a_path, filter_param_id)
151
- && path_to_local_id( b, map_param_id)
152
- && cx. typeck_results( ) . expr_ty_adjusted( a) == cx. typeck_results( ) . expr_ty_adjusted( b)
173
+ ( "" , "*" . repeat( derefs) )
153
174
} ;
154
-
155
- if simple_equal || SpanlessEq :: new( cx) . expr_fallback( eq_fallback) . eq_expr( filter_arg, map_arg_peeled) ;
156
- then {
157
- let span = filter_span. with_hi( expr. span. hi( ) ) ;
158
- let ( filter_name, lint) = if is_find {
159
- ( "find" , MANUAL_FIND_MAP )
160
- } else {
161
- ( "filter" , MANUAL_FILTER_MAP )
162
- } ;
163
- let msg = format!( "`{filter_name}(..).map(..)` can be simplified as `{filter_name}_map(..)`" ) ;
164
- let ( to_opt, deref) = if is_result {
165
- ( ".ok()" , String :: new( ) )
166
- } else {
167
- let derefs = cx. typeck_results( )
168
- . expr_adjustments( map_arg)
169
- . iter( )
170
- . filter( |adj| matches!( adj. kind, Adjust :: Deref ( _) ) )
171
- . count( ) ;
172
-
173
- ( "" , "*" . repeat( derefs) )
174
- } ;
175
- let sugg = format!(
176
- "{filter_name}_map(|{map_param_ident}| {deref}{}{to_opt})" ,
177
- snippet( cx, map_arg. span, ".." ) ,
178
- ) ;
179
- span_lint_and_sugg( cx, lint, span, & msg, "try" , sugg, Applicability :: MachineApplicable ) ;
180
- }
175
+ let sugg = format!(
176
+ "{filter_name}_map(|{map_param_ident}| {deref}{}{to_opt})" ,
177
+ snippet( cx, map_arg. span, ".." ) ,
178
+ ) ;
179
+ span_lint_and_sugg( cx, lint, span, & msg, "try" , sugg, Applicability :: MachineApplicable ) ;
180
+ }
181
181
}
182
182
}
183
183
0 commit comments