@@ -83,6 +83,12 @@ declare_clippy_lint! {
83
83
"needless unit expression"
84
84
}
85
85
86
+ #[ derive( PartialEq , Eq , Copy , Clone ) ]
87
+ enum RetReplacement {
88
+ Empty ,
89
+ Unit
90
+ }
91
+
86
92
declare_lint_pass ! ( Return => [ NEEDLESS_RETURN , LET_AND_RETURN , UNUSED_UNIT ] ) ;
87
93
88
94
impl Return {
@@ -91,21 +97,21 @@ impl Return {
91
97
if let Some ( stmt) = block. stmts . last ( ) {
92
98
match stmt. node {
93
99
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 ) ;
95
101
} ,
96
102
_ => ( ) ,
97
103
}
98
104
}
99
105
}
100
106
101
107
// 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 ( & mut self , cx : & EarlyContext < ' _ > , expr : & ast:: Expr , span : Option < Span > , replacement : RetReplacement ) {
103
109
match expr. node {
104
110
// simple return is always "bad"
105
- ast:: ExprKind :: Ret ( Some ( ref inner) ) => {
111
+ ast:: ExprKind :: Ret ( ref inner) => {
106
112
// allow `#[cfg(a)] return a; #[cfg(b)] return b;`
107
113
if !expr. attrs . iter ( ) . any ( attr_is_cfg) {
108
- self . emit_return_lint ( cx, span. expect ( "`else return` is not possible" ) , inner. span ) ;
114
+ self . emit_return_lint ( cx, span. expect ( "`else return` is not possible" ) , inner. as_ref ( ) . map ( |i| i . span ) , replacement ) ;
109
115
}
110
116
} ,
111
117
// a whole block? check it!
@@ -117,32 +123,61 @@ impl Return {
117
123
// (except for unit type functions) so we don't match it
118
124
ast:: ExprKind :: If ( _, ref ifblock, Some ( ref elsexpr) ) => {
119
125
self . check_block_return ( cx, ifblock) ;
120
- self . check_final_expr ( cx, elsexpr, None ) ;
126
+ self . check_final_expr ( cx, elsexpr, None , RetReplacement :: Empty ) ;
121
127
} ,
122
128
// a match expr, check all arms
123
129
ast:: ExprKind :: Match ( _, ref arms) => {
124
130
for arm in arms {
125
- self . check_final_expr ( cx, & arm. body , Some ( arm. body . span ) ) ;
131
+ self . check_final_expr ( cx, & arm. body , Some ( arm. body . span ) , RetReplacement :: Unit ) ;
126
132
}
127
133
} ,
128
134
_ => ( ) ,
129
135
}
130
136
}
131
137
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 ;
135
- }
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
- ) ;
138
+ fn emit_return_lint ( & mut self , cx : & EarlyContext < ' _ > , ret_span : Span , inner_span : Option < Span > , replacement : RetReplacement ) {
139
+ match inner_span {
140
+ Some ( inner_span) => {
141
+ if in_external_macro ( cx. sess ( ) , inner_span) || in_macro_or_desugar ( inner_span) {
142
+ return ;
143
+ }
144
+
145
+ span_lint_and_then ( cx, NEEDLESS_RETURN , ret_span, "unneeded return statement" , |db| {
146
+ if let Some ( snippet) = snippet_opt ( cx, inner_span) {
147
+ db. span_suggestion (
148
+ ret_span,
149
+ "remove `return` as shown" ,
150
+ snippet,
151
+ Applicability :: MachineApplicable ,
152
+ ) ;
153
+ }
154
+ } )
155
+ } ,
156
+ None => {
157
+ match replacement {
158
+ RetReplacement :: Empty => {
159
+ span_lint_and_then ( cx, NEEDLESS_RETURN , ret_span, "unneeded return statement" , |db| {
160
+ db. span_suggestion (
161
+ ret_span,
162
+ "remove `return`" ,
163
+ String :: new ( ) ,
164
+ Applicability :: MachineApplicable ,
165
+ ) ;
166
+ } ) ;
167
+ }
168
+ RetReplacement :: Unit => {
169
+ span_lint_and_then ( cx, NEEDLESS_RETURN , ret_span, "unneeded return statement" , |db| {
170
+ db. span_suggestion (
171
+ ret_span,
172
+ "replace `return` with the unit type `()`" ,
173
+ "()" . to_string ( ) ,
174
+ Applicability :: MachineApplicable ,
175
+ ) ;
176
+ } ) ;
177
+ }
178
+ }
144
179
}
145
- } ) ;
180
+ }
146
181
}
147
182
148
183
// Check for "let x = EXPR; x"
@@ -195,7 +230,7 @@ impl EarlyLintPass for Return {
195
230
fn check_fn ( & mut self , cx : & EarlyContext < ' _ > , kind : FnKind < ' _ > , decl : & ast:: FnDecl , span : Span , _: ast:: NodeId ) {
196
231
match kind {
197
232
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 ) ) ,
233
+ FnKind :: Closure ( body) => self . check_final_expr ( cx, body, Some ( body. span ) , RetReplacement :: Empty ) ,
199
234
}
200
235
if_chain ! {
201
236
if let ast:: FunctionRetTy :: Ty ( ref ty) = decl. output;
0 commit comments