A new lint for shared code in if blocks

* Added expression check for shared_code_in_if_blocks
* Finishing touches for the shared_code_in_if_blocks lint
* Applying PR suggestions
* Update lints yay
* Moved test into subfolder
This commit is contained in:
xFrednet 2020-12-11 22:29:53 +00:00
parent 232e2b79f2
commit d1df73228a
17 changed files with 780 additions and 207 deletions

View file

@ -1,5 +1,5 @@
#![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
#![allow(clippy::if_same_then_else)]
#![allow(clippy::if_same_then_else, clippy::shared_code_in_if_blocks)]
fn test_complex_conditions() {
let x: Result<(), ()> = Ok(());

View file

@ -5,7 +5,8 @@
clippy::never_loop,
clippy::no_effect,
clippy::unused_unit,
clippy::zero_divided_by_zero
clippy::zero_divided_by_zero,
clippy::shared_code_in_if_blocks
)]
struct Foo {

View file

@ -1,19 +1,5 @@
error: this `if` has identical blocks
--> $DIR/if_same_then_else.rs:28:12
|
LL | } else {
| ____________^
LL | | //~ ERROR same body as `if` block
LL | | Foo { bar: 42 };
LL | | 0..10;
... |
LL | | foo();
LL | | }
| |_____^
|
= note: `-D clippy::if-same-then-else` implied by `-D warnings`
note: same as this
--> $DIR/if_same_then_else.rs:20:13
--> $DIR/if_same_then_else.rs:21:13
|
LL | if true {
| _____________^
@ -24,79 +10,80 @@ LL | | ..;
LL | | foo();
LL | | } else {
| |_____^
error: this `if` has identical blocks
--> $DIR/if_same_then_else.rs:66:12
|
LL | } else {
| ____________^
LL | | //~ ERROR same body as `if` block
LL | | 0.0
LL | | };
| |_____^
|
= note: `-D clippy::if-same-then-else` implied by `-D warnings`
note: same as this
--> $DIR/if_same_then_else.rs:64:21
|
LL | let _ = if true {
| _____________________^
LL | | 0.0
LL | | } else {
| |_____^
error: this `if` has identical blocks
--> $DIR/if_same_then_else.rs:73:12
--> $DIR/if_same_then_else.rs:29:12
|
LL | } else {
| ____________^
LL | | //~ ERROR same body as `if` block
LL | | -0.0
LL | | };
| |_____^
|
note: same as this
--> $DIR/if_same_then_else.rs:71:21
|
LL | let _ = if true {
| _____________________^
LL | | -0.0
LL | | } else {
| |_____^
error: this `if` has identical blocks
--> $DIR/if_same_then_else.rs:89:12
|
LL | } else {
| ____________^
LL | | //~ ERROR same body as `if` block
LL | | 42
LL | | };
| |_____^
|
note: same as this
--> $DIR/if_same_then_else.rs:87:21
|
LL | let _ = if true {
| _____________________^
LL | | 42
LL | | } else {
| |_____^
error: this `if` has identical blocks
--> $DIR/if_same_then_else.rs:101:12
|
LL | } else {
| ____________^
LL | | //~ ERROR same body as `if` block
LL | | let bar = if true { 42 } else { 43 };
LL | |
LL | | Foo { bar: 42 };
LL | | 0..10;
... |
LL | | bar + 1;
LL | | foo();
LL | | }
| |_____^
error: this `if` has identical blocks
--> $DIR/if_same_then_else.rs:65:21
|
LL | let _ = if true {
| _____________________^
LL | | 0.0
LL | | } else {
| |_____^
|
note: same as this
--> $DIR/if_same_then_else.rs:94:13
--> $DIR/if_same_then_else.rs:67:12
|
LL | } else {
| ____________^
LL | | //~ ERROR same body as `if` block
LL | | 0.0
LL | | };
| |_____^
error: this `if` has identical blocks
--> $DIR/if_same_then_else.rs:72:21
|
LL | let _ = if true {
| _____________________^
LL | | -0.0
LL | | } else {
| |_____^
|
note: same as this
--> $DIR/if_same_then_else.rs:74:12
|
LL | } else {
| ____________^
LL | | //~ ERROR same body as `if` block
LL | | -0.0
LL | | };
| |_____^
error: this `if` has identical blocks
--> $DIR/if_same_then_else.rs:88:21
|
LL | let _ = if true {
| _____________________^
LL | | 42
LL | | } else {
| |_____^
|
note: same as this
--> $DIR/if_same_then_else.rs:90:12
|
LL | } else {
| ____________^
LL | | //~ ERROR same body as `if` block
LL | | 42
LL | | };
| |_____^
error: this `if` has identical blocks
--> $DIR/if_same_then_else.rs:95:13
|
LL | if true {
| _____________^
@ -107,6 +94,19 @@ LL | | while foo() {
LL | | bar + 1;
LL | | } else {
| |_____^
|
note: same as this
--> $DIR/if_same_then_else.rs:102:12
|
LL | } else {
| ____________^
LL | | //~ ERROR same body as `if` block
LL | | let bar = if true { 42 } else { 43 };
LL | |
... |
LL | | bar + 1;
LL | | }
| |_____^
error: aborting due to 5 previous errors

View file

@ -5,7 +5,8 @@
clippy::collapsible_if,
clippy::ifs_same_cond,
clippy::needless_return,
clippy::single_element_loop
clippy::single_element_loop,
clippy::shared_code_in_if_blocks
)]
fn if_same_then_else2() -> Result<&'static str, ()> {

View file

@ -24,8 +24,31 @@ LL | | if foo.is_some() {
LL | | }
LL | | } else {
| |_____^
|
= note: `-D clippy::if-same-then-else` implied by `-D warnings`
note: same as this
--> $DIR/if_same_then_else2.rs:21:12
|
LL | } else {
| ____________^
LL | | //~ ERROR same body as `if` block
LL | | for _ in &[42] {
LL | | let foo: &Option<_> = &Some::<u8>(42);
... |
LL | | }
LL | | }
| |_____^
error: this `if` has identical blocks
--> $DIR/if_same_then_else2.rs:33:13
|
LL | if true {
| _____________^
LL | | if let Some(a) = Some(42) {}
LL | | } else {
| |_____^
|
note: same as this
--> $DIR/if_same_then_else2.rs:35:12
|
LL | } else {
@ -34,17 +57,17 @@ LL | | //~ ERROR same body as `if` block
LL | | if let Some(a) = Some(42) {}
LL | | }
| |_____^
|
note: same as this
--> $DIR/if_same_then_else2.rs:33:13
error: this `if` has identical blocks
--> $DIR/if_same_then_else2.rs:40:13
|
LL | if true {
| _____________^
LL | | if let Some(a) = Some(42) {}
LL | | if let (1, .., 3) = (1, 2, 3) {}
LL | | } else {
| |_____^
error: this `if` has identical blocks
|
note: same as this
--> $DIR/if_same_then_else2.rs:42:12
|
LL | } else {
@ -53,17 +76,17 @@ LL | | //~ ERROR same body as `if` block
LL | | if let (1, .., 3) = (1, 2, 3) {}
LL | | }
| |_____^
|
note: same as this
--> $DIR/if_same_then_else2.rs:40:13
|
LL | if true {
| _____________^
LL | | if let (1, .., 3) = (1, 2, 3) {}
LL | | } else {
| |_____^
error: this `if` has identical blocks
--> $DIR/if_same_then_else2.rs:90:21
|
LL | let _ = if true {
| _____________________^
LL | | f32::NAN
LL | | } else {
| |_____^
|
note: same as this
--> $DIR/if_same_then_else2.rs:92:12
|
LL | } else {
@ -72,17 +95,17 @@ LL | | //~ ERROR same body as `if` block
LL | | f32::NAN
LL | | };
| |_____^
|
note: same as this
--> $DIR/if_same_then_else2.rs:90:21
|
LL | let _ = if true {
| _____________________^
LL | | f32::NAN
LL | | } else {
| |_____^
error: this `if` has identical blocks
--> $DIR/if_same_then_else2.rs:97:13
|
LL | if true {
| _____________^
LL | | Ok("foo")?;
LL | | } else {
| |_____^
|
note: same as this
--> $DIR/if_same_then_else2.rs:99:12
|
LL | } else {
@ -91,27 +114,8 @@ LL | | //~ ERROR same body as `if` block
LL | | Ok("foo")?;
LL | | }
| |_____^
|
note: same as this
--> $DIR/if_same_then_else2.rs:97:13
|
LL | if true {
| _____________^
LL | | Ok("foo")?;
LL | | } else {
| |_____^
error: this `if` has identical blocks
--> $DIR/if_same_then_else2.rs:124:12
|
LL | } else {
| ____________^
LL | | let foo = "";
LL | | return Ok(&foo[0..]);
LL | | }
| |_____^
|
note: same as this
--> $DIR/if_same_then_else2.rs:121:20
|
LL | } else if true {
@ -120,6 +124,16 @@ LL | | let foo = "";
LL | | return Ok(&foo[0..]);
LL | | } else {
| |_____^
|
note: same as this
--> $DIR/if_same_then_else2.rs:124:12
|
LL | } else {
| ____________^
LL | | let foo = "";
LL | | return Ok(&foo[0..]);
LL | | }
| |_____^
error: aborting due to 6 previous errors

View file

@ -2,7 +2,8 @@
unused_variables,
unused_assignments,
clippy::similar_names,
clippy::blacklisted_name
clippy::blacklisted_name,
clippy::shared_code_in_if_blocks
)]
#![warn(clippy::useless_let_if_seq)]

View file

@ -1,5 +1,5 @@
error: `if _ { .. } else { .. }` is an expression
--> $DIR/let_if_seq.rs:64:5
--> $DIR/let_if_seq.rs:65:5
|
LL | / let mut foo = 0;
LL | | if f() {
@ -11,7 +11,7 @@ LL | | }
= note: you might not need `mut` at all
error: `if _ { .. } else { .. }` is an expression
--> $DIR/let_if_seq.rs:69:5
--> $DIR/let_if_seq.rs:70:5
|
LL | / let mut bar = 0;
LL | | if f() {
@ -25,7 +25,7 @@ LL | | }
= note: you might not need `mut` at all
error: `if _ { .. } else { .. }` is an expression
--> $DIR/let_if_seq.rs:77:5
--> $DIR/let_if_seq.rs:78:5
|
LL | / let quz;
LL | | if f() {
@ -36,7 +36,7 @@ LL | | }
| |_____^ help: it is more idiomatic to write: `let quz = if f() { 42 } else { 0 };`
error: `if _ { .. } else { .. }` is an expression
--> $DIR/let_if_seq.rs:106:5
--> $DIR/let_if_seq.rs:107:5
|
LL | / let mut baz = 0;
LL | | if f() {

View file

@ -0,0 +1,47 @@
#![allow(dead_code)]
#![deny(clippy::if_same_then_else, clippy::shared_code_in_if_blocks)]
// This tests the shared_code_in_if_blocks lint at the end of blocks
fn simple_examples() {
// TODO xFrednet 2021-01-06: Test with const literals at the end
let x = 1;
let _ = if x == 7 {
println!("Branch I");
let start_value = 0;
println!("=^.^=");
// Same but not moveable due to `start_value`
let _ = start_value;
// The rest is self contained and moveable => Only lint the rest
let result = false;
println!("Block end!");
result
} else {
println!("Branch II");
let start_value = 8;
println!("xD");
// Same but not moveable due to `start_value`
let _ = start_value;
// The rest is self contained and moveable => Only lint the rest
let result = false;
println!("Block end!");
result
};
}
/// Simple examples where the move can cause some problems due to moved values
fn simple_but_suggestion_is_invalid() {
// TODO xFrednet 2021-01-12: This
}
/// Tests where the blocks are not linted due to the used value scope
fn not_moveable_due_to_value_scope() {
// TODO xFrednet 2021-01-12: This
}
fn main() {}

View file

@ -0,0 +1,83 @@
#![allow(dead_code, clippy::eval_order_dependence)]
#![deny(clippy::if_same_then_else, clippy::shared_code_in_if_blocks)]
// This tests the shared_code_in_if_blocks lint at the start of blocks
fn simple_examples() {
let x = 0;
// Simple
if true {
println!("Hello World!");
println!("I'm branch nr: 1");
} else {
println!("Hello World!");
println!("I'm branch nr: 2");
}
// Else if
if x == 0 {
let y = 9;
println!("The value y was set to: `{}`", y);
let _z = y;
println!("I'm the true start index of arrays");
} else if x == 1 {
let y = 9;
println!("The value y was set to: `{}`", y);
let _z = y;
println!("I start counting from 1 so my array starts from `1`");
} else {
let y = 9;
println!("The value y was set to: `{}`", y);
let _z = y;
println!("Ha, Pascal allows you to start the array where you want")
}
// Return a value
let _ = if x == 7 {
let y = 16;
println!("What can I say except: \"you're welcome?\"");
let _ = y;
x
} else {
let y = 16;
println!("Thank you");
y
};
}
/// Simple examples where the move can cause some problems due to moved values
fn simple_but_suggestion_is_invalid() {
let x = 10;
// Can't be automatically moved because used_value_name is getting used again
let used_value_name = 19;
if x == 10 {
let used_value_name = "Different type";
println!("Str: {}", used_value_name);
let _ = 1;
} else {
let used_value_name = "Different type";
println!("Str: {}", used_value_name);
let _ = 2;
}
let _ = used_value_name;
// This can be automatically moved as `can_be_overridden` is not used again
let can_be_overridden = 8;
let _ = can_be_overridden;
if x == 11 {
let can_be_overridden = "Move me";
println!("I'm also moveable");
let _ = 111;
} else {
let can_be_overridden = "Move me";
println!("I'm also moveable");
let _ = 222;
}
}
fn main() {}

View file

@ -0,0 +1,22 @@
#![allow(dead_code)]
#![deny(clippy::if_same_then_else, clippy::shared_code_in_if_blocks)]
// shared_code_in_if_blocks at the top and bottom of the if blocks
fn main() {
// TODO xFrednet 2021-01-12: This
}
// General TODOs By xFrednet:
//
// * Make a test with overlapping eq regions (else ifs)
// * Test if as function parameter, tuple constructor, index, while loop condition
// * Test where only the expression is the same
// * Test where the block only has an expression
// * Test with let on a previous line let _ = \n if...
// * Tests with unreadable formatting (Inline if, Not indented)
// * Test multiline condition if x == 9 \n x == 8 {}
// * Test if for return/break (Only move to front)
// * Test in inline closures
// * Test with structs and tuples

View file

@ -0,0 +1,157 @@
#![allow(dead_code, clippy::eval_order_dependence)]
#![deny(clippy::if_same_then_else, clippy::shared_code_in_if_blocks)]
// This tests the shared_code_in_if_blocks lint at the start of blocks
// Tests with value references are includes in "shared_code_at_bot.rs"
fn valid_examples() {
let x = 2;
// The edge statements are different
if x == 9 {
let y = 1 << 5;
println!("This is the same: vvv");
let _z = y;
println!("The block expression is different");
println!("Different end 1");
} else {
let y = 1 << 7;
println!("This is the same: vvv");
let _z = y;
println!("The block expression is different");
println!("Different end 2");
}
// No else
if x == 2 {
println!("Hello world!");
println!("Hello back, how are you?");
// This is different vvvv
println!("Howdy stranger =^.^=");
println!("Bye Bye World");
} else if x == 9 {
println!("Hello world!");
println!("Hello back, how are you?");
// This is different vvvv
println!("Hello reviewer :D");
println!("Bye Bye World");
}
// Overlapping statements only in else if blocks -> Don't lint
if x == 0 {
println!("I'm important!")
} else if x == 17 {
println!("I share code in else if");
println!("x is 17");
} else {
println!("I share code in else if");
println!("x is nether x nor 17");
}
// Mutability is different
if x == 13 {
let mut y = 9;
println!("Value y is: {}", y);
y += 16;
let _z1 = y;
} else {
let y = 9;
println!("Value y is: {}", y);
let _z2 = y;
}
// Same blocks but at start and bottom so no `if_same_then_else` lint
if x == 418 {
let y = 9;
let z = 8;
let _ = (x, y, z);
// Don't tell the programmer, my code is also in the else block
} else if x == 419 {
println!("+-----------+");
println!("| |");
println!("| O O |");
println!("| ° |");
println!("| \\_____/ |");
println!("| |");
println!("+-----------+");
} else {
let y = 9;
let z = 8;
let _ = (x, y, z);
// I'm so much better than the x == 418 block. Trust me
}
}
/// This makes sure that the `if_same_then_else` masks the `shared_code_in_if_blocks` lint
fn trigger_other_lint() {
let x = 0;
let y = 1;
// Same block
if x == 0 {
let u = 19;
println!("How are u today?");
let _ = "This is a string";
} else {
let u = 19;
println!("How are u today?");
let _ = "This is a string";
}
// More complex same blocks
if x == 17 {
#[derive(Debug)]
struct Duck {
num: u64,
};
let pet = Duck { num: 18 };
println!("{:?}", pet);
} else {
#[derive(Debug)]
struct Duck {
num: u64,
};
let pet = Duck { num: 18 };
println!("{:?}", pet);
}
// Only same expression
let _ = if x == 6 { 7 } else { 7 };
// Same in else if block
let _ = if x == 67 {
println!("Well I'm the most important block");
"I'm a pretty string"
} else if x == 68 {
println!("I'm a doppelgänger");
// Don't listen to my clone below
if y == 90 {
"=^.^="
} else {
":D"
}
} else {
// Don't listen to my clone above
println!("I'm a doppelgänger");
if y == 90 {
"=^.^="
} else {
":D"
}
};
}
fn main() {}