1
1
use crate :: utils:: {
2
- contains_return, in_macro, is_type_diagnostic_item, match_qpath, paths, return_ty, snippet, span_lint_and_then ,
3
- visitors:: find_all_ret_expressions,
2
+ contains_return, in_macro, is_type_diagnostic_item, match_qpath, paths, return_ty, snippet, span_lint_and_sugg ,
3
+ span_lint_and_then , visitors:: find_all_ret_expressions,
4
4
} ;
5
5
use if_chain:: if_chain;
6
6
use rustc_errors:: Applicability ;
@@ -64,6 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
64
64
span : Span ,
65
65
hir_id : HirId ,
66
66
) {
67
+ // Abort if public function/method or closure.
67
68
match fn_kind {
68
69
FnKind :: ItemFn ( .., visibility, _) | FnKind :: Method ( .., Some ( visibility) , _) => {
69
70
if visibility. node . is_pub ( ) {
@@ -74,6 +75,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
74
75
_ => ( ) ,
75
76
}
76
77
78
+ // Abort if the method is implementing a trait or of it a trait method.
77
79
if let Some ( Node :: Item ( item) ) = cx. tcx . hir ( ) . find ( cx. tcx . hir ( ) . get_parent_node ( hir_id) ) {
78
80
if matches ! (
79
81
item. kind,
@@ -83,22 +85,43 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
83
85
}
84
86
}
85
87
86
- let ( return_type, path) = if is_type_diagnostic_item ( cx, return_ty ( cx, hir_id) , sym:: option_type) {
88
+ // Check if return type is Option or Result. If neither, abort.
89
+ let return_ty = return_ty ( cx, hir_id) ;
90
+ let ( return_type_label, path) = if is_type_diagnostic_item ( cx, return_ty, sym:: option_type) {
87
91
( "Option" , & paths:: OPTION_SOME )
88
- } else if is_type_diagnostic_item ( cx, return_ty ( cx , hir_id ) , sym:: result_type) {
92
+ } else if is_type_diagnostic_item ( cx, return_ty, sym:: result_type) {
89
93
( "Result" , & paths:: RESULT_OK )
90
94
} else {
91
95
return ;
92
96
} ;
93
97
98
+ // Take the first inner type of the Option or Result. If can't, abort.
99
+ let inner_ty = if_chain ! {
100
+ // Skip Option or Result and take the first outermost inner type.
101
+ if let Some ( inner_ty) = return_ty. walk( ) . nth( 1 ) ;
102
+ if let GenericArgKind :: Type ( inner_ty) = inner_ty. unpack( ) ;
103
+ then {
104
+ inner_ty
105
+ } else {
106
+ return ;
107
+ }
108
+ } ;
109
+
110
+ // Check if all return expression respect the following condition and collect them.
94
111
let mut suggs = Vec :: new ( ) ;
95
112
let can_sugg = find_all_ret_expressions ( cx, & body. value , |ret_expr| {
96
113
if_chain ! {
114
+ // Abort if in macro.
97
115
if !in_macro( ret_expr. span) ;
116
+ // Check if a function call.
98
117
if let ExprKind :: Call ( ref func, ref args) = ret_expr. kind;
118
+ // Get the Path of the function call.
99
119
if let ExprKind :: Path ( ref qpath) = func. kind;
120
+ // Check if OPTION_SOME or RESULT_OK, depending on return type.
100
121
if match_qpath( qpath, path) ;
122
+ // Make sure the function call has only one argument.
101
123
if args. len( ) == 1 ;
124
+ // Make sure the function argument does not contain a return expression.
102
125
if !contains_return( & args[ 0 ] ) ;
103
126
then {
104
127
suggs. push( ( ret_expr. span, snippet( cx, args[ 0 ] . span. source_callsite( ) , ".." ) . to_string( ) ) ) ;
@@ -110,39 +133,42 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
110
133
} ) ;
111
134
112
135
if can_sugg && !suggs. is_empty ( ) {
113
- span_lint_and_then (
114
- cx,
115
- UNNECESSARY_WRAPS ,
116
- span,
117
- format ! (
118
- "this function's return value is unnecessarily wrapped by `{}`" ,
119
- return_type
120
- )
121
- . as_str ( ) ,
122
- |diag| {
123
- let inner_ty = return_ty ( cx, hir_id)
124
- . walk ( )
125
- . skip ( 1 ) // skip `std::option::Option` or `std::result::Result`
126
- . take ( 1 ) // take the first outermost inner type
127
- . filter_map ( |inner| match inner. unpack ( ) {
128
- GenericArgKind :: Type ( inner_ty) => Some ( inner_ty. to_string ( ) ) ,
129
- _ => None ,
130
- } ) ;
131
- inner_ty. for_each ( |inner_ty| {
136
+ // Issue 6640: If the inner type is Unit, emit lint similar to clippy::unused_unit.
137
+ if inner_ty. is_unit ( ) {
138
+ span_lint_and_sugg (
139
+ cx,
140
+ UNNECESSARY_WRAPS ,
141
+ fn_decl. output . span ( ) ,
142
+ "unneeded wrapped unit return type" ,
143
+ format ! ( "remove the `-> {}<()>`" , return_type_label) . as_str ( ) ,
144
+ String :: new ( ) ,
145
+ Applicability :: MaybeIncorrect ,
146
+ ) ;
147
+ } else {
148
+ span_lint_and_then (
149
+ cx,
150
+ UNNECESSARY_WRAPS ,
151
+ span,
152
+ format ! (
153
+ "this function's return value is unnecessarily wrapped by `{}`" ,
154
+ return_type_label
155
+ )
156
+ . as_str ( ) ,
157
+ |diag| {
132
158
diag. span_suggestion (
133
159
fn_decl. output . span ( ) ,
134
- format ! ( "remove `{}` from the return type..." , return_type ) . as_str ( ) ,
135
- inner_ty,
160
+ format ! ( "remove `{}` from the return type..." , return_type_label ) . as_str ( ) ,
161
+ inner_ty. to_string ( ) ,
136
162
Applicability :: MaybeIncorrect ,
137
163
) ;
138
- } ) ;
139
- diag . multipart_suggestion (
140
- "...and change the returning expressions" ,
141
- suggs ,
142
- Applicability :: MaybeIncorrect ,
143
- ) ;
144
- } ,
145
- ) ;
164
+ diag . multipart_suggestion (
165
+ "...and change the returning expressions" ,
166
+ suggs ,
167
+ Applicability :: MaybeIncorrect ,
168
+ ) ;
169
+ } ,
170
+ ) ;
171
+ }
146
172
}
147
173
}
148
174
}
0 commit comments