Skip to content

Commit 09f5f15

Browse files
committed
Auto merge of #7308 - lengyijun:redundant_allocation_arc, r=xFrednet,flip1995
add Arc to `redundant_allocation` fixes #7303 changelog: add Arc to `redundant_allocation`
2 parents 2b193e2 + e575610 commit 09f5f15

8 files changed

+509
-165
lines changed

clippy_lints/src/types/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -178,8 +178,8 @@ declare_clippy_lint! {
178178
declare_clippy_lint! {
179179
/// **What it does:** Checks for use of redundant allocations anywhere in the code.
180180
///
181-
/// **Why is this bad?** Expressions such as `Rc<&T>`, `Rc<Rc<T>>`, `Rc<Box<T>>`, `Box<&T>`
182-
/// add an unnecessary level of indirection.
181+
/// **Why is this bad?** Expressions such as `Rc<&T>`, `Rc<Rc<T>>`, `Rc<Arc<T>>`, `Rc<Box<T>>`, Arc<&T>`, `Arc<Rc<T>>`,
182+
/// `Arc<Arc<T>>`, `Arc<Box<T>>`, `Box<&T>`, `Box<Rc<T>>`, `Box<Arc<T>>`, `Box<Box<T>>`, add an unnecessary level of indirection.
183183
///
184184
/// **Known problems:** None.
185185
///
+89-64
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
use clippy_utils::diagnostics::span_lint_and_sugg;
2-
use clippy_utils::source::snippet_with_applicability;
1+
use clippy_utils::diagnostics::span_lint_and_then;
2+
use clippy_utils::source::{snippet, snippet_with_applicability};
33
use clippy_utils::{get_qpath_generic_tys, is_ty_param_diagnostic_item, is_ty_param_lang_item};
44
use rustc_errors::Applicability;
55
use rustc_hir::{self as hir, def_id::DefId, LangItem, QPath, TyKind};
@@ -9,74 +9,99 @@ use rustc_span::symbol::sym;
99
use super::{utils, REDUNDANT_ALLOCATION};
1010

1111
pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool {
12-
if Some(def_id) == cx.tcx.lang_items().owned_box() {
13-
if let Some(span) = utils::match_borrows_parameter(cx, qpath) {
14-
let mut applicability = Applicability::MachineApplicable;
15-
span_lint_and_sugg(
16-
cx,
17-
REDUNDANT_ALLOCATION,
18-
hir_ty.span,
19-
"usage of `Box<&T>`",
20-
"try",
21-
snippet_with_applicability(cx, span, "..", &mut applicability).to_string(),
22-
applicability,
23-
);
24-
return true;
25-
}
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;
2640
}
2741

28-
if cx.tcx.is_diagnostic_item(sym::Rc, def_id) {
29-
if let Some(ty) = is_ty_param_diagnostic_item(cx, qpath, sym::Rc) {
30-
let mut applicability = Applicability::MachineApplicable;
31-
span_lint_and_sugg(
32-
cx,
33-
REDUNDANT_ALLOCATION,
34-
hir_ty.span,
35-
"usage of `Rc<Rc<T>>`",
36-
"try",
37-
snippet_with_applicability(cx, ty.span, "..", &mut applicability).to_string(),
38-
applicability,
39-
);
40-
true
41-
} else if let Some(ty) = is_ty_param_lang_item(cx, qpath, LangItem::OwnedBox) {
42-
let qpath = match &ty.kind {
43-
TyKind::Path(qpath) => qpath,
44-
_ => return false,
45-
};
46-
let inner_span = match get_qpath_generic_tys(qpath).next() {
47-
Some(ty) => ty.span,
48-
None => return false,
49-
};
50-
let mut applicability = Applicability::MachineApplicable;
51-
span_lint_and_sugg(
52-
cx,
53-
REDUNDANT_ALLOCATION,
54-
hir_ty.span,
55-
"usage of `Rc<Box<T>>`",
56-
"try",
57-
format!(
58-
"Rc<{}>",
59-
snippet_with_applicability(cx, inner_span, "..", &mut applicability)
60-
),
61-
applicability,
62-
);
63-
true
64-
} else {
65-
utils::match_borrows_parameter(cx, qpath).map_or(false, |span| {
66-
let mut applicability = Applicability::MachineApplicable;
67-
span_lint_and_sugg(
68-
cx,
69-
REDUNDANT_ALLOCATION,
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(
7070
hir_ty.span,
71-
"usage of `Rc<&T>`",
7271
"try",
73-
snippet_with_applicability(cx, span, "..", &mut applicability).to_string(),
72+
format!("{}<{}>", outer_sym, generic_snippet),
7473
applicability,
7574
);
76-
true
77-
})
78-
}
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+
);
7983
} else {
80-
false
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+
);
81105
}
106+
true
82107
}

tests/ui/redundant_allocation.fixed

-48
This file was deleted.

tests/ui/redundant_allocation.rs

+50-18
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
1-
// run-rustfix
21
#![warn(clippy::all)]
32
#![allow(clippy::boxed_local, clippy::needless_pass_by_value)]
43
#![allow(clippy::blacklisted_name, unused_variables, dead_code)]
5-
6-
use std::boxed::Box;
7-
use std::rc::Rc;
4+
#![allow(unused_imports)]
85

96
pub struct MyStruct {}
107

@@ -17,32 +14,67 @@ pub enum MyEnum {
1714
Two,
1815
}
1916

20-
// Rc<&T>
17+
mod outer_box {
18+
use crate::MyEnum;
19+
use crate::MyStruct;
20+
use crate::SubT;
21+
use std::boxed::Box;
22+
use std::rc::Rc;
23+
use std::sync::Arc;
2124

22-
pub fn test1<T>(foo: Rc<&T>) {}
25+
pub fn box_test6<T>(foo: Box<Rc<T>>) {}
2326

24-
pub fn test2(foo: Rc<&MyStruct>) {}
27+
pub fn box_test7<T>(foo: Box<Arc<T>>) {}
2528

26-
pub fn test3(foo: Rc<&MyEnum>) {}
29+
pub fn box_test8() -> Box<Rc<SubT<usize>>> {
30+
unimplemented!();
31+
}
2732

28-
pub fn test4_neg(foo: Rc<SubT<&usize>>) {}
33+
pub fn box_test9<T>(foo: Box<Arc<T>>) -> Box<Arc<SubT<T>>> {
34+
unimplemented!();
35+
}
36+
}
2937

30-
// Rc<Rc<T>>
38+
mod outer_rc {
39+
use crate::MyEnum;
40+
use crate::MyStruct;
41+
use crate::SubT;
42+
use std::boxed::Box;
43+
use std::rc::Rc;
44+
use std::sync::Arc;
3145

32-
pub fn test5(a: Rc<Rc<bool>>) {}
46+
pub fn rc_test5(a: Rc<Box<bool>>) {}
3347

34-
// Rc<Box<T>>
48+
pub fn rc_test7(a: Rc<Arc<bool>>) {}
3549

36-
pub fn test6(a: Rc<Box<bool>>) {}
50+
pub fn rc_test8() -> Rc<Box<SubT<usize>>> {
51+
unimplemented!();
52+
}
3753

38-
// Box<&T>
54+
pub fn rc_test9<T>(foo: Rc<Arc<T>>) -> Rc<Arc<SubT<T>>> {
55+
unimplemented!();
56+
}
57+
}
3958

40-
pub fn test7<T>(foo: Box<&T>) {}
59+
mod outer_arc {
60+
use crate::MyEnum;
61+
use crate::MyStruct;
62+
use crate::SubT;
63+
use std::boxed::Box;
64+
use std::rc::Rc;
65+
use std::sync::Arc;
4166

42-
pub fn test8(foo: Box<&MyStruct>) {}
67+
pub fn arc_test5(a: Arc<Box<bool>>) {}
4368

44-
pub fn test9(foo: Box<&MyEnum>) {}
69+
pub fn arc_test6(a: Arc<Rc<bool>>) {}
4570

46-
pub fn test10_neg(foo: Box<SubT<&usize>>) {}
71+
pub fn arc_test8() -> Arc<Box<SubT<usize>>> {
72+
unimplemented!();
73+
}
74+
75+
pub fn arc_test9<T>(foo: Arc<Rc<T>>) -> Arc<Rc<SubT<T>>> {
76+
unimplemented!();
77+
}
78+
}
4779

4880
fn main() {}

0 commit comments

Comments
 (0)