Skip to content

Commit 020a85b

Browse files
committed
useless Rc<Rc<T>>, Rc<Box<T>>, Rc<&T>
1 parent a14a2c3 commit 020a85b

File tree

12 files changed

+285
-25
lines changed

12 files changed

+285
-25
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1433,6 +1433,9 @@ 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+
[`rc_borrows`]: https://rust-lang.github.io/rust-clippy/master/index.html#rc_borrows
1437+
[`rc_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#rc_box
1438+
[`rc_rc`]: https://rust-lang.github.io/rust-clippy/master/index.html#rc_rc
14361439
[`redundant_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_clone
14371440
[`redundant_closure`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure
14381441
[`redundant_closure_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure_call

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
77

8-
[There are 361 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
8+
[There are 365 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
99

1010
We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you:
1111

clippy_lints/src/lib.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -811,6 +811,9 @@ 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::RC_BORROWS,
815+
&types::RC_BOX,
816+
&types::RC_RC,
814817
&types::TYPE_COMPLEXITY,
815818
&types::UNIT_ARG,
816819
&types::UNIT_CMP,
@@ -1374,6 +1377,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
13741377
LintId::of(&types::IMPLICIT_HASHER),
13751378
LintId::of(&types::LET_UNIT_VALUE),
13761379
LintId::of(&types::OPTION_OPTION),
1380+
LintId::of(&types::RC_BORROWS),
1381+
LintId::of(&types::RC_BOX),
1382+
LintId::of(&types::RC_RC),
13771383
LintId::of(&types::TYPE_COMPLEXITY),
13781384
LintId::of(&types::UNIT_ARG),
13791385
LintId::of(&types::UNIT_CMP),
@@ -1656,6 +1662,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
16561662
LintId::of(&trivially_copy_pass_by_ref::TRIVIALLY_COPY_PASS_BY_REF),
16571663
LintId::of(&types::BOX_BORROWS),
16581664
LintId::of(&types::BOX_VEC),
1665+
LintId::of(&types::RC_BORROWS),
1666+
LintId::of(&types::RC_BOX),
1667+
LintId::of(&types::RC_RC),
16591668
LintId::of(&vec::USELESS_VEC),
16601669
]);
16611670

clippy_lints/src/types.rs

Lines changed: 146 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -194,11 +194,98 @@ declare_clippy_lint! {
194194
"a box of borrowed type"
195195
}
196196

197+
declare_clippy_lint! {
198+
/// **What it does:** Checks for use of `Rc<&T>` anywhere in the code.
199+
///
200+
/// **Why is this bad?** Wrapping a reference `&T` with an `Rc` adds unnecessary
201+
/// level of indirection.
202+
///
203+
/// **Known problems:** None.
204+
///
205+
/// **Example:**
206+
/// ```rust
207+
/// # use std::rc::Rc;
208+
/// fn foo(bar: Rc<&usize>) {}
209+
/// ```
210+
///
211+
/// Better:
212+
///
213+
/// ```rust
214+
/// # use std::rc::Rc;
215+
/// fn foo(bar: &usize) {}
216+
/// ```
217+
pub RC_BORROWS,
218+
perf,
219+
"a Rc of borrowed type"
220+
}
221+
222+
declare_clippy_lint! {
223+
/// **What it does:** Checks for use of `Rc<Rc<T>>` anywhere in the code.
224+
///
225+
/// **Why is this bad?** Reference counting pointer of reference counting pointer
226+
/// is an unnecessary level of indirection.
227+
///
228+
/// **Known problems:** None.
229+
///
230+
/// **Example:**
231+
/// ```rust
232+
/// # use std::rc::Rc;
233+
/// fn foo(bar: Rc<Rc<usize>>) {}
234+
/// ```
235+
///
236+
/// Better:
237+
///
238+
/// ```rust
239+
/// # use std::rc::Rc;
240+
/// fn foo(bar: Rc<usize>) {}
241+
/// ```
242+
pub RC_RC,
243+
perf,
244+
"an Rc of Rc"
245+
}
246+
247+
declare_clippy_lint! {
248+
/// **What it does:** Checks for use of `Rc<Box<T>>` anywhere in the code.
249+
///
250+
/// **Why is this bad?** `Rc` already keeps its contents in a separate area on
251+
/// the heap. So if you `Box` its contents, you just add another level of indirection.
252+
///
253+
/// **Known problems:** None.
254+
///
255+
/// **Example:**
256+
/// ```rust
257+
/// # use std::rc::Rc;
258+
/// # use std::boxed::Box;
259+
/// fn foo(bar: Rc<Box<usize>>) {}
260+
/// ```
261+
///
262+
/// Better:
263+
///
264+
/// ```rust
265+
/// # use std::rc::Rc;
266+
/// # use std::boxed::Box;
267+
/// fn foo(bar: Rc<usize>) {}
268+
/// ```
269+
pub RC_BOX,
270+
perf,
271+
"an Rc of Box"
272+
}
273+
197274
pub struct Types {
198275
vec_box_size_threshold: u64,
199276
}
200277

201-
impl_lint_pass!(Types => [BOX_VEC, VEC_BOX, OPTION_OPTION, LINKEDLIST, BORROWED_BOX, BOX_BORROWS]);
278+
impl_lint_pass!(Types => [
279+
BOX_VEC,
280+
VEC_BOX,
281+
OPTION_OPTION,
282+
LINKEDLIST,
283+
BORROWED_BOX,
284+
BOX_BORROWS,
285+
RC_RC,
286+
RC_BOX,
287+
RC_BORROWS
288+
]);
202289

203290
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Types {
204291
fn check_fn(
@@ -259,6 +346,24 @@ fn match_type_parameter(cx: &LateContext<'_, '_>, qpath: &QPath<'_>, path: &[&st
259346
false
260347
}
261348

349+
fn match_borrows_parameter<'a>(cx: &'a LateContext<'_, '_>, qpath: &QPath<'_>) -> Option<Ty<'a>> {
350+
if_chain! {
351+
let last = last_path_segment(qpath); // why last path segment?
352+
if let Some(ref params) = last.args;
353+
if !params.parenthesized; // what are parenthesized params?
354+
if let Some(ty) = params.args.iter().find_map(|arg| match arg {
355+
GenericArg::Type(ty) => Some(ty),
356+
_ => None,
357+
});
358+
if let TyKind::Rptr(..) = ty.kind;
359+
let ty_ty = hir_ty_to_ty(cx.tcx, ty);
360+
then {
361+
return Some(ty_ty);
362+
}
363+
}
364+
None
365+
}
366+
262367
impl Types {
263368
pub fn new(vec_box_size_threshold: u64) -> Self {
264369
Self { vec_box_size_threshold }
@@ -291,26 +396,15 @@ impl Types {
291396
let res = qpath_res(cx, qpath, hir_id);
292397
if let Some(def_id) = res.opt_def_id() {
293398
if Some(def_id) == cx.tcx.lang_items().owned_box() {
294-
if_chain! {
295-
let last = last_path_segment(qpath);
296-
if let Some(ref params) = last.args;
297-
if !params.parenthesized;
298-
if let Some(ty) = params.args.iter().find_map(|arg| match arg {
299-
GenericArg::Type(ty) => Some(ty),
300-
_ => None,
301-
});
302-
if let TyKind::Rptr(..) = ty.kind;
303-
let ty_ty = hir_ty_to_ty(cx.tcx, ty);
304-
then {
305-
span_lint_and_help(
306-
cx,
307-
BOX_BORROWS,
308-
hir_ty.span,
309-
"usage of `Box<&T>`",
310-
format!("try `{}`", ty_ty).as_str(),
311-
);
312-
return; // don't recurse into the type
313-
}
399+
if let Some(ty_ty) = match_borrows_parameter(cx, qpath) {
400+
span_lint_and_help(
401+
cx,
402+
BOX_BORROWS,
403+
hir_ty.span,
404+
"usage of `Box<&T>`",
405+
format!("try `{}`", ty_ty).as_str(),
406+
);
407+
return; // don't recurse into the type
314408
}
315409
if match_type_parameter(cx, qpath, &paths::VEC) {
316410
span_lint_and_help(
@@ -322,6 +416,37 @@ impl Types {
322416
);
323417
return; // don't recurse into the type
324418
}
419+
} else if Some(def_id) == cx.tcx.lang_items().rc() {
420+
if match_type_parameter(cx, qpath, &paths::RC) {
421+
span_lint_and_help(
422+
cx,
423+
RC_RC,
424+
hir_ty.span,
425+
"usage of `Rc<Rc<T>>`",
426+
"Rc<Rc<T>> can be simplified to Rc<T>",
427+
);
428+
return; // don't recurse into the type
429+
}
430+
if match_type_parameter(cx, qpath, &paths::BOX) {
431+
span_lint_and_help(
432+
cx,
433+
RC_BOX,
434+
hir_ty.span,
435+
"usage of `Rc<Box<T>>`",
436+
"Rc<Box<T>> can be simplified to Rc<T>",
437+
);
438+
return; // don't recurse into the type
439+
}
440+
if let Some(ty_ty) = match_borrows_parameter(cx, qpath) {
441+
span_lint_and_help(
442+
cx,
443+
RC_BORROWS,
444+
hir_ty.span,
445+
"usage of `Rc<&T>`",
446+
format!("try `{}`", ty_ty).as_str(),
447+
);
448+
return; // don't recurse into the type
449+
}
325450
} else if cx.tcx.is_diagnostic_item(Symbol::intern("vec_type"), def_id) {
326451
if_chain! {
327452
// Get the _ part of Vec<_>

clippy_lints/src/utils/paths.rs

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

src/lintlist/mod.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ pub use lint::Lint;
66
pub use lint::LINT_LEVELS;
77

88
// begin lint list, do not remove this comment, it’s used in `update_lints`
9-
pub const ALL_LINTS: [Lint; 361] = [
9+
pub const ALL_LINTS: [Lint; 365] = [
1010
Lint {
1111
name: "absurd_extreme_comparisons",
1212
group: "correctness",
@@ -1722,6 +1722,27 @@ pub const ALL_LINTS: [Lint; 361] = [
17221722
deprecation: None,
17231723
module: "ranges",
17241724
},
1725+
Lint {
1726+
name: "rc_borrows",
1727+
group: "perf",
1728+
desc: "a Rc of borrowed type",
1729+
deprecation: None,
1730+
module: "types",
1731+
},
1732+
Lint {
1733+
name: "rc_box",
1734+
group: "perf",
1735+
desc: "an Rc of Box",
1736+
deprecation: None,
1737+
module: "types",
1738+
},
1739+
Lint {
1740+
name: "rc_rc",
1741+
group: "perf",
1742+
desc: "an Rc of Rc",
1743+
deprecation: None,
1744+
module: "types",
1745+
},
17251746
Lint {
17261747
name: "redundant_clone",
17271748
group: "perf",

tests/ui/must_use_candidates.fixed

Lines changed: 1 addition & 1 deletion
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::rc_borrows)]
44
#![warn(clippy::must_use_candidate)]
55
use std::rc::Rc;
66
use std::sync::atomic::{AtomicBool, Ordering};

tests/ui/must_use_candidates.rs

Lines changed: 1 addition & 1 deletion
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::rc_borrows)]
44
#![warn(clippy::must_use_candidate)]
55
use std::rc::Rc;
66
use std::sync::atomic::{AtomicBool, Ordering};

tests/ui/rc_borrows.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#![warn(clippy::all)]
2+
#![allow(clippy::boxed_local, clippy::needless_pass_by_value)]
3+
#![allow(clippy::blacklisted_name)]
4+
5+
use std::rc::Rc;
6+
7+
pub struct MyStruct {}
8+
9+
pub struct SubT<T> {
10+
foo: T,
11+
}
12+
13+
pub enum MyEnum {
14+
One,
15+
Two,
16+
}
17+
18+
pub fn test<T>(foo: Rc<&T>) {}
19+
20+
pub fn test1(foo: Rc<&usize>) {}
21+
22+
pub fn test2(foo: Rc<&MyStruct>) {}
23+
24+
pub fn test3(foo: Rc<&MyEnum>) {}
25+
26+
pub fn test4(foo: Rc<&&MyEnum>) {}
27+
28+
pub fn test6(foo: Rc<SubT<&usize>>) {}
29+
30+
fn main() {}

tests/ui/rc_borrows.stderr

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
error: usage of `Rc<&T>`
2+
--> $DIR/rc_borrows.rs:18:21
3+
|
4+
LL | pub fn test<T>(foo: Rc<&T>) {}
5+
| ^^^^^^
6+
|
7+
= note: `-D clippy::rc-borrows` implied by `-D warnings`
8+
= help: try `&T`
9+
10+
error: usage of `Rc<&T>`
11+
--> $DIR/rc_borrows.rs:20:19
12+
|
13+
LL | pub fn test1(foo: Rc<&usize>) {}
14+
| ^^^^^^^^^^
15+
|
16+
= help: try `&usize`
17+
18+
error: usage of `Rc<&T>`
19+
--> $DIR/rc_borrows.rs:22:19
20+
|
21+
LL | pub fn test2(foo: Rc<&MyStruct>) {}
22+
| ^^^^^^^^^^^^^
23+
|
24+
= help: try `&MyStruct`
25+
26+
error: usage of `Rc<&T>`
27+
--> $DIR/rc_borrows.rs:24:19
28+
|
29+
LL | pub fn test3(foo: Rc<&MyEnum>) {}
30+
| ^^^^^^^^^^^
31+
|
32+
= help: try `&MyEnum`
33+
34+
error: usage of `Rc<&T>`
35+
--> $DIR/rc_borrows.rs:26:19
36+
|
37+
LL | pub fn test4(foo: Rc<&&MyEnum>) {}
38+
| ^^^^^^^^^^^^
39+
|
40+
= help: try `&&MyEnum`
41+
42+
error: aborting due to 5 previous errors
43+

tests/ui/rc_rc.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
use std::boxed::Box;
2+
use std::rc::Rc;
3+
4+
pub fn test(a: Rc<Rc<bool>>) {}
5+
6+
pub fn test2(a: Rc<Box<bool>>) {}
7+
8+
fn main() {}

0 commit comments

Comments
 (0)