11use  clippy_utils:: diagnostics:: span_lint_and_help; 
22use  clippy_utils:: ty:: { match_type,  peel_mid_ty_refs_is_mutable} ; 
3- use  clippy_utils:: { fn_def_id,  path_to_local_id,  paths,  peel_ref_operators} ; 
3+ use  clippy_utils:: { fn_def_id,  is_trait_method ,   path_to_local_id,  paths,  peel_ref_operators} ; 
44use  rustc_ast:: Mutability ; 
55use  rustc_hir:: intravisit:: { walk_expr,  Visitor } ; 
66use  rustc_hir:: lang_items:: LangItem ; 
77use  rustc_hir:: { Block ,  Expr ,  ExprKind ,  HirId ,  Local ,  Node ,  PatKind ,  PathSegment ,  StmtKind } ; 
88use  rustc_lint:: { LateContext ,  LateLintPass } ; 
9- use  rustc_middle:: ty:: Ty ; 
109use  rustc_session:: { declare_tool_lint,  impl_lint_pass} ; 
10+ use  rustc_span:: sym; 
1111
1212declare_clippy_lint !  { 
1313    /// ### What it does 
@@ -117,6 +117,10 @@ impl<'a, 'tcx> PeekableVisitor<'a, 'tcx> {
117117
118118impl < ' tcx >  Visitor < ' _ >  for  PeekableVisitor < ' _ ,  ' tcx >  { 
119119    fn  visit_expr ( & mut  self ,  ex :  & ' _  Expr < ' _ > )  { 
120+         if  self . found_peek_call  { 
121+             return ; 
122+         } 
123+ 
120124        if  path_to_local_id ( ex,  self . expected_hir_id )  { 
121125            for  ( _,  node)  in  self . cx . tcx . hir ( ) . parent_iter ( ex. hir_id )  { 
122126                match  node { 
@@ -138,50 +142,50 @@ impl<'tcx> Visitor<'_> for PeekableVisitor<'_, 'tcx> {
138142                                    return ; 
139143                                } 
140144
141-                                 for  arg in  args. iter ( ) . map ( |arg| peel_ref_operators ( self . cx ,  arg) )  { 
142-                                     if  let  ExprKind :: Path ( _)  = arg. kind 
143-                                         && let  Some ( ty)  = self 
144-                                             . cx 
145-                                             . typeck_results ( ) 
146-                                             . expr_ty_opt ( arg) 
147-                                             . map ( Ty :: peel_refs) 
148-                                         && match_type ( self . cx ,  ty,  & paths:: PEEKABLE ) 
149-                                     { 
150-                                         self . found_peek_call  = true ; 
151-                                         return ; 
152-                                     } 
145+                                 if  args. iter ( ) . any ( |arg| { 
146+                                     matches ! ( arg. kind,  ExprKind :: Path ( _) )  && arg_is_mut_peekable ( self . cx ,  arg) 
147+                                 } )  { 
148+                                     self . found_peek_call  = true ; 
149+                                     return ; 
153150                                } 
154151                            } , 
155-                             // Peekable::peek() 
156-                             ExprKind :: MethodCall ( PathSegment  {  ident :  method_name,  .. } ,  [ arg,  ..] ,  _)  => { 
157-                                 let  arg = peel_ref_operators ( self . cx ,  arg) ; 
158-                                 let  method_name = method_name. name . as_str ( ) ; 
159- 
160-                                 if  ( method_name == "peek" 
161-                                     || method_name == "peek_mut" 
162-                                     || method_name == "next_if" 
163-                                     || method_name == "next_if_eq" ) 
164-                                     && let  ExprKind :: Path ( _)  = arg. kind 
165-                                     && let  Some ( ty)  = self . cx . typeck_results ( ) . expr_ty_opt ( arg) . map ( Ty :: peel_refs) 
166-                                     && match_type ( self . cx ,  ty,  & paths:: PEEKABLE ) 
152+                             // Catch anything taking a Peekable mutably 
153+                             ExprKind :: MethodCall ( 
154+                                 PathSegment  {  ident :  method_name,  .. } , 
155+                                 [ self_arg,  remaining_args @ ..] , 
156+                                 _, 
157+                             )  => { 
158+                                 // `Peekable` methods 
159+                                 if  matches ! ( 
160+                                     method_name. name. as_str( ) , 
161+                                     "peek"  | "peek_mut"  | "next_if"  | "next_if_eq" 
162+                                 )  && arg_is_mut_peekable ( self . cx ,  self_arg) 
163+                                 { 
164+                                     self . found_peek_call  = true ; 
165+                                     return ; 
166+                                 } 
167+ 
168+                                 // foo.some_method() excluding Iterator methods 
169+                                 if  remaining_args. iter ( ) . any ( |arg| arg_is_mut_peekable ( self . cx ,  arg) ) 
170+                                     && !is_trait_method ( self . cx ,  expr,  sym:: Iterator ) 
167171                                { 
168172                                    self . found_peek_call  = true ; 
169173                                    return ; 
170174                                } 
175+ 
176+                                 return ; 
171177                            } , 
172-                             // Don't bother if moved into a struct 
173-                             ExprKind :: Struct ( ..)  => { 
178+                             ExprKind :: AddrOf ( _,  Mutability :: Mut ,  _)  | ExprKind :: Unary ( ..)  | ExprKind :: DropTemps ( _)  => { 
179+                             } , 
180+                             ExprKind :: AddrOf ( _,  Mutability :: Not ,  _)  => return , 
181+                             _ => { 
174182                                self . found_peek_call  = true ; 
175183                                return ; 
176184                            } , 
177-                             _ => { } , 
178185                        } 
179186                    } , 
180187                    Node :: Local ( Local  {  init :  Some ( init) ,  .. } )  => { 
181-                         if  let  Some ( ty)  = self . cx . typeck_results ( ) . expr_ty_opt ( init) 
182-                             && let  ( ty,  _,  Mutability :: Mut )  = peel_mid_ty_refs_is_mutable ( ty) 
183-                             && match_type ( self . cx ,  ty,  & paths:: PEEKABLE ) 
184-                         { 
188+                         if  arg_is_mut_peekable ( self . cx ,  init)  { 
185189                            self . found_peek_call  = true ; 
186190                            return ; 
187191                        } 
@@ -206,3 +210,14 @@ impl<'tcx> Visitor<'_> for PeekableVisitor<'_, 'tcx> {
206210        walk_expr ( self ,  ex) ; 
207211    } 
208212} 
213+ 
214+ fn  arg_is_mut_peekable ( cx :  & LateContext < ' _ > ,  arg :  & Expr < ' _ > )  -> bool  { 
215+     if  let  Some ( ty)  = cx. typeck_results ( ) . expr_ty_opt ( arg) 
216+         && let  ( ty,  _,  Mutability :: Mut )  = peel_mid_ty_refs_is_mutable ( ty) 
217+         && match_type ( cx,  ty,  & paths:: PEEKABLE ) 
218+     { 
219+         true 
220+     }  else  { 
221+         false 
222+     } 
223+ } 
0 commit comments