Skip to content

Commit c403105

Browse files
committed
box_vec: dont use Box<&T>
1 parent 8485d40 commit c403105

File tree

7 files changed

+104
-4
lines changed

7 files changed

+104
-4
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -1074,6 +1074,7 @@ Released 2018-09-13
10741074
[`bool_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_comparison
10751075
[`borrow_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_interior_mutable_const
10761076
[`borrowed_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrowed_box
1077+
[`box_borrow`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_borrow
10771078
[`box_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_vec
10781079
[`boxed_local`]: https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local
10791080
[`builtin_type_shadow`]: https://rust-lang.github.io/rust-clippy/master/index.html#builtin_type_shadow

README.md

+1-1
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 362 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

+3
Original file line numberDiff line numberDiff line change
@@ -785,6 +785,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
785785
&try_err::TRY_ERR,
786786
&types::ABSURD_EXTREME_COMPARISONS,
787787
&types::BORROWED_BOX,
788+
&types::BOX_BORROW,
788789
&types::BOX_VEC,
789790
&types::CAST_LOSSLESS,
790791
&types::CAST_POSSIBLE_TRUNCATION,
@@ -1355,6 +1356,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
13551356
LintId::of(&try_err::TRY_ERR),
13561357
LintId::of(&types::ABSURD_EXTREME_COMPARISONS),
13571358
LintId::of(&types::BORROWED_BOX),
1359+
LintId::of(&types::BOX_BORROW),
13581360
LintId::of(&types::BOX_VEC),
13591361
LintId::of(&types::CAST_PTR_ALIGNMENT),
13601362
LintId::of(&types::CAST_REF_TO_MUT),
@@ -1647,6 +1649,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
16471649
LintId::of(&redundant_clone::REDUNDANT_CLONE),
16481650
LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
16491651
LintId::of(&trivially_copy_pass_by_ref::TRIVIALLY_COPY_PASS_BY_REF),
1652+
LintId::of(&types::BOX_BORROW),
16501653
LintId::of(&types::BOX_VEC),
16511654
LintId::of(&vec::USELESS_VEC),
16521655
]);

clippy_lints/src/types.rs

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

174+
declare_clippy_lint! {
175+
/// **What it does:** Checks for use of `Box<&T>` anywhere in the code.
176+
///
177+
/// **Why is this bad?** Any `Box<&T>` can also be a `&T`, which is more
178+
/// general.
179+
///
180+
/// **Known problems:** None.
181+
///
182+
/// **Example:**
183+
/// ```rust,ignore
184+
/// struct X {
185+
/// values: Box<&T>,
186+
/// }
187+
/// ```
188+
///
189+
/// Better:
190+
///
191+
/// ```rust,ignore
192+
/// struct X {
193+
/// values: &T,
194+
/// }
195+
/// ```
196+
pub BOX_BORROW,
197+
perf,
198+
"a box of borrowed type"
199+
}
200+
174201
pub struct Types {
175202
vec_box_size_threshold: u64,
176203
}
177204

178-
impl_lint_pass!(Types => [BOX_VEC, VEC_BOX, OPTION_OPTION, LINKEDLIST, BORROWED_BOX]);
205+
impl_lint_pass!(Types => [BOX_VEC, VEC_BOX, OPTION_OPTION, LINKEDLIST, BORROWED_BOX, BOX_BORROW]);
179206

180207
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Types {
181208
fn check_fn(
@@ -236,6 +263,24 @@ fn match_type_parameter(cx: &LateContext<'_, '_>, qpath: &QPath<'_>, path: &[&st
236263
false
237264
}
238265

266+
/// Checks if `qpath` last segment type parameter is a reference
267+
fn match_type_parameter_rptr(qpath: &QPath<'_>) -> bool {
268+
let last = last_path_segment(qpath);
269+
if_chain! {
270+
if let Some(ref params) = last.args;
271+
if !params.parenthesized;
272+
if let Some(ty) = params.args.iter().find_map(|arg| match arg {
273+
GenericArg::Type(ty) => Some(ty),
274+
_ => None,
275+
});
276+
if let TyKind::Rptr(ref _lifetime_opt, ref _mut) = ty.kind;
277+
then {
278+
return true;
279+
}
280+
}
281+
false
282+
}
283+
239284
impl Types {
240285
pub fn new(vec_box_size_threshold: u64) -> Self {
241286
Self { vec_box_size_threshold }
@@ -267,6 +312,29 @@ impl Types {
267312
let res = qpath_res(cx, qpath, hir_id);
268313
if let Some(def_id) = res.opt_def_id() {
269314
if Some(def_id) == cx.tcx.lang_items().owned_box() {
315+
if match_type_parameter_rptr(qpath) {
316+
let last = last_path_segment(qpath);
317+
if_chain! {
318+
if let Some(ref params) = last.args;
319+
if !params.parenthesized;
320+
if let Some(ty) = params.args.iter().find_map(|arg| match arg {
321+
GenericArg::Type(ty) => Some(ty),
322+
_ => None,
323+
});
324+
if let TyKind::Rptr(ref _lifetime_opt, ref _mut) = ty.kind;
325+
then {
326+
let ty_ty = hir_ty_to_ty(cx.tcx, ty);
327+
span_lint_and_help(
328+
cx,
329+
BOX_BORROW,
330+
hir_ty.span,
331+
"usage of `Box<&T>`",
332+
format!("try `{}`", ty_ty).as_str(),
333+
);
334+
return; // don't recurse into the type
335+
}
336+
}
337+
}
270338
if match_type_parameter(cx, qpath, &paths::VEC) {
271339
span_lint_and_help(
272340
cx,

src/lintlist/mod.rs

+8-1
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; 362] = [
1010
Lint {
1111
name: "absurd_extreme_comparisons",
1212
group: "correctness",
@@ -98,6 +98,13 @@ pub const ALL_LINTS: [Lint; 361] = [
9898
deprecation: None,
9999
module: "types",
100100
},
101+
Lint {
102+
name: "box_borrow",
103+
group: "perf",
104+
desc: "a box of borrowed type",
105+
deprecation: None,
106+
module: "types",
107+
},
101108
Lint {
102109
name: "box_vec",
103110
group: "perf",

tests/ui/box_vec.rs

+4
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ pub fn test_local_not_linted() {
2424
let _: Box<Vec<bool>>;
2525
}
2626

27+
pub fn test3<T>(foo: Box<&T>) {}
28+
29+
pub fn test4(foo: Box<&usize>) {}
30+
2731
fn main() {
2832
test(Box::new(Vec::new()));
2933
test2(Box::new(|v| println!("{:?}", v)));

tests/ui/box_vec.stderr

+18-1
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,22 @@ LL | pub fn test(foo: Box<Vec<bool>>) {
77
= note: `-D clippy::box-vec` implied by `-D warnings`
88
= help: `Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation.
99

10-
error: aborting due to previous error
10+
error: usage of `Box<&T>`
11+
--> $DIR/box_vec.rs:27:22
12+
|
13+
LL | pub fn test3<T>(foo: Box<&T>) {}
14+
| ^^^^^^^
15+
|
16+
= note: `-D clippy::box-borrow` implied by `-D warnings`
17+
= help: try `&T`
18+
19+
error: usage of `Box<&T>`
20+
--> $DIR/box_vec.rs:29:19
21+
|
22+
LL | pub fn test4(foo: Box<&usize>) {}
23+
| ^^^^^^^^^^^
24+
|
25+
= help: try `&usize`
26+
27+
error: aborting due to 3 previous errors
1128

0 commit comments

Comments
 (0)