11use 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,
44} ;
55use if_chain:: if_chain;
66use rustc_errors:: Applicability ;
@@ -64,6 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
6464 span : Span ,
6565 hir_id : HirId ,
6666 ) {
67+ // Abort if public function/method or closure.
6768 match fn_kind {
6869 FnKind :: ItemFn ( .., visibility, _) | FnKind :: Method ( .., Some ( visibility) , _) => {
6970 if visibility. node . is_pub ( ) {
@@ -74,6 +75,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
7475 _ => ( ) ,
7576 }
7677
78+ // Abort if the method is implementing a trait or of it a trait method.
7779 if let Some ( Node :: Item ( item) ) = cx. tcx . hir ( ) . find ( cx. tcx . hir ( ) . get_parent_node ( hir_id) ) {
7880 if matches ! (
7981 item. kind,
@@ -83,22 +85,43 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
8385 }
8486 }
8587
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) {
8791 ( "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) {
8993 ( "Result" , & paths:: RESULT_OK )
9094 } else {
9195 return ;
9296 } ;
9397
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.
94111 let mut suggs = Vec :: new ( ) ;
95112 let can_sugg = find_all_ret_expressions ( cx, & body. value , |ret_expr| {
96113 if_chain ! {
114+ // Abort if in macro.
97115 if !in_macro( ret_expr. span) ;
116+ // Check if a function call.
98117 if let ExprKind :: Call ( ref func, ref args) = ret_expr. kind;
118+ // Get the Path of the function call.
99119 if let ExprKind :: Path ( ref qpath) = func. kind;
120+ // Check if OPTION_SOME or RESULT_OK, depending on return type.
100121 if match_qpath( qpath, path) ;
122+ // Make sure the function call has only one argument.
101123 if args. len( ) == 1 ;
124+ // Make sure the function argument does not contain a return expression.
102125 if !contains_return( & args[ 0 ] ) ;
103126 then {
104127 suggs. push( ( ret_expr. span, snippet( cx, args[ 0 ] . span. source_callsite( ) , ".." ) . to_string( ) ) ) ;
@@ -110,39 +133,42 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
110133 } ) ;
111134
112135 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| {
132158 diag. span_suggestion (
133159 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 ( ) ,
136162 Applicability :: MaybeIncorrect ,
137163 ) ;
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+ }
146172 }
147173 }
148174}
0 commit comments