Skip to content

Commit 74b85a4

Browse files
committed
Refactor: Remove duplicated codes from excessive_for_each
1 parent fa1cc0e commit 74b85a4

File tree

1 file changed

+25
-56
lines changed

1 file changed

+25
-56
lines changed

clippy_lints/src/methods/excessive_for_each.rs

Lines changed: 25 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@ use rustc_hir::{
44
Expr, ExprKind,
55
};
66
use rustc_lint::LateContext;
7-
use rustc_middle::{hir::map::Map, ty, ty::Ty};
7+
use rustc_middle::hir::map::Map;
88
use rustc_span::source_map::Span;
99

10-
use crate::utils::{match_trait_method, match_type, paths, snippet, span_lint_and_then};
11-
1210
use 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+
1416
pub(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

Comments
 (0)