Skip to content

Commit 31d8210

Browse files
authored
unused_enumerate_index: move to loops lint pass (#15279)
Needed to split the lint crate. Both the method and loop versions of the lint should also behave the same now. changelog: None
2 parents 7562179 + ce6f8bc commit 31d8210

File tree

5 files changed

+107
-201
lines changed

5 files changed

+107
-201
lines changed

clippy_lints/src/loops/mod.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -880,6 +880,15 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
880880
missing_spin_loop::check(cx, condition, body);
881881
manual_while_let_some::check(cx, condition, body, span);
882882
}
883+
884+
if let ExprKind::MethodCall(path, recv, [arg], _) = expr.kind
885+
&& matches!(
886+
path.ident.name,
887+
sym::all | sym::any | sym::filter_map | sym::find_map | sym::flat_map | sym::for_each | sym::map
888+
)
889+
{
890+
unused_enumerate_index::check_method(cx, expr, recv, arg);
891+
}
883892
}
884893
}
885894

@@ -908,7 +917,7 @@ impl Loops {
908917
same_item_push::check(cx, pat, arg, body, expr, self.msrv);
909918
manual_flatten::check(cx, pat, arg, body, span, self.msrv);
910919
manual_find::check(cx, pat, arg, body, span, expr);
911-
unused_enumerate_index::check(cx, pat, arg, body);
920+
unused_enumerate_index::check(cx, arg, pat, None, body);
912921
char_indices_as_byte_indices::check(cx, pat, arg, body);
913922
}
914923

Lines changed: 70 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,87 @@
11
use super::UNUSED_ENUMERATE_INDEX;
2-
use clippy_utils::diagnostics::span_lint_and_then;
3-
use clippy_utils::res::MaybeDef;
4-
use clippy_utils::source::snippet;
5-
use clippy_utils::{pat_is_wild, sugg};
2+
use clippy_utils::diagnostics::span_lint_hir_and_then;
3+
use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
4+
use clippy_utils::source::{SpanRangeExt, walk_span_to_context};
5+
use clippy_utils::{expr_or_init, pat_is_wild};
66
use rustc_errors::Applicability;
7-
use rustc_hir::def::DefKind;
8-
use rustc_hir::{Expr, ExprKind, Pat, PatKind};
7+
use rustc_hir::{Expr, ExprKind, Pat, PatKind, TyKind};
98
use rustc_lint::LateContext;
10-
use rustc_span::sym;
9+
use rustc_span::{Span, SyntaxContext, sym};
1110

12-
/// Checks for the `UNUSED_ENUMERATE_INDEX` lint.
13-
///
14-
/// The lint is also partially implemented in `clippy_lints/src/methods/unused_enumerate_index.rs`.
15-
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>, arg: &Expr<'_>, body: &'tcx Expr<'tcx>) {
16-
if let PatKind::Tuple([index, elem], _) = pat.kind
17-
&& let ExprKind::MethodCall(_method, self_arg, [], _) = arg.kind
18-
&& let ty = cx.typeck_results().expr_ty(arg)
19-
&& pat_is_wild(cx, &index.kind, body)
20-
&& ty.is_diag_item(cx, sym::Enumerate)
21-
&& let Some((DefKind::AssocFn, call_id)) = cx.typeck_results().type_dependent_def(arg.hir_id)
22-
&& cx.tcx.is_diagnostic_item(sym::enumerate_method, call_id)
11+
pub(super) fn check<'tcx>(
12+
cx: &LateContext<'tcx>,
13+
iter_expr: &'tcx Expr<'tcx>,
14+
pat: &Pat<'tcx>,
15+
ty_spans: Option<(Span, Span)>,
16+
body: &'tcx Expr<'tcx>,
17+
) {
18+
if let PatKind::Tuple([idx_pat, inner_pat], _) = pat.kind
19+
&& cx.typeck_results().expr_ty(iter_expr).is_diag_item(cx, sym::Enumerate)
20+
&& pat_is_wild(cx, &idx_pat.kind, body)
21+
&& let enumerate_call = expr_or_init(cx, iter_expr)
22+
&& let ExprKind::MethodCall(_, _, [], enumerate_span) = enumerate_call.kind
23+
&& let Some(enumerate_id) = cx.typeck_results().type_dependent_def_id(enumerate_call.hir_id)
24+
&& cx.tcx.is_diagnostic_item(sym::enumerate_method, enumerate_id)
25+
&& !enumerate_call.span.from_expansion()
26+
&& !pat.span.from_expansion()
27+
&& !idx_pat.span.from_expansion()
28+
&& !inner_pat.span.from_expansion()
29+
&& let Some(enumerate_range) = enumerate_span.map_range(cx, |_, text, range| {
30+
text.get(..range.start)?
31+
.ends_with('.')
32+
.then_some(range.start - 1..range.end)
33+
})
2334
{
24-
span_lint_and_then(
35+
let enumerate_span = Span::new(enumerate_range.start, enumerate_range.end, SyntaxContext::root(), None);
36+
span_lint_hir_and_then(
2537
cx,
2638
UNUSED_ENUMERATE_INDEX,
27-
arg.span,
39+
enumerate_call.hir_id,
40+
enumerate_span,
2841
"you seem to use `.enumerate()` and immediately discard the index",
2942
|diag| {
30-
let base_iter = sugg::Sugg::hir(cx, self_arg, "base iter");
43+
let mut spans = Vec::with_capacity(5);
44+
spans.push((enumerate_span, String::new()));
45+
spans.push((pat.span.with_hi(inner_pat.span.lo()), String::new()));
46+
spans.push((pat.span.with_lo(inner_pat.span.hi()), String::new()));
47+
if let Some((outer, inner)) = ty_spans {
48+
spans.push((outer.with_hi(inner.lo()), String::new()));
49+
spans.push((outer.with_lo(inner.hi()), String::new()));
50+
}
3151
diag.multipart_suggestion(
3252
"remove the `.enumerate()` call",
33-
vec![
34-
(pat.span, snippet(cx, elem.span, "..").into_owned()),
35-
(arg.span, base_iter.to_string()),
36-
],
53+
spans,
3754
Applicability::MachineApplicable,
3855
);
3956
},
4057
);
4158
}
4259
}
60+
61+
pub(super) fn check_method<'tcx>(
62+
cx: &LateContext<'tcx>,
63+
e: &'tcx Expr<'tcx>,
64+
recv: &'tcx Expr<'tcx>,
65+
arg: &'tcx Expr<'tcx>,
66+
) {
67+
if let ExprKind::Closure(closure) = arg.kind
68+
&& let body = cx.tcx.hir_body(closure.body)
69+
&& let [param] = body.params
70+
&& cx.ty_based_def(e).opt_parent(cx).is_diag_item(cx, sym::Iterator)
71+
&& let [input] = closure.fn_decl.inputs
72+
&& !arg.span.from_expansion()
73+
&& !input.span.from_expansion()
74+
&& !recv.span.from_expansion()
75+
&& !param.span.from_expansion()
76+
{
77+
let ty_spans = if let TyKind::Tup([_, inner]) = input.kind {
78+
let Some(inner) = walk_span_to_context(inner.span, SyntaxContext::root()) else {
79+
return;
80+
};
81+
Some((input.span, inner))
82+
} else {
83+
None
84+
};
85+
check(cx, recv, param.pat, ty_spans, body.value);
86+
}
87+
}

clippy_lints/src/methods/mod.rs

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,6 @@ mod unnecessary_option_map_or_else;
138138
mod unnecessary_result_map_or_else;
139139
mod unnecessary_sort_by;
140140
mod unnecessary_to_owned;
141-
mod unused_enumerate_index;
142141
mod unwrap_expect_used;
143142
mod useless_asref;
144143
mod useless_nonzero_new_unchecked;
@@ -5026,7 +5025,6 @@ impl Methods {
50265025
zst_offset::check(cx, expr, recv);
50275026
},
50285027
(sym::all, [arg]) => {
5029-
unused_enumerate_index::check(cx, expr, recv, arg);
50305028
needless_character_iteration::check(cx, expr, recv, arg, true);
50315029
match method_call(recv) {
50325030
Some((sym::cloned, recv2, [], _, _)) => {
@@ -5056,7 +5054,6 @@ impl Methods {
50565054
}
50575055
},
50585056
(sym::any, [arg]) => {
5059-
unused_enumerate_index::check(cx, expr, recv, arg);
50605057
needless_character_iteration::check(cx, expr, recv, arg, false);
50615058
match method_call(recv) {
50625059
Some((sym::cloned, recv2, [], _, _)) => iter_overeager_cloned::check(
@@ -5216,7 +5213,6 @@ impl Methods {
52165213
}
52175214
},
52185215
(sym::filter_map, [arg]) => {
5219-
unused_enumerate_index::check(cx, expr, recv, arg);
52205216
unnecessary_filter_map::check(cx, expr, arg, call_span, unnecessary_filter_map::Kind::FilterMap);
52215217
filter_map_bool_then::check(cx, expr, arg, call_span);
52225218
filter_map_identity::check(cx, expr, arg, span);
@@ -5231,11 +5227,9 @@ impl Methods {
52315227
);
52325228
},
52335229
(sym::find_map, [arg]) => {
5234-
unused_enumerate_index::check(cx, expr, recv, arg);
52355230
unnecessary_filter_map::check(cx, expr, arg, call_span, unnecessary_filter_map::Kind::FindMap);
52365231
},
52375232
(sym::flat_map, [arg]) => {
5238-
unused_enumerate_index::check(cx, expr, recv, arg);
52395233
flat_map_identity::check(cx, expr, arg, span);
52405234
flat_map_option::check(cx, expr, arg, span);
52415235
lines_filter_map_ok::check_filter_or_flat_map(
@@ -5263,20 +5257,17 @@ impl Methods {
52635257
manual_try_fold::check(cx, expr, init, acc, call_span, self.msrv);
52645258
unnecessary_fold::check(cx, expr, init, acc, span);
52655259
},
5266-
(sym::for_each, [arg]) => {
5267-
unused_enumerate_index::check(cx, expr, recv, arg);
5268-
match method_call(recv) {
5269-
Some((sym::inspect, _, [_], span2, _)) => inspect_for_each::check(cx, expr, span2),
5270-
Some((sym::cloned, recv2, [], _, _)) => iter_overeager_cloned::check(
5271-
cx,
5272-
expr,
5273-
recv,
5274-
recv2,
5275-
iter_overeager_cloned::Op::NeedlessMove(arg),
5276-
false,
5277-
),
5278-
_ => {},
5279-
}
5260+
(sym::for_each, [arg]) => match method_call(recv) {
5261+
Some((sym::inspect, _, [_], span2, _)) => inspect_for_each::check(cx, expr, span2),
5262+
Some((sym::cloned, recv2, [], _, _)) => iter_overeager_cloned::check(
5263+
cx,
5264+
expr,
5265+
recv,
5266+
recv2,
5267+
iter_overeager_cloned::Op::NeedlessMove(arg),
5268+
false,
5269+
),
5270+
_ => {},
52805271
},
52815272
(sym::get, [arg]) => {
52825273
get_first::check(cx, expr, recv, arg);
@@ -5337,7 +5328,6 @@ impl Methods {
53375328
},
53385329
(name @ (sym::map | sym::map_err), [m_arg]) => {
53395330
if name == sym::map {
5340-
unused_enumerate_index::check(cx, expr, recv, m_arg);
53415331
map_clone::check(cx, expr, recv, m_arg, self.msrv);
53425332
map_with_unused_argument_over_ranges::check(cx, expr, recv, m_arg, self.msrv, span);
53435333
manual_is_variant_and::check_map(cx, expr);

clippy_lints/src/methods/unused_enumerate_index.rs

Lines changed: 0 additions & 138 deletions
This file was deleted.

0 commit comments

Comments
 (0)