From 86fee9ad5d7be72d41966bf40cdd6380dad58b88 Mon Sep 17 00:00:00 2001 From: lapla-cogito Date: Fri, 13 Dec 2024 11:29:39 +0900 Subject: [PATCH] make slice_iter_any lint universal --- clippy_lints/src/declared_lints.rs | 2 +- clippy_lints/src/lib.rs | 2 + clippy_lints/src/methods/mod.rs | 28 ---------- clippy_lints/src/methods/slice_iter_any.rs | 42 --------------- clippy_lints/src/slice_iter_any.rs | 63 ++++++++++++++++++++++ 5 files changed, 66 insertions(+), 71 deletions(-) delete mode 100644 clippy_lints/src/methods/slice_iter_any.rs create mode 100644 clippy_lints/src/slice_iter_any.rs diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 6789d9e75006..8cf26f56c432 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -464,7 +464,6 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::methods::SHOULD_IMPLEMENT_TRAIT_INFO, crate::methods::SINGLE_CHAR_ADD_STR_INFO, crate::methods::SKIP_WHILE_NEXT_INFO, - crate::methods::SLICE_ITER_ANY_INFO, crate::methods::STABLE_SORT_PRIMITIVE_INFO, crate::methods::STRING_EXTEND_CHARS_INFO, crate::methods::STRING_LIT_CHARS_ANY_INFO, @@ -677,6 +676,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::single_range_in_vec_init::SINGLE_RANGE_IN_VEC_INIT_INFO, crate::size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT_INFO, crate::size_of_ref::SIZE_OF_REF_INFO, + crate::slice_iter_any::SLICE_ITER_ANY_INFO, crate::slow_vector_initialization::SLOW_VECTOR_INITIALIZATION_INFO, crate::std_instead_of_core::ALLOC_INSTEAD_OF_CORE_INFO, crate::std_instead_of_core::STD_INSTEAD_OF_ALLOC_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 017e6e2a1423..b9cb15dfcb40 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -339,6 +339,7 @@ mod single_component_path_imports; mod single_range_in_vec_init; mod size_of_in_element_count; mod size_of_ref; +mod slice_iter_any; mod slow_vector_initialization; mod std_instead_of_core; mod string_patterns; @@ -967,5 +968,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(manual_ignore_case_cmp::ManualIgnoreCaseCmp)); store.register_late_pass(|_| Box::new(unnecessary_literal_bound::UnnecessaryLiteralBound)); store.register_late_pass(move |_| Box::new(arbitrary_source_item_ordering::ArbitrarySourceItemOrdering::new(conf))); + store.register_late_pass(|_| Box::new(slice_iter_any::SliceIterAny)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index de298b5db890..810287fa5416 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -100,7 +100,6 @@ 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; @@ -4285,31 +4284,6 @@ declare_clippy_lint! { "map of a trivial closure (not dependent on parameter) over a range" } -declare_clippy_lint! { - /// ### What it does - /// Checks for usage of `iter().any()` on slices of `u8` or `i8` and suggests using `contains()` instead. - /// - /// ### Why is this bad? - /// `iter().any()` on slices of `u8` or `i8` is optimized to use `memchr`. - /// - /// ### Example - /// ```no_run - /// fn foo(values: &[u8]) -> bool { - /// values.iter().any(|&v| v == 10) - /// } - /// ``` - /// Use instead: - /// ```no_run - /// fn foo(values: &[u8]) -> bool { - /// values.contains(&10) - /// } - /// ``` - #[clippy::version = "1.85.0"] - pub SLICE_ITER_ANY, - perf, - "using `contains()` instead of `iter().any()` on u8/i8 slices is more efficient" -} - pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -4475,7 +4449,6 @@ impl_lint_pass!(Methods => [ MAP_ALL_ANY_IDENTITY, MAP_WITH_UNUSED_ARGUMENT_OVER_RANGES, UNNECESSARY_MAP_OR, - SLICE_ITER_ANY, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -4710,7 +4683,6 @@ impl Methods { ("any", [arg]) => { unused_enumerate_index::check(cx, expr, recv, arg); needless_character_iteration::check(cx, expr, recv, arg, false); - slice_iter_any::check(cx, expr); match method_call(recv) { Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check( cx, diff --git a/clippy_lints/src/methods/slice_iter_any.rs b/clippy_lints/src/methods/slice_iter_any.rs deleted file mode 100644 index 849f760e4c77..000000000000 --- a/clippy_lints/src/methods/slice_iter_any.rs +++ /dev/null @@ -1,42 +0,0 @@ -use clippy_utils::diagnostics::span_lint; -use rustc_hir::{Expr, ExprKind}; -use rustc_lint::LateContext; -use rustc_middle::ty::{self}; - -use super::{SLICE_ITER_ANY, method_call}; - -pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { - if !expr.span.from_expansion() - // any() - && let Some((name, recv, args, _, _)) = method_call(expr) - && name == "any" - // check if the inner closure is a equality check - && args.len() == 1 - && let ExprKind::Closure(closure) = args[0].kind - && let body = cx.tcx.hir().body(closure.body) - && let ExprKind::Binary(op, _, _) = body.value.kind - && op.node == rustc_ast::ast::BinOpKind::Eq - // iter() - && let Some((name, recv, _, _, _)) = method_call(recv) - && name == "iter" - { - // check if the receiver is a u8/i8 slice - let ref_type = cx.typeck_results().expr_ty(recv); - - match ref_type.kind() { - ty::Ref(_, inner_type, _) - if inner_type.is_slice() - && let ty::Slice(slice_type) = inner_type.kind() - && (slice_type.to_string() == "u8" || slice_type.to_string() == "i8") => - { - span_lint( - cx, - SLICE_ITER_ANY, - expr.span, - "using `contains()` instead of `iter().any()` on u8/i8 slices is more efficient", - ); - }, - _ => {}, - } - } -} diff --git a/clippy_lints/src/slice_iter_any.rs b/clippy_lints/src/slice_iter_any.rs new file mode 100644 index 000000000000..52cc66675ed3 --- /dev/null +++ b/clippy_lints/src/slice_iter_any.rs @@ -0,0 +1,63 @@ +use crate::methods::method_call; +use clippy_utils::diagnostics::span_lint; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{self, IntTy, UintTy}; +use rustc_session::declare_lint_pass; + +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `iter().any()` on slices of `u8` or `i8` and suggests using `contains()` instead. + /// + /// ### Why is this bad? + /// `iter().any()` on slices of `u8` or `i8` is optimized to use `memchr`. + /// + /// ### Example + /// ```no_run + /// fn foo(values: &[u8]) -> bool { + /// values.iter().any(|&v| v == 10) + /// } + /// ``` + /// Use instead: + /// ```no_run + /// fn foo(values: &[u8]) -> bool { + /// values.contains(&10) + /// } + /// ``` + #[clippy::version = "1.85.0"] + pub SLICE_ITER_ANY, + perf, + "using `contains()` instead of `iter().any()` on u8/i8 slices is more efficient" +} + +declare_lint_pass!(SliceIterAny => [SLICE_ITER_ANY]); + +impl LateLintPass<'_> for SliceIterAny { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + if !expr.span.from_expansion() + // any() + && let Some((name, recv, args, _, _)) = method_call(expr) + && name == "any" + // check if the inner closure is a equality check + && args.len() == 1 + && let ExprKind::Closure(closure) = args[0].kind + && let body = cx.tcx.hir().body(closure.body) + && let ExprKind::Binary(op, _, _) = body.value.kind + && op.node == rustc_ast::ast::BinOpKind::Eq + // iter() + && let Some((name, recv, _, _, _)) = method_call(recv) + && name == "iter" + // check if the receiver is a u8/i8 slice + && let ty::Ref(_, inner_type, _) = cx.typeck_results().expr_ty(recv).kind() + && let ty::Slice(slice_type) = inner_type.kind() + && matches!(slice_type.kind(), ty::Uint(UintTy::U8) | ty::Int(IntTy::I8)) + { + span_lint( + cx, + SLICE_ITER_ANY, + expr.span, + "using `contains()` instead of `iter().any()` on u8/i8 slices is more efficient", + ); + } + } +}