@@ -32,8 +32,8 @@ declare_clippy_lint! {
32
32
"suspicious formatting of `*=`, `-=` or `!=`"
33
33
}
34
34
35
- /// **What it does:** Checks for formatting of `else if `. It lints if the `else`
36
- /// and `if` are not on the same line or the `else` seems to be missing.
35
+ /// **What it does:** Checks for formatting of `else`. It lints if the `else`
36
+ /// is followed immediately by a newline or the `else` seems to be missing.
37
37
///
38
38
/// **Why is this bad?** This is probably some refactoring remnant, even if the
39
39
/// code is correct, it might look confusing.
@@ -43,19 +43,29 @@ declare_clippy_lint! {
43
43
/// **Example:**
44
44
/// ```rust,ignore
45
45
/// if foo {
46
+ /// } { // looks like an `else` is missing here
47
+ /// }
48
+ ///
49
+ /// if foo {
46
50
/// } if bar { // looks like an `else` is missing here
47
51
/// }
48
52
///
49
53
/// if foo {
50
54
/// } else
51
55
///
56
+ /// { // this is the `else` block of the previous `if`, but should it be?
57
+ /// }
58
+ ///
59
+ /// if foo {
60
+ /// } else
61
+ ///
52
62
/// if bar { // this is the `else` block of the previous `if`, but should it be?
53
63
/// }
54
64
/// ```
55
65
declare_clippy_lint ! {
56
66
pub SUSPICIOUS_ELSE_FORMATTING ,
57
67
style,
58
- "suspicious formatting of `else if `"
68
+ "suspicious formatting of `else`"
59
69
}
60
70
61
71
/// **What it does:** Checks for possible missing comma in an array. It lints if
@@ -98,7 +108,7 @@ impl EarlyLintPass for Formatting {
98
108
match ( & w[ 0 ] . node , & w[ 1 ] . node ) {
99
109
( & ast:: StmtKind :: Expr ( ref first) , & ast:: StmtKind :: Expr ( ref second) ) |
100
110
( & ast:: StmtKind :: Expr ( ref first) , & ast:: StmtKind :: Semi ( ref second) ) => {
101
- check_consecutive_ifs ( cx, first, second) ;
111
+ check_missing_else ( cx, first, second) ;
102
112
} ,
103
113
_ => ( ) ,
104
114
}
@@ -107,7 +117,7 @@ impl EarlyLintPass for Formatting {
107
117
108
118
fn check_expr ( & mut self , cx : & EarlyContext < ' _ > , expr : & ast:: Expr ) {
109
119
check_assign ( cx, expr) ;
110
- check_else_if ( cx, expr) ;
120
+ check_else ( cx, expr) ;
111
121
check_array ( cx, expr) ;
112
122
}
113
123
}
@@ -141,10 +151,12 @@ fn check_assign(cx: &EarlyContext<'_>, expr: &ast::Expr) {
141
151
}
142
152
}
143
153
144
- /// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for weird `else if `.
145
- fn check_else_if ( cx : & EarlyContext < ' _ > , expr : & ast:: Expr ) {
154
+ /// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for weird `else`.
155
+ fn check_else ( cx : & EarlyContext < ' _ > , expr : & ast:: Expr ) {
146
156
if let Some ( ( then, & Some ( ref else_) ) ) = unsugar_if ( expr) {
147
- if unsugar_if ( else_) . is_some ( ) && !differing_macro_contexts ( then. span , else_. span ) && !in_macro ( then. span ) {
157
+ if ( is_block ( else_) || unsugar_if ( else_) . is_some ( ) )
158
+ && !differing_macro_contexts ( then. span , else_. span ) && !in_macro ( then. span )
159
+ {
148
160
// this will be a span from the closing ‘}’ of the “then” block (excluding) to
149
161
// the
150
162
// “if” of the “else if” block (excluding)
@@ -158,14 +170,23 @@ fn check_else_if(cx: &EarlyContext<'_>, expr: &ast::Expr) {
158
170
. expect ( "there must be a `else` here" ) ;
159
171
160
172
if else_snippet[ else_pos..] . contains ( '\n' ) {
173
+ let else_desc = if unsugar_if ( else_) . is_some ( ) {
174
+ "if"
175
+ } else {
176
+ "{..}"
177
+ } ;
178
+
161
179
span_note_and_lint (
162
180
cx,
163
181
SUSPICIOUS_ELSE_FORMATTING ,
164
182
else_span,
165
- "this is an `else if ` but the formatting might hide it" ,
183
+ & format ! ( "this is an `else {} ` but the formatting might hide it" , else_desc ) ,
166
184
else_span,
167
- "to remove this lint, remove the `else` or remove the new line between `else` \
168
- and `if`",
185
+ & format ! (
186
+ "to remove this lint, remove the `else` or remove the new line between \
187
+ `else` and `{}`",
188
+ else_desc,
189
+ ) ,
169
190
) ;
170
191
}
171
192
}
@@ -199,30 +220,46 @@ fn check_array(cx: &EarlyContext<'_>, expr: &ast::Expr) {
199
220
}
200
221
}
201
222
202
- /// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for consecutive ifs .
203
- fn check_consecutive_ifs ( cx : & EarlyContext < ' _ > , first : & ast:: Expr , second : & ast:: Expr ) {
223
+ /// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for missing `else` .
224
+ fn check_missing_else ( cx : & EarlyContext < ' _ > , first : & ast:: Expr , second : & ast:: Expr ) {
204
225
if !differing_macro_contexts ( first. span , second. span ) && !in_macro ( first. span ) && unsugar_if ( first) . is_some ( )
205
- && unsugar_if ( second) . is_some ( )
226
+ && ( is_block ( second ) || unsugar_if ( second) . is_some ( ) )
206
227
{
207
228
// where the else would be
208
229
let else_span = first. span . between ( second. span ) ;
209
230
210
231
if let Some ( else_snippet) = snippet_opt ( cx, else_span) {
211
232
if !else_snippet. contains ( '\n' ) {
233
+ let ( looks_like, next_thing) = if unsugar_if ( second) . is_some ( ) {
234
+ ( "an `else if`" , "the second `if`" )
235
+ } else {
236
+ ( "an `else {..}`" , "the next block" )
237
+ } ;
238
+
212
239
span_note_and_lint (
213
240
cx,
214
241
SUSPICIOUS_ELSE_FORMATTING ,
215
242
else_span,
216
- "this looks like an `else if` but the `else` is missing" ,
243
+ & format ! ( "this looks like {} but the `else` is missing" , looks_like ) ,
217
244
else_span,
218
- "to remove this lint, add the missing `else` or add a new line before the second \
219
- `if`",
245
+ & format ! (
246
+ "to remove this lint, add the missing `else` or add a new line before {}" ,
247
+ next_thing,
248
+ ) ,
220
249
) ;
221
250
}
222
251
}
223
252
}
224
253
}
225
254
255
+ fn is_block ( expr : & ast:: Expr ) -> bool {
256
+ if let ast:: ExprKind :: Block ( ..) = expr. node {
257
+ true
258
+ } else {
259
+ false
260
+ }
261
+ }
262
+
226
263
/// Match `if` or `if let` expressions and return the `then` and `else` block.
227
264
fn unsugar_if ( expr : & ast:: Expr ) -> Option < ( & P < ast:: Block > , & Option < P < ast:: Expr > > ) > {
228
265
match expr. node {
0 commit comments