11use clippy_utils:: { diagnostics:: span_lint_and_sugg, ty:: implements_trait} ;
22use 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 } ;
44use rustc_hir_analysis:: hir_ty_to_ty;
55use 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
88declare_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
6684impl 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}
0 commit comments