@@ -3,7 +3,7 @@ use clippy_utils::source::snippet_with_applicability;
33use clippy_utils:: { fn_def_id, match_def_path} ;
44use rustc_errors:: Applicability ;
55use rustc_hir:: def:: Res ;
6- use rustc_hir:: { Block , Closure , Expr , ExprKind , FnDecl , HirId , Node , Pat , Path , QPath , Ty } ;
6+ use rustc_hir:: { Block , Closure , Expr , ExprKind , FnDecl , HirId , Node , Pat , Path , QPath , Ty , Param , Body } ;
77use rustc_lint:: { LateContext , LateLintPass } ;
88use rustc_session:: declare_lint_pass;
99use rustc_span:: Span ;
@@ -58,14 +58,18 @@ impl<'tcx> LateLintPass<'tcx> for AndThenThenSome {
5858fn then_some_closure_arg < ' tcx > ( cx : & LateContext < ' tcx > , expr : & Expr < ' tcx > ) -> Option < ( Span , & ' tcx Expr < ' tcx > ) > {
5959 match expr. kind {
6060 ExprKind :: Closure ( Closure {
61- fn_decl : FnDecl {
61+ /* fn_decl: FnDecl {
6262 inputs: [Ty { hir_id: arg_id, .. }],
6363 ..
64- } ,
64+ },*/
6565 body,
6666 ..
6767 } ) => {
68- if let Node :: Expr ( expr) = cx. tcx . hir_node ( body. hir_id ) {
68+ if let Node :: Expr ( expr) = cx. tcx . hir_node ( body. hir_id ) &&
69+ let Body { params : [ Param { hir_id : arg_id, .. } ] , .. } =
70+ cx. tcx . hir ( ) . body ( * body)
71+ {
72+
6973 ( peel_closure_body ( cx, expr, * arg_id) ) . map ( |body| ( cx. tcx . hir ( ) . span ( * arg_id) , body) )
7074 } else {
7175 None
@@ -101,6 +105,16 @@ fn peel_closure_body<'tcx>(
101105 }
102106}
103107
108+ fn get_pat_hid ( node : Node < ' _ > ) -> Option < HirId > {
109+ match node {
110+ Node :: Param ( Param { pat : Pat { hir_id, .. } , .. } ) |
111+ Node :: Pat ( Pat { hir_id, .. } ) => Some ( * hir_id) ,
112+ _ => {
113+ None
114+ } ,
115+ }
116+ }
117+
104118fn is_local_defined_at ( cx : & LateContext < ' _ > , local : & Expr < ' _ > , arg_hid : HirId ) -> bool {
105119 match local. kind {
106120 ExprKind :: Path ( QPath :: Resolved (
@@ -110,19 +124,9 @@ fn is_local_defined_at(cx: &LateContext<'_>, local: &Expr<'_>, arg_hid: HirId) -
110124 ..
111125 } ,
112126 ) ) => {
113- // FIXME: this is the best way i could find to compare if
114- // a local refers to a specific closure argument.
115- //
116- // it breaks if the closure argument has an explicitly declared type,
117- // since the spans only align for TyKind::Infer
118- if let Node :: Pat ( Pat { span : local_span, .. } ) = ( cx. tcx . hir_node ( * local_hid) )
119- && let Node :: Ty ( Ty { span : arg_span, .. } ) = ( cx. tcx . hir_node ( arg_hid) )
120- && local_span == arg_span
121- {
122- true
123- } else {
124- false
125- }
127+ let local_pat_id = get_pat_hid ( cx. tcx . hir_node ( * local_hid) ) ;
128+ local_pat_id. is_some ( ) &&
129+ local_pat_id == get_pat_hid ( cx. tcx . hir_node ( arg_hid) )
126130 } ,
127131 // is not local at all, so definitly isn't a local defined at the given position
128132 _ => false ,
@@ -132,7 +136,7 @@ fn is_local_defined_at(cx: &LateContext<'_>, local: &Expr<'_>, arg_hid: HirId) -
132136fn show_sugg ( cx : & LateContext < ' _ > , span : Span , selfarg : & Expr < ' _ > , closure_args : Span , predicate : & Expr < ' _ > ) {
133137 let mut appl = Applicability :: MachineApplicable ;
134138 let sugg = format ! (
135- "{}.filter(|{}| {})" ,
139+ "{}.filter(|& {}| {})" ,
136140 snippet_with_applicability( cx, selfarg. span, "<OPTION>" , & mut appl) ,
137141 snippet_with_applicability( cx, closure_args, "<ARGS>" , & mut appl) ,
138142 snippet_with_applicability( cx, predicate. span, "<PREDICATE>" , & mut appl)
0 commit comments