]> git.lizzy.rs Git - rust.git/blob - src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
Rollup merge of #103732 - Mark-Simulacrum:revert-compiler-builtins, r=jyn514
[rust.git] / src / tools / clippy / clippy_lints / src / types / redundant_allocation.rs
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;
9
10 use super::{utils, REDUNDANT_ALLOCATION};
11
12 pub(super) fn check(
13     cx: &LateContext<'_>,
14     hir_ty: &hir::Ty<'_>,
15     qpath: &QPath<'_>,
16     def_id: DefId,
17 ) -> bool {
18     let mut applicability = Applicability::MaybeIncorrect;
19     let outer_sym = if Some(def_id) == cx.tcx.lang_items().owned_box() {
20         "Box"
21     } else if cx.tcx.is_diagnostic_item(sym::Rc, def_id) {
22         "Rc"
23     } else if cx.tcx.is_diagnostic_item(sym::Arc, def_id) {
24         "Arc"
25     } else {
26         return false;
27     };
28
29     if let Some(span) = utils::match_borrows_parameter(cx, qpath) {
30         let generic_snippet = snippet_with_applicability(cx, span, "..", &mut applicability);
31         span_lint_and_then(
32             cx,
33             REDUNDANT_ALLOCATION,
34             hir_ty.span,
35             &format!("usage of `{outer_sym}<{generic_snippet}>`"),
36             |diag| {
37                 diag.span_suggestion(
38                     hir_ty.span,
39                     "try",
40                     format!("{generic_snippet}"),
41                     applicability,
42                 );
43                 diag.note(&format!(
44                     "`{generic_snippet}` is already a pointer, `{outer_sym}<{generic_snippet}>` allocates a pointer on the heap"
45                 ));
46             },
47         );
48         return true;
49     }
50
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),
57         _ => return false,
58     };
59
60     let TyKind::Path(inner_qpath) = &ty.kind else {
61         return false
62     };
63     let inner_span = match qpath_generic_tys(inner_qpath).next() {
64         Some(ty) => {
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) {
69                 return false;
70             }
71             ty.span
72         }
73         None => return false,
74     };
75     if inner_sym == outer_sym {
76         let generic_snippet = snippet_with_applicability(cx, inner_span, "..", &mut applicability);
77         span_lint_and_then(
78             cx,
79             REDUNDANT_ALLOCATION,
80             hir_ty.span,
81             &format!("usage of `{outer_sym}<{inner_sym}<{generic_snippet}>>`"),
82             |diag| {
83                 diag.span_suggestion(
84                     hir_ty.span,
85                     "try",
86                     format!("{outer_sym}<{generic_snippet}>"),
87                     applicability,
88                 );
89                 diag.note(&format!(
90                     "`{inner_sym}<{generic_snippet}>` is already on the heap, `{outer_sym}<{inner_sym}<{generic_snippet}>>` makes an extra allocation"
91                 ));
92             },
93         );
94     } else {
95         let generic_snippet = snippet(cx, inner_span, "..");
96         span_lint_and_then(
97             cx,
98             REDUNDANT_ALLOCATION,
99             hir_ty.span,
100             &format!("usage of `{outer_sym}<{inner_sym}<{generic_snippet}>>`"),
101             |diag| {
102                 diag.note(&format!(
103                     "`{inner_sym}<{generic_snippet}>` is already on the heap, `{outer_sym}<{inner_sym}<{generic_snippet}>>` makes an extra allocation"
104                 ));
105                 diag.help(&format!(
106                     "consider using just `{outer_sym}<{generic_snippet}>` or `{inner_sym}<{generic_snippet}>`"
107                 ));
108             },
109         );
110     }
111     true
112 }