@@ -30,12 +30,12 @@ fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) ->
3030 match closure_expr. kind {
3131 hir:: ExprKind :: MethodCall ( hir:: PathSegment { ident, .. } , receiver, ..) => {
3232 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+ }
3939 }
4040 false
4141 } ,
@@ -92,92 +92,92 @@ pub(super) fn check(
9292 }
9393
9494 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 }
106148 } ;
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 )
115160 } 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 )
136162 } ;
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( ) ;
137172
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) )
153174 } ;
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+ }
181181 }
182182}
183183
0 commit comments