Skip to content

Commit 2502898

Browse files
committed
Move ByteCount into Methods lint pass
1 parent 21f5954 commit 2502898

File tree

6 files changed

+111
-110
lines changed

6 files changed

+111
-110
lines changed

clippy_lints/src/bytecount.rs

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

clippy_lints/src/lib.register_lints.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ store.register_lints(&[
5959
booleans::NONMINIMAL_BOOL,
6060
booleans::OVERLY_COMPLEX_BOOL_EXPR,
6161
borrow_deref_ref::BORROW_DEREF_REF,
62-
bytecount::NAIVE_BYTECOUNT,
6362
bytes_count_to_len::BYTES_COUNT_TO_LEN,
6463
cargo::CARGO_COMMON_METADATA,
6564
cargo::MULTIPLE_CRATE_VERSIONS,
@@ -330,6 +329,7 @@ store.register_lints(&[
330329
methods::MAP_FLATTEN,
331330
methods::MAP_IDENTITY,
332331
methods::MAP_UNWRAP_OR,
332+
methods::NAIVE_BYTECOUNT,
333333
methods::NEEDLESS_OPTION_AS_DEREF,
334334
methods::NEEDLESS_OPTION_TAKE,
335335
methods::NEEDLESS_SPLITN,

clippy_lints/src/lib.register_pedantic.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
66
LintId::of(attrs::INLINE_ALWAYS),
7-
LintId::of(bytecount::NAIVE_BYTECOUNT),
87
LintId::of(case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS),
98
LintId::of(casts::BORROW_AS_PTR),
109
LintId::of(casts::CAST_LOSSLESS),
@@ -64,6 +63,7 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
6463
LintId::of(methods::IMPLICIT_CLONE),
6564
LintId::of(methods::INEFFICIENT_TO_STRING),
6665
LintId::of(methods::MAP_UNWRAP_OR),
66+
LintId::of(methods::NAIVE_BYTECOUNT),
6767
LintId::of(methods::UNNECESSARY_JOIN),
6868
LintId::of(misc::USED_UNDERSCORE_BINDING),
6969
LintId::of(mismatching_type_param_order::MISMATCHING_TYPE_PARAM_ORDER),

clippy_lints/src/lib.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,6 @@ mod blocks_in_if_conditions;
180180
mod bool_assert_comparison;
181181
mod booleans;
182182
mod borrow_deref_ref;
183-
mod bytecount;
184183
mod bytes_count_to_len;
185184
mod cargo;
186185
mod case_sensitive_file_extension_comparisons;
@@ -718,7 +717,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
718717
);
719718
store.register_late_pass(move || Box::new(pass_by_ref_or_value));
720719
store.register_late_pass(|| Box::new(ref_option_ref::RefOptionRef));
721-
store.register_late_pass(|| Box::new(bytecount::ByteCount));
722720
store.register_late_pass(|| Box::new(infinite_iter::InfiniteIter));
723721
store.register_late_pass(|| Box::new(inline_fn_without_body::InlineFnWithoutBody));
724722
store.register_late_pass(|| Box::new(useless_conversion::UselessConversion::default()));

clippy_lints/src/methods/bytecount.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
use clippy_utils::diagnostics::span_lint_and_sugg;
2+
use clippy_utils::source::snippet_with_applicability;
3+
use clippy_utils::ty::match_type;
4+
use clippy_utils::visitors::is_local_used;
5+
use clippy_utils::{path_to_local_id, paths, peel_blocks, peel_ref_operators, strip_pat_refs};
6+
use if_chain::if_chain;
7+
use rustc_errors::Applicability;
8+
use rustc_hir::{BinOpKind, Closure, Expr, ExprKind, PatKind};
9+
use rustc_lint::LateContext;
10+
use rustc_middle::ty::{self, UintTy};
11+
use rustc_span::sym;
12+
13+
use super::NAIVE_BYTECOUNT;
14+
15+
pub(super) fn check<'tcx>(
16+
cx: &LateContext<'tcx>,
17+
expr: &'tcx Expr<'_>,
18+
filter_recv: &'tcx Expr<'_>,
19+
filter_arg: &'tcx Expr<'_>,
20+
) {
21+
if_chain! {
22+
if let ExprKind::Closure(&Closure { body, .. }) = filter_arg.kind;
23+
let body = cx.tcx.hir().body(body);
24+
if let [param] = body.params;
25+
if let PatKind::Binding(_, arg_id, _, _) = strip_pat_refs(param.pat).kind;
26+
if let ExprKind::Binary(ref op, l, r) = body.value.kind;
27+
if op.node == BinOpKind::Eq;
28+
if match_type(cx,
29+
cx.typeck_results().expr_ty(filter_recv).peel_refs(),
30+
&paths::SLICE_ITER);
31+
let operand_is_arg = |expr| {
32+
let expr = peel_ref_operators(cx, peel_blocks(expr));
33+
path_to_local_id(expr, arg_id)
34+
};
35+
let needle = if operand_is_arg(l) {
36+
r
37+
} else if operand_is_arg(r) {
38+
l
39+
} else {
40+
return;
41+
};
42+
if ty::Uint(UintTy::U8) == *cx.typeck_results().expr_ty(needle).peel_refs().kind();
43+
if !is_local_used(cx, needle, arg_id);
44+
then {
45+
let haystack = if let ExprKind::MethodCall(path, args, _) =
46+
filter_recv.kind {
47+
let p = path.ident.name;
48+
if (p == sym::iter || p == sym!(iter_mut)) && args.len() == 1 {
49+
&args[0]
50+
} else {
51+
filter_recv
52+
}
53+
} else {
54+
filter_recv
55+
};
56+
let mut applicability = Applicability::MaybeIncorrect;
57+
span_lint_and_sugg(
58+
cx,
59+
NAIVE_BYTECOUNT,
60+
expr.span,
61+
"you appear to be counting bytes the naive way",
62+
"consider using the bytecount crate",
63+
format!("bytecount::count({}, {})",
64+
snippet_with_applicability(cx, haystack.span, "..", &mut applicability),
65+
snippet_with_applicability(cx, needle.span, "..", &mut applicability)),
66+
applicability,
67+
);
68+
}
69+
};
70+
}

clippy_lints/src/methods/mod.rs

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
mod bind_instead_of_map;
2+
mod bytecount;
23
mod bytes_nth;
34
mod chars_cmp;
45
mod chars_cmp_with_unwrap;
@@ -82,7 +83,9 @@ use bind_instead_of_map::BindInsteadOfMap;
8283
use clippy_utils::consts::{constant, Constant};
8384
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
8485
use clippy_utils::ty::{contains_adt_constructor, contains_ty, implements_trait, is_copy, is_type_diagnostic_item};
85-
use clippy_utils::{contains_return, get_trait_def_id, iter_input_pats, meets_msrv, msrvs, paths, return_ty};
86+
use clippy_utils::{
87+
contains_return, get_trait_def_id, is_trait_method, iter_input_pats, meets_msrv, msrvs, paths, return_ty,
88+
};
8689
use if_chain::if_chain;
8790
use rustc_hir as hir;
8891
use rustc_hir::def::Res;
@@ -2368,6 +2371,37 @@ declare_clippy_lint! {
23682371
"Iterator for empty array"
23692372
}
23702373

2374+
declare_clippy_lint! {
2375+
/// ### What it does
2376+
/// Checks for naive byte counts
2377+
///
2378+
/// ### Why is this bad?
2379+
/// The [`bytecount`](https://crates.io/crates/bytecount)
2380+
/// crate has methods to count your bytes faster, especially for large slices.
2381+
///
2382+
/// ### Known problems
2383+
/// If you have predominantly small slices, the
2384+
/// `bytecount::count(..)` method may actually be slower. However, if you can
2385+
/// ensure that less than 2³²-1 matches arise, the `naive_count_32(..)` can be
2386+
/// faster in those cases.
2387+
///
2388+
/// ### Example
2389+
/// ```rust
2390+
/// # let vec = vec![1_u8];
2391+
/// let count = vec.iter().filter(|x| **x == 0u8).count();
2392+
/// ```
2393+
///
2394+
/// Use instead:
2395+
/// ```rust,ignore
2396+
/// # let vec = vec![1_u8];
2397+
/// let count = bytecount::count(&vec, 0u8);
2398+
/// ```
2399+
#[clippy::version = "pre 1.29.0"]
2400+
pub NAIVE_BYTECOUNT,
2401+
pedantic,
2402+
"use of naive `<slice>.filter(|&x| x == y).count()` to count byte values"
2403+
}
2404+
23712405
pub struct Methods {
23722406
avoid_breaking_exported_api: bool,
23732407
msrv: Option<RustcVersion>,
@@ -2471,7 +2505,8 @@ impl_lint_pass!(Methods => [
24712505
NO_EFFECT_REPLACE,
24722506
OBFUSCATED_IF_ELSE,
24732507
ITER_ON_SINGLE_ITEMS,
2474-
ITER_ON_EMPTY_COLLECTIONS
2508+
ITER_ON_EMPTY_COLLECTIONS,
2509+
NAIVE_BYTECOUNT,
24752510
]);
24762511

24772512
/// Extracts a method call name, args, and `Span` of the method name.
@@ -2726,12 +2761,13 @@ impl Methods {
27262761
},
27272762
_ => {},
27282763
},
2729-
("count", []) => match method_call(recv) {
2764+
("count", []) if is_trait_method(cx, expr, sym::Iterator) => match method_call(recv) {
27302765
Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, true, false),
27312766
Some((name2 @ ("into_iter" | "iter" | "iter_mut"), [recv2], _)) => {
27322767
iter_count::check(cx, expr, recv2, name2);
27332768
},
27342769
Some(("map", [_, arg], _)) => suspicious_map::check(cx, expr, recv, arg),
2770+
Some(("filter", [recv2, arg], _)) => bytecount::check(cx, expr, recv2, arg),
27352771
_ => {},
27362772
},
27372773
("drain", [arg]) => {

0 commit comments

Comments
 (0)