Skip to content

Commit 0dcf54a

Browse files
committed
useless Rc<Rc<T>>, Rc<Box<T>>, Rc<&T>, Box<&T>
1 parent 326b220 commit 0dcf54a

10 files changed

+259
-8
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -1433,6 +1433,7 @@ Released 2018-09-13
14331433
[`range_plus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_plus_one
14341434
[`range_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_step_by_zero
14351435
[`range_zip_with_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_zip_with_len
1436+
[`redundant_allocation`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation
14361437
[`redundant_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_clone
14371438
[`redundant_closure`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure
14381439
[`redundant_closure_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure_call

clippy_lints/src/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -811,6 +811,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
811811
&types::LET_UNIT_VALUE,
812812
&types::LINKEDLIST,
813813
&types::OPTION_OPTION,
814+
&types::REDUNDANT_ALLOCATION,
814815
&types::TYPE_COMPLEXITY,
815816
&types::UNIT_ARG,
816817
&types::UNIT_CMP,
@@ -1376,6 +1377,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
13761377
LintId::of(&types::IMPLICIT_HASHER),
13771378
LintId::of(&types::LET_UNIT_VALUE),
13781379
LintId::of(&types::OPTION_OPTION),
1380+
LintId::of(&types::REDUNDANT_ALLOCATION),
13791381
LintId::of(&types::TYPE_COMPLEXITY),
13801382
LintId::of(&types::UNIT_ARG),
13811383
LintId::of(&types::UNIT_CMP),
@@ -1661,6 +1663,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
16611663
LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
16621664
LintId::of(&trivially_copy_pass_by_ref::TRIVIALLY_COPY_PASS_BY_REF),
16631665
LintId::of(&types::BOX_VEC),
1666+
LintId::of(&types::REDUNDANT_ALLOCATION),
16641667
LintId::of(&vec::USELESS_VEC),
16651668
]);
16661669

clippy_lints/src/types.rs

+97-6
Original file line numberDiff line numberDiff line change
@@ -171,11 +171,35 @@ declare_clippy_lint! {
171171
"a borrow of a boxed type"
172172
}
173173

174+
declare_clippy_lint! {
175+
/// **What it does:** Checks for use of redundant allocations anywhere in the code.
176+
///
177+
/// **Why is this bad?** Expressions such as `Rc<&T>`, `Rc<Rc<T>>`, `Rc<Box<T>>`, `Box<&T>`
178+
/// add an unnecessary level of indirection.
179+
///
180+
/// **Known problems:** None.
181+
///
182+
/// **Example:**
183+
/// ```rust
184+
/// # use std::rc::Rc;
185+
/// fn foo(bar: Rc<&usize>) {}
186+
/// ```
187+
///
188+
/// Better:
189+
///
190+
/// ```rust
191+
/// fn foo(bar: &usize) {}
192+
/// ```
193+
pub REDUNDANT_ALLOCATION,
194+
perf,
195+
"redundant allocation"
196+
}
197+
174198
pub struct Types {
175199
vec_box_size_threshold: u64,
176200
}
177201

178-
impl_lint_pass!(Types => [BOX_VEC, VEC_BOX, OPTION_OPTION, LINKEDLIST, BORROWED_BOX]);
202+
impl_lint_pass!(Types => [BOX_VEC, VEC_BOX, OPTION_OPTION, LINKEDLIST, BORROWED_BOX, REDUNDANT_ALLOCATION]);
179203

180204
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Types {
181205
fn check_fn(
@@ -217,7 +241,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Types {
217241
}
218242

219243
/// Checks if `qpath` has last segment with type parameter matching `path`
220-
fn match_type_parameter(cx: &LateContext<'_, '_>, qpath: &QPath<'_>, path: &[&str]) -> bool {
244+
fn match_type_parameter(cx: &LateContext<'_, '_>, qpath: &QPath<'_>, path: &[&str]) -> Option<Span> {
221245
let last = last_path_segment(qpath);
222246
if_chain! {
223247
if let Some(ref params) = last.args;
@@ -230,10 +254,27 @@ fn match_type_parameter(cx: &LateContext<'_, '_>, qpath: &QPath<'_>, path: &[&st
230254
if let Some(did) = qpath_res(cx, qpath, ty.hir_id).opt_def_id();
231255
if match_def_path(cx, did, path);
232256
then {
233-
return true;
257+
return Some(ty.span);
234258
}
235259
}
236-
false
260+
None
261+
}
262+
263+
fn match_borrows_parameter(_cx: &LateContext<'_, '_>, qpath: &QPath<'_>) -> Option<Span> {
264+
let last = last_path_segment(qpath);
265+
if_chain! {
266+
if let Some(ref params) = last.args;
267+
if !params.parenthesized;
268+
if let Some(ty) = params.args.iter().find_map(|arg| match arg {
269+
GenericArg::Type(ty) => Some(ty),
270+
_ => None,
271+
});
272+
if let TyKind::Rptr(..) = ty.kind;
273+
then {
274+
return Some(ty.span);
275+
}
276+
}
277+
None
237278
}
238279

239280
impl Types {
@@ -257,6 +298,7 @@ impl Types {
257298
/// The parameter `is_local` distinguishes the context of the type; types from
258299
/// local bindings should only be checked for the `BORROWED_BOX` lint.
259300
#[allow(clippy::too_many_lines)]
301+
#[allow(clippy::cognitive_complexity)]
260302
fn check_ty(&mut self, cx: &LateContext<'_, '_>, hir_ty: &hir::Ty<'_>, is_local: bool) {
261303
if hir_ty.span.from_expansion() {
262304
return;
@@ -267,7 +309,19 @@ impl Types {
267309
let res = qpath_res(cx, qpath, hir_id);
268310
if let Some(def_id) = res.opt_def_id() {
269311
if Some(def_id) == cx.tcx.lang_items().owned_box() {
270-
if match_type_parameter(cx, qpath, &paths::VEC) {
312+
if let Some(span) = match_borrows_parameter(cx, qpath) {
313+
span_lint_and_sugg(
314+
cx,
315+
REDUNDANT_ALLOCATION,
316+
hir_ty.span,
317+
"usage of `Box<&T>`",
318+
"try",
319+
snippet(cx, span, "..").to_string(),
320+
Applicability::MachineApplicable,
321+
);
322+
return; // don't recurse into the type
323+
}
324+
if match_type_parameter(cx, qpath, &paths::VEC).is_some() {
271325
span_lint_and_help(
272326
cx,
273327
BOX_VEC,
@@ -277,6 +331,43 @@ impl Types {
277331
);
278332
return; // don't recurse into the type
279333
}
334+
} else if Some(def_id) == cx.tcx.lang_items().rc() {
335+
if let Some(span) = match_type_parameter(cx, qpath, &paths::RC) {
336+
span_lint_and_sugg(
337+
cx,
338+
REDUNDANT_ALLOCATION,
339+
hir_ty.span,
340+
"usage of `Rc<Rc<T>>`",
341+
"try",
342+
snippet(cx, span, "..").to_string(),
343+
Applicability::MachineApplicable,
344+
);
345+
return; // don't recurse into the type
346+
}
347+
if let Some(span) = match_type_parameter(cx, qpath, &paths::BOX) {
348+
span_lint_and_sugg(
349+
cx,
350+
REDUNDANT_ALLOCATION,
351+
hir_ty.span,
352+
"usage of `Rc<Box<T>>`",
353+
"try",
354+
snippet(cx, span, "..").to_string(),
355+
Applicability::MachineApplicable,
356+
);
357+
return; // don't recurse into the type
358+
}
359+
if let Some(span) = match_borrows_parameter(cx, qpath) {
360+
span_lint_and_sugg(
361+
cx,
362+
REDUNDANT_ALLOCATION,
363+
hir_ty.span,
364+
"usage of `Rc<&T>`",
365+
"try",
366+
snippet(cx, span, "..").to_string(),
367+
Applicability::MachineApplicable,
368+
);
369+
return; // don't recurse into the type
370+
}
280371
} else if cx.tcx.is_diagnostic_item(Symbol::intern("vec_type"), def_id) {
281372
if_chain! {
282373
// Get the _ part of Vec<_>
@@ -314,7 +405,7 @@ impl Types {
314405
}
315406
}
316407
} else if match_def_path(cx, def_id, &paths::OPTION) {
317-
if match_type_parameter(cx, qpath, &paths::OPTION) {
408+
if let Some(_) = match_type_parameter(cx, qpath, &paths::OPTION) {
318409
span_lint(
319410
cx,
320411
OPTION_OPTION,

clippy_lints/src/utils/paths.rs

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ pub const BEGIN_PANIC: [&str; 3] = ["std", "panicking", "begin_panic"];
1010
pub const BEGIN_PANIC_FMT: [&str; 3] = ["std", "panicking", "begin_panic_fmt"];
1111
pub const BINARY_HEAP: [&str; 4] = ["alloc", "collections", "binary_heap", "BinaryHeap"];
1212
pub const BORROW_TRAIT: [&str; 3] = ["core", "borrow", "Borrow"];
13+
pub const BOX: [&str; 3] = ["alloc", "boxed", "Box"];
1314
pub const BTREEMAP: [&str; 5] = ["alloc", "collections", "btree", "map", "BTreeMap"];
1415
pub const BTREEMAP_ENTRY: [&str; 5] = ["alloc", "collections", "btree", "map", "Entry"];
1516
pub const BTREESET: [&str; 5] = ["alloc", "collections", "btree", "set", "BTreeSet"];

src/lintlist/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -1725,6 +1725,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
17251725
deprecation: None,
17261726
module: "ranges",
17271727
},
1728+
Lint {
1729+
name: "redundant_allocation",
1730+
group: "perf",
1731+
desc: "redundant allocation",
1732+
deprecation: None,
1733+
module: "types",
1734+
},
17281735
Lint {
17291736
name: "redundant_clone",
17301737
group: "perf",

tests/ui/must_use_candidates.fixed

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// run-rustfix
22
#![feature(never_type)]
3-
#![allow(unused_mut)]
3+
#![allow(unused_mut, clippy::redundant_allocation)]
44
#![warn(clippy::must_use_candidate)]
55
use std::rc::Rc;
66
use std::sync::atomic::{AtomicBool, Ordering};

tests/ui/must_use_candidates.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// run-rustfix
22
#![feature(never_type)]
3-
#![allow(unused_mut)]
3+
#![allow(unused_mut, clippy::redundant_allocation)]
44
#![warn(clippy::must_use_candidate)]
55
use std::rc::Rc;
66
use std::sync::atomic::{AtomicBool, Ordering};

tests/ui/redundant_allocation.fixed

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// run-rustfix
2+
#![warn(clippy::all)]
3+
#![allow(clippy::boxed_local, clippy::needless_pass_by_value)]
4+
#![allow(clippy::blacklisted_name, unused_variables, dead_code)]
5+
6+
use std::boxed::Box;
7+
use std::rc::Rc;
8+
9+
pub struct MyStruct {}
10+
11+
pub struct SubT<T> {
12+
foo: T,
13+
}
14+
15+
pub enum MyEnum {
16+
One,
17+
Two,
18+
}
19+
20+
// Rc<&T>
21+
22+
pub fn test1<T>(foo: &T) {}
23+
24+
pub fn test2(foo: &MyStruct) {}
25+
26+
pub fn test3(foo: &MyEnum) {}
27+
28+
pub fn test4_neg(foo: Rc<SubT<&usize>>) {}
29+
30+
// Rc<Rc<T>>
31+
32+
pub fn test5(a: Rc<bool>) {}
33+
34+
// Rc<Box<T>>
35+
36+
pub fn test6(a: Box<bool>) {}
37+
38+
// Box<&T>
39+
40+
pub fn test7<T>(foo: &T) {}
41+
42+
pub fn test8(foo: &MyStruct) {}
43+
44+
pub fn test9(foo: &MyEnum) {}
45+
46+
pub fn test10_neg(foo: Box<SubT<&usize>>) {}
47+
48+
fn main() {}

tests/ui/redundant_allocation.rs

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// run-rustfix
2+
#![warn(clippy::all)]
3+
#![allow(clippy::boxed_local, clippy::needless_pass_by_value)]
4+
#![allow(clippy::blacklisted_name, unused_variables, dead_code)]
5+
6+
use std::boxed::Box;
7+
use std::rc::Rc;
8+
9+
pub struct MyStruct {}
10+
11+
pub struct SubT<T> {
12+
foo: T,
13+
}
14+
15+
pub enum MyEnum {
16+
One,
17+
Two,
18+
}
19+
20+
// Rc<&T>
21+
22+
pub fn test1<T>(foo: Rc<&T>) {}
23+
24+
pub fn test2(foo: Rc<&MyStruct>) {}
25+
26+
pub fn test3(foo: Rc<&MyEnum>) {}
27+
28+
pub fn test4_neg(foo: Rc<SubT<&usize>>) {}
29+
30+
// Rc<Rc<T>>
31+
32+
pub fn test5(a: Rc<Rc<bool>>) {}
33+
34+
// Rc<Box<T>>
35+
36+
pub fn test6(a: Rc<Box<bool>>) {}
37+
38+
// Box<&T>
39+
40+
pub fn test7<T>(foo: Box<&T>) {}
41+
42+
pub fn test8(foo: Box<&MyStruct>) {}
43+
44+
pub fn test9(foo: Box<&MyEnum>) {}
45+
46+
pub fn test10_neg(foo: Box<SubT<&usize>>) {}
47+
48+
fn main() {}

tests/ui/redundant_allocation.stderr

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
error: usage of `Rc<&T>`
2+
--> $DIR/redundant_allocation.rs:22:22
3+
|
4+
LL | pub fn test1<T>(foo: Rc<&T>) {}
5+
| ^^^^^^ help: try: `&T`
6+
|
7+
= note: `-D clippy::redundant-allocation` implied by `-D warnings`
8+
9+
error: usage of `Rc<&T>`
10+
--> $DIR/redundant_allocation.rs:24:19
11+
|
12+
LL | pub fn test2(foo: Rc<&MyStruct>) {}
13+
| ^^^^^^^^^^^^^ help: try: `&MyStruct`
14+
15+
error: usage of `Rc<&T>`
16+
--> $DIR/redundant_allocation.rs:26:19
17+
|
18+
LL | pub fn test3(foo: Rc<&MyEnum>) {}
19+
| ^^^^^^^^^^^ help: try: `&MyEnum`
20+
21+
error: usage of `Rc<Rc<T>>`
22+
--> $DIR/redundant_allocation.rs:32:17
23+
|
24+
LL | pub fn test5(a: Rc<Rc<bool>>) {}
25+
| ^^^^^^^^^^^^ help: try: `Rc<bool>`
26+
27+
error: usage of `Rc<Box<T>>`
28+
--> $DIR/redundant_allocation.rs:36:17
29+
|
30+
LL | pub fn test6(a: Rc<Box<bool>>) {}
31+
| ^^^^^^^^^^^^^ help: try: `Box<bool>`
32+
33+
error: usage of `Box<&T>`
34+
--> $DIR/redundant_allocation.rs:40:22
35+
|
36+
LL | pub fn test7<T>(foo: Box<&T>) {}
37+
| ^^^^^^^ help: try: `&T`
38+
39+
error: usage of `Box<&T>`
40+
--> $DIR/redundant_allocation.rs:42:19
41+
|
42+
LL | pub fn test8(foo: Box<&MyStruct>) {}
43+
| ^^^^^^^^^^^^^^ help: try: `&MyStruct`
44+
45+
error: usage of `Box<&T>`
46+
--> $DIR/redundant_allocation.rs:44:19
47+
|
48+
LL | pub fn test9(foo: Box<&MyEnum>) {}
49+
| ^^^^^^^^^^^^ help: try: `&MyEnum`
50+
51+
error: aborting due to 8 previous errors
52+

0 commit comments

Comments
 (0)