blob: 238e1fe988b398f630cafb0441c31e2c8584240b [file] [log] [blame] [edit]
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet_with_context;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_middle::ty::{self, IsSuggestable};
use rustc_span::symbol::sym;
use super::CLONE_ON_REF_PTR;
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>) {
let obj_ty = cx.typeck_results().expr_ty(receiver).peel_refs();
if let ty::Adt(adt, subst) = obj_ty.kind()
&& let Some(name) = cx.tcx.get_diagnostic_name(adt.did())
{
let caller_type = match name {
sym::Rc => "std::rc::Rc",
sym::Arc => "std::sync::Arc",
sym::RcWeak => "std::rc::Weak",
sym::ArcWeak => "std::sync::Weak",
_ => return,
};
span_lint_and_then(
cx,
CLONE_ON_REF_PTR,
expr.span,
"using `.clone()` on a ref-counted pointer",
|diag| {
// Sometimes unnecessary ::<_> after Rc/Arc/Weak
let mut app = Applicability::Unspecified;
let snippet = snippet_with_context(cx, receiver.span, expr.span.ctxt(), "..", &mut app).0;
let generic = subst.type_at(0);
if generic.is_suggestable(cx.tcx, true) {
diag.span_suggestion(
expr.span,
"try",
format!("{caller_type}::<{generic}>::clone(&{snippet})"),
app,
);
} else {
diag.span_suggestion(
expr.span,
"try",
format!("{caller_type}::</* generic */>::clone(&{snippet})"),
Applicability::HasPlaceholders,
);
}
},
);
}
}