Skip to content

Commit 85f88b6

Browse files
whirmfelix91grHU90m
committed
redundant_box lint
Co-Authored-by: Félix Fischer <felix91gr@gmail.com> Co-Authored-by: Hugo McNally <hugo.mcnally@gmail.com>
1 parent 6275f52 commit 85f88b6

File tree

8 files changed

+326
-0
lines changed

8 files changed

+326
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6201,6 +6201,7 @@ Released 2018-09-13
62016201
[`redundant_as_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_as_str
62026202
[`redundant_async_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_async_block
62036203
[`redundant_at_rest_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_at_rest_pattern
6204+
[`redundant_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_box
62046205
[`redundant_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_clone
62056206
[`redundant_closure`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure
62066207
[`redundant_closure_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure_call

clippy_lints/src/box_ref.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
631631
crate::rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT_INFO,
632632
crate::read_zero_byte_vec::READ_ZERO_BYTE_VEC_INFO,
633633
crate::redundant_async_block::REDUNDANT_ASYNC_BLOCK_INFO,
634+
crate::redundant_box::REDUNDANT_BOX_INFO,
634635
crate::redundant_clone::REDUNDANT_CLONE_INFO,
635636
crate::redundant_closure_call::REDUNDANT_CLOSURE_CALL_INFO,
636637
crate::redundant_else::REDUNDANT_ELSE_INFO,

clippy_lints/src/lib.rs

100644100755
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,7 @@ mod raw_strings;
310310
mod rc_clone_in_vec_init;
311311
mod read_zero_byte_vec;
312312
mod redundant_async_block;
313+
mod redundant_box;
313314
mod redundant_clone;
314315
mod redundant_closure_call;
315316
mod redundant_else;
@@ -946,5 +947,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
946947
store.register_late_pass(|_| Box::new(single_option_map::SingleOptionMap));
947948
store.register_late_pass(move |_| Box::new(redundant_test_prefix::RedundantTestPrefix));
948949
store.register_late_pass(|_| Box::new(cloned_ref_to_slice_refs::ClonedRefToSliceRefs::new(conf)));
950+
store.register_late_pass(|_| Box::new(redundant_box::RedundantBox));
949951
// add lints here, do not remove this comment, it's used in `new_lint`
950952
}

clippy_lints/src/redundant_box.rs

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

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 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: 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 = 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 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+
// 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.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)