]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/bytes_count_to_len.rs
Rollup merge of #97798 - WaffleLapkin:allow_for_suggestions_that_are_quite_far_away_f...
[rust.git] / clippy_lints / src / bytes_count_to_len.rs
1 use clippy_utils::diagnostics::span_lint_and_sugg;
2 use clippy_utils::source::snippet_with_applicability;
3 use clippy_utils::ty::is_type_diagnostic_item;
4 use clippy_utils::{match_def_path, paths};
5 use if_chain::if_chain;
6 use rustc_errors::Applicability;
7 use rustc_hir as hir;
8 use rustc_lint::{LateContext, LateLintPass};
9 use rustc_middle::ty;
10 use rustc_session::{declare_lint_pass, declare_tool_lint};
11 use rustc_span::sym;
12
13 declare_clippy_lint! {
14     /// ### What it does
15     /// It checks for `str::bytes().count()` and suggests replacing it with
16     /// `str::len()`.
17     ///
18     /// ### Why is this bad?
19     /// `str::bytes().count()` is longer and may not be as performant as using
20     /// `str::len()`.
21     ///
22     /// ### Example
23     /// ```rust
24     /// "hello".bytes().count();
25     /// String::from("hello").bytes().count();
26     /// ```
27     /// Use instead:
28     /// ```rust
29     /// "hello".len();
30     /// String::from("hello").len();
31     /// ```
32     #[clippy::version = "1.62.0"]
33     pub BYTES_COUNT_TO_LEN,
34     complexity,
35     "Using `bytes().count()` when `len()` performs the same functionality"
36 }
37
38 declare_lint_pass!(BytesCountToLen => [BYTES_COUNT_TO_LEN]);
39
40 impl<'tcx> LateLintPass<'tcx> for BytesCountToLen {
41     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
42         if_chain! {
43             if let hir::ExprKind::MethodCall(_, expr_args, _) = &expr.kind;
44             if let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
45             if match_def_path(cx, expr_def_id, &paths::ITER_COUNT);
46
47             if let [bytes_expr] = &**expr_args;
48             if let hir::ExprKind::MethodCall(_, bytes_args, _) = &bytes_expr.kind;
49             if let Some(bytes_def_id) = cx.typeck_results().type_dependent_def_id(bytes_expr.hir_id);
50             if match_def_path(cx, bytes_def_id, &paths::STR_BYTES);
51
52             if let [str_expr] = &**bytes_args;
53             let ty = cx.typeck_results().expr_ty(str_expr).peel_refs();
54
55             if is_type_diagnostic_item(cx, ty, sym::String) || ty.kind() == &ty::Str;
56             then {
57                 let mut applicability = Applicability::MachineApplicable;
58                 span_lint_and_sugg(
59                     cx,
60                     BYTES_COUNT_TO_LEN,
61                     expr.span,
62                     "using long and hard to read `.bytes().count()`",
63                     "consider calling `.len()` instead",
64                     format!("{}.len()", snippet_with_applicability(cx, str_expr.span, "..", &mut applicability)),
65                     applicability
66                 );
67             }
68         };
69     }
70 }