@@ -4,13 +4,15 @@ use rustc_hir::{
4
4
Expr , ExprKind ,
5
5
} ;
6
6
use rustc_lint:: LateContext ;
7
- use rustc_middle:: { hir:: map:: Map , ty , ty :: Ty } ;
7
+ use rustc_middle:: hir:: map:: Map ;
8
8
use rustc_span:: source_map:: Span ;
9
9
10
- use crate :: utils:: { match_trait_method, match_type, paths, snippet, span_lint_and_then} ;
11
-
12
10
use if_chain:: if_chain;
13
11
12
+ use crate :: utils:: { has_iter_method, match_trait_method, paths, snippet, span_lint_and_then} ;
13
+
14
+ use super :: EXCESSIVE_FOR_EACH ;
15
+
14
16
pub ( super ) fn lint ( cx : & LateContext < ' _ > , expr : & ' tcx Expr < ' _ > , args : & [ & [ Expr < ' _ > ] ] ) {
15
17
if args. len ( ) < 2 {
16
18
return ;
@@ -25,73 +27,40 @@ pub(super) fn lint(cx: &LateContext<'_>, expr: &'tcx Expr<'_>, args: &[&[Expr<'_
25
27
let iter_receiver = & args[ 1 ] [ 0 ] ;
26
28
27
29
if_chain ! {
30
+ if has_iter_method( cx, cx. typeck_results( ) . expr_ty( iter_receiver) ) . is_some( ) ;
28
31
if match_trait_method( cx, expr, & paths:: ITERATOR ) ;
29
- if is_target_ty( cx, cx. typeck_results( ) . expr_ty( iter_receiver) ) ;
30
32
if let ExprKind :: Closure ( _, _, body_id, ..) = for_each_arg. kind;
31
33
let body = cx. tcx. hir( ) . body( body_id) ;
32
34
if let ExprKind :: Block ( ..) = body. value. kind;
33
35
then {
34
36
let mut ret_collector = RetCollector :: new( ) ;
35
37
ret_collector. visit_expr( & body. value) ;
36
38
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`.
38
40
if ret_collector. ret_in_loop {
39
41
return ;
40
42
}
41
43
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
+ )
91
62
}
92
63
}
93
-
94
- false
95
64
}
96
65
97
66
/// This type plays two roles.
0 commit comments