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