about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-07-15 07:20:37 +0000
committerbors <bors@rust-lang.org>2021-07-15 07:20:37 +0000
commit09f5f15d8ba660d9c657fdc4a34d7aab7bc4ecad (patch)
tree33e0d456a1429d1bbbb8d17ab800b73a28952828
parent2b193e247f108c303d2ef9818ddd4aadceaf5760 (diff)
parente575610fb32c50236d56d7001f13d1143205ae5a (diff)
downloadrust-09f5f15d8ba660d9c657fdc4a34d7aab7bc4ecad.tar.gz
rust-09f5f15d8ba660d9c657fdc4a34d7aab7bc4ecad.zip
Auto merge of #7308 - lengyijun:redundant_allocation_arc, r=xFrednet,flip1995
add Arc to `redundant_allocation`

 fixes #7303
changelog:  add Arc to `redundant_allocation`
-rw-r--r--clippy_lints/src/types/mod.rs4
-rw-r--r--clippy_lints/src/types/redundant_allocation.rs153
-rw-r--r--tests/ui/redundant_allocation.fixed48
-rw-r--r--tests/ui/redundant_allocation.rs68
-rw-r--r--tests/ui/redundant_allocation.stderr152
-rw-r--r--tests/ui/redundant_allocation_fixable.fixed75
-rw-r--r--tests/ui/redundant_allocation_fixable.rs75
-rw-r--r--tests/ui/redundant_allocation_fixable.stderr99
8 files changed, 509 insertions, 165 deletions
diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs
index c26268a875c..7d629b5455b 100644
--- a/clippy_lints/src/types/mod.rs
+++ b/clippy_lints/src/types/mod.rs
@@ -178,8 +178,8 @@ declare_clippy_lint! {
 declare_clippy_lint! {
     /// **What it does:** Checks for use of redundant allocations anywhere in the code.
     ///
-    /// **Why is this bad?** Expressions such as `Rc<&T>`, `Rc<Rc<T>>`, `Rc<Box<T>>`, `Box<&T>`
-    /// add an unnecessary level of indirection.
+    /// **Why is this bad?** Expressions such as `Rc<&T>`, `Rc<Rc<T>>`, `Rc<Arc<T>>`, `Rc<Box<T>>`, Arc<&T>`, `Arc<Rc<T>>`,
+    /// `Arc<Arc<T>>`, `Arc<Box<T>>`, `Box<&T>`, `Box<Rc<T>>`, `Box<Arc<T>>`, `Box<Box<T>>`, add an unnecessary level of indirection.
     ///
     /// **Known problems:** None.
     ///
diff --git a/clippy_lints/src/types/redundant_allocation.rs b/clippy_lints/src/types/redundant_allocation.rs
index c0c1f340583..8e83dcbf704 100644
--- a/clippy_lints/src/types/redundant_allocation.rs
+++ b/clippy_lints/src/types/redundant_allocation.rs
@@ -1,5 +1,5 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::source::{snippet, snippet_with_applicability};
 use clippy_utils::{get_qpath_generic_tys, is_ty_param_diagnostic_item, is_ty_param_lang_item};
 use rustc_errors::Applicability;
 use rustc_hir::{self as hir, def_id::DefId, LangItem, QPath, TyKind};
@@ -9,74 +9,99 @@ use rustc_span::symbol::sym;
 use super::{utils, REDUNDANT_ALLOCATION};
 
 pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool {
-    if Some(def_id) == cx.tcx.lang_items().owned_box() {
-        if let Some(span) = utils::match_borrows_parameter(cx, qpath) {
-            let mut applicability = Applicability::MachineApplicable;
-            span_lint_and_sugg(
-                cx,
-                REDUNDANT_ALLOCATION,
-                hir_ty.span,
-                "usage of `Box<&T>`",
-                "try",
-                snippet_with_applicability(cx, span, "..", &mut applicability).to_string(),
-                applicability,
-            );
-            return true;
-        }
+    let outer_sym = if Some(def_id) == cx.tcx.lang_items().owned_box() {
+        "Box"
+    } else if cx.tcx.is_diagnostic_item(sym::Rc, def_id) {
+        "Rc"
+    } else if cx.tcx.is_diagnostic_item(sym::Arc, def_id) {
+        "Arc"
+    } else {
+        return false;
+    };
+
+    if let Some(span) = utils::match_borrows_parameter(cx, qpath) {
+        let mut applicability = Applicability::MaybeIncorrect;
+        let generic_snippet = snippet_with_applicability(cx, span, "..", &mut applicability);
+        span_lint_and_then(
+            cx,
+            REDUNDANT_ALLOCATION,
+            hir_ty.span,
+            &format!("usage of `{}<{}>`", outer_sym, generic_snippet),
+            |diag| {
+                diag.span_suggestion(hir_ty.span, "try", format!("{}", generic_snippet), applicability);
+                diag.note(&format!(
+                    "`{generic}` is already a pointer, `{outer}<{generic}>` allocates a pointer on the heap",
+                    outer = outer_sym,
+                    generic = generic_snippet
+                ));
+            },
+        );
+        return true;
     }
 
-    if cx.tcx.is_diagnostic_item(sym::Rc, def_id) {
-        if let Some(ty) = is_ty_param_diagnostic_item(cx, qpath, sym::Rc) {
-            let mut applicability = Applicability::MachineApplicable;
-            span_lint_and_sugg(
-                cx,
-                REDUNDANT_ALLOCATION,
-                hir_ty.span,
-                "usage of `Rc<Rc<T>>`",
-                "try",
-                snippet_with_applicability(cx, ty.span, "..", &mut applicability).to_string(),
-                applicability,
-            );
-            true
-        } else if let Some(ty) = is_ty_param_lang_item(cx, qpath, LangItem::OwnedBox) {
-            let qpath = match &ty.kind {
-                TyKind::Path(qpath) => qpath,
-                _ => return false,
-            };
-            let inner_span = match get_qpath_generic_tys(qpath).next() {
-                Some(ty) => ty.span,
-                None => return false,
-            };
-            let mut applicability = Applicability::MachineApplicable;
-            span_lint_and_sugg(
-                cx,
-                REDUNDANT_ALLOCATION,
-                hir_ty.span,
-                "usage of `Rc<Box<T>>`",
-                "try",
-                format!(
-                    "Rc<{}>",
-                    snippet_with_applicability(cx, inner_span, "..", &mut applicability)
-                ),
-                applicability,
-            );
-            true
-        } else {
-            utils::match_borrows_parameter(cx, qpath).map_or(false, |span| {
-                let mut applicability = Applicability::MachineApplicable;
-                span_lint_and_sugg(
-                    cx,
-                    REDUNDANT_ALLOCATION,
+    let (inner_sym, ty) = if let Some(ty) = is_ty_param_lang_item(cx, qpath, LangItem::OwnedBox) {
+        ("Box", ty)
+    } else if let Some(ty) = is_ty_param_diagnostic_item(cx, qpath, sym::Rc) {
+        ("Rc", ty)
+    } else if let Some(ty) = is_ty_param_diagnostic_item(cx, qpath, sym::Arc) {
+        ("Arc", ty)
+    } else {
+        return false;
+    };
+
+    let inner_qpath = match &ty.kind {
+        TyKind::Path(inner_qpath) => inner_qpath,
+        _ => return false,
+    };
+    let inner_span = match get_qpath_generic_tys(inner_qpath).next() {
+        Some(ty) => ty.span,
+        None => return false,
+    };
+    if inner_sym == outer_sym {
+        let mut applicability = Applicability::MaybeIncorrect;
+        let generic_snippet = snippet_with_applicability(cx, inner_span, "..", &mut applicability);
+        span_lint_and_then(
+            cx,
+            REDUNDANT_ALLOCATION,
+            hir_ty.span,
+            &format!("usage of `{}<{}<{}>>`", outer_sym, inner_sym, generic_snippet),
+            |diag| {
+                diag.span_suggestion(
                     hir_ty.span,
-                    "usage of `Rc<&T>`",
                     "try",
-                    snippet_with_applicability(cx, span, "..", &mut applicability).to_string(),
+                    format!("{}<{}>", outer_sym, generic_snippet),
                     applicability,
                 );
-                true
-            })
-        }
+                diag.note(&format!(
+                    "`{inner}<{generic}>` is already on the heap, `{outer}<{inner}<{generic}>>` makes an extra allocation",
+                    outer = outer_sym,
+                    inner = inner_sym,
+                    generic = generic_snippet
+                ));
+            },
+        );
     } else {
-        false
+        let generic_snippet = snippet(cx, inner_span, "..");
+        span_lint_and_then(
+            cx,
+            REDUNDANT_ALLOCATION,
+            hir_ty.span,
+            &format!("usage of `{}<{}<{}>>`", outer_sym, inner_sym, generic_snippet),
+            |diag| {
+                diag.note(&format!(
+                    "`{inner}<{generic}>` is already on the heap, `{outer}<{inner}<{generic}>>` makes an extra allocation",
+                    outer = outer_sym,
+                    inner = inner_sym,
+                    generic = generic_snippet
+                ));
+                diag.help(&format!(
+                    "consider using just `{outer}<{generic}>` or `{inner}<{generic}>`",
+                    outer = outer_sym,
+                    inner = inner_sym,
+                    generic = generic_snippet
+                ));
+            },
+        );
     }
+    true
 }
diff --git a/tests/ui/redundant_allocation.fixed b/tests/ui/redundant_allocation.fixed
deleted file mode 100644
index 6514fd6d1ac..00000000000
--- a/tests/ui/redundant_allocation.fixed
+++ /dev/null
@@ -1,48 +0,0 @@
-// run-rustfix
-#![warn(clippy::all)]
-#![allow(clippy::boxed_local, clippy::needless_pass_by_value)]
-#![allow(clippy::blacklisted_name, unused_variables, dead_code)]
-
-use std::boxed::Box;
-use std::rc::Rc;
-
-pub struct MyStruct {}
-
-pub struct SubT<T> {
-    foo: T,
-}
-
-pub enum MyEnum {
-    One,
-    Two,
-}
-
-// Rc<&T>
-
-pub fn test1<T>(foo: &T) {}
-
-pub fn test2(foo: &MyStruct) {}
-
-pub fn test3(foo: &MyEnum) {}
-
-pub fn test4_neg(foo: Rc<SubT<&usize>>) {}
-
-// Rc<Rc<T>>
-
-pub fn test5(a: Rc<bool>) {}
-
-// Rc<Box<T>>
-
-pub fn test6(a: Rc<bool>) {}
-
-// Box<&T>
-
-pub fn test7<T>(foo: &T) {}
-
-pub fn test8(foo: &MyStruct) {}
-
-pub fn test9(foo: &MyEnum) {}
-
-pub fn test10_neg(foo: Box<SubT<&usize>>) {}
-
-fn main() {}
diff --git a/tests/ui/redundant_allocation.rs b/tests/ui/redundant_allocation.rs
index 677b3e56d4d..1b4f2a66c70 100644
--- a/tests/ui/redundant_allocation.rs
+++ b/tests/ui/redundant_allocation.rs
@@ -1,10 +1,7 @@
-// run-rustfix
 #![warn(clippy::all)]
 #![allow(clippy::boxed_local, clippy::needless_pass_by_value)]
 #![allow(clippy::blacklisted_name, unused_variables, dead_code)]
-
-use std::boxed::Box;
-use std::rc::Rc;
+#![allow(unused_imports)]
 
 pub struct MyStruct {}
 
@@ -17,32 +14,67 @@ pub enum MyEnum {
     Two,
 }
 
-// Rc<&T>
+mod outer_box {
+    use crate::MyEnum;
+    use crate::MyStruct;
+    use crate::SubT;
+    use std::boxed::Box;
+    use std::rc::Rc;
+    use std::sync::Arc;
 
-pub fn test1<T>(foo: Rc<&T>) {}
+    pub fn box_test6<T>(foo: Box<Rc<T>>) {}
 
-pub fn test2(foo: Rc<&MyStruct>) {}
+    pub fn box_test7<T>(foo: Box<Arc<T>>) {}
 
-pub fn test3(foo: Rc<&MyEnum>) {}
+    pub fn box_test8() -> Box<Rc<SubT<usize>>> {
+        unimplemented!();
+    }
 
-pub fn test4_neg(foo: Rc<SubT<&usize>>) {}
+    pub fn box_test9<T>(foo: Box<Arc<T>>) -> Box<Arc<SubT<T>>> {
+        unimplemented!();
+    }
+}
 
-// Rc<Rc<T>>
+mod outer_rc {
+    use crate::MyEnum;
+    use crate::MyStruct;
+    use crate::SubT;
+    use std::boxed::Box;
+    use std::rc::Rc;
+    use std::sync::Arc;
 
-pub fn test5(a: Rc<Rc<bool>>) {}
+    pub fn rc_test5(a: Rc<Box<bool>>) {}
 
-// Rc<Box<T>>
+    pub fn rc_test7(a: Rc<Arc<bool>>) {}
 
-pub fn test6(a: Rc<Box<bool>>) {}
+    pub fn rc_test8() -> Rc<Box<SubT<usize>>> {
+        unimplemented!();
+    }
 
-// Box<&T>
+    pub fn rc_test9<T>(foo: Rc<Arc<T>>) -> Rc<Arc<SubT<T>>> {
+        unimplemented!();
+    }
+}
 
-pub fn test7<T>(foo: Box<&T>) {}
+mod outer_arc {
+    use crate::MyEnum;
+    use crate::MyStruct;
+    use crate::SubT;
+    use std::boxed::Box;
+    use std::rc::Rc;
+    use std::sync::Arc;
 
-pub fn test8(foo: Box<&MyStruct>) {}
+    pub fn arc_test5(a: Arc<Box<bool>>) {}
 
-pub fn test9(foo: Box<&MyEnum>) {}
+    pub fn arc_test6(a: Arc<Rc<bool>>) {}
 
-pub fn test10_neg(foo: Box<SubT<&usize>>) {}
+    pub fn arc_test8() -> Arc<Box<SubT<usize>>> {
+        unimplemented!();
+    }
+
+    pub fn arc_test9<T>(foo: Arc<Rc<T>>) -> Arc<Rc<SubT<T>>> {
+        unimplemented!();
+    }
+}
 
 fn main() {}
diff --git a/tests/ui/redundant_allocation.stderr b/tests/ui/redundant_allocation.stderr
index 92e4f67f5db..fdab74eb538 100644
--- a/tests/ui/redundant_allocation.stderr
+++ b/tests/ui/redundant_allocation.stderr
@@ -1,52 +1,138 @@
-error: usage of `Rc<&T>`
-  --> $DIR/redundant_allocation.rs:22:22
+error: usage of `Box<Rc<T>>`
+  --> $DIR/redundant_allocation.rs:25:30
    |
-LL | pub fn test1<T>(foo: Rc<&T>) {}
-   |                      ^^^^^^ help: try: `&T`
+LL |     pub fn box_test6<T>(foo: Box<Rc<T>>) {}
+   |                              ^^^^^^^^^^
    |
    = note: `-D clippy::redundant-allocation` implied by `-D warnings`
+   = note: `Rc<T>` is already on the heap, `Box<Rc<T>>` makes an extra allocation
+   = help: consider using just `Box<T>` or `Rc<T>`
 
-error: usage of `Rc<&T>`
-  --> $DIR/redundant_allocation.rs:24:19
+error: usage of `Box<Arc<T>>`
+  --> $DIR/redundant_allocation.rs:27:30
    |
-LL | pub fn test2(foo: Rc<&MyStruct>) {}
-   |                   ^^^^^^^^^^^^^ help: try: `&MyStruct`
+LL |     pub fn box_test7<T>(foo: Box<Arc<T>>) {}
+   |                              ^^^^^^^^^^^
+   |
+   = note: `Arc<T>` is already on the heap, `Box<Arc<T>>` makes an extra allocation
+   = help: consider using just `Box<T>` or `Arc<T>`
+
+error: usage of `Box<Rc<SubT<usize>>>`
+  --> $DIR/redundant_allocation.rs:29:27
+   |
+LL |     pub fn box_test8() -> Box<Rc<SubT<usize>>> {
+   |                           ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `Rc<SubT<usize>>` is already on the heap, `Box<Rc<SubT<usize>>>` makes an extra allocation
+   = help: consider using just `Box<SubT<usize>>` or `Rc<SubT<usize>>`
+
+error: usage of `Box<Arc<T>>`
+  --> $DIR/redundant_allocation.rs:33:30
+   |
+LL |     pub fn box_test9<T>(foo: Box<Arc<T>>) -> Box<Arc<SubT<T>>> {
+   |                              ^^^^^^^^^^^
+   |
+   = note: `Arc<T>` is already on the heap, `Box<Arc<T>>` makes an extra allocation
+   = help: consider using just `Box<T>` or `Arc<T>`
+
+error: usage of `Box<Arc<SubT<T>>>`
+  --> $DIR/redundant_allocation.rs:33:46
+   |
+LL |     pub fn box_test9<T>(foo: Box<Arc<T>>) -> Box<Arc<SubT<T>>> {
+   |                                              ^^^^^^^^^^^^^^^^^
+   |
+   = note: `Arc<SubT<T>>` is already on the heap, `Box<Arc<SubT<T>>>` makes an extra allocation
+   = help: consider using just `Box<SubT<T>>` or `Arc<SubT<T>>`
+
+error: usage of `Rc<Box<bool>>`
+  --> $DIR/redundant_allocation.rs:46:24
+   |
+LL |     pub fn rc_test5(a: Rc<Box<bool>>) {}
+   |                        ^^^^^^^^^^^^^
+   |
+   = note: `Box<bool>` is already on the heap, `Rc<Box<bool>>` makes an extra allocation
+   = help: consider using just `Rc<bool>` or `Box<bool>`
+
+error: usage of `Rc<Arc<bool>>`
+  --> $DIR/redundant_allocation.rs:48:24
+   |
+LL |     pub fn rc_test7(a: Rc<Arc<bool>>) {}
+   |                        ^^^^^^^^^^^^^
+   |
+   = note: `Arc<bool>` is already on the heap, `Rc<Arc<bool>>` makes an extra allocation
+   = help: consider using just `Rc<bool>` or `Arc<bool>`
+
+error: usage of `Rc<Box<SubT<usize>>>`
+  --> $DIR/redundant_allocation.rs:50:26
+   |
+LL |     pub fn rc_test8() -> Rc<Box<SubT<usize>>> {
+   |                          ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `Box<SubT<usize>>` is already on the heap, `Rc<Box<SubT<usize>>>` makes an extra allocation
+   = help: consider using just `Rc<SubT<usize>>` or `Box<SubT<usize>>`
+
+error: usage of `Rc<Arc<T>>`
+  --> $DIR/redundant_allocation.rs:54:29
+   |
+LL |     pub fn rc_test9<T>(foo: Rc<Arc<T>>) -> Rc<Arc<SubT<T>>> {
+   |                             ^^^^^^^^^^
+   |
+   = note: `Arc<T>` is already on the heap, `Rc<Arc<T>>` makes an extra allocation
+   = help: consider using just `Rc<T>` or `Arc<T>`
 
-error: usage of `Rc<&T>`
-  --> $DIR/redundant_allocation.rs:26:19
+error: usage of `Rc<Arc<SubT<T>>>`
+  --> $DIR/redundant_allocation.rs:54:44
+   |
+LL |     pub fn rc_test9<T>(foo: Rc<Arc<T>>) -> Rc<Arc<SubT<T>>> {
+   |                                            ^^^^^^^^^^^^^^^^
    |
-LL | pub fn test3(foo: Rc<&MyEnum>) {}
-   |                   ^^^^^^^^^^^ help: try: `&MyEnum`
+   = note: `Arc<SubT<T>>` is already on the heap, `Rc<Arc<SubT<T>>>` makes an extra allocation
+   = help: consider using just `Rc<SubT<T>>` or `Arc<SubT<T>>`
 
-error: usage of `Rc<Rc<T>>`
-  --> $DIR/redundant_allocation.rs:32:17
+error: usage of `Arc<Box<bool>>`
+  --> $DIR/redundant_allocation.rs:67:25
    |
-LL | pub fn test5(a: Rc<Rc<bool>>) {}
-   |                 ^^^^^^^^^^^^ help: try: `Rc<bool>`
+LL |     pub fn arc_test5(a: Arc<Box<bool>>) {}
+   |                         ^^^^^^^^^^^^^^
+   |
+   = note: `Box<bool>` is already on the heap, `Arc<Box<bool>>` makes an extra allocation
+   = help: consider using just `Arc<bool>` or `Box<bool>`
 
-error: usage of `Rc<Box<T>>`
-  --> $DIR/redundant_allocation.rs:36:17
+error: usage of `Arc<Rc<bool>>`
+  --> $DIR/redundant_allocation.rs:69:25
+   |
+LL |     pub fn arc_test6(a: Arc<Rc<bool>>) {}
+   |                         ^^^^^^^^^^^^^
    |
-LL | pub fn test6(a: Rc<Box<bool>>) {}
-   |                 ^^^^^^^^^^^^^ help: try: `Rc<bool>`
+   = note: `Rc<bool>` is already on the heap, `Arc<Rc<bool>>` makes an extra allocation
+   = help: consider using just `Arc<bool>` or `Rc<bool>`
 
-error: usage of `Box<&T>`
-  --> $DIR/redundant_allocation.rs:40:22
+error: usage of `Arc<Box<SubT<usize>>>`
+  --> $DIR/redundant_allocation.rs:71:27
    |
-LL | pub fn test7<T>(foo: Box<&T>) {}
-   |                      ^^^^^^^ help: try: `&T`
+LL |     pub fn arc_test8() -> Arc<Box<SubT<usize>>> {
+   |                           ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `Box<SubT<usize>>` is already on the heap, `Arc<Box<SubT<usize>>>` makes an extra allocation
+   = help: consider using just `Arc<SubT<usize>>` or `Box<SubT<usize>>`
 
-error: usage of `Box<&T>`
-  --> $DIR/redundant_allocation.rs:42:19
+error: usage of `Arc<Rc<T>>`
+  --> $DIR/redundant_allocation.rs:75:30
+   |
+LL |     pub fn arc_test9<T>(foo: Arc<Rc<T>>) -> Arc<Rc<SubT<T>>> {
+   |                              ^^^^^^^^^^
    |
-LL | pub fn test8(foo: Box<&MyStruct>) {}
-   |                   ^^^^^^^^^^^^^^ help: try: `&MyStruct`
+   = note: `Rc<T>` is already on the heap, `Arc<Rc<T>>` makes an extra allocation
+   = help: consider using just `Arc<T>` or `Rc<T>`
 
-error: usage of `Box<&T>`
-  --> $DIR/redundant_allocation.rs:44:19
+error: usage of `Arc<Rc<SubT<T>>>`
+  --> $DIR/redundant_allocation.rs:75:45
+   |
+LL |     pub fn arc_test9<T>(foo: Arc<Rc<T>>) -> Arc<Rc<SubT<T>>> {
+   |                                             ^^^^^^^^^^^^^^^^
    |
-LL | pub fn test9(foo: Box<&MyEnum>) {}
-   |                   ^^^^^^^^^^^^ help: try: `&MyEnum`
+   = note: `Rc<SubT<T>>` is already on the heap, `Arc<Rc<SubT<T>>>` makes an extra allocation
+   = help: consider using just `Arc<SubT<T>>` or `Rc<SubT<T>>`
 
-error: aborting due to 8 previous errors
+error: aborting due to 15 previous errors
 
diff --git a/tests/ui/redundant_allocation_fixable.fixed b/tests/ui/redundant_allocation_fixable.fixed
new file mode 100644
index 00000000000..ef089b25f47
--- /dev/null
+++ b/tests/ui/redundant_allocation_fixable.fixed
@@ -0,0 +1,75 @@
+// run-rustfix
+#![warn(clippy::all)]
+#![allow(clippy::boxed_local, clippy::needless_pass_by_value)]
+#![allow(clippy::blacklisted_name, unused_variables, dead_code)]
+#![allow(unused_imports)]
+
+pub struct MyStruct {}
+
+pub struct SubT<T> {
+    foo: T,
+}
+
+pub enum MyEnum {
+    One,
+    Two,
+}
+
+mod outer_box {
+    use crate::MyEnum;
+    use crate::MyStruct;
+    use crate::SubT;
+    use std::boxed::Box;
+    use std::rc::Rc;
+    use std::sync::Arc;
+
+    pub fn box_test1<T>(foo: &T) {}
+
+    pub fn box_test2(foo: &MyStruct) {}
+
+    pub fn box_test3(foo: &MyEnum) {}
+
+    pub fn box_test4_neg(foo: Box<SubT<&usize>>) {}
+
+    pub fn box_test5<T>(foo: Box<T>) {}
+}
+
+mod outer_rc {
+    use crate::MyEnum;
+    use crate::MyStruct;
+    use crate::SubT;
+    use std::boxed::Box;
+    use std::rc::Rc;
+    use std::sync::Arc;
+
+    pub fn rc_test1<T>(foo: &T) {}
+
+    pub fn rc_test2(foo: &MyStruct) {}
+
+    pub fn rc_test3(foo: &MyEnum) {}
+
+    pub fn rc_test4_neg(foo: Rc<SubT<&usize>>) {}
+
+    pub fn rc_test6(a: Rc<bool>) {}
+}
+
+mod outer_arc {
+    use crate::MyEnum;
+    use crate::MyStruct;
+    use crate::SubT;
+    use std::boxed::Box;
+    use std::rc::Rc;
+    use std::sync::Arc;
+
+    pub fn arc_test1<T>(foo: &T) {}
+
+    pub fn arc_test2(foo: &MyStruct) {}
+
+    pub fn arc_test3(foo: &MyEnum) {}
+
+    pub fn arc_test4_neg(foo: Arc<SubT<&usize>>) {}
+
+    pub fn arc_test7(a: Arc<bool>) {}
+}
+
+fn main() {}
diff --git a/tests/ui/redundant_allocation_fixable.rs b/tests/ui/redundant_allocation_fixable.rs
new file mode 100644
index 00000000000..fefa87721d7
--- /dev/null
+++ b/tests/ui/redundant_allocation_fixable.rs
@@ -0,0 +1,75 @@
+// run-rustfix
+#![warn(clippy::all)]
+#![allow(clippy::boxed_local, clippy::needless_pass_by_value)]
+#![allow(clippy::blacklisted_name, unused_variables, dead_code)]
+#![allow(unused_imports)]
+
+pub struct MyStruct {}
+
+pub struct SubT<T> {
+    foo: T,
+}
+
+pub enum MyEnum {
+    One,
+    Two,
+}
+
+mod outer_box {
+    use crate::MyEnum;
+    use crate::MyStruct;
+    use crate::SubT;
+    use std::boxed::Box;
+    use std::rc::Rc;
+    use std::sync::Arc;
+
+    pub fn box_test1<T>(foo: Box<&T>) {}
+
+    pub fn box_test2(foo: Box<&MyStruct>) {}
+
+    pub fn box_test3(foo: Box<&MyEnum>) {}
+
+    pub fn box_test4_neg(foo: Box<SubT<&usize>>) {}
+
+    pub fn box_test5<T>(foo: Box<Box<T>>) {}
+}
+
+mod outer_rc {
+    use crate::MyEnum;
+    use crate::MyStruct;
+    use crate::SubT;
+    use std::boxed::Box;
+    use std::rc::Rc;
+    use std::sync::Arc;
+
+    pub fn rc_test1<T>(foo: Rc<&T>) {}
+
+    pub fn rc_test2(foo: Rc<&MyStruct>) {}
+
+    pub fn rc_test3(foo: Rc<&MyEnum>) {}
+
+    pub fn rc_test4_neg(foo: Rc<SubT<&usize>>) {}
+
+    pub fn rc_test6(a: Rc<Rc<bool>>) {}
+}
+
+mod outer_arc {
+    use crate::MyEnum;
+    use crate::MyStruct;
+    use crate::SubT;
+    use std::boxed::Box;
+    use std::rc::Rc;
+    use std::sync::Arc;
+
+    pub fn arc_test1<T>(foo: Arc<&T>) {}
+
+    pub fn arc_test2(foo: Arc<&MyStruct>) {}
+
+    pub fn arc_test3(foo: Arc<&MyEnum>) {}
+
+    pub fn arc_test4_neg(foo: Arc<SubT<&usize>>) {}
+
+    pub fn arc_test7(a: Arc<Arc<bool>>) {}
+}
+
+fn main() {}
diff --git a/tests/ui/redundant_allocation_fixable.stderr b/tests/ui/redundant_allocation_fixable.stderr
new file mode 100644
index 00000000000..fdd76ef17a5
--- /dev/null
+++ b/tests/ui/redundant_allocation_fixable.stderr
@@ -0,0 +1,99 @@
+error: usage of `Box<&T>`
+  --> $DIR/redundant_allocation_fixable.rs:26:30
+   |
+LL |     pub fn box_test1<T>(foo: Box<&T>) {}
+   |                              ^^^^^^^ help: try: `&T`
+   |
+   = note: `-D clippy::redundant-allocation` implied by `-D warnings`
+   = note: `&T` is already a pointer, `Box<&T>` allocates a pointer on the heap
+
+error: usage of `Box<&MyStruct>`
+  --> $DIR/redundant_allocation_fixable.rs:28:27
+   |
+LL |     pub fn box_test2(foo: Box<&MyStruct>) {}
+   |                           ^^^^^^^^^^^^^^ help: try: `&MyStruct`
+   |
+   = note: `&MyStruct` is already a pointer, `Box<&MyStruct>` allocates a pointer on the heap
+
+error: usage of `Box<&MyEnum>`
+  --> $DIR/redundant_allocation_fixable.rs:30:27
+   |
+LL |     pub fn box_test3(foo: Box<&MyEnum>) {}
+   |                           ^^^^^^^^^^^^ help: try: `&MyEnum`
+   |
+   = note: `&MyEnum` is already a pointer, `Box<&MyEnum>` allocates a pointer on the heap
+
+error: usage of `Box<Box<T>>`
+  --> $DIR/redundant_allocation_fixable.rs:34:30
+   |
+LL |     pub fn box_test5<T>(foo: Box<Box<T>>) {}
+   |                              ^^^^^^^^^^^ help: try: `Box<T>`
+   |
+   = note: `Box<T>` is already on the heap, `Box<Box<T>>` makes an extra allocation
+
+error: usage of `Rc<&T>`
+  --> $DIR/redundant_allocation_fixable.rs:45:29
+   |
+LL |     pub fn rc_test1<T>(foo: Rc<&T>) {}
+   |                             ^^^^^^ help: try: `&T`
+   |
+   = note: `&T` is already a pointer, `Rc<&T>` allocates a pointer on the heap
+
+error: usage of `Rc<&MyStruct>`
+  --> $DIR/redundant_allocation_fixable.rs:47:26
+   |
+LL |     pub fn rc_test2(foo: Rc<&MyStruct>) {}
+   |                          ^^^^^^^^^^^^^ help: try: `&MyStruct`
+   |
+   = note: `&MyStruct` is already a pointer, `Rc<&MyStruct>` allocates a pointer on the heap
+
+error: usage of `Rc<&MyEnum>`
+  --> $DIR/redundant_allocation_fixable.rs:49:26
+   |
+LL |     pub fn rc_test3(foo: Rc<&MyEnum>) {}
+   |                          ^^^^^^^^^^^ help: try: `&MyEnum`
+   |
+   = note: `&MyEnum` is already a pointer, `Rc<&MyEnum>` allocates a pointer on the heap
+
+error: usage of `Rc<Rc<bool>>`
+  --> $DIR/redundant_allocation_fixable.rs:53:24
+   |
+LL |     pub fn rc_test6(a: Rc<Rc<bool>>) {}
+   |                        ^^^^^^^^^^^^ help: try: `Rc<bool>`
+   |
+   = note: `Rc<bool>` is already on the heap, `Rc<Rc<bool>>` makes an extra allocation
+
+error: usage of `Arc<&T>`
+  --> $DIR/redundant_allocation_fixable.rs:64:30
+   |
+LL |     pub fn arc_test1<T>(foo: Arc<&T>) {}
+   |                              ^^^^^^^ help: try: `&T`
+   |
+   = note: `&T` is already a pointer, `Arc<&T>` allocates a pointer on the heap
+
+error: usage of `Arc<&MyStruct>`
+  --> $DIR/redundant_allocation_fixable.rs:66:27
+   |
+LL |     pub fn arc_test2(foo: Arc<&MyStruct>) {}
+   |                           ^^^^^^^^^^^^^^ help: try: `&MyStruct`
+   |
+   = note: `&MyStruct` is already a pointer, `Arc<&MyStruct>` allocates a pointer on the heap
+
+error: usage of `Arc<&MyEnum>`
+  --> $DIR/redundant_allocation_fixable.rs:68:27
+   |
+LL |     pub fn arc_test3(foo: Arc<&MyEnum>) {}
+   |                           ^^^^^^^^^^^^ help: try: `&MyEnum`
+   |
+   = note: `&MyEnum` is already a pointer, `Arc<&MyEnum>` allocates a pointer on the heap
+
+error: usage of `Arc<Arc<bool>>`
+  --> $DIR/redundant_allocation_fixable.rs:72:25
+   |
+LL |     pub fn arc_test7(a: Arc<Arc<bool>>) {}
+   |                         ^^^^^^^^^^^^^^ help: try: `Arc<bool>`
+   |
+   = note: `Arc<bool>` is already on the heap, `Arc<Arc<bool>>` makes an extra allocation
+
+error: aborting due to 12 previous errors
+