Skip to content

Commit d54475b

Browse files
committed
add slice_iter_any lint
1 parent 19357ca commit d54475b

16 files changed

+240
-202
lines changed

CHANGELOG.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6116,7 +6116,6 @@ Released 2018-09-13
61166116
[`unnecessary_first_then_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_first_then_check
61176117
[`unnecessary_fold`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_fold
61186118
[`unnecessary_get_then_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_get_then_check
6119-
[`unnecessary_iter_any`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_iter_any
61206119
[`unnecessary_join`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_join
61216120
[`unnecessary_lazy_evaluations`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_lazy_evaluations
61226121
[`unnecessary_literal_bound`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_literal_bound

clippy_lints/src/declared_lints.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -483,7 +483,6 @@ pub static LINTS: &[&crate::LintInfo] = &[
483483
crate::methods::UNNECESSARY_FIRST_THEN_CHECK_INFO,
484484
crate::methods::UNNECESSARY_FOLD_INFO,
485485
crate::methods::UNNECESSARY_GET_THEN_CHECK_INFO,
486-
crate::methods::UNNECESSARY_ITER_ANY_INFO,
487486
crate::methods::UNNECESSARY_JOIN_INFO,
488487
crate::methods::UNNECESSARY_LAZY_EVALUATIONS_INFO,
489488
crate::methods::UNNECESSARY_LITERAL_UNWRAP_INFO,

clippy_lints/src/methods/iter_any.rs

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

clippy_lints/src/methods/mod.rs

Lines changed: 5 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ mod inspect_for_each;
3737
mod into_iter_on_ref;
3838
mod is_digit_ascii_radix;
3939
mod is_empty;
40-
mod iter_any;
4140
mod iter_cloned_collect;
4241
mod iter_count;
4342
mod iter_filter;
@@ -101,6 +100,7 @@ mod single_char_add_str;
101100
mod single_char_insert_string;
102101
mod single_char_push_string;
103102
mod skip_while_next;
103+
mod slice_iter_any;
104104
mod stable_sort_primitive;
105105
mod str_split;
106106
mod str_splitn;
@@ -4287,10 +4287,10 @@ declare_clippy_lint! {
42874287

42884288
declare_clippy_lint! {
42894289
/// ### What it does
4290-
/// Checks for usage of `iter().any()` on slices of `u8`/`i8` when it can be replaced with `contains()` and suggests doing so.
4290+
/// Checks for usage of `iter().any()` on numeric slices when it can be replaced with `contains()` and suggests doing so.
42914291
///
42924292
/// ### Why is this bad?
4293-
/// `contains()` on slices of `u8`/`i8` is faster than `iter().any()` in such cases.
4293+
/// `contains()` on numeric slices is faster than `iter().any()`.
42944294
///
42954295
/// ### Example
42964296
/// ```no_run
@@ -4307,30 +4307,7 @@ declare_clippy_lint! {
43074307
#[clippy::version = "1.85.0"]
43084308
pub SLICE_ITER_ANY,
43094309
perf,
4310-
"using `contains()` instead of `iter().any()` on `u8`/`i8` slices is more fast"
4311-
}
4312-
4313-
declare_clippy_lint! {
4314-
/// ### What it does
4315-
/// Checks for usage of `iter().any()` when it can be replaced with `contains()` and suggests doing so.
4316-
///
4317-
/// ### Why is this bad?
4318-
/// It makes the code less readable.
4319-
///
4320-
/// ### Example
4321-
/// ```no_run
4322-
/// let values = &[1, 2, 3];
4323-
/// let _ = values.iter().any(|&v| v == 2);
4324-
/// ```
4325-
/// Use instead:
4326-
/// ```no_run
4327-
/// let values = &[1, 2, 3];
4328-
/// let _ = values.contains(&2);
4329-
/// ```
4330-
#[clippy::version = "1.85.0"]
4331-
pub UNNECESSARY_ITER_ANY,
4332-
style,
4333-
"using `contains()` instead of `iter().any()` is more readable"
4310+
"detect use of `iter().any()` on numeric slices and suggest using `contains()`"
43344311
}
43354312

43364313
pub struct Methods {
@@ -4499,7 +4476,6 @@ impl_lint_pass!(Methods => [
44994476
MAP_WITH_UNUSED_ARGUMENT_OVER_RANGES,
45004477
UNNECESSARY_MAP_OR,
45014478
SLICE_ITER_ANY,
4502-
UNNECESSARY_ITER_ANY,
45034479
]);
45044480

45054481
/// Extracts a method call name, args, and `Span` of the method name.
@@ -4734,7 +4710,7 @@ impl Methods {
47344710
("any", [arg]) => {
47354711
unused_enumerate_index::check(cx, expr, recv, arg);
47364712
needless_character_iteration::check(cx, expr, recv, arg, false);
4737-
iter_any::check(cx, expr);
4713+
slice_iter_any::check(cx, expr, &self.msrv);
47384714
match method_call(recv) {
47394715
Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(
47404716
cx,
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
use clippy_utils::diagnostics::span_lint;
2+
use clippy_utils::msrvs::Msrv;
3+
use rustc_hir::{BinOpKind, Expr, ExprKind};
4+
use rustc_lint::LateContext;
5+
use rustc_middle::ty::{self};
6+
use rustc_session::RustcVersion;
7+
use rustc_span::source_map::Spanned;
8+
9+
use super::{SLICE_ITER_ANY, method_call};
10+
11+
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) {
12+
if !expr.span.from_expansion()
13+
// any()
14+
&& let Some((name, recv, args, _, _)) = method_call(expr)
15+
&& name == "any"
16+
// check if `iter().any()` can be replaced with `contains()`
17+
&& args.len() == 1
18+
&& let ExprKind::Closure(closure) = args[0].kind
19+
&& let body = cx.tcx.hir().body(closure.body)
20+
&& let ExprKind::Binary(op, lhs, rhs) = body.value.kind
21+
&& can_replace_with_contains(op, lhs, rhs)
22+
// iter()
23+
&& let Some((name, recv, _, _, _)) = method_call(recv)
24+
&& name == "iter"
25+
{
26+
let ref_type = cx.typeck_results().expr_ty_adjusted(recv);
27+
28+
match ref_type.kind() {
29+
ty::Ref(_, inner_type, _) if inner_type.is_slice() => {
30+
// check if the receiver is a numeric slice
31+
if let ty::Slice(slice_type) = inner_type.kind()
32+
&& ((slice_type.to_string() == "u8" || slice_type.to_string() == "i8")
33+
|| (slice_type.is_numeric()
34+
&& msrv.meets(RustcVersion {
35+
major: 1,
36+
minor: 84,
37+
patch: 0,
38+
})))
39+
{
40+
span_lint(
41+
cx,
42+
SLICE_ITER_ANY,
43+
expr.span,
44+
"using `contains()` instead of `iter().any()` is more efficient",
45+
);
46+
}
47+
},
48+
_ => {},
49+
}
50+
}
51+
}
52+
53+
fn can_replace_with_contains(op: Spanned<BinOpKind>, lhs: &Expr<'_>, rhs: &Expr<'_>) -> bool {
54+
matches!(
55+
(op.node, &lhs.kind, &rhs.kind),
56+
(BinOpKind::Eq, ExprKind::Path(_), ExprKind::Lit(_) | ExprKind::Path(_))
57+
| (BinOpKind::Eq, ExprKind::Lit(_), ExprKind::Path(_))
58+
)
59+
}

tests/ui/iter_any.rs

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

tests/ui/iter_any.stderr

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

tests/ui/needless_collect.fixed

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1-
#![allow(unused, clippy::needless_if, clippy::suspicious_map, clippy::iter_count)]
1+
#![allow(
2+
unused,
3+
clippy::needless_if,
4+
clippy::suspicious_map,
5+
clippy::iter_count,
6+
clippy::slice_iter_any
7+
)]
28

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

511
#[warn(clippy::needless_collect)]
6-
#[allow(
7-
unused_variables,
8-
clippy::unnecessary_iter_any,
9-
clippy::iter_cloned_collect,
10-
clippy::iter_next_slice
11-
)]
12+
#[allow(unused_variables, clippy::iter_cloned_collect, clippy::iter_next_slice)]
1213
fn main() {
1314
let sample = [1; 5];
1415
let len = sample.iter().count();

tests/ui/needless_collect.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1-
#![allow(unused, clippy::needless_if, clippy::suspicious_map, clippy::iter_count)]
1+
#![allow(
2+
unused,
3+
clippy::needless_if,
4+
clippy::suspicious_map,
5+
clippy::iter_count,
6+
clippy::slice_iter_any
7+
)]
28

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

511
#[warn(clippy::needless_collect)]
6-
#[allow(
7-
unused_variables,
8-
clippy::unnecessary_iter_any,
9-
clippy::iter_cloned_collect,
10-
clippy::iter_next_slice
11-
)]
12+
#[allow(unused_variables, clippy::iter_cloned_collect, clippy::iter_next_slice)]
1213
fn main() {
1314
let sample = [1; 5];
1415
let len = sample.iter().collect::<Vec<_>>().len();

0 commit comments

Comments
 (0)