11use 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,
44} ;
55use if_chain:: if_chain;
66use rustc_errors:: Applicability ;
77use rustc_hir:: intravisit:: FnKind ;
88use rustc_hir:: { Body , ExprKind , FnDecl , HirId , Impl , ItemKind , Node } ;
99use rustc_lint:: { LateContext , LateLintPass } ;
10- use rustc_middle:: ty:: subst :: GenericArgKind ;
10+ use rustc_middle:: ty;
1111use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
1212use rustc_span:: symbol:: sym;
1313use rustc_span:: Span ;
@@ -85,46 +85,44 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
8585 }
8686 }
8787
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 ) )
10594 } else {
10695 return ;
10796 }
97+ } else {
98+ return ;
10899 } ;
109100
110101 // Check if all return expression respect the following condition and collect them.
111102 let mut suggs = Vec :: new ( ) ;
112103 let can_sugg = find_all_ret_expressions ( cx, & body. value , |ret_expr| {
113104 if_chain ! {
114- // Abort if in macro.
115105 if !in_macro( ret_expr. span) ;
116106 // Check if a function call.
117107 if let ExprKind :: Call ( ref func, ref args) = ret_expr. kind;
118108 // Get the Path of the function call.
119109 if let ExprKind :: Path ( ref qpath) = func. kind;
120110 // Check if OPTION_SOME or RESULT_OK, depending on return type.
121111 if match_qpath( qpath, path) ;
122- // Make sure the function call has only one argument.
123112 if args. len( ) == 1 ;
124113 // Make sure the function argument does not contain a return expression.
125114 if !contains_return( & args[ 0 ] ) ;
126115 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+ ) ;
128126 true
129127 } else {
130128 false
@@ -133,42 +131,36 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
133131 } ) ;
134132
135133 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+ )
147140 } else {
148- span_lint_and_then (
149- cx,
150- UNNECESSARY_WRAPS ,
151- span,
141+ (
152142 format ! (
153143 "this function's return value is unnecessarily wrapped by `{}`" ,
154144 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 ,
170157 ) ;
171- }
158+ diag. multipart_suggestion (
159+ "...and then change the returning expressions" ,
160+ suggs,
161+ Applicability :: MaybeIncorrect ,
162+ ) ;
163+ } ) ;
172164 }
173165 }
174166}
0 commit comments