4 use syntax
::ast
::{Name, UintTy}
;
5 use utils
::{contains_name, match_type, paths, single_segment_path, snippet, span_lint_and_sugg, walk_ptrs_ty}
;
7 /// **What it does:** Checks for naive byte counts
9 /// **Why is this bad?** The [`bytecount`](https://crates.io/crates/bytecount)
10 /// crate has methods to count your bytes faster, especially for large slices.
12 /// **Known problems:** If you have predominantly small slices, the
13 /// `bytecount::count(..)` method may actually be slower. However, if you can
14 /// ensure that less than 2³²-1 matches arise, the `naive_count_32(..)` can be
15 /// faster in those cases.
20 /// &my_data.filter(|&x| x == 0u8).count() // use bytecount::count instead
25 "use of naive `<slice>.filter(|&x| x == y).count()` to count byte values"
28 #[derive(Copy, Clone)]
31 impl LintPass
for ByteCount
{
32 fn get_lints(&self) -> LintArray
{
33 lint_array
!(NAIVE_BYTECOUNT
)
37 impl<'a
, 'tcx
> LateLintPass
<'a
, 'tcx
> for ByteCount
{
38 fn check_expr(&mut self, cx
: &LateContext
, expr
: &Expr
) {
40 let ExprMethodCall(ref count
, _
, ref count_args
) = expr
.node
,
41 count
.name
== "count",
42 count_args
.len() == 1,
43 let ExprMethodCall(ref filter
, _
, ref filter_args
) = count_args
[0].node
,
44 filter
.name
== "filter",
45 filter_args
.len() == 2,
46 let ExprClosure(_
, _
, body_id
, _
, _
) = filter_args
[1].node
,
48 let body
= cx
.tcx
.hir
.body(body_id
);
50 body
.arguments
.len() == 1,
51 let Some(argname
) = get_pat_name(&body
.arguments
[0].pat
),
52 let ExprBinary(ref op
, ref l
, ref r
) = body
.value
.node
,
55 walk_ptrs_ty(cx
.tables
.expr_ty(&filter_args
[0])),
58 let needle
= match get_path_name(l
) {
59 Some(name
) if check_arg(name
, argname
, r
) => r
,
60 _
=> match get_path_name(r
) {
61 Some(name
) if check_arg(name
, argname
, l
) => l
,
65 if ty
::TyUint(UintTy
::U8
) != walk_ptrs_ty(cx
.tables
.expr_ty(needle
)).sty
{
68 let haystack
= if let ExprMethodCall(ref path
, _
, ref args
) =
71 if (p
== "iter" || p
== "iter_mut") && args
.len() == 1 {
79 span_lint_and_sugg(cx
,
82 "You appear to be counting bytes the naive way",
83 "Consider using the bytecount crate",
84 format
!("bytecount::count({}, {})",
85 snippet(cx
, haystack
.span
, ".."),
86 snippet(cx
, needle
.span
, "..")));
92 fn check_arg(name
: Name
, arg
: Name
, needle
: &Expr
) -> bool
{
93 name
== arg
&& !contains_name(name
, needle
)
96 fn get_pat_name(pat
: &Pat
) -> Option
<Name
> {
98 PatKind
::Binding(_
, _
, ref spname
, _
) => Some(spname
.node
),
99 PatKind
::Path(ref qpath
) => single_segment_path(qpath
).map(|ps
| ps
.name
),
100 PatKind
::Box(ref p
) |
101 PatKind
::Ref(ref p
, _
) => get_pat_name(&*p
),
106 fn get_path_name(expr
: &Expr
) -> Option
<Name
> {
109 ExprAddrOf(_
, ref e
) |
110 ExprUnary(UnOp
::UnDeref
, ref e
) => get_path_name(e
),
111 ExprBlock(ref b
) => {
112 if b
.stmts
.is_empty() {
113 b
.expr
.as_ref().and_then(|p
| get_path_name(p
))
118 ExprPath(ref qpath
) => single_segment_path(qpath
).map(|ps
| ps
.name
),