@@ -83,6 +83,12 @@ declare_clippy_lint! {
8383 "needless unit expression"
8484}
8585
86+ #[ derive( PartialEq , Eq , Copy , Clone ) ]
87+ enum RetReplacement {
88+ Empty ,
89+ Unit ,
90+ }
91+
8692declare_lint_pass ! ( Return => [ NEEDLESS_RETURN , LET_AND_RETURN , UNUSED_UNIT ] ) ;
8793
8894impl Return {
@@ -91,21 +97,32 @@ impl Return {
9197 if let Some ( stmt) = block. stmts . last ( ) {
9298 match stmt. node {
9399 ast:: StmtKind :: Expr ( ref expr) | ast:: StmtKind :: Semi ( ref expr) => {
94- self . check_final_expr ( cx, expr, Some ( stmt. span ) ) ;
100+ self . check_final_expr ( cx, expr, Some ( stmt. span ) , RetReplacement :: Empty ) ;
95101 } ,
96102 _ => ( ) ,
97103 }
98104 }
99105 }
100106
101107 // Check a the final expression in a block if it's a return.
102- fn check_final_expr ( & mut self , cx : & EarlyContext < ' _ > , expr : & ast:: Expr , span : Option < Span > ) {
108+ fn check_final_expr (
109+ & mut self ,
110+ cx : & EarlyContext < ' _ > ,
111+ expr : & ast:: Expr ,
112+ span : Option < Span > ,
113+ replacement : RetReplacement ,
114+ ) {
103115 match expr. node {
104116 // simple return is always "bad"
105- ast:: ExprKind :: Ret ( Some ( ref inner) ) => {
117+ ast:: ExprKind :: Ret ( ref inner) => {
106118 // allow `#[cfg(a)] return a; #[cfg(b)] return b;`
107119 if !expr. attrs . iter ( ) . any ( attr_is_cfg) {
108- self . emit_return_lint ( cx, span. expect ( "`else return` is not possible" ) , inner. span ) ;
120+ self . emit_return_lint (
121+ cx,
122+ span. expect ( "`else return` is not possible" ) ,
123+ inner. as_ref ( ) . map ( |i| i. span ) ,
124+ replacement,
125+ ) ;
109126 }
110127 } ,
111128 // a whole block? check it!
@@ -117,32 +134,60 @@ impl Return {
117134 // (except for unit type functions) so we don't match it
118135 ast:: ExprKind :: If ( _, ref ifblock, Some ( ref elsexpr) ) => {
119136 self . check_block_return ( cx, ifblock) ;
120- self . check_final_expr ( cx, elsexpr, None ) ;
137+ self . check_final_expr ( cx, elsexpr, None , RetReplacement :: Empty ) ;
121138 } ,
122139 // a match expr, check all arms
123140 ast:: ExprKind :: Match ( _, ref arms) => {
124141 for arm in arms {
125- self . check_final_expr ( cx, & arm. body , Some ( arm. body . span ) ) ;
142+ self . check_final_expr ( cx, & arm. body , Some ( arm. body . span ) , RetReplacement :: Unit ) ;
126143 }
127144 } ,
128145 _ => ( ) ,
129146 }
130147 }
131148
132- fn emit_return_lint ( & mut self , cx : & EarlyContext < ' _ > , ret_span : Span , inner_span : Span ) {
133- if in_external_macro ( cx. sess ( ) , inner_span) || in_macro_or_desugar ( inner_span) {
134- return ;
149+ fn emit_return_lint (
150+ & mut self ,
151+ cx : & EarlyContext < ' _ > ,
152+ ret_span : Span ,
153+ inner_span : Option < Span > ,
154+ replacement : RetReplacement ,
155+ ) {
156+ match inner_span {
157+ Some ( inner_span) => {
158+ if in_external_macro ( cx. sess ( ) , inner_span) || in_macro_or_desugar ( inner_span) {
159+ return ;
160+ }
161+
162+ span_lint_and_then ( cx, NEEDLESS_RETURN , ret_span, "unneeded return statement" , |db| {
163+ if let Some ( snippet) = snippet_opt ( cx, inner_span) {
164+ db. span_suggestion ( ret_span, "remove `return`" , snippet, Applicability :: MachineApplicable ) ;
165+ }
166+ } )
167+ } ,
168+ None => match replacement {
169+ RetReplacement :: Empty => {
170+ span_lint_and_then ( cx, NEEDLESS_RETURN , ret_span, "unneeded return statement" , |db| {
171+ db. span_suggestion (
172+ ret_span,
173+ "remove `return`" ,
174+ String :: new ( ) ,
175+ Applicability :: MachineApplicable ,
176+ ) ;
177+ } ) ;
178+ } ,
179+ RetReplacement :: Unit => {
180+ span_lint_and_then ( cx, NEEDLESS_RETURN , ret_span, "unneeded return statement" , |db| {
181+ db. span_suggestion (
182+ ret_span,
183+ "replace `return` with the unit type" ,
184+ "()" . to_string ( ) ,
185+ Applicability :: MachineApplicable ,
186+ ) ;
187+ } ) ;
188+ } ,
189+ } ,
135190 }
136- span_lint_and_then ( cx, NEEDLESS_RETURN , ret_span, "unneeded return statement" , |db| {
137- if let Some ( snippet) = snippet_opt ( cx, inner_span) {
138- db. span_suggestion (
139- ret_span,
140- "remove `return` as shown" ,
141- snippet,
142- Applicability :: MachineApplicable ,
143- ) ;
144- }
145- } ) ;
146191 }
147192
148193 // Check for "let x = EXPR; x"
@@ -195,7 +240,7 @@ impl EarlyLintPass for Return {
195240 fn check_fn ( & mut self , cx : & EarlyContext < ' _ > , kind : FnKind < ' _ > , decl : & ast:: FnDecl , span : Span , _: ast:: NodeId ) {
196241 match kind {
197242 FnKind :: ItemFn ( .., block) | FnKind :: Method ( .., block) => self . check_block_return ( cx, block) ,
198- FnKind :: Closure ( body) => self . check_final_expr ( cx, body, Some ( body. span ) ) ,
243+ FnKind :: Closure ( body) => self . check_final_expr ( cx, body, Some ( body. span ) , RetReplacement :: Empty ) ,
199244 }
200245 if_chain ! {
201246 if let ast:: FunctionRetTy :: Ty ( ref ty) = decl. output;
0 commit comments