1
1
use clippy_utils:: { diagnostics:: span_lint_and_sugg, ty:: implements_trait} ;
2
2
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 } ;
4
4
use rustc_hir_analysis:: hir_ty_to_ty;
5
5
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 } ;
7
7
8
8
declare_clippy_lint ! {
9
9
/// ### What it does
@@ -33,40 +33,58 @@ declare_clippy_lint! {
33
33
pedantic,
34
34
"Needlessly returning a Box"
35
35
}
36
- declare_lint_pass ! ( UnnecessaryBoxReturns => [ UNNECESSARY_BOX_RETURNS ] ) ;
37
36
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
+ }
40
40
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 ] ) ;
43
42
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
+ }
46
48
}
47
49
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) ;
50
60
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
+ }
63
81
}
64
82
}
65
83
66
84
impl LateLintPass < ' _ > for UnnecessaryBoxReturns {
67
85
fn check_trait_item ( & mut self , cx : & LateContext < ' _ > , item : & TraitItem < ' _ > ) {
68
86
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 ) ;
70
88
}
71
89
72
90
fn check_impl_item ( & mut self , cx : & LateContext < ' _ > , item : & rustc_hir:: ImplItem < ' _ > ) {
@@ -79,11 +97,11 @@ impl LateLintPass<'_> for UnnecessaryBoxReturns {
79
97
}
80
98
81
99
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 ) ;
83
101
}
84
102
85
103
fn check_item ( & mut self , cx : & LateContext < ' _ > , item : & Item < ' _ > ) {
86
104
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 ) ;
88
106
}
89
107
}
0 commit comments