mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-23 07:14:28 +00:00
feat: unused_enumerate_index lint
This commit is contained in:
parent
7d34406015
commit
0b90f72064
@ -5561,6 +5561,7 @@ Released 2018-09-13
|
||||
[`unstable_as_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#unstable_as_slice
|
||||
[`unused_async`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_async
|
||||
[`unused_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_collect
|
||||
[`unused_enumerate_index`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_enumerate_index
|
||||
[`unused_format_specs`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_format_specs
|
||||
[`unused_io_amount`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_io_amount
|
||||
[`unused_label`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_label
|
||||
|
@ -274,6 +274,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
||||
crate::loops::NEVER_LOOP_INFO,
|
||||
crate::loops::SAME_ITEM_PUSH_INFO,
|
||||
crate::loops::SINGLE_ELEMENT_LOOP_INFO,
|
||||
crate::loops::UNUSED_ENUMERATE_INDEX_INFO,
|
||||
crate::loops::WHILE_IMMUTABLE_CONDITION_INFO,
|
||||
crate::loops::WHILE_LET_LOOP_INFO,
|
||||
crate::loops::WHILE_LET_ON_ITERATOR_INFO,
|
||||
|
@ -14,6 +14,7 @@ mod needless_range_loop;
|
||||
mod never_loop;
|
||||
mod same_item_push;
|
||||
mod single_element_loop;
|
||||
mod unused_enumerate_index;
|
||||
mod utils;
|
||||
mod while_immutable_condition;
|
||||
mod while_let_loop;
|
||||
@ -577,6 +578,33 @@ declare_clippy_lint! {
|
||||
"manual implementation of `Iterator::find`"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for `for (_, v) in a.iter().enumerate()`
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// The index from `.enumerate()` is immediately dropped.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// let v = vec![1, 2, 3, 4];
|
||||
/// for (_, x) in v.iter().enumerate() {
|
||||
/// print!("{x}")
|
||||
/// }
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// let v = vec![1, 2, 3, 4];
|
||||
/// for x in v.iter() {
|
||||
/// print!("{x}")
|
||||
/// }
|
||||
/// ```
|
||||
#[clippy::version = "1.69.0"]
|
||||
pub UNUSED_ENUMERATE_INDEX,
|
||||
style,
|
||||
"using .enumerate() and immediately dropping the index"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Looks for loops that check for emptiness of a `Vec` in the condition and pop an element
|
||||
@ -619,6 +647,7 @@ impl Loops {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_lint_pass!(Loops => [
|
||||
MANUAL_MEMCPY,
|
||||
MANUAL_FLATTEN,
|
||||
@ -638,7 +667,8 @@ impl_lint_pass!(Loops => [
|
||||
SINGLE_ELEMENT_LOOP,
|
||||
MISSING_SPIN_LOOP,
|
||||
MANUAL_FIND,
|
||||
MANUAL_WHILE_LET_SOME
|
||||
MANUAL_WHILE_LET_SOME,
|
||||
UNUSED_ENUMERATE_INDEX,
|
||||
]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for Loops {
|
||||
@ -717,6 +747,7 @@ impl Loops {
|
||||
same_item_push::check(cx, pat, arg, body, expr);
|
||||
manual_flatten::check(cx, pat, arg, body, span);
|
||||
manual_find::check(cx, pat, arg, body, span, expr);
|
||||
unused_enumerate_index::check(cx, pat, arg, body);
|
||||
}
|
||||
|
||||
fn check_for_loop_arg(&self, cx: &LateContext<'_>, _: &Pat<'_>, arg: &Expr<'_>) {
|
||||
|
75
clippy_lints/src/loops/unused_enumerate_index.rs
Normal file
75
clippy_lints/src/loops/unused_enumerate_index.rs
Normal file
@ -0,0 +1,75 @@
|
||||
use super::UNUSED_ENUMERATE_INDEX;
|
||||
use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::sugg;
|
||||
use clippy_utils::visitors::is_local_used;
|
||||
use rustc_hir::{Expr, ExprKind, Pat, PatKind};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty;
|
||||
|
||||
/// Checks for the `UNUSED_ENUMERATE_INDEX` lint.
|
||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx Expr<'_>, body: &'tcx Expr<'_>) {
|
||||
let pat_span = pat.span;
|
||||
|
||||
let PatKind::Tuple(pat, _) = pat.kind else {
|
||||
return;
|
||||
};
|
||||
|
||||
if pat.len() != 2 {
|
||||
return;
|
||||
}
|
||||
|
||||
let arg_span = arg.span;
|
||||
|
||||
let ExprKind::MethodCall(method, self_arg, [], _) = arg.kind else {
|
||||
return;
|
||||
};
|
||||
|
||||
if method.ident.as_str() != "enumerate" {
|
||||
return;
|
||||
}
|
||||
|
||||
let ty = cx.typeck_results().expr_ty(arg);
|
||||
|
||||
if !pat_is_wild(cx, &pat[0].kind, body) {
|
||||
return;
|
||||
}
|
||||
|
||||
let new_pat_span = pat[1].span;
|
||||
|
||||
let name = match *ty.kind() {
|
||||
ty::Adt(base, _substs) => cx.tcx.def_path_str(base.did()),
|
||||
_ => return,
|
||||
};
|
||||
|
||||
if name != "std::iter::Enumerate" && name != "core::iter::Enumerate" {
|
||||
return;
|
||||
}
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
UNUSED_ENUMERATE_INDEX,
|
||||
arg_span,
|
||||
"you seem to use `.enumerate()` and immediately discard the index",
|
||||
|diag| {
|
||||
let base_iter = sugg::Sugg::hir(cx, self_arg, "base iter");
|
||||
multispan_sugg(
|
||||
diag,
|
||||
"remove the `.enumerate()` call",
|
||||
vec![
|
||||
(pat_span, snippet(cx, new_pat_span, "value").into_owned()),
|
||||
(arg_span, base_iter.to_string()),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Returns `true` if the pattern is a `PatWild` or an ident prefixed with `_`.
|
||||
fn pat_is_wild<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx PatKind<'_>, body: &'tcx Expr<'_>) -> bool {
|
||||
match *pat {
|
||||
PatKind::Wild => true,
|
||||
PatKind::Binding(_, id, ident, None) if ident.as_str().starts_with('_') => !is_local_used(cx, body, id),
|
||||
_ => false,
|
||||
}
|
||||
}
|
10
tests/ui/unused_enumerate_index.fixed
Normal file
10
tests/ui/unused_enumerate_index.fixed
Normal file
@ -0,0 +1,10 @@
|
||||
// run-rustfix
|
||||
#![allow(unused)]
|
||||
#![warn(clippy::unused_enumerate_index)]
|
||||
|
||||
fn main() {
|
||||
let v = [1, 2, 3];
|
||||
for x in v.iter() {
|
||||
print!("{x}");
|
||||
}
|
||||
}
|
10
tests/ui/unused_enumerate_index.rs
Normal file
10
tests/ui/unused_enumerate_index.rs
Normal file
@ -0,0 +1,10 @@
|
||||
// run-rustfix
|
||||
#![allow(unused)]
|
||||
#![warn(clippy::unused_enumerate_index)]
|
||||
|
||||
fn main() {
|
||||
let v = [1, 2, 3];
|
||||
for (_, x) in v.iter().enumerate() {
|
||||
print!("{x}");
|
||||
}
|
||||
}
|
15
tests/ui/unused_enumerate_index.stderr
Normal file
15
tests/ui/unused_enumerate_index.stderr
Normal file
@ -0,0 +1,15 @@
|
||||
error: you seem to use `.enumerate()` and immediately discard the index
|
||||
--> $DIR/unused_enumerate_index.rs:7:19
|
||||
|
|
||||
LL | for (_, x) in v.iter().enumerate() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::unused-enumerate-index` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(clippy::unused_enumerate_index)]`
|
||||
help: remove the `.enumerate()` call
|
||||
|
|
||||
LL | for x in v.iter() {
|
||||
| ~ ~~~~~~~~
|
||||
|
||||
error: aborting due to previous error
|
||||
|
Loading…
Reference in New Issue
Block a user