Skip to content

Commit 27da9aa

Browse files
committed
Avoid breaking exported API
1 parent 3569f87 commit 27da9aa

File tree

6 files changed

+61
-33
lines changed

6 files changed

+61
-33
lines changed

book/src/lint_configuration.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ Suppress lints whenever the suggested change would cause breakage for other crat
130130
* [option_option](https://rust-lang.github.io/rust-clippy/master/index.html#option_option)
131131
* [linkedlist](https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist)
132132
* [rc_mutex](https://rust-lang.github.io/rust-clippy/master/index.html#rc_mutex)
133+
* [unnecessary_box_returns](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_box_returns)
133134

134135

135136
### msrv

clippy_lints/src/lib.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -941,7 +941,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
941941
store.register_late_pass(|_| Box::new(allow_attributes::AllowAttribute));
942942
store.register_late_pass(move |_| Box::new(manual_main_separator_str::ManualMainSeparatorStr::new(msrv())));
943943
store.register_late_pass(|_| Box::new(unnecessary_struct_initialization::UnnecessaryStruct));
944-
store.register_late_pass(|_| Box::new(unnecessary_box_returns::UnnecessaryBoxReturns));
944+
store.register_late_pass(move |_| {
945+
Box::new(unnecessary_box_returns::UnnecessaryBoxReturns::new(
946+
avoid_breaking_exported_api,
947+
))
948+
});
945949
// add lints here, do not remove this comment, it's used in `new_lint`
946950
}
947951

clippy_lints/src/unnecessary_box_returns.rs

Lines changed: 44 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use clippy_utils::{diagnostics::span_lint_and_sugg, ty::implements_trait};
22
use rustc_errors::Applicability;
3-
use rustc_hir::{FnDecl, FnRetTy, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind};
3+
use rustc_hir::{def_id::LocalDefId, FnDecl, FnRetTy, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind};
44
use rustc_hir_analysis::hir_ty_to_ty;
55
use rustc_lint::{LateContext, LateLintPass};
6-
use rustc_session::{declare_lint_pass, declare_tool_lint};
6+
use rustc_session::{declare_tool_lint, impl_lint_pass};
77

88
declare_clippy_lint! {
99
/// ### What it does
@@ -33,40 +33,58 @@ declare_clippy_lint! {
3333
pedantic,
3434
"Needlessly returning a Box"
3535
}
36-
declare_lint_pass!(UnnecessaryBoxReturns => [UNNECESSARY_BOX_RETURNS]);
3736

38-
fn check_fn_decl(cx: &LateContext<'_>, decl: &FnDecl<'_>) {
39-
let FnRetTy::Return(return_ty_hir) = &decl.output else { return };
37+
pub struct UnnecessaryBoxReturns {
38+
avoid_breaking_exported_api: bool,
39+
}
4040

41-
// this is safe, since we're not in a body
42-
let return_ty = hir_ty_to_ty(cx.tcx, return_ty_hir);
41+
impl_lint_pass!(UnnecessaryBoxReturns => [UNNECESSARY_BOX_RETURNS]);
4342

44-
if !return_ty.is_box() {
45-
return;
43+
impl UnnecessaryBoxReturns {
44+
pub fn new(avoid_breaking_exported_api: bool) -> Self {
45+
Self {
46+
avoid_breaking_exported_api,
47+
}
4648
}
4749

48-
let boxed_ty = return_ty.boxed_ty();
49-
let Some(sized_trait) = cx.tcx.lang_items().sized_trait() else { return };
50+
fn check_fn_decl(&mut self, cx: &LateContext<'_>, decl: &FnDecl<'_>, def_id: LocalDefId) {
51+
// we don't want to tell someone to break an exported function if they ask us not to
52+
if self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(def_id) {
53+
return;
54+
}
55+
56+
let FnRetTy::Return(return_ty_hir) = &decl.output else { return };
57+
58+
// this is safe, since we're not in a body
59+
let return_ty = hir_ty_to_ty(cx.tcx, return_ty_hir);
5060

51-
// it's sometimes useful to return Box<T> if T is unsized, so don't lint those
52-
if implements_trait(cx, boxed_ty, sized_trait, &[]) {
53-
span_lint_and_sugg(
54-
cx,
55-
UNNECESSARY_BOX_RETURNS,
56-
return_ty_hir.span,
57-
format!("boxed return of the sized type `{boxed_ty}`").as_str(),
58-
"try",
59-
boxed_ty.to_string(),
60-
// the return value and function callers also needs to be changed, so this can't be MachineApplicable
61-
Applicability::Unspecified,
62-
);
61+
if !return_ty.is_box() {
62+
return;
63+
}
64+
65+
let boxed_ty = return_ty.boxed_ty();
66+
let Some(sized_trait) = cx.tcx.lang_items().sized_trait() else { return };
67+
68+
// it's sometimes useful to return Box<T> if T is unsized, so don't lint those
69+
if implements_trait(cx, boxed_ty, sized_trait, &[]) {
70+
span_lint_and_sugg(
71+
cx,
72+
UNNECESSARY_BOX_RETURNS,
73+
return_ty_hir.span,
74+
format!("boxed return of the sized type `{boxed_ty}`").as_str(),
75+
"try",
76+
boxed_ty.to_string(),
77+
// the return value and function callers also needs to be changed, so this can't be MachineApplicable
78+
Applicability::Unspecified,
79+
);
80+
}
6381
}
6482
}
6583

6684
impl LateLintPass<'_> for UnnecessaryBoxReturns {
6785
fn check_trait_item(&mut self, cx: &LateContext<'_>, item: &TraitItem<'_>) {
6886
let TraitItemKind::Fn(signature, _) = &item.kind else { return };
69-
check_fn_decl(cx, signature.decl);
87+
self.check_fn_decl(cx, signature.decl, item.owner_id.def_id);
7088
}
7189

7290
fn check_impl_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::ImplItem<'_>) {
@@ -79,11 +97,11 @@ impl LateLintPass<'_> for UnnecessaryBoxReturns {
7997
}
8098

8199
let ImplItemKind::Fn(signature, ..) = &item.kind else { return };
82-
check_fn_decl(cx, signature.decl);
100+
self.check_fn_decl(cx, signature.decl, item.owner_id.def_id);
83101
}
84102

85103
fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
86104
let ItemKind::Fn(signature, ..) = &item.kind else { return };
87-
check_fn_decl(cx, signature.decl);
105+
self.check_fn_decl(cx, signature.decl, item.owner_id.def_id);
88106
}
89107
}

clippy_lints/src/utils/conf.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ define_Conf! {
249249
/// arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"]
250250
/// ```
251251
(arithmetic_side_effects_allowed_unary: rustc_data_structures::fx::FxHashSet<String> = <_>::default()),
252-
/// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX.
252+
/// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX, UNNECESSARY_BOX_RETURNS.
253253
///
254254
/// Suppress lints whenever the suggested change would cause breakage for other crates.
255255
(avoid_breaking_exported_api: bool = true),

tests/ui/unnecessary_box_returns.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ trait Bar {
55
fn baz(&self) -> Box<usize>;
66
}
77

8-
struct Foo {}
8+
pub struct Foo {}
99

1010
impl Bar for Foo {
1111
// don't lint: this is a problem with the trait, not the implementation
@@ -27,7 +27,12 @@ fn boxed_usize() -> Box<usize> {
2727
}
2828

2929
// lint
30-
fn boxed_foo() -> Box<Foo> {
30+
fn _boxed_foo() -> Box<Foo> {
31+
Box::new(Foo {})
32+
}
33+
34+
// don't lint: this is exported
35+
pub fn boxed_foo() -> Box<Foo> {
3136
Box::new(Foo {})
3237
}
3338

tests/ui/unnecessary_box_returns.stderr

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ LL | fn boxed_usize() -> Box<usize> {
1919
| ^^^^^^^^^^ help: try: `usize`
2020

2121
error: boxed return of the sized type `Foo`
22-
--> $DIR/unnecessary_box_returns.rs:30:19
22+
--> $DIR/unnecessary_box_returns.rs:30:20
2323
|
24-
LL | fn boxed_foo() -> Box<Foo> {
25-
| ^^^^^^^^ help: try: `Foo`
24+
LL | fn _boxed_foo() -> Box<Foo> {
25+
| ^^^^^^^^ help: try: `Foo`
2626

2727
error: aborting due to 4 previous errors
2828

0 commit comments

Comments
 (0)