1 use clippy_utils
::diagnostics
::span_lint_and_then
;
2 use clippy_utils
::source
::snippet_with_applicability
;
3 use clippy_utils
::ty
::{is_type_diagnostic_item, walk_ptrs_ty_depth}
;
4 use clippy_utils
::{match_def_path, paths}
;
5 use if_chain
::if_chain
;
6 use rustc_errors
::Applicability
;
8 use rustc_lint
::LateContext
;
9 use rustc_middle
::ty
::{self, Ty}
;
10 use rustc_span
::symbol
::{sym, Symbol}
;
12 use super::INEFFICIENT_TO_STRING
;
14 /// Checks for the `INEFFICIENT_TO_STRING` lint
16 cx
: &LateContext
<'tcx
>,
19 receiver
: &hir
::Expr
<'_
>,
20 args
: &[hir
::Expr
<'_
>],
23 if args
.is_empty() && method_name
== sym
::to_string
;
24 if let Some(to_string_meth_did
) = cx
.typeck_results().type_dependent_def_id(expr
.hir_id
);
25 if match_def_path(cx
, to_string_meth_did
, &paths
::TO_STRING_METHOD
);
26 if let Some(substs
) = cx
.typeck_results().node_substs_opt(expr
.hir_id
);
27 let arg_ty
= cx
.typeck_results().expr_ty_adjusted(receiver
);
28 let self_ty
= substs
.type_at(0);
29 let (deref_self_ty
, deref_count
) = walk_ptrs_ty_depth(self_ty
);
31 if specializes_tostring(cx
, deref_self_ty
);
35 INEFFICIENT_TO_STRING
,
37 &format
!("calling `to_string` on `{}`", arg_ty
),
40 "`{}` implements `ToString` through a slower blanket impl, but `{}` has a fast specialization of `ToString`",
41 self_ty
, deref_self_ty
43 let mut applicability
= Applicability
::MachineApplicable
;
44 let arg_snippet
= snippet_with_applicability(cx
, receiver
.span
, "..", &mut applicability
);
47 "try dereferencing the receiver",
48 format
!("({}{}).to_string()", "*".repeat(deref_count
), arg_snippet
),
57 /// Returns whether `ty` specializes `ToString`.
58 /// Currently, these are `str`, `String`, and `Cow<'_, str>`.
59 fn specializes_tostring(cx
: &LateContext
<'_
>, ty
: Ty
<'_
>) -> bool
{
60 if let ty
::Str
= ty
.kind() {
64 if is_type_diagnostic_item(cx
, ty
, sym
::String
) {
68 if let ty
::Adt(adt
, substs
) = ty
.kind() {
69 match_def_path(cx
, adt
.did(), &paths
::COW
) && substs
.type_at(1).is_str()