mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-23 21:23:56 +00:00
Auto merge of #3341 - HMPerson1:possibly_missing_else, r=phansch
Teach `suspicious_else_formatting` about `if .. {..} {..}` We essentially treat bare blocks `{..}` identically to `if .. {..}`, except for different lint messages. Fixes #3044
This commit is contained in:
commit
d9cc71fc42
3 changed files with 160 additions and 64 deletions
|
@ -31,8 +31,8 @@ declare_clippy_lint! {
|
||||||
"suspicious formatting of `*=`, `-=` or `!=`"
|
"suspicious formatting of `*=`, `-=` or `!=`"
|
||||||
}
|
}
|
||||||
|
|
||||||
/// **What it does:** Checks for formatting of `else if`. It lints if the `else`
|
/// **What it does:** Checks for formatting of `else`. It lints if the `else`
|
||||||
/// and `if` are not on the same line or the `else` seems to be missing.
|
/// is followed immediately by a newline or the `else` seems to be missing.
|
||||||
///
|
///
|
||||||
/// **Why is this bad?** This is probably some refactoring remnant, even if the
|
/// **Why is this bad?** This is probably some refactoring remnant, even if the
|
||||||
/// code is correct, it might look confusing.
|
/// code is correct, it might look confusing.
|
||||||
|
@ -42,19 +42,29 @@ declare_clippy_lint! {
|
||||||
/// **Example:**
|
/// **Example:**
|
||||||
/// ```rust,ignore
|
/// ```rust,ignore
|
||||||
/// if foo {
|
/// if foo {
|
||||||
|
/// } { // looks like an `else` is missing here
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// if foo {
|
||||||
/// } if bar { // looks like an `else` is missing here
|
/// } if bar { // looks like an `else` is missing here
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// if foo {
|
/// if foo {
|
||||||
/// } else
|
/// } else
|
||||||
///
|
///
|
||||||
|
/// { // this is the `else` block of the previous `if`, but should it be?
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// if foo {
|
||||||
|
/// } else
|
||||||
|
///
|
||||||
/// if bar { // this is the `else` block of the previous `if`, but should it be?
|
/// if bar { // this is the `else` block of the previous `if`, but should it be?
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
declare_clippy_lint! {
|
declare_clippy_lint! {
|
||||||
pub SUSPICIOUS_ELSE_FORMATTING,
|
pub SUSPICIOUS_ELSE_FORMATTING,
|
||||||
style,
|
style,
|
||||||
"suspicious formatting of `else if`"
|
"suspicious formatting of `else`"
|
||||||
}
|
}
|
||||||
|
|
||||||
/// **What it does:** Checks for possible missing comma in an array. It lints if
|
/// **What it does:** Checks for possible missing comma in an array. It lints if
|
||||||
|
@ -96,7 +106,7 @@ impl EarlyLintPass for Formatting {
|
||||||
match (&w[0].node, &w[1].node) {
|
match (&w[0].node, &w[1].node) {
|
||||||
(&ast::StmtKind::Expr(ref first), &ast::StmtKind::Expr(ref second))
|
(&ast::StmtKind::Expr(ref first), &ast::StmtKind::Expr(ref second))
|
||||||
| (&ast::StmtKind::Expr(ref first), &ast::StmtKind::Semi(ref second)) => {
|
| (&ast::StmtKind::Expr(ref first), &ast::StmtKind::Semi(ref second)) => {
|
||||||
check_consecutive_ifs(cx, first, second);
|
check_missing_else(cx, first, second);
|
||||||
},
|
},
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
@ -105,7 +115,7 @@ impl EarlyLintPass for Formatting {
|
||||||
|
|
||||||
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
|
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
|
||||||
check_assign(cx, expr);
|
check_assign(cx, expr);
|
||||||
check_else_if(cx, expr);
|
check_else(cx, expr);
|
||||||
check_array(cx, expr);
|
check_array(cx, expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,10 +149,18 @@ fn check_assign(cx: &EarlyContext<'_>, expr: &ast::Expr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for weird `else if`.
|
/// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for weird `else`.
|
||||||
fn check_else_if(cx: &EarlyContext<'_>, expr: &ast::Expr) {
|
fn check_else(cx: &EarlyContext<'_>, expr: &ast::Expr) {
|
||||||
if let Some((then, &Some(ref else_))) = unsugar_if(expr) {
|
if let Some((then, &Some(ref else_))) = unsugar_if(expr) {
|
||||||
if unsugar_if(else_).is_some() && !differing_macro_contexts(then.span, else_.span) && !in_macro(then.span) {
|
if (is_block(else_) || unsugar_if(else_).is_some())
|
||||||
|
&& !differing_macro_contexts(then.span, else_.span)
|
||||||
|
&& !in_macro(then.span)
|
||||||
|
{
|
||||||
|
// workaround for rust-lang/rust#43081
|
||||||
|
if expr.span.lo().0 == 0 && expr.span.hi().0 == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// this will be a span from the closing ‘}’ of the “then” block (excluding) to
|
// this will be a span from the closing ‘}’ of the “then” block (excluding) to
|
||||||
// the
|
// the
|
||||||
// “if” of the “else if” block (excluding)
|
// “if” of the “else if” block (excluding)
|
||||||
|
@ -154,14 +172,19 @@ fn check_else_if(cx: &EarlyContext<'_>, expr: &ast::Expr) {
|
||||||
let else_pos = else_snippet.find("else").expect("there must be a `else` here");
|
let else_pos = else_snippet.find("else").expect("there must be a `else` here");
|
||||||
|
|
||||||
if else_snippet[else_pos..].contains('\n') {
|
if else_snippet[else_pos..].contains('\n') {
|
||||||
|
let else_desc = if unsugar_if(else_).is_some() { "if" } else { "{..}" };
|
||||||
|
|
||||||
span_note_and_lint(
|
span_note_and_lint(
|
||||||
cx,
|
cx,
|
||||||
SUSPICIOUS_ELSE_FORMATTING,
|
SUSPICIOUS_ELSE_FORMATTING,
|
||||||
else_span,
|
else_span,
|
||||||
"this is an `else if` but the formatting might hide it",
|
&format!("this is an `else {}` but the formatting might hide it", else_desc),
|
||||||
else_span,
|
else_span,
|
||||||
"to remove this lint, remove the `else` or remove the new line between `else` \
|
&format!(
|
||||||
and `if`",
|
"to remove this lint, remove the `else` or remove the new line between \
|
||||||
|
`else` and `{}`",
|
||||||
|
else_desc,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -200,32 +223,47 @@ fn check_array(cx: &EarlyContext<'_>, expr: &ast::Expr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for consecutive ifs.
|
fn check_missing_else(cx: &EarlyContext<'_>, first: &ast::Expr, second: &ast::Expr) {
|
||||||
fn check_consecutive_ifs(cx: &EarlyContext<'_>, first: &ast::Expr, second: &ast::Expr) {
|
|
||||||
if !differing_macro_contexts(first.span, second.span)
|
if !differing_macro_contexts(first.span, second.span)
|
||||||
&& !in_macro(first.span)
|
&& !in_macro(first.span)
|
||||||
&& unsugar_if(first).is_some()
|
&& unsugar_if(first).is_some()
|
||||||
&& unsugar_if(second).is_some()
|
&& (is_block(second) || unsugar_if(second).is_some())
|
||||||
{
|
{
|
||||||
// where the else would be
|
// where the else would be
|
||||||
let else_span = first.span.between(second.span);
|
let else_span = first.span.between(second.span);
|
||||||
|
|
||||||
if let Some(else_snippet) = snippet_opt(cx, else_span) {
|
if let Some(else_snippet) = snippet_opt(cx, else_span) {
|
||||||
if !else_snippet.contains('\n') {
|
if !else_snippet.contains('\n') {
|
||||||
|
let (looks_like, next_thing) = if unsugar_if(second).is_some() {
|
||||||
|
("an `else if`", "the second `if`")
|
||||||
|
} else {
|
||||||
|
("an `else {..}`", "the next block")
|
||||||
|
};
|
||||||
|
|
||||||
span_note_and_lint(
|
span_note_and_lint(
|
||||||
cx,
|
cx,
|
||||||
SUSPICIOUS_ELSE_FORMATTING,
|
SUSPICIOUS_ELSE_FORMATTING,
|
||||||
else_span,
|
else_span,
|
||||||
"this looks like an `else if` but the `else` is missing",
|
&format!("this looks like {} but the `else` is missing", looks_like),
|
||||||
else_span,
|
else_span,
|
||||||
"to remove this lint, add the missing `else` or add a new line before the second \
|
&format!(
|
||||||
`if`",
|
"to remove this lint, add the missing `else` or add a new line before {}",
|
||||||
|
next_thing,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_block(expr: &ast::Expr) -> bool {
|
||||||
|
if let ast::ExprKind::Block(..) = expr.node {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Match `if` or `if let` expressions and return the `then` and `else` block.
|
/// Match `if` or `if let` expressions and return the `then` and `else` block.
|
||||||
fn unsugar_if(expr: &ast::Expr) -> Option<(&P<ast::Block>, &Option<P<ast::Expr>>)> {
|
fn unsugar_if(expr: &ast::Expr) -> Option<(&P<ast::Block>, &Option<P<ast::Expr>>)> {
|
||||||
match expr.node {
|
match expr.node {
|
||||||
|
|
|
@ -16,7 +16,11 @@
|
||||||
fn foo() -> bool { true }
|
fn foo() -> bool { true }
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// weird `else if` formatting:
|
// weird `else` formatting:
|
||||||
|
if foo() {
|
||||||
|
} {
|
||||||
|
}
|
||||||
|
|
||||||
if foo() {
|
if foo() {
|
||||||
} if foo() {
|
} if foo() {
|
||||||
}
|
}
|
||||||
|
@ -41,6 +45,17 @@ fn main() {
|
||||||
let _ = 0;
|
let _ = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if foo() {
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
if foo() {
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
if foo() {
|
if foo() {
|
||||||
} else
|
} else
|
||||||
if foo() { // the span of the above error should continue here
|
if foo() { // the span of the above error should continue here
|
||||||
|
@ -53,6 +68,20 @@ fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// those are ok:
|
// those are ok:
|
||||||
|
if foo() {
|
||||||
|
}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
if foo() {
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
|
||||||
|
if foo() {
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
}
|
||||||
|
|
||||||
if foo() {
|
if foo() {
|
||||||
}
|
}
|
||||||
if foo() {
|
if foo() {
|
||||||
|
|
|
@ -1,90 +1,119 @@
|
||||||
error: this looks like an `else if` but the `else` is missing
|
error: this looks like an `else {..}` but the `else` is missing
|
||||||
--> $DIR/formatting.rs:21:6
|
--> $DIR/formatting.rs:21:6
|
||||||
|
|
|
|
||||||
21 | } if foo() {
|
21 | } {
|
||||||
| ^
|
| ^
|
||||||
|
|
|
|
||||||
= note: `-D clippy::suspicious-else-formatting` implied by `-D warnings`
|
= note: `-D clippy::suspicious-else-formatting` implied by `-D warnings`
|
||||||
= note: to remove this lint, add the missing `else` or add a new line before the second `if`
|
= note: to remove this lint, add the missing `else` or add a new line before the next block
|
||||||
|
|
||||||
error: this looks like an `else if` but the `else` is missing
|
error: this looks like an `else if` but the `else` is missing
|
||||||
--> $DIR/formatting.rs:28:10
|
--> $DIR/formatting.rs:25:6
|
||||||
|
|
|
|
||||||
28 | } if foo() {
|
25 | } if foo() {
|
||||||
| ^
|
| ^
|
||||||
|
|
|
|
||||||
= note: to remove this lint, add the missing `else` or add a new line before the second `if`
|
= note: to remove this lint, add the missing `else` or add a new line before the second `if`
|
||||||
|
|
||||||
error: this looks like an `else if` but the `else` is missing
|
error: this looks like an `else if` but the `else` is missing
|
||||||
--> $DIR/formatting.rs:36:10
|
--> $DIR/formatting.rs:32:10
|
||||||
|
|
|
|
||||||
36 | } if foo() {
|
32 | } if foo() {
|
||||||
| ^
|
| ^
|
||||||
|
|
|
|
||||||
= note: to remove this lint, add the missing `else` or add a new line before the second `if`
|
= note: to remove this lint, add the missing `else` or add a new line before the second `if`
|
||||||
|
|
||||||
|
error: this looks like an `else if` but the `else` is missing
|
||||||
|
--> $DIR/formatting.rs:40:10
|
||||||
|
|
|
||||||
|
40 | } if foo() {
|
||||||
|
| ^
|
||||||
|
|
|
||||||
|
= note: to remove this lint, add the missing `else` or add a new line before the second `if`
|
||||||
|
|
||||||
|
error: this is an `else {..}` but the formatting might hide it
|
||||||
|
--> $DIR/formatting.rs:49:6
|
||||||
|
|
|
||||||
|
49 | } else
|
||||||
|
| ______^
|
||||||
|
50 | | {
|
||||||
|
| |____^
|
||||||
|
|
|
||||||
|
= note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}`
|
||||||
|
|
||||||
|
error: this is an `else {..}` but the formatting might hide it
|
||||||
|
--> $DIR/formatting.rs:54:6
|
||||||
|
|
|
||||||
|
54 | }
|
||||||
|
| ______^
|
||||||
|
55 | | else
|
||||||
|
56 | | {
|
||||||
|
| |____^
|
||||||
|
|
|
||||||
|
= note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}`
|
||||||
|
|
||||||
error: this is an `else if` but the formatting might hide it
|
error: this is an `else if` but the formatting might hide it
|
||||||
--> $DIR/formatting.rs:45:6
|
--> $DIR/formatting.rs:60:6
|
||||||
|
|
|
|
||||||
45 | } else
|
60 | } else
|
||||||
| ______^
|
| ______^
|
||||||
46 | | if foo() { // the span of the above error should continue here
|
61 | | if foo() { // the span of the above error should continue here
|
||||||
| |____^
|
| |____^
|
||||||
|
|
|
|
||||||
= note: to remove this lint, remove the `else` or remove the new line between `else` and `if`
|
= note: to remove this lint, remove the `else` or remove the new line between `else` and `if`
|
||||||
|
|
||||||
error: this is an `else if` but the formatting might hide it
|
error: this is an `else if` but the formatting might hide it
|
||||||
--> $DIR/formatting.rs:50:6
|
--> $DIR/formatting.rs:65:6
|
||||||
|
|
|
|
||||||
50 | }
|
65 | }
|
||||||
| ______^
|
| ______^
|
||||||
51 | | else
|
66 | | else
|
||||||
52 | | if foo() { // the span of the above error should continue here
|
67 | | if foo() { // the span of the above error should continue here
|
||||||
| |____^
|
| |____^
|
||||||
|
|
|
|
||||||
= note: to remove this lint, remove the `else` or remove the new line between `else` and `if`
|
= note: to remove this lint, remove the `else` or remove the new line between `else` and `if`
|
||||||
|
|
||||||
error: this looks like you are trying to use `.. -= ..`, but you really are doing `.. = (- ..)`
|
error: this looks like you are trying to use `.. -= ..`, but you really are doing `.. = (- ..)`
|
||||||
--> $DIR/formatting.rs:77:6
|
--> $DIR/formatting.rs:106:6
|
||||||
|
|
|
|
||||||
77 | a =- 35;
|
106 | a =- 35;
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
|
|
|
||||||
= note: `-D clippy::suspicious-assignment-formatting` implied by `-D warnings`
|
= note: `-D clippy::suspicious-assignment-formatting` implied by `-D warnings`
|
||||||
= note: to remove this lint, use either `-=` or `= -`
|
= note: to remove this lint, use either `-=` or `= -`
|
||||||
|
|
||||||
error: this looks like you are trying to use `.. *= ..`, but you really are doing `.. = (* ..)`
|
error: this looks like you are trying to use `.. *= ..`, but you really are doing `.. = (* ..)`
|
||||||
--> $DIR/formatting.rs:78:6
|
--> $DIR/formatting.rs:107:6
|
||||||
|
|
|
|
||||||
78 | a =* &191;
|
107 | a =* &191;
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
|
|
|
||||||
= note: to remove this lint, use either `*=` or `= *`
|
= note: to remove this lint, use either `*=` or `= *`
|
||||||
|
|
||||||
error: this looks like you are trying to use `.. != ..`, but you really are doing `.. = (! ..)`
|
error: this looks like you are trying to use `.. != ..`, but you really are doing `.. = (! ..)`
|
||||||
--> $DIR/formatting.rs:81:6
|
--> $DIR/formatting.rs:110:6
|
||||||
|
|
|
|
||||||
81 | b =! false;
|
110 | b =! false;
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
|
|
|
||||||
= note: to remove this lint, use either `!=` or `= !`
|
= note: to remove this lint, use either `!=` or `= !`
|
||||||
|
|
||||||
error: possibly missing a comma here
|
error: possibly missing a comma here
|
||||||
--> $DIR/formatting.rs:90:19
|
--> $DIR/formatting.rs:119:19
|
||||||
|
|
|
|
||||||
90 | -1, -2, -3 // <= no comma here
|
119 | -1, -2, -3 // <= no comma here
|
||||||
| ^
|
| ^
|
||||||
|
|
|
|
||||||
= note: `-D clippy::possible-missing-comma` implied by `-D warnings`
|
= note: `-D clippy::possible-missing-comma` implied by `-D warnings`
|
||||||
= note: to remove this lint, add a comma or write the expr in a single line
|
= note: to remove this lint, add a comma or write the expr in a single line
|
||||||
|
|
||||||
error: possibly missing a comma here
|
error: possibly missing a comma here
|
||||||
--> $DIR/formatting.rs:94:19
|
--> $DIR/formatting.rs:123:19
|
||||||
|
|
|
|
||||||
94 | -1, -2, -3 // <= no comma here
|
123 | -1, -2, -3 // <= no comma here
|
||||||
| ^
|
| ^
|
||||||
|
|
|
|
||||||
= note: to remove this lint, add a comma or write the expr in a single line
|
= note: to remove this lint, add a comma or write the expr in a single line
|
||||||
|
|
||||||
error: aborting due to 10 previous errors
|
error: aborting due to 13 previous errors
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue