Skip to content

Commit 15e8321

Browse files
whirmfelix91grHU90m
authored andcommitted
redundant_box lint
Co-Authored-by: Félix Fischer <[email protected]> Co-Authored-by: Hugo McNally <[email protected]>
1 parent c6f2557 commit 15e8321

File tree

7 files changed

+320
-0
lines changed

7 files changed

+320
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6702,6 +6702,7 @@ Released 2018-09-13
67026702
[`redundant_as_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_as_str
67036703
[`redundant_async_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_async_block
67046704
[`redundant_at_rest_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_at_rest_pattern
6705+
[`redundant_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_box
67056706
[`redundant_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_clone
67066707
[`redundant_closure`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure
67076708
[`redundant_closure_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure_call

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[
638638
crate::rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT_INFO,
639639
crate::read_zero_byte_vec::READ_ZERO_BYTE_VEC_INFO,
640640
crate::redundant_async_block::REDUNDANT_ASYNC_BLOCK_INFO,
641+
crate::redundant_box::REDUNDANT_BOX_INFO,
641642
crate::redundant_clone::REDUNDANT_CLONE_INFO,
642643
crate::redundant_closure_call::REDUNDANT_CLOSURE_CALL_INFO,
643644
crate::redundant_else::REDUNDANT_ELSE_INFO,

clippy_lints/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,7 @@ mod raw_strings;
308308
mod rc_clone_in_vec_init;
309309
mod read_zero_byte_vec;
310310
mod redundant_async_block;
311+
mod redundant_box;
311312
mod redundant_clone;
312313
mod redundant_closure_call;
313314
mod redundant_else;
@@ -834,5 +835,6 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co
834835
store.register_late_pass(|_| Box::new(toplevel_ref_arg::ToplevelRefArg));
835836
store.register_late_pass(|_| Box::new(volatile_composites::VolatileComposites));
836837
store.register_late_pass(|_| Box::new(replace_box::ReplaceBox));
838+
store.register_late_pass(|_| Box::new(redundant_box::RedundantBox));
837839
// add lints here, do not remove this comment, it's used in `new_lint`
838840
}

clippy_lints/src/redundant_box.rs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
use clippy_utils::diagnostics::span_lint_and_sugg;
2+
use clippy_utils::qpath_generic_tys;
3+
use clippy_utils::source::snippet;
4+
use clippy_utils::ty::approx_ty_size;
5+
use rustc_errors::Applicability;
6+
use rustc_hir::{AmbigArg, Expr, ExprKind, TyKind};
7+
use rustc_lint::{LateContext, LateLintPass, LintContext};
8+
use rustc_middle::ty::Ty;
9+
use rustc_session::declare_lint_pass;
10+
11+
declare_clippy_lint! {
12+
/// ### What it does
13+
///
14+
/// ### Why is this bad?
15+
///
16+
/// ### Example
17+
/// ```no_run
18+
/// // example code where clippy issues a warning
19+
/// ```
20+
/// Use instead:
21+
/// ```no_run
22+
/// // example code which does not raise clippy warning
23+
/// ```
24+
#[clippy::version = "1.88.0"]
25+
pub REDUNDANT_BOX,
26+
nursery,
27+
"default lint description"
28+
}
29+
30+
// TODO Rename lint as we are not just checking references anymore
31+
declare_lint_pass!(RedundantBox => [REDUNDANT_BOX]);
32+
33+
// TODO could we do everything with only check_ty() xor check_expr()?
34+
impl LateLintPass<'_> for RedundantBox {
35+
fn check_ty<'tcx>(&mut self, cx: &LateContext<'tcx>, hir_ty: &rustc_hir::Ty<'tcx, AmbigArg>) {
36+
let ty = clippy_utils::ty::ty_from_hir_ty(cx, hir_ty.as_unambig_ty());
37+
if let Some(boxed_ty) = ty.boxed_ty()
38+
&& is_thin_type(cx, boxed_ty)
39+
&& let TyKind::Path(path) = hir_ty.kind
40+
&& let Some(boxed_ty) = qpath_generic_tys(&path).next()
41+
{
42+
emit_lint(cx, hir_ty.span, boxed_ty.span);
43+
}
44+
}
45+
46+
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
47+
let ty = cx.typeck_results().expr_ty(expr);
48+
if let Some(boxed_ty) = ty.boxed_ty()
49+
&& is_thin_type(cx, boxed_ty)
50+
&& let ExprKind::Call(_, &[Expr { span, .. }]) = expr.kind
51+
{
52+
emit_lint(cx, expr.span, span);
53+
}
54+
}
55+
}
56+
57+
fn is_thin_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
58+
ty.is_sized(cx.tcx, cx.typing_env()) && {
59+
let size = 8 * approx_ty_size(cx, ty);
60+
0 < size && size <= u64::from(cx.sess().target.pointer_width)
61+
}
62+
}
63+
64+
fn emit_lint(cx: &LateContext<'_>, from_span: rustc_span::Span, to_span: rustc_span::Span) {
65+
span_lint_and_sugg(
66+
cx,
67+
REDUNDANT_BOX,
68+
from_span,
69+
"TODO: lint msg",
70+
"Remove Box",
71+
format!("{}", snippet(cx, to_span, "<default>")),
72+
Applicability::MachineApplicable,
73+
);
74+
}

tests/ui/redundant_box.fixed

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
#![warn(clippy::redundant_box)]
2+
3+
fn main() {}
4+
5+
fn string_slice_is_ok_to_box() {
6+
let the_slice = "";
7+
let the_ok = Box::new(the_slice);
8+
}
9+
10+
fn ref_to_string_slice_is_redundant_to_box() {
11+
let the_slice = "";
12+
let redundant = &the_slice;
13+
//~^ redundant_box
14+
}
15+
16+
fn vec_slice_is_ok_to_box() {
17+
let the_vec = Vec::<u8>::new();
18+
let the_slice = &the_vec[0..3];
19+
let the_ok = Box::new(the_slice);
20+
}
21+
22+
fn wide_int_is_ok_to_box() {
23+
let the_wide_int = 1u128;
24+
let the_ok = Box::new(the_wide_int);
25+
}
26+
27+
fn wide_int_ref_is_redundant_to_box() {
28+
let the_wide_int = 1u128;
29+
let redundant = &the_wide_int;
30+
//~^ redundant_box
31+
}
32+
33+
// Tests for some of the cases listed on https://github.com/rust-lang/rust-clippy/issues/2394
34+
// Box<&T>
35+
//TODO: Maybe these could go away as they are caught by `clippy::redundant_allocation``
36+
fn generic_boxed_thin_ref_is_redundant_to_box() {
37+
#[allow(clippy::redundant_allocation)]
38+
fn fun<T>(t: &T) -> &T {
39+
//~^ redundant_box
40+
t
41+
//~^ redundant_box
42+
}
43+
44+
let thin = 1u32;
45+
let redundant = &thin;
46+
//~^ redundant_box
47+
}
48+
49+
fn generic_boxed_wide_ref_is_ok_to_box() {
50+
fn fun<T>(ok_to_box: T) -> Box<T> {
51+
Box::new(ok_to_box)
52+
}
53+
54+
let wide = "";
55+
let ok_boxed_wide_ref = fun(wide);
56+
}
57+
58+
// Box::new(SomeT) where sizeof::<T>() <= sizeof::<usize>()
59+
// unless there are Box::into_raw calls within the function
60+
fn smaller_than_usize_is_redundant_to_box() {
61+
let redundant = 1u16;
62+
//~^ redundant_box
63+
}
64+
65+
fn usize_ref_is_redundant_to_box() {
66+
let the_val = 1usize;
67+
let redundant = &the_val;
68+
//~^ redundant_box
69+
}
70+
71+
fn reference_to_a_literal_is_redundant_to_box() {
72+
let a = 1u32;
73+
let redundant = &a;
74+
//~^ redundant_box
75+
}
76+
77+
fn type_annotations_of_a_boxed_int_is_redundant_to_box() {
78+
let a = 1u32;
79+
let redundant = &a;
80+
//~^ redundant_box
81+
let redundant: &u32 = redundant;
82+
//~^ redundant_box
83+
}
84+
85+
// TODO: Investigate how to implement this:
86+
// fn smaller_than_usize_is_ok_to_box_if_using_into_raw() {
87+
// let boxed = Box::new(1u8);
88+
// let ptr = Box::into_raw(boxed);
89+
// }

tests/ui/redundant_box.rs

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
#![warn(clippy::redundant_box)]
2+
3+
fn main() {}
4+
5+
fn string_slice_is_ok_to_box() {
6+
let the_slice = "";
7+
let the_ok = Box::new(the_slice);
8+
}
9+
10+
fn ref_to_string_slice_is_redundant_to_box() {
11+
let the_slice = "";
12+
let redundant = Box::new(&the_slice);
13+
//~^ redundant_box
14+
}
15+
16+
fn vec_slice_is_ok_to_box() {
17+
let the_vec = Vec::<u8>::new();
18+
let the_slice = &the_vec[0..3];
19+
let the_ok = Box::new(the_slice);
20+
}
21+
22+
fn wide_int_is_ok_to_box() {
23+
let the_wide_int = 1u128;
24+
let the_ok = Box::new(the_wide_int);
25+
}
26+
27+
fn wide_int_ref_is_redundant_to_box() {
28+
let the_wide_int = 1u128;
29+
let redundant = Box::new(&the_wide_int);
30+
//~^ redundant_box
31+
}
32+
33+
// Tests for some of the cases listed on https://github.com/rust-lang/rust-clippy/issues/2394
34+
// Box<&T>
35+
//TODO: Maybe these could go away as they are caught by `clippy::redundant_allocation``
36+
fn generic_boxed_thin_ref_is_redundant_to_box() {
37+
#[allow(clippy::redundant_allocation)]
38+
fn fun<T>(t: &T) -> Box<&T> {
39+
//~^ redundant_box
40+
Box::new(t)
41+
//~^ redundant_box
42+
}
43+
44+
let thin = 1u32;
45+
let redundant = fun(&thin);
46+
//~^ redundant_box
47+
}
48+
49+
fn generic_boxed_wide_ref_is_ok_to_box() {
50+
fn fun<T>(ok_to_box: T) -> Box<T> {
51+
Box::new(ok_to_box)
52+
}
53+
54+
let wide = "";
55+
let ok_boxed_wide_ref = fun(wide);
56+
}
57+
58+
// Box::new(SomeT) where sizeof::<T>() <= sizeof::<usize>()
59+
// unless there are Box::into_raw calls within the function
60+
fn smaller_than_usize_is_redundant_to_box() {
61+
let redundant = Box::new(1u16);
62+
//~^ redundant_box
63+
}
64+
65+
fn usize_ref_is_redundant_to_box() {
66+
let the_val = 1usize;
67+
let redundant = Box::new(&the_val);
68+
//~^ redundant_box
69+
}
70+
71+
fn reference_to_a_literal_is_redundant_to_box() {
72+
let a = 1u32;
73+
let redundant = Box::new(&a);
74+
//~^ redundant_box
75+
}
76+
77+
fn type_annotations_of_a_boxed_int_is_redundant_to_box() {
78+
let a = 1u32;
79+
let redundant = Box::new(&a);
80+
//~^ redundant_box
81+
let redundant: Box<&u32> = redundant;
82+
//~^ redundant_box
83+
}
84+
85+
fn smaller_than_usize_is_ok_to_box_if_using_into_raw() {
86+
let boxed = Box::new(1u8);
87+
let ptr = Box::into_raw(boxed);
88+
}

tests/ui/redundant_box.stderr

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
error: TODO: lint msg
2+
--> tests/ui/redundant_box.rs:12:21
3+
|
4+
LL | let redundant = Box::new(&the_slice);
5+
| ^^^^^^^^^^^^^^^^^^^^ help: Remove Box: `&the_slice`
6+
|
7+
= note: `-D clippy::redundant-box` implied by `-D warnings`
8+
= help: to override `-D warnings` add `#[allow(clippy::redundant_box)]`
9+
10+
error: TODO: lint msg
11+
--> tests/ui/redundant_box.rs:29:21
12+
|
13+
LL | let redundant = Box::new(&the_wide_int);
14+
| ^^^^^^^^^^^^^^^^^^^^^^^ help: Remove Box: `&the_wide_int`
15+
16+
error: TODO: lint msg
17+
--> tests/ui/redundant_box.rs:38:25
18+
|
19+
LL | fn fun<T>(t: &T) -> Box<&T> {
20+
| ^^^^^^^ help: Remove Box: `&T`
21+
22+
error: TODO: lint msg
23+
--> tests/ui/redundant_box.rs:40:9
24+
|
25+
LL | Box::new(t)
26+
| ^^^^^^^^^^^ help: Remove Box: `t`
27+
28+
error: TODO: lint msg
29+
--> tests/ui/redundant_box.rs:45:21
30+
|
31+
LL | let redundant = fun(&thin);
32+
| ^^^^^^^^^^ help: Remove Box: `&thin`
33+
34+
error: TODO: lint msg
35+
--> tests/ui/redundant_box.rs:61:21
36+
|
37+
LL | let redundant = Box::new(1u16);
38+
| ^^^^^^^^^^^^^^ help: Remove Box: `1u16`
39+
40+
error: TODO: lint msg
41+
--> tests/ui/redundant_box.rs:67:21
42+
|
43+
LL | let redundant = Box::new(&the_val);
44+
| ^^^^^^^^^^^^^^^^^^ help: Remove Box: `&the_val`
45+
46+
error: TODO: lint msg
47+
--> tests/ui/redundant_box.rs:73:21
48+
|
49+
LL | let redundant = Box::new(&a);
50+
| ^^^^^^^^^^^^ help: Remove Box: `&a`
51+
52+
error: TODO: lint msg
53+
--> tests/ui/redundant_box.rs:79:21
54+
|
55+
LL | let redundant = Box::new(&a);
56+
| ^^^^^^^^^^^^ help: Remove Box: `&a`
57+
58+
error: TODO: lint msg
59+
--> tests/ui/redundant_box.rs:81:20
60+
|
61+
LL | let redundant: Box<&u32> = redundant;
62+
| ^^^^^^^^^ help: Remove Box: `&u32`
63+
64+
error: aborting due to 10 previous errors
65+

0 commit comments

Comments
 (0)