1 use clippy_utils::diagnostics::span_lint_and_then;
2 use clippy_utils::source::{snippet, snippet_with_applicability};
3 use clippy_utils::{path_def_id, qpath_generic_tys};
4 use rustc_errors::Applicability;
5 use rustc_hir::{self as hir, def_id::DefId, QPath, TyKind};
6 use rustc_hir_analysis::hir_ty_to_ty;
7 use rustc_lint::LateContext;
8 use rustc_span::symbol::sym;
10 use super::{utils, REDUNDANT_ALLOCATION};
18 let mut applicability = Applicability::MaybeIncorrect;
19 let outer_sym = if Some(def_id) == cx.tcx.lang_items().owned_box() {
21 } else if cx.tcx.is_diagnostic_item(sym::Rc, def_id) {
23 } else if cx.tcx.is_diagnostic_item(sym::Arc, def_id) {
29 if let Some(span) = utils::match_borrows_parameter(cx, qpath) {
30 let generic_snippet = snippet_with_applicability(cx, span, "..", &mut applicability);
35 &format!("usage of `{outer_sym}<{generic_snippet}>`"),
40 format!("{generic_snippet}"),
44 "`{generic_snippet}` is already a pointer, `{outer_sym}<{generic_snippet}>` allocates a pointer on the heap"
51 let Some(ty) = qpath_generic_tys(qpath).next() else { return false };
52 let Some(id) = path_def_id(cx, ty) else { return false };
53 let (inner_sym, ty) = match cx.tcx.get_diagnostic_name(id) {
54 Some(sym::Arc) => ("Arc", ty),
55 Some(sym::Rc) => ("Rc", ty),
56 _ if Some(id) == cx.tcx.lang_items().owned_box() => ("Box", ty),
60 let TyKind::Path(inner_qpath) = &ty.kind else {
63 let inner_span = match qpath_generic_tys(inner_qpath).next() {
65 // Reallocation of a fat pointer causes it to become thin. `hir_ty_to_ty` is safe to use
66 // here because `mod.rs` guarantees this lint is only run on types outside of bodies and
67 // is not run on locals.
68 if !hir_ty_to_ty(cx.tcx, ty).is_sized(cx.tcx, cx.param_env) {
75 if inner_sym == outer_sym {
76 let generic_snippet = snippet_with_applicability(cx, inner_span, "..", &mut applicability);
81 &format!("usage of `{outer_sym}<{inner_sym}<{generic_snippet}>>`"),
86 format!("{outer_sym}<{generic_snippet}>"),
90 "`{inner_sym}<{generic_snippet}>` is already on the heap, `{outer_sym}<{inner_sym}<{generic_snippet}>>` makes an extra allocation"
95 let generic_snippet = snippet(cx, inner_span, "..");
100 &format!("usage of `{outer_sym}<{inner_sym}<{generic_snippet}>>`"),
103 "`{inner_sym}<{generic_snippet}>` is already on the heap, `{outer_sym}<{inner_sym}<{generic_snippet}>>` makes an extra allocation"
106 "consider using just `{outer_sym}<{generic_snippet}>` or `{inner_sym}<{generic_snippet}>`"