1- use clippy_utils:: diagnostics:: span_lint_and_note;
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} ;
25use if_chain:: if_chain;
6+ use rustc_errors:: Applicability ;
37use rustc_hir as hir;
48use rustc_lint:: { LateContext , LateLintPass } ;
9+ use rustc_middle:: ty;
510use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
11+ use rustc_span:: sym;
612
713declare_clippy_lint ! {
814 /// ### What it does
@@ -16,37 +22,47 @@ declare_clippy_lint! {
1622 /// ### Example
1723 /// ```rust
1824 /// "hello".bytes().count();
25+ /// String::from("hello").bytes().count();
1926 /// ```
2027 /// Use instead:
2128 /// ```rust
2229 /// "hello".len();
30+ /// String::from("hello").len();
2331 /// ```
24- #[ clippy:: version = "1.60 .0" ]
32+ #[ clippy:: version = "1.62 .0" ]
2533 pub BYTES_COUNT_TO_LEN ,
2634 complexity,
27- "Using bytest ().count() when len() performs the same functionality"
35+ "Using `bytes ().count()` when ` len()` performs the same functionality"
2836}
2937
3038declare_lint_pass ! ( BytesCountToLen => [ BYTES_COUNT_TO_LEN ] ) ;
3139
3240impl < ' tcx > LateLintPass < ' tcx > for BytesCountToLen {
3341 fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx hir:: Expr < ' _ > ) {
3442 if_chain ! {
35- //check for method call called "count"
36- if let hir:: ExprKind :: MethodCall ( count_path, count_args, _) = & expr. kind;
37- if count_path. ident. name == rustc_span:: sym:: count;
38- if let [ bytes_expr] = & * * count_args;
39- //check for method call called "bytes" that was linked to "count"
40- if let hir:: ExprKind :: MethodCall ( bytes_path, _, _) = & bytes_expr. kind;
41- if bytes_path. ident. name. as_str( ) == "bytes" ;
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 ;
4256 then {
43- span_lint_and_note(
57+ let mut applicability = Applicability :: MachineApplicable ;
58+ span_lint_and_sugg(
4459 cx,
4560 BYTES_COUNT_TO_LEN ,
4661 expr. span,
4762 "using long and hard to read `.bytes().count()`" ,
48- None ,
49- "`.len()` achieves same functionality"
63+ "consider calling `.len()` instead" ,
64+ format!( "{}.len()" , snippet_with_applicability( cx, str_expr. span, ".." , & mut applicability) ) ,
65+ applicability
5066 ) ;
5167 }
5268 } ;
0 commit comments