@@ -3,8 +3,9 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
33use clippy_utils:: source:: { snippet, snippet_with_applicability} ;
44use clippy_utils:: sugg:: Sugg ;
55use clippy_utils:: ty:: is_type_diagnostic_item;
6- use clippy_utils:: { can_move_expr_to_closure, is_trait_method, path_to_local_id, CaptureKind } ;
6+ use clippy_utils:: { can_move_expr_to_closure, is_trait_method, path_to_local , path_to_local_id, CaptureKind } ;
77use if_chain:: if_chain;
8+ use rustc_data_structures:: fx:: FxHashMap ;
89use rustc_errors:: Applicability ;
910use rustc_hir:: intravisit:: { walk_block, walk_expr, NestedVisitorMap , Visitor } ;
1011use rustc_hir:: { Block , Expr , ExprKind , HirId , HirIdSet , Local , Mutability , Node , PatKind , Stmt , StmtKind } ;
@@ -174,15 +175,23 @@ struct IterFunctionVisitor<'b, 'a> {
174175 illegal_mutable_capture_ids : HirIdSet ,
175176 current_mutably_captured_ids : HirIdSet ,
176177 cx : & ' a LateContext < ' b > ,
177- uses : Vec < IterFunction > ,
178+ uses : Vec < Option < IterFunction > > ,
179+ hir_id_uses_map : FxHashMap < HirId , usize > ,
180+ current_statement_hir_id : Option < HirId > ,
178181 seen_other : bool ,
179182 target : HirId ,
180183}
181184impl < ' tcx > Visitor < ' tcx > for IterFunctionVisitor < ' _ , ' tcx > {
182185 fn visit_block ( & mut self , block : & ' txc Block < ' tcx > ) {
183- for elem in block. stmts . iter ( ) . filter_map ( get_expr_from_stmt) . chain ( block. expr ) {
184- self . current_mutably_captured_ids = HirIdSet :: default ( ) ;
185- self . visit_expr ( elem) ;
186+ for ( expr, hir_id) in block
187+ . stmts
188+ . iter ( )
189+ . filter_map ( get_expr_and_hir_id_from_stmt)
190+ . chain ( block. expr . map ( |expr| ( expr, None ) ) )
191+ {
192+ self . current_statement_hir_id = hir_id;
193+ self . current_mutably_captured_ids = get_captured_ids ( self . cx , self . cx . typeck_results ( ) . expr_ty ( expr) ) ;
194+ self . visit_expr ( expr) ;
186195 }
187196 }
188197
@@ -202,28 +211,53 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> {
202211 . next ( )
203212 . is_none ( )
204213 {
214+ if let Some ( hir_id) = self . current_statement_hir_id {
215+ self . hir_id_uses_map . insert ( hir_id, self . uses . len ( ) ) ;
216+ }
205217 match & * method_name. ident . name . as_str ( ) {
206- "into_iter" => self . uses . push ( IterFunction {
218+ "into_iter" => self . uses . push ( Some ( IterFunction {
207219 func : IterFunctionKind :: IntoIter ,
208220 span : expr. span ,
209- } ) ,
210- "len" => self . uses . push ( IterFunction {
221+ } ) ) ,
222+ "len" => self . uses . push ( Some ( IterFunction {
211223 func : IterFunctionKind :: Len ,
212224 span : expr. span ,
213- } ) ,
214- "is_empty" => self . uses . push ( IterFunction {
225+ } ) ) ,
226+ "is_empty" => self . uses . push ( Some ( IterFunction {
215227 func : IterFunctionKind :: IsEmpty ,
216228 span : expr. span ,
217- } ) ,
218- "contains" => self . uses . push ( IterFunction {
229+ } ) ) ,
230+ "contains" => self . uses . push ( Some ( IterFunction {
219231 func : IterFunctionKind :: Contains ( args[ 0 ] . span ) ,
220232 span : expr. span ,
221- } ) ,
222- _ => self . seen_other = true ,
233+ } ) ) ,
234+ _ => {
235+ self . seen_other = true ;
236+ if let Some ( hir_id) = self . current_statement_hir_id {
237+ self . hir_id_uses_map . remove ( & hir_id) ;
238+ }
239+ } ,
223240 }
224241 }
225242 return ;
226243 }
244+
245+ if let Some ( hir_id) = path_to_local ( recv) {
246+ if let Some ( index) = self . hir_id_uses_map . remove ( & hir_id) {
247+ if self
248+ . illegal_mutable_capture_ids
249+ . intersection ( & self . current_mutably_captured_ids )
250+ . next ( )
251+ . is_none ( )
252+ {
253+ if let Some ( hir_id) = self . current_statement_hir_id {
254+ self . hir_id_uses_map . insert ( hir_id, index) ;
255+ }
256+ } else {
257+ self . uses [ index] = None ;
258+ }
259+ }
260+ }
227261 }
228262 // Check if the collection is used for anything else
229263 if path_to_local_id ( expr, self . target ) {
@@ -239,11 +273,17 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> {
239273 }
240274}
241275
242- fn get_expr_from_stmt < ' v > ( stmt : & ' v Stmt < ' v > ) -> Option < & ' v Expr < ' v > > {
276+ fn get_expr_and_hir_id_from_stmt < ' v > ( stmt : & ' v Stmt < ' v > ) -> Option < ( & ' v Expr < ' v > , Option < HirId > ) > {
243277 match stmt. kind {
244- StmtKind :: Expr ( expr) | StmtKind :: Semi ( expr) => Some ( expr) ,
278+ StmtKind :: Expr ( expr) | StmtKind :: Semi ( expr) => Some ( ( expr, None ) ) ,
245279 StmtKind :: Item ( ..) => None ,
246- StmtKind :: Local ( Local { init, .. } ) => * init,
280+ StmtKind :: Local ( Local { init, pat, .. } ) => {
281+ if let PatKind :: Binding ( _, hir_id, ..) = pat. kind {
282+ init. map ( |init_expr| ( init_expr, Some ( hir_id) ) )
283+ } else {
284+ init. map ( |init_expr| ( init_expr, None ) )
285+ }
286+ } ,
247287 }
248288}
249289
@@ -284,9 +324,15 @@ fn detect_iter_and_into_iters<'tcx: 'a, 'a>(
284324 cx,
285325 current_mutably_captured_ids : HirIdSet :: default ( ) ,
286326 illegal_mutable_capture_ids : captured_ids,
327+ hir_id_uses_map : FxHashMap :: default ( ) ,
328+ current_statement_hir_id : None ,
287329 } ;
288330 visitor. visit_block ( block) ;
289- if visitor. seen_other { None } else { Some ( visitor. uses ) }
331+ if visitor. seen_other {
332+ None
333+ } else {
334+ Some ( visitor. uses . into_iter ( ) . flatten ( ) . collect ( ) )
335+ }
290336}
291337
292338#[ allow( rustc:: usage_of_ty_tykind) ]
0 commit comments