1
1
use crate :: utils:: {
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,
2
+ contains_return, in_macro, match_qpath, paths, return_ty, snippet, span_lint_and_then ,
3
+ visitors:: find_all_ret_expressions,
4
4
} ;
5
5
use if_chain:: if_chain;
6
6
use rustc_errors:: Applicability ;
7
7
use rustc_hir:: intravisit:: FnKind ;
8
8
use rustc_hir:: { Body , ExprKind , FnDecl , HirId , Impl , ItemKind , Node } ;
9
9
use rustc_lint:: { LateContext , LateLintPass } ;
10
- use rustc_middle:: ty:: subst :: GenericArgKind ;
10
+ use rustc_middle:: ty;
11
11
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
12
12
use rustc_span:: symbol:: sym;
13
13
use rustc_span:: Span ;
@@ -85,46 +85,44 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
85
85
}
86
86
}
87
87
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) {
91
- ( "Option" , & paths:: OPTION_SOME )
92
- } else if is_type_diagnostic_item ( cx, return_ty, sym:: result_type) {
93
- ( "Result" , & paths:: RESULT_OK )
94
- } else {
95
- return ;
96
- } ;
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
88
+ // Get the wrapper and inner types, if can't, abort.
89
+ let ( return_type_label, path, inner_type) = if let ty:: Adt ( adt_def, subst) = return_ty ( cx, hir_id) . kind ( ) {
90
+ if cx. tcx . is_diagnostic_item ( sym:: option_type, adt_def. did ) {
91
+ ( "Option" , & paths:: OPTION_SOME , subst. type_at ( 0 ) )
92
+ } else if cx. tcx . is_diagnostic_item ( sym:: result_type, adt_def. did ) {
93
+ ( "Result" , & paths:: RESULT_OK , subst. type_at ( 0 ) )
105
94
} else {
106
95
return ;
107
96
}
97
+ } else {
98
+ return ;
108
99
} ;
109
100
110
101
// Check if all return expression respect the following condition and collect them.
111
102
let mut suggs = Vec :: new ( ) ;
112
103
let can_sugg = find_all_ret_expressions ( cx, & body. value , |ret_expr| {
113
104
if_chain ! {
114
- // Abort if in macro.
115
105
if !in_macro( ret_expr. span) ;
116
106
// Check if a function call.
117
107
if let ExprKind :: Call ( ref func, ref args) = ret_expr. kind;
118
108
// Get the Path of the function call.
119
109
if let ExprKind :: Path ( ref qpath) = func. kind;
120
110
// Check if OPTION_SOME or RESULT_OK, depending on return type.
121
111
if match_qpath( qpath, path) ;
122
- // Make sure the function call has only one argument.
123
112
if args. len( ) == 1 ;
124
113
// Make sure the function argument does not contain a return expression.
125
114
if !contains_return( & args[ 0 ] ) ;
126
115
then {
127
- suggs. push( ( ret_expr. span, snippet( cx, args[ 0 ] . span. source_callsite( ) , ".." ) . to_string( ) ) ) ;
116
+ suggs. push(
117
+ (
118
+ ret_expr. span,
119
+ if inner_type. is_unit( ) {
120
+ "" . to_string( )
121
+ } else {
122
+ snippet( cx, args[ 0 ] . span. source_callsite( ) , ".." ) . to_string( )
123
+ }
124
+ )
125
+ ) ;
128
126
true
129
127
} else {
130
128
false
@@ -133,42 +131,36 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
133
131
} ) ;
134
132
135
133
if can_sugg && !suggs. is_empty ( ) {
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
- ) ;
134
+ let ( lint_msg, return_type_suggestion_msg, return_type_suggestion) = if inner_type. is_unit ( ) {
135
+ (
136
+ "this function's return value is unnecessary" . to_string ( ) ,
137
+ "remove the return type..." . to_string ( ) ,
138
+ snippet ( cx, fn_decl. output . span ( ) , ".." ) . to_string ( ) ,
139
+ )
147
140
} else {
148
- span_lint_and_then (
149
- cx,
150
- UNNECESSARY_WRAPS ,
151
- span,
141
+ (
152
142
format ! (
153
143
"this function's return value is unnecessarily wrapped by `{}`" ,
154
144
return_type_label
155
- )
156
- . as_str ( ) ,
157
- |diag| {
158
- diag. span_suggestion (
159
- fn_decl. output . span ( ) ,
160
- format ! ( "remove `{}` from the return type..." , return_type_label) . as_str ( ) ,
161
- inner_ty. to_string ( ) ,
162
- Applicability :: MaybeIncorrect ,
163
- ) ;
164
- diag. multipart_suggestion (
165
- "...and change the returning expressions" ,
166
- suggs,
167
- Applicability :: MaybeIncorrect ,
168
- ) ;
169
- } ,
145
+ ) ,
146
+ format ! ( "remove `{}` from the return type..." , return_type_label) ,
147
+ inner_type. to_string ( ) ,
148
+ )
149
+ } ;
150
+
151
+ span_lint_and_then ( cx, UNNECESSARY_WRAPS , span, lint_msg. as_str ( ) , |diag| {
152
+ diag. span_suggestion (
153
+ fn_decl. output . span ( ) ,
154
+ return_type_suggestion_msg. as_str ( ) ,
155
+ return_type_suggestion,
156
+ Applicability :: MaybeIncorrect ,
170
157
) ;
171
- }
158
+ diag. multipart_suggestion (
159
+ "...and then change the returning expressions" ,
160
+ suggs,
161
+ Applicability :: MaybeIncorrect ,
162
+ ) ;
163
+ } ) ;
172
164
}
173
165
}
174
166
}
0 commit comments