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;
8 use rustc_lint::{LateContext, LateLintPass};
10 use rustc_session::{declare_lint_pass, declare_tool_lint};
13 declare_clippy_lint! {
15 /// It checks for `str::bytes().count()` and suggests replacing it with
18 /// ### Why is this bad?
19 /// `str::bytes().count()` is longer and may not be as performant as using
24 /// "hello".bytes().count();
25 /// String::from("hello").bytes().count();
30 /// String::from("hello").len();
32 #[clippy::version = "1.62.0"]
33 pub BYTES_COUNT_TO_LEN,
35 "Using `bytes().count()` when `len()` performs the same functionality"
38 declare_lint_pass!(BytesCountToLen => [BYTES_COUNT_TO_LEN]);
40 impl<'tcx> LateLintPass<'tcx> for BytesCountToLen {
41 fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
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);
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);
52 if let [str_expr] = &**bytes_args;
53 let ty = cx.typeck_results().expr_ty(str_expr).peel_refs();
55 if is_type_diagnostic_item(cx, ty, sym::String) || ty.kind() == &ty::Str;
57 let mut applicability = Applicability::MachineApplicable;
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)),