Skip to content

Commit d7eea04

Browse files
committed
box_vec: dont use Box<&T>
1 parent 23549a8 commit d7eea04

File tree

7 files changed

+176
-5
lines changed

7 files changed

+176
-5
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -1166,6 +1166,7 @@ Released 2018-09-13
11661166
[`bool_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_comparison
11671167
[`borrow_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_interior_mutable_const
11681168
[`borrowed_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrowed_box
1169+
[`box_borrow`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_borrow
11691170
[`box_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_vec
11701171
[`boxed_local`]: https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local
11711172
[`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
@@ -788,6 +788,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
788788
&try_err::TRY_ERR,
789789
&types::ABSURD_EXTREME_COMPARISONS,
790790
&types::BORROWED_BOX,
791+
&types::BOX_BORROW,
791792
&types::BOX_VEC,
792793
&types::CAST_LOSSLESS,
793794
&types::CAST_POSSIBLE_TRUNCATION,
@@ -1358,6 +1359,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
13581359
LintId::of(&try_err::TRY_ERR),
13591360
LintId::of(&types::ABSURD_EXTREME_COMPARISONS),
13601361
LintId::of(&types::BORROWED_BOX),
1362+
LintId::of(&types::BOX_BORROW),
13611363
LintId::of(&types::BOX_VEC),
13621364
LintId::of(&types::CAST_PTR_ALIGNMENT),
13631365
LintId::of(&types::CAST_REF_TO_MUT),
@@ -1650,6 +1652,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
16501652
LintId::of(&redundant_clone::REDUNDANT_CLONE),
16511653
LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
16521654
LintId::of(&trivially_copy_pass_by_ref::TRIVIALLY_COPY_PASS_BY_REF),
1655+
LintId::of(&types::BOX_BORROW),
16531656
LintId::of(&types::BOX_VEC),
16541657
LintId::of(&vec::USELESS_VEC),
16551658
]);

clippy_lints/src/types.rs

+50-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(
@@ -257,6 +284,7 @@ impl Types {
257284
/// The parameter `is_local` distinguishes the context of the type; types from
258285
/// local bindings should only be checked for the `BORROWED_BOX` lint.
259286
#[allow(clippy::too_many_lines)]
287+
#[allow(clippy::cognitive_complexity)]
260288
fn check_ty(&mut self, cx: &LateContext<'_, '_>, hir_ty: &hir::Ty<'_>, is_local: bool) {
261289
if hir_ty.span.from_expansion() {
262290
return;
@@ -267,6 +295,27 @@ impl Types {
267295
let res = qpath_res(cx, qpath, hir_id);
268296
if let Some(def_id) = res.opt_def_id() {
269297
if Some(def_id) == cx.tcx.lang_items().owned_box() {
298+
if_chain! {
299+
let last = last_path_segment(qpath);
300+
if let Some(ref params) = last.args;
301+
if !params.parenthesized;
302+
if let Some(ty) = params.args.iter().find_map(|arg| match arg {
303+
GenericArg::Type(ty) => Some(ty),
304+
_ => None,
305+
});
306+
if let TyKind::Rptr(..) = ty.kind;
307+
let ty_ty = hir_ty_to_ty(cx.tcx, ty);
308+
then {
309+
span_lint_and_help(
310+
cx,
311+
BOX_BORROW,
312+
hir_ty.span,
313+
"usage of `Box<&T>`",
314+
format!("try `{}`", ty_ty).as_str(),
315+
);
316+
return; // don't recurse into the type
317+
}
318+
}
270319
if match_type_parameter(cx, qpath, &paths::VEC) {
271320
span_lint_and_help(
272321
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

+25
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,17 @@ macro_rules! boxit {
88
};
99
}
1010

11+
struct MyStruct {}
12+
13+
struct SubT<T> {
14+
foo: T
15+
}
16+
17+
enum MyEnum {
18+
One,
19+
Two
20+
}
21+
1122
fn test_macro() {
1223
boxit!(Vec::new(), Vec<u8>);
1324
}
@@ -24,6 +35,20 @@ pub fn test_local_not_linted() {
2435
let _: Box<Vec<bool>>;
2536
}
2637

38+
pub fn test3<T>(foo: Box<&T>) {}
39+
40+
pub fn test4(foo: Box<&usize>) {}
41+
42+
pub fn test5(foo: Box<&MyStruct>) {}
43+
44+
pub fn test6(foo: Box<&MyEnum>) {}
45+
46+
pub fn test7(foo: Box<&&MyEnum>) {}
47+
48+
pub fn test8(foo: Box<Box<&usize>>) {}
49+
50+
pub fn test9(foo: Box<SubT<&usize>>) {}
51+
2752
fn main() {
2853
test(Box::new(Vec::new()));
2954
test2(Box::new(|v| println!("{:?}", v)));

tests/ui/box_vec.stderr

+88-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,97 @@
1+
error[E0446]: private type `My` in public interface
2+
--> $DIR/box_vec.rs:42:1
3+
|
4+
LL | struct My {}
5+
| - `My` declared as private
6+
...
7+
LL | pub fn test5(foo: Box<&My>) {}
8+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type
9+
10+
error[E0446]: private type `OneOrTwo` in public interface
11+
--> $DIR/box_vec.rs:44:1
12+
|
13+
LL | enum OneOrTwo {
14+
| - `OneOrTwo` declared as private
15+
...
16+
LL | pub fn test6(foo: Box<&OneOrTwo>) {}
17+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type
18+
19+
error[E0446]: private type `OneOrTwo` in public interface
20+
--> $DIR/box_vec.rs:46:1
21+
|
22+
LL | enum OneOrTwo {
23+
| - `OneOrTwo` declared as private
24+
...
25+
LL | pub fn test7(foo: Box<&&OneOrTwo>) {}
26+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type
27+
28+
error[E0446]: private type `SubT<&usize>` in public interface
29+
--> $DIR/box_vec.rs:50:1
30+
|
31+
LL | struct SubT<T> {
32+
| - `SubT<&usize>` declared as private
33+
...
34+
LL | pub fn test9(foo: Box<SubT<&usize>>) {}
35+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type
36+
137
error: you seem to be trying to use `Box<Vec<T>>`. Consider using just `Vec<T>`
2-
--> $DIR/box_vec.rs:14:18
38+
--> $DIR/box_vec.rs:25:18
339
|
440
LL | pub fn test(foo: Box<Vec<bool>>) {
541
| ^^^^^^^^^^^^^^
642
|
743
= note: `-D clippy::box-vec` implied by `-D warnings`
844
= help: `Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation.
945

10-
error: aborting due to previous error
46+
error: usage of `Box<&T>`
47+
--> $DIR/box_vec.rs:38:22
48+
|
49+
LL | pub fn test3<T>(foo: Box<&T>) {}
50+
| ^^^^^^^
51+
|
52+
= note: `-D clippy::box-borrow` implied by `-D warnings`
53+
= help: try `&T`
54+
55+
error: usage of `Box<&T>`
56+
--> $DIR/box_vec.rs:40:19
57+
|
58+
LL | pub fn test4(foo: Box<&usize>) {}
59+
| ^^^^^^^^^^^
60+
|
61+
= help: try `&usize`
62+
63+
error: usage of `Box<&T>`
64+
--> $DIR/box_vec.rs:42:19
65+
|
66+
LL | pub fn test5(foo: Box<&My>) {}
67+
| ^^^^^^^^
68+
|
69+
= help: try `&My`
70+
71+
error: usage of `Box<&T>`
72+
--> $DIR/box_vec.rs:44:19
73+
|
74+
LL | pub fn test6(foo: Box<&OneOrTwo>) {}
75+
| ^^^^^^^^^^^^^^
76+
|
77+
= help: try `&OneOrTwo`
78+
79+
error: usage of `Box<&T>`
80+
--> $DIR/box_vec.rs:46:19
81+
|
82+
LL | pub fn test7(foo: Box<&&OneOrTwo>) {}
83+
| ^^^^^^^^^^^^^^^
84+
|
85+
= help: try `&&OneOrTwo`
86+
87+
error: usage of `Box<&T>`
88+
--> $DIR/box_vec.rs:48:23
89+
|
90+
LL | pub fn test8(foo: Box<Box<&usize>>) {}
91+
| ^^^^^^^^^^^
92+
|
93+
= help: try `&usize`
94+
95+
error: aborting due to 11 previous errors
1196

97+
For more information about this error, try `rustc --explain E0446`.

0 commit comments

Comments
 (0)