@@ -4,13 +4,15 @@ use rustc_hir::{
44 Expr , ExprKind ,
55} ;
66use rustc_lint:: LateContext ;
7- use rustc_middle:: { hir:: map:: Map , ty , ty :: Ty } ;
7+ use rustc_middle:: hir:: map:: Map ;
88use rustc_span:: source_map:: Span ;
99
10- use crate :: utils:: { match_trait_method, match_type, paths, snippet, span_lint_and_then} ;
11-
1210use if_chain:: if_chain;
1311
12+ use crate :: utils:: { has_iter_method, match_trait_method, paths, snippet, span_lint_and_then} ;
13+
14+ use super :: EXCESSIVE_FOR_EACH ;
15+
1416pub ( super ) fn lint ( cx : & LateContext < ' _ > , expr : & ' tcx Expr < ' _ > , args : & [ & [ Expr < ' _ > ] ] ) {
1517 if args. len ( ) < 2 {
1618 return ;
@@ -25,73 +27,40 @@ pub(super) fn lint(cx: &LateContext<'_>, expr: &'tcx Expr<'_>, args: &[&[Expr<'_
2527 let iter_receiver = & args[ 1 ] [ 0 ] ;
2628
2729 if_chain ! {
30+ if has_iter_method( cx, cx. typeck_results( ) . expr_ty( iter_receiver) ) . is_some( ) ;
2831 if match_trait_method( cx, expr, & paths:: ITERATOR ) ;
29- if is_target_ty( cx, cx. typeck_results( ) . expr_ty( iter_receiver) ) ;
3032 if let ExprKind :: Closure ( _, _, body_id, ..) = for_each_arg. kind;
3133 let body = cx. tcx. hir( ) . body( body_id) ;
3234 if let ExprKind :: Block ( ..) = body. value. kind;
3335 then {
3436 let mut ret_collector = RetCollector :: new( ) ;
3537 ret_collector. visit_expr( & body. value) ;
3638
37- // Skip the lint if `return` is used in `Loop` to avoid a suggest using `'label`.
39+ // Skip the lint if `return` is used in `Loop` in order not to suggest using `'label`.
3840 if ret_collector. ret_in_loop {
3941 return ;
4042 }
4143
42- let sugg =
43- format!( "for {} in {} {{ .. }}" , snippet( cx, body. params[ 0 ] . pat. span, "" ) , snippet( cx, for_each_receiver. span, "" ) ) ;
44-
45- let mut notes = vec![ ] ;
46- for span in ret_collector. spans {
47- let note = format!( "change `return` to `continue` in the loop body" ) ;
48- notes. push( ( span, note) ) ;
49- }
50-
51- span_lint_and_then( cx,
52- super :: EXCESSIVE_FOR_EACH ,
53- expr. span,
54- "excessive use of `for_each`" ,
55- |diag| {
56- diag. span_suggestion( expr. span, "try" , sugg, Applicability :: HasPlaceholders ) ;
57- for note in notes {
58- diag. span_note( note. 0 , & note. 1 ) ;
59- }
60- }
61- ) ;
62- }
63- }
64- }
65-
66- type PathSegment = & ' static [ & ' static str ] ;
67-
68- const TARGET_ITER_RECEIVER_TY : & [ PathSegment ] = & [
69- & paths:: VEC ,
70- & paths:: VEC_DEQUE ,
71- & paths:: LINKED_LIST ,
72- & paths:: HASHMAP ,
73- & paths:: BTREEMAP ,
74- & paths:: HASHSET ,
75- & paths:: BTREESET ,
76- & paths:: BINARY_HEAP ,
77- ] ;
78-
79- fn is_target_ty ( cx : & LateContext < ' _ > , expr_ty : Ty < ' _ > ) -> bool {
80- let expr_ty = expr_ty. peel_refs ( ) ;
81- for target in TARGET_ITER_RECEIVER_TY {
82- if match_type ( cx, expr_ty, target) {
83- return true ;
84- }
85- }
86-
87- if_chain ! {
88- if matches!( expr_ty. kind( ) , ty:: Slice ( _) | ty:: Array ( ..) ) ;
89- then {
90- return true ;
44+ let sugg = format!(
45+ "for {} in {} {{ .. }}" ,
46+ snippet( cx, body. params[ 0 ] . pat. span, "" ) ,
47+ snippet( cx, for_each_receiver. span, "" )
48+ ) ;
49+
50+ span_lint_and_then(
51+ cx,
52+ EXCESSIVE_FOR_EACH ,
53+ expr. span,
54+ "excessive use of `for_each`" ,
55+ |diag| {
56+ diag. span_suggestion( expr. span, "try" , sugg, Applicability :: HasPlaceholders ) ;
57+ for span in ret_collector. spans {
58+ diag. span_note( span, "change `return` to `continue` in the loop body" ) ;
59+ }
60+ }
61+ )
9162 }
9263 }
93-
94- false
9564}
9665
9766/// This type plays two roles.
0 commit comments