1 use clippy_utils
::diagnostics
::span_lint_and_sugg
;
2 use clippy_utils
::source
::snippet_with_context
;
3 use clippy_utils
::ty
::peel_mid_ty_refs
;
4 use clippy_utils
::{is_diag_item_method, is_diag_trait_item}
;
5 use if_chain
::if_chain
;
6 use rustc_errors
::Applicability
;
8 use rustc_lint
::LateContext
;
11 use super::IMPLICIT_CLONE
;
13 pub fn check(cx
: &LateContext
<'_
>, method_name
: &str, expr
: &hir
::Expr
<'_
>, recv
: &hir
::Expr
<'_
>) {
15 if let Some(method_def_id
) = cx
.typeck_results().type_dependent_def_id(expr
.hir_id
);
16 if is_clone_like(cx
, method_name
, method_def_id
);
17 let return_type
= cx
.typeck_results().expr_ty(expr
);
18 let input_type
= cx
.typeck_results().expr_ty(recv
);
19 let (input_type
, ref_count
) = peel_mid_ty_refs(input_type
);
20 if let Some(ty_name
) = input_type
.ty_adt_def().map(|adt_def
| cx
.tcx
.item_name(adt_def
.did()));
21 if return_type
== input_type
;
23 let mut app
= Applicability
::MachineApplicable
;
24 let recv_snip
= snippet_with_context(cx
, recv
.span
, expr
.span
.ctxt(), "..", &mut app
).0;
29 &format
!("implicitly cloning a `{}` by calling `{}` on its dereferenced type", ty_name
, method_name
),
32 format
!("({}{}).clone()", "*".repeat(ref_count
- 1), recv_snip
)
34 format
!("{}.clone()", recv_snip
)
42 /// Returns true if the named method can be used to clone the receiver.
43 /// Note that `to_string` is not flagged by `implicit_clone`. So other lints that call
44 /// `is_clone_like` and that do flag `to_string` must handle it separately. See, e.g.,
45 /// `is_to_owned_like` in `unnecessary_to_owned.rs`.
46 pub fn is_clone_like(cx
: &LateContext
<'_
>, method_name
: &str, method_def_id
: hir
::def_id
::DefId
) -> bool
{
48 "to_os_string" => is_diag_item_method(cx
, method_def_id
, sym
::OsStr
),
49 "to_owned" => is_diag_trait_item(cx
, method_def_id
, sym
::ToOwned
),
50 "to_path_buf" => is_diag_item_method(cx
, method_def_id
, sym
::Path
),
53 .impl_of_method(method_def_id
)
54 .filter(|&impl_did
| cx
.tcx
.type_of(impl_did
).is_slice() && cx
.tcx
.impl_trait_ref(impl_did
).is_none())