Skip to content

Commit 1b55c81

Browse files
committed
Lint on trait declarations, not implementations
1 parent 022f76d commit 1b55c81

File tree

3 files changed

+91
-48
lines changed

3 files changed

+91
-48
lines changed
+52-44
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
use clippy_utils::diagnostics::span_lint_and_then;
22
use rustc_errors::Applicability;
3-
use rustc_hir::{def_id::LocalDefId, intravisit::FnKind, Body, FnDecl, FnRetTy};
3+
use rustc_hir::{def_id::LocalDefId, FnDecl, FnRetTy, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind};
44
use rustc_lint::{LateContext, LateLintPass};
55
use rustc_session::{declare_lint_pass, declare_tool_lint};
6-
use rustc_span::Span;
76

87
declare_clippy_lint! {
98
/// ### What it does
@@ -35,54 +34,63 @@ declare_clippy_lint! {
3534
}
3635
declare_lint_pass!(UnnecessaryBoxReturns => [UNNECESSARY_BOX_RETURNS]);
3736

38-
impl LateLintPass<'_> for UnnecessaryBoxReturns {
39-
fn check_fn(
40-
&mut self,
41-
cx: &LateContext<'_>,
42-
fn_kind: FnKind<'_>,
43-
decl: &FnDecl<'_>,
44-
_: &Body<'_>,
45-
_: Span,
46-
def_id: LocalDefId,
47-
) {
48-
// it's unclear what part of a closure you would span, so for now it's ignored
49-
// if this is changed, please also make sure not to call `hir_ty_to_ty` below
50-
if matches!(fn_kind, FnKind::Closure) {
51-
return;
52-
}
37+
fn check_fn_decl(cx: &LateContext<'_>, decl: &FnDecl<'_>, def_id: LocalDefId) {
38+
let FnRetTy::Return(return_ty_hir) = &decl.output else { return };
5339

54-
let FnRetTy::Return(return_ty_hir) = &decl.output else { return };
40+
let return_ty = cx
41+
.tcx
42+
.erase_late_bound_regions(cx.tcx.fn_sig(def_id).skip_binder())
43+
.output();
5544

56-
let return_ty = cx
57-
.tcx
58-
.erase_late_bound_regions(cx.tcx.fn_sig(def_id).skip_binder())
59-
.output();
45+
if !return_ty.is_box() {
46+
return;
47+
}
6048

61-
if !return_ty.is_box() {
49+
let boxed_ty = return_ty.boxed_ty();
50+
51+
// it's sometimes useful to return Box<T> if T is unsized, so don't lint those
52+
if boxed_ty.is_sized(cx.tcx, cx.param_env) {
53+
span_lint_and_then(
54+
cx,
55+
UNNECESSARY_BOX_RETURNS,
56+
return_ty_hir.span,
57+
format!("boxed return of the sized type `{boxed_ty}`").as_str(),
58+
|diagnostic| {
59+
diagnostic.span_suggestion(
60+
return_ty_hir.span,
61+
"try",
62+
boxed_ty.to_string(),
63+
// the return value and function callers also needs to
64+
// be changed, so this can't be MachineApplicable
65+
Applicability::Unspecified,
66+
);
67+
diagnostic.help("changing this also requires a change to the return expressions in this function");
68+
},
69+
);
70+
}
71+
}
72+
73+
impl LateLintPass<'_> for UnnecessaryBoxReturns {
74+
fn check_trait_item(&mut self, cx: &LateContext<'_>, item: &TraitItem<'_>) {
75+
let TraitItemKind::Fn(signature, _) = &item.kind else { return };
76+
check_fn_decl(cx, signature.decl, item.owner_id.def_id);
77+
}
78+
79+
fn check_impl_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::ImplItem<'_>) {
80+
// Ignore implementations of traits, because the lint should be on the
81+
// trait, not on the implmentation of it.
82+
let Node::Item(parent) = cx.tcx.hir().get_parent(item.hir_id()) else { return };
83+
let ItemKind::Impl(parent) = parent.kind else { return };
84+
if parent.of_trait.is_some() {
6285
return;
6386
}
6487

65-
let boxed_ty = return_ty.boxed_ty();
88+
let ImplItemKind::Fn(signature, ..) = &item.kind else { return };
89+
check_fn_decl(cx, signature.decl, item.owner_id.def_id);
90+
}
6691

67-
// it's sometimes useful to return Box<T> if T is unsized, so don't lint those
68-
if boxed_ty.is_sized(cx.tcx, cx.param_env) {
69-
span_lint_and_then(
70-
cx,
71-
UNNECESSARY_BOX_RETURNS,
72-
return_ty_hir.span,
73-
format!("boxed return of the sized type `{boxed_ty}`").as_str(),
74-
|diagnostic| {
75-
diagnostic.span_suggestion(
76-
return_ty_hir.span,
77-
"try",
78-
boxed_ty.to_string(),
79-
// the return value and function callers also needs to
80-
// be changed, so this can't be MachineApplicable
81-
Applicability::Unspecified,
82-
);
83-
diagnostic.help("changing this also requires a change to the return expressions in this function");
84-
},
85-
);
86-
}
92+
fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
93+
let ItemKind::Fn(signature, ..) = &item.kind else { return };
94+
check_fn_decl(cx, signature.decl, item.owner_id.def_id);
8795
}
8896
}

tests/ui/unnecessary_box_returns.rs

+19
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,26 @@
11
#![warn(clippy::unnecessary_box_returns)]
22

3+
trait Bar {
4+
// lint
5+
fn baz(&self) -> Box<usize>;
6+
}
7+
38
struct Foo {}
49

10+
impl Bar for Foo {
11+
// don't lint: this is a problem with the trait, not the implementation
12+
fn baz(&self) -> Box<usize> {
13+
Box::new(42)
14+
}
15+
}
16+
17+
impl Foo {
18+
fn baz(&self) -> Box<usize> {
19+
// lint
20+
Box::new(13)
21+
}
22+
}
23+
524
// lint
625
fn boxed_usize() -> Box<usize> {
726
Box::new(5)
+20-4
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,35 @@
11
error: boxed return of the sized type `usize`
2-
--> $DIR/unnecessary_box_returns.rs:6:21
2+
--> $DIR/unnecessary_box_returns.rs:5:22
3+
|
4+
LL | fn baz(&self) -> Box<usize>;
5+
| ^^^^^^^^^^ help: try: `usize`
6+
|
7+
= help: changing this also requires a change to the return expressions in this function
8+
= note: `-D clippy::unnecessary-box-returns` implied by `-D warnings`
9+
10+
error: boxed return of the sized type `usize`
11+
--> $DIR/unnecessary_box_returns.rs:18:22
12+
|
13+
LL | fn baz(&self) -> Box<usize> {
14+
| ^^^^^^^^^^ help: try: `usize`
15+
|
16+
= help: changing this also requires a change to the return expressions in this function
17+
18+
error: boxed return of the sized type `usize`
19+
--> $DIR/unnecessary_box_returns.rs:25:21
320
|
421
LL | fn boxed_usize() -> Box<usize> {
522
| ^^^^^^^^^^ help: try: `usize`
623
|
724
= help: changing this also requires a change to the return expressions in this function
8-
= note: `-D clippy::unnecessary-box-returns` implied by `-D warnings`
925

1026
error: boxed return of the sized type `Foo`
11-
--> $DIR/unnecessary_box_returns.rs:11:19
27+
--> $DIR/unnecessary_box_returns.rs:30:19
1228
|
1329
LL | fn boxed_foo() -> Box<Foo> {
1430
| ^^^^^^^^ help: try: `Foo`
1531
|
1632
= help: changing this also requires a change to the return expressions in this function
1733

18-
error: aborting due to 2 previous errors
34+
error: aborting due to 4 previous errors
1935

0 commit comments

Comments
 (0)