]> git.lizzy.rs Git - rust.git/blob - src/tools/clippy/clippy_lints/src/methods/bytecount.rs
Rollup merge of #105663 - andrewpollack:patch-1, r=tmandry
[rust.git] / src / tools / clippy / clippy_lints / src / methods / bytecount.rs
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, receiver, [], _) =
46                     filter_recv.kind {
47                 let p = path.ident.name;
48                 if p == sym::iter || p == sym!(iter_mut) {
49                     receiver
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 }