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