Skip to content

Commit

Permalink
add slice_iter_any lint
Browse files Browse the repository at this point in the history
  • Loading branch information
lapla-cogito committed Dec 22, 2024
1 parent 19357ca commit e964cbc
Show file tree
Hide file tree
Showing 16 changed files with 257 additions and 202 deletions.
1 change: 0 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6116,7 +6116,6 @@ Released 2018-09-13
[`unnecessary_first_then_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_first_then_check
[`unnecessary_fold`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_fold
[`unnecessary_get_then_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_get_then_check
[`unnecessary_iter_any`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_iter_any
[`unnecessary_join`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_join
[`unnecessary_lazy_evaluations`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_lazy_evaluations
[`unnecessary_literal_bound`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_literal_bound
Expand Down
1 change: 0 additions & 1 deletion clippy_lints/src/declared_lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,6 @@ pub static LINTS: &[&crate::LintInfo] = &[
crate::methods::UNNECESSARY_FIRST_THEN_CHECK_INFO,
crate::methods::UNNECESSARY_FOLD_INFO,
crate::methods::UNNECESSARY_GET_THEN_CHECK_INFO,
crate::methods::UNNECESSARY_ITER_ANY_INFO,
crate::methods::UNNECESSARY_JOIN_INFO,
crate::methods::UNNECESSARY_LAZY_EVALUATIONS_INFO,
crate::methods::UNNECESSARY_LITERAL_UNWRAP_INFO,
Expand Down
60 changes: 0 additions & 60 deletions clippy_lints/src/methods/iter_any.rs

This file was deleted.

34 changes: 5 additions & 29 deletions clippy_lints/src/methods/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ mod inspect_for_each;
mod into_iter_on_ref;
mod is_digit_ascii_radix;
mod is_empty;
mod iter_any;
mod iter_cloned_collect;
mod iter_count;
mod iter_filter;
Expand Down Expand Up @@ -101,6 +100,7 @@ mod single_char_add_str;
mod single_char_insert_string;
mod single_char_push_string;
mod skip_while_next;
mod slice_iter_any;
mod stable_sort_primitive;
mod str_split;
mod str_splitn;
Expand Down Expand Up @@ -4287,10 +4287,10 @@ declare_clippy_lint! {

declare_clippy_lint! {
/// ### What it does
/// Checks for usage of `iter().any()` on slices of `u8`/`i8` when it can be replaced with `contains()` and suggests doing so.
/// Checks for usage of `iter().any()` on numeric slices when it can be replaced with `contains()` and suggests doing so.
///
/// ### Why is this bad?
/// `contains()` on slices of `u8`/`i8` is faster than `iter().any()` in such cases.
/// `contains()` on numeric slices is faster than `iter().any()`.
///
/// ### Example
/// ```no_run
Expand All @@ -4307,30 +4307,7 @@ declare_clippy_lint! {
#[clippy::version = "1.85.0"]
pub SLICE_ITER_ANY,
perf,
"using `contains()` instead of `iter().any()` on `u8`/`i8` slices is more fast"
}

declare_clippy_lint! {
/// ### What it does
/// Checks for usage of `iter().any()` when it can be replaced with `contains()` and suggests doing so.
///
/// ### Why is this bad?
/// It makes the code less readable.
///
/// ### Example
/// ```no_run
/// let values = &[1, 2, 3];
/// let _ = values.iter().any(|&v| v == 2);
/// ```
/// Use instead:
/// ```no_run
/// let values = &[1, 2, 3];
/// let _ = values.contains(&2);
/// ```
#[clippy::version = "1.85.0"]
pub UNNECESSARY_ITER_ANY,
style,
"using `contains()` instead of `iter().any()` is more readable"
"detect use of `iter().any()` on numeric slices and suggest using `contains()`"
}

pub struct Methods {
Expand Down Expand Up @@ -4499,7 +4476,6 @@ impl_lint_pass!(Methods => [
MAP_WITH_UNUSED_ARGUMENT_OVER_RANGES,
UNNECESSARY_MAP_OR,
SLICE_ITER_ANY,
UNNECESSARY_ITER_ANY,
]);

/// Extracts a method call name, args, and `Span` of the method name.
Expand Down Expand Up @@ -4734,7 +4710,7 @@ impl Methods {
("any", [arg]) => {
unused_enumerate_index::check(cx, expr, recv, arg);
needless_character_iteration::check(cx, expr, recv, arg, false);
iter_any::check(cx, expr);
slice_iter_any::check(cx, expr, &self.msrv);
match method_call(recv) {
Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(
cx,
Expand Down
66 changes: 66 additions & 0 deletions clippy_lints/src/methods/slice_iter_any.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
use clippy_utils::diagnostics::span_lint;
use clippy_utils::msrvs::Msrv;
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::LateContext;
use rustc_middle::ty::{self};
use rustc_session::RustcVersion;
use rustc_span::source_map::Spanned;

use super::{SLICE_ITER_ANY, method_call};

pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) {
if !expr.span.from_expansion()
// any()
&& let Some((name, recv, args, _, _)) = method_call(expr)
&& name == "any"
// check if `iter().any()` can be replaced with `contains()`
&& args.len() == 1
&& let ExprKind::Closure(closure) = args[0].kind
&& let body = cx.tcx.hir().body(closure.body)
&& let ExprKind::Binary(op, lhs, rhs) = body.value.kind
&& can_replace_with_contains(op, lhs, rhs)
// iter()
&& let Some((name, recv, _, _, _)) = method_call(recv)
&& name == "iter"
{
let ref_type = cx.typeck_results().expr_ty_adjusted(recv);

match ref_type.kind() {
ty::Ref(_, inner_type, _) if inner_type.is_slice() => {
// check if the receiver is a numeric slice
if let ty::Slice(slice_type) = inner_type.kind()
&& ((slice_type.to_string() == "u8" || slice_type.to_string() == "i8")
|| (slice_type.is_numeric()
&& msrv.meets(RustcVersion {
major: 1,
minor: 84,
patch: 0,
})))
{
span_lint(
cx,
SLICE_ITER_ANY,
expr.span,
"using `contains()` instead of `iter().any()` is more efficient",
);
}
},
_ => {},
}
}
}

fn can_replace_with_contains(op: Spanned<BinOpKind>, lhs: &Expr<'_>, rhs: &Expr<'_>) -> bool {
matches!(
(op.node, &lhs.kind, &rhs.kind),
(
BinOpKind::Eq,
ExprKind::Path(_) | ExprKind::Unary(_, _),
ExprKind::Lit(_) | ExprKind::Path(_)
) | (
BinOpKind::Eq,
ExprKind::Lit(_),
ExprKind::Path(_) | ExprKind::Unary(_, _)
)
)
}
36 changes: 0 additions & 36 deletions tests/ui/iter_any.rs

This file was deleted.

38 changes: 0 additions & 38 deletions tests/ui/iter_any.stderr

This file was deleted.

15 changes: 8 additions & 7 deletions tests/ui/needless_collect.fixed
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
#![allow(unused, clippy::needless_if, clippy::suspicious_map, clippy::iter_count)]
#![allow(
unused,
clippy::needless_if,
clippy::suspicious_map,
clippy::iter_count,
clippy::slice_iter_any
)]

use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList};

#[warn(clippy::needless_collect)]
#[allow(
unused_variables,
clippy::unnecessary_iter_any,
clippy::iter_cloned_collect,
clippy::iter_next_slice
)]
#[allow(unused_variables, clippy::iter_cloned_collect, clippy::iter_next_slice)]
fn main() {
let sample = [1; 5];
let len = sample.iter().count();
Expand Down
15 changes: 8 additions & 7 deletions tests/ui/needless_collect.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
#![allow(unused, clippy::needless_if, clippy::suspicious_map, clippy::iter_count)]
#![allow(
unused,
clippy::needless_if,
clippy::suspicious_map,
clippy::iter_count,
clippy::slice_iter_any
)]

use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList};

#[warn(clippy::needless_collect)]
#[allow(
unused_variables,
clippy::unnecessary_iter_any,
clippy::iter_cloned_collect,
clippy::iter_next_slice
)]
#[allow(unused_variables, clippy::iter_cloned_collect, clippy::iter_next_slice)]
fn main() {
let sample = [1; 5];
let len = sample.iter().collect::<Vec<_>>().len();
Expand Down
Loading

0 comments on commit e964cbc

Please sign in to comment.