Skip to content

Commit 858b3b0

Browse files
committed
Added the new lint with some docs and tests
1 parent 5ed64d4 commit 858b3b0

File tree

6 files changed

+132
-0
lines changed

6 files changed

+132
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4974,6 +4974,7 @@ Released 2018-09-13
49744974
[`unit_hash`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_hash
49754975
[`unit_return_expecting_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_return_expecting_ord
49764976
[`unknown_clippy_lints`]: https://rust-lang.github.io/rust-clippy/master/index.html#unknown_clippy_lints
4977+
[`unnecessary_box_returns`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_box_returns
49774978
[`unnecessary_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_cast
49784979
[`unnecessary_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_filter_map
49794980
[`unnecessary_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_find_map

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
616616
crate::unit_types::UNIT_CMP_INFO,
617617
crate::unnamed_address::FN_ADDRESS_COMPARISONS_INFO,
618618
crate::unnamed_address::VTABLE_ADDRESS_COMPARISONS_INFO,
619+
crate::unnecessary_box_returns::UNNECESSARY_BOX_RETURNS_INFO,
619620
crate::unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS_INFO,
620621
crate::unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS_INFO,
621622
crate::unnecessary_struct_initialization::UNNECESSARY_STRUCT_INITIALIZATION_INFO,

clippy_lints/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,7 @@ mod uninit_vec;
300300
mod unit_return_expecting_ord;
301301
mod unit_types;
302302
mod unnamed_address;
303+
mod unnecessary_box_returns;
303304
mod unnecessary_owned_empty_strings;
304305
mod unnecessary_self_imports;
305306
mod unnecessary_struct_initialization;
@@ -940,6 +941,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
940941
store.register_late_pass(|_| Box::new(allow_attributes::AllowAttribute));
941942
store.register_late_pass(move |_| Box::new(manual_main_separator_str::ManualMainSeparatorStr::new(msrv())));
942943
store.register_late_pass(|_| Box::new(unnecessary_struct_initialization::UnnecessaryStruct));
944+
store.register_late_pass(|_| Box::new(unnecessary_box_returns::UnnecessaryBoxReturns));
943945
// add lints here, do not remove this comment, it's used in `new_lint`
944946
}
945947

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
use clippy_utils::{diagnostics::span_lint_and_sugg, ty::implements_trait};
2+
use rustc_errors::Applicability;
3+
use rustc_hir::{def_id::LocalDefId, intravisit::FnKind, Body, FnDecl, FnRetTy};
4+
use rustc_hir_analysis::hir_ty_to_ty;
5+
use rustc_lint::{LateContext, LateLintPass};
6+
use rustc_session::{declare_lint_pass, declare_tool_lint};
7+
use rustc_span::Span;
8+
9+
declare_clippy_lint! {
10+
/// ### What it does
11+
///
12+
/// Checks for a return type containing a `Box<T>` where `T` implements `Sized`
13+
///
14+
/// ### Why is this bad?
15+
///
16+
/// It's better to just return `T` in these cases. The caller may not need
17+
/// the value to be boxed, and it's expensive to free the memory once the
18+
/// `Box<T>` been dropped.
19+
///
20+
/// ### Example
21+
/// ```rust
22+
/// fn foo() -> Box<String> {
23+
/// Box::new(String::from("Hello, world!"))
24+
/// }
25+
/// ```
26+
/// Use instead:
27+
/// ```rust
28+
/// fn foo() -> String {
29+
/// String::from("Hello, world!")
30+
/// }
31+
/// ```
32+
#[clippy::version = "1.64.0"]
33+
pub UNNECESSARY_BOX_RETURNS,
34+
pedantic,
35+
"Needlessly returning a Box"
36+
}
37+
declare_lint_pass!(UnnecessaryBoxReturns => [UNNECESSARY_BOX_RETURNS]);
38+
39+
impl LateLintPass<'_> for UnnecessaryBoxReturns {
40+
fn check_fn(
41+
&mut self,
42+
cx: &LateContext<'_>,
43+
fn_kind: FnKind<'_>,
44+
decl: &FnDecl<'_>,
45+
_: &Body<'_>,
46+
_: Span,
47+
_: LocalDefId,
48+
) {
49+
// it's unclear what part of a closure you would span, so for now it's ignored
50+
// if this is changed, please also make sure not to call `hir_ty_to_ty` below
51+
if matches!(fn_kind, FnKind::Closure) {
52+
return;
53+
}
54+
55+
let FnRetTy::Return(return_ty_hir) = &decl.output else { return };
56+
57+
// this is safe, since we're not in a body
58+
let return_ty = hir_ty_to_ty(cx.tcx, return_ty_hir);
59+
60+
if !return_ty.is_box() {
61+
return;
62+
}
63+
64+
let boxed_ty = return_ty.boxed_ty();
65+
let Some(sized_trait) = cx.tcx.lang_items().sized_trait() else { return };
66+
67+
// it's sometimes useful to return Box<T> if T is unsized, so don't lint those
68+
if implements_trait(cx, boxed_ty, sized_trait, &[]) {
69+
span_lint_and_sugg(
70+
cx,
71+
UNNECESSARY_BOX_RETURNS,
72+
return_ty_hir.span,
73+
format!("boxed return of the sized type `{boxed_ty}`").as_str(),
74+
"try",
75+
boxed_ty.to_string(),
76+
// the return value and function callers also needs to be changed, so this can't be MachineApplicable
77+
Applicability::Unspecified,
78+
);
79+
}
80+
}
81+
}

tests/ui/unnecessary_box_returns.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#![warn(clippy::unnecessary_box_returns)]
2+
3+
struct Foo {}
4+
5+
// lint
6+
fn boxed_usize() -> Box<usize> {
7+
Box::new(5)
8+
}
9+
10+
// lint
11+
fn boxed_foo() -> Box<Foo> {
12+
Box::new(Foo {})
13+
}
14+
15+
// don't lint: str is unsized
16+
fn boxed_str() -> Box<str> {
17+
"Hello, world!".to_string().into_boxed_str()
18+
}
19+
20+
// don't lint: this has an unspecified return type
21+
fn default() {}
22+
23+
// don't lint: this doesn't return a Box
24+
fn string() -> String {
25+
String::from("Hello, world")
26+
}
27+
28+
fn main() {
29+
// don't lint: this is a closure
30+
let a = || -> Box<usize> { Box::new(5) };
31+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error: boxed return of the sized type `usize`
2+
--> $DIR/unnecessary_box_returns.rs:6:21
3+
|
4+
LL | fn boxed_usize() -> Box<usize> {
5+
| ^^^^^^^^^^ help: try: `usize`
6+
|
7+
= note: `-D clippy::unnecessary-box-returns` implied by `-D warnings`
8+
9+
error: boxed return of the sized type `Foo`
10+
--> $DIR/unnecessary_box_returns.rs:11:19
11+
|
12+
LL | fn boxed_foo() -> Box<Foo> {
13+
| ^^^^^^^^ help: try: `Foo`
14+
15+
error: aborting due to 2 previous errors
16+

0 commit comments

Comments
 (0)