@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
22use rustc_errors:: Applicability ;
33use rustc_hir:: { def_id:: LocalDefId , FnDecl , FnRetTy , ImplItemKind , Item , ItemKind , Node , TraitItem , TraitItemKind } ;
44use rustc_lint:: { LateContext , LateLintPass } ;
5- use rustc_session:: { declare_lint_pass , declare_tool_lint } ;
5+ use rustc_session:: { declare_tool_lint , impl_lint_pass } ;
66
77declare_clippy_lint ! {
88 /// ### What it does
@@ -32,48 +32,66 @@ declare_clippy_lint! {
3232 pedantic,
3333 "Needlessly returning a Box"
3434}
35- declare_lint_pass ! ( UnnecessaryBoxReturns => [ UNNECESSARY_BOX_RETURNS ] ) ;
3635
37- fn check_fn_decl ( cx : & LateContext < ' _ > , decl : & FnDecl < ' _ > , def_id : LocalDefId ) {
38- let FnRetTy :: Return ( return_ty_hir) = & decl. output else { return } ;
36+ pub struct UnnecessaryBoxReturns {
37+ avoid_breaking_exported_api : bool ,
38+ }
3939
40- let return_ty = cx
41- . tcx
42- . erase_late_bound_regions ( cx. tcx . fn_sig ( def_id) . skip_binder ( ) )
43- . output ( ) ;
40+ impl_lint_pass ! ( UnnecessaryBoxReturns => [ UNNECESSARY_BOX_RETURNS ] ) ;
4441
45- if !return_ty. is_box ( ) {
46- return ;
42+ impl UnnecessaryBoxReturns {
43+ pub fn new ( avoid_breaking_exported_api : bool ) -> Self {
44+ Self {
45+ avoid_breaking_exported_api,
46+ }
4747 }
4848
49- let boxed_ty = return_ty. boxed_ty ( ) ;
49+ fn check_fn_decl ( & mut self , cx : & LateContext < ' _ > , decl : & FnDecl < ' _ > , def_id : LocalDefId ) {
50+ // we don't want to tell someone to break an exported function if they ask us not to
51+ if self . avoid_breaking_exported_api && cx. effective_visibilities . is_exported ( def_id) {
52+ return ;
53+ }
54+
55+ let FnRetTy :: Return ( return_ty_hir) = & decl. output else { return } ;
56+
57+ let return_ty = cx
58+ . tcx
59+ . erase_late_bound_regions ( cx. tcx . fn_sig ( def_id) . skip_binder ( ) )
60+ . output ( ) ;
5061
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- ) ;
62+ if !return_ty. is_box ( ) {
63+ return ;
64+ }
65+
66+ let boxed_ty = return_ty. boxed_ty ( ) ;
67+
68+ // it's sometimes useful to return Box<T> if T is unsized, so don't lint those
69+ if boxed_ty. is_sized ( cx. tcx , cx. param_env ) {
70+ span_lint_and_then (
71+ cx,
72+ UNNECESSARY_BOX_RETURNS ,
73+ return_ty_hir. span ,
74+ format ! ( "boxed return of the sized type `{boxed_ty}`" ) . as_str ( ) ,
75+ |diagnostic| {
76+ diagnostic. span_suggestion (
77+ return_ty_hir. span ,
78+ "try" ,
79+ boxed_ty. to_string ( ) ,
80+ // the return value and function callers also needs to
81+ // be changed, so this can't be MachineApplicable
82+ Applicability :: Unspecified ,
83+ ) ;
84+ diagnostic. help ( "changing this also requires a change to the return expressions in this function" ) ;
85+ } ,
86+ ) ;
87+ }
7088 }
7189}
7290
7391impl LateLintPass < ' _ > for UnnecessaryBoxReturns {
7492 fn check_trait_item ( & mut self , cx : & LateContext < ' _ > , item : & TraitItem < ' _ > ) {
7593 let TraitItemKind :: Fn ( signature, _) = & item. kind else { return } ;
76- check_fn_decl ( cx, signature. decl , item. owner_id . def_id ) ;
94+ self . check_fn_decl ( cx, signature. decl , item. owner_id . def_id ) ;
7795 }
7896
7997 fn check_impl_item ( & mut self , cx : & LateContext < ' _ > , item : & rustc_hir:: ImplItem < ' _ > ) {
@@ -86,11 +104,11 @@ impl LateLintPass<'_> for UnnecessaryBoxReturns {
86104 }
87105
88106 let ImplItemKind :: Fn ( signature, ..) = & item. kind else { return } ;
89- check_fn_decl ( cx, signature. decl , item. owner_id . def_id ) ;
107+ self . check_fn_decl ( cx, signature. decl , item. owner_id . def_id ) ;
90108 }
91109
92110 fn check_item ( & mut self , cx : & LateContext < ' _ > , item : & Item < ' _ > ) {
93111 let ItemKind :: Fn ( signature, ..) = & item. kind else { return } ;
94- check_fn_decl ( cx, signature. decl , item. owner_id . def_id ) ;
112+ self . check_fn_decl ( cx, signature. decl , item. owner_id . def_id ) ;
95113 }
96114}
0 commit comments