Skip to content

Commit 72bb0e9

Browse files
committed
The shared_code_in_if_blocks lint only operats on entire if expr not else ifs
1 parent 604f409 commit 72bb0e9

File tree

3 files changed

+141
-19
lines changed

3 files changed

+141
-19
lines changed

clippy_lints/src/copies.rs

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::utils::{both, count_eq, eq_expr_value, in_macro, search_same, SpanlessEq, SpanlessHash};
22
use crate::utils::{
3-
first_line_of_span, get_parent_expr, higher, if_sequence, indent_of, reindent_multiline, snippet,
4-
span_lint_and_note, span_lint_and_sugg, span_lint_and_then,
3+
first_line_of_span, get_parent_expr, higher, if_sequence, indent_of, parent_node_is_if_expr, reindent_multiline,
4+
snippet, span_lint_and_note, span_lint_and_sugg, span_lint_and_then,
55
};
66
use rustc_data_structures::fx::FxHashSet;
77
use rustc_errors::Applicability;
@@ -141,7 +141,7 @@ declare_clippy_lint! {
141141
/// };
142142
/// ```
143143
pub SHARED_CODE_IN_IF_BLOCKS,
144-
pedantic,
144+
nursery,
145145
"`if` statement with shared code in all blocks"
146146
}
147147

@@ -185,7 +185,7 @@ fn lint_same_then_else<'tcx>(
185185
) {
186186
// We only lint ifs with multiple blocks
187187
// TODO xFrednet 2021-01-01: Check if it's an else if block
188-
if blocks.len() < 2 {
188+
if blocks.len() < 2 || parent_node_is_if_expr(expr, cx) {
189189
return;
190190
}
191191

@@ -195,7 +195,7 @@ fn lint_same_then_else<'tcx>(
195195
let mut start_eq = usize::MAX;
196196
let mut end_eq = usize::MAX;
197197
let mut expr_eq = true;
198-
for (index, win) in blocks.windows(2).enumerate() {
198+
for win in blocks.windows(2) {
199199
let l_stmts = win[0].stmts;
200200
let r_stmts = win[1].stmts;
201201

@@ -207,9 +207,7 @@ fn lint_same_then_else<'tcx>(
207207
let block_expr_eq = both(&win[0].expr, &win[1].expr, |l, r| evaluator.eq_expr(l, r));
208208

209209
// IF_SAME_THEN_ELSE
210-
// We only lint the first two blocks (index == 0). Further blocks will be linted when that if
211-
// statement is checked
212-
if index == 0 && block_expr_eq && l_stmts.len() == r_stmts.len() && l_stmts.len() == current_start_eq {
210+
if block_expr_eq && l_stmts.len() == r_stmts.len() && l_stmts.len() == current_start_eq {
213211
span_lint_and_note(
214212
cx,
215213
IF_SAME_THEN_ELSE,
@@ -220,16 +218,24 @@ fn lint_same_then_else<'tcx>(
220218
);
221219

222220
return;
221+
} else {
222+
println!(
223+
"{:?}\n - expr_eq: {:10}, l_stmts.len(): {:10}, r_stmts.len(): {:10}",
224+
win[0].span,
225+
block_expr_eq,
226+
l_stmts.len(),
227+
r_stmts.len()
228+
)
223229
}
224230

225231
start_eq = start_eq.min(current_start_eq);
226232
end_eq = end_eq.min(current_end_eq);
227233
expr_eq &= block_expr_eq;
234+
}
228235

229-
// We can return if the eq count is 0 from both sides or if it has no unconditional else case
230-
if !has_unconditional_else || (start_eq == 0 && end_eq == 0 && (has_expr && !expr_eq)) {
231-
return;
232-
}
236+
// SHARED_CODE_IN_IF_BLOCKS prerequisites
237+
if !has_unconditional_else || (start_eq == 0 && end_eq == 0 && (has_expr && !expr_eq)) {
238+
return;
233239
}
234240

235241
if has_expr && !expr_eq {
@@ -280,11 +286,14 @@ fn lint_same_then_else<'tcx>(
280286
end_eq -= moved_start;
281287
}
282288

283-
let mut end_linable = true;
284-
if let Some(expr) = block.expr {
289+
let end_linable = if let Some(expr) = block.expr {
285290
intravisit::walk_expr(&mut walker, expr);
286-
end_linable = walker.uses.iter().any(|x| !block_defs.contains(x));
287-
}
291+
walker.uses.iter().any(|x| !block_defs.contains(x))
292+
} else if end_eq == 0 {
293+
false
294+
} else {
295+
true
296+
};
288297

289298
emit_shared_code_in_if_blocks_lint(cx, start_eq, end_eq, end_linable, blocks, expr);
290299
}
@@ -356,7 +365,7 @@ fn emit_shared_code_in_if_blocks_lint(
356365
SHARED_CODE_IN_IF_BLOCKS,
357366
*span,
358367
"All code blocks contain the same code",
359-
"Consider moving the code out like this",
368+
"Consider moving the statements out like this",
360369
sugg.clone(),
361370
Applicability::Unspecified,
362371
);

tests/ui/shared_code_in_if_blocks/shared_at_bot.rs

Lines changed: 105 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,119 @@ fn simple_examples() {
3232
println!("Block end!");
3333
result
3434
};
35+
36+
if x == 9 {
37+
println!("The index is: 6");
38+
39+
println!("Same end of block");
40+
} else if x == 8 {
41+
println!("The index is: 4");
42+
43+
println!("Same end of block");
44+
} else {
45+
println!("Same end of block");
46+
}
47+
48+
// TODO xFrednet 2021-01.13: Fix lint for `if let`
49+
let index = Some(8);
50+
if let Some(index) = index {
51+
println!("The index is: {}", index);
52+
53+
println!("Same end of block");
54+
} else {
55+
println!("Same end of block");
56+
}
57+
58+
if x == 9 {
59+
if x == 8 {
60+
// No parent!!
61+
println!("Hello World");
62+
println!("---");
63+
} else {
64+
println!("Hello World");
65+
}
66+
}
3567
}
3668

3769
/// Simple examples where the move can cause some problems due to moved values
3870
fn simple_but_suggestion_is_invalid() {
39-
// TODO xFrednet 2021-01-12: This
71+
let x = 16;
72+
73+
// Local value
74+
let later_used_value = 17;
75+
if x == 9 {
76+
let _ = 9;
77+
let later_used_value = "A string value";
78+
println!("{}", later_used_value);
79+
} else {
80+
let later_used_value = "A string value";
81+
println!("{}", later_used_value);
82+
// I'm expecting a note about this
83+
}
84+
println!("{}", later_used_value);
85+
86+
// outer function
87+
if x == 78 {
88+
let simple_examples = "I now identify as a &str :)";
89+
println!("This is the new simple_example: {}", simple_examples);
90+
} else {
91+
println!("Separator print statement");
92+
93+
let simple_examples = "I now identify as a &str :)";
94+
println!("This is the new simple_example: {}", simple_examples);
95+
}
96+
simple_examples();
4097
}
4198

4299
/// Tests where the blocks are not linted due to the used value scope
43100
fn not_moveable_due_to_value_scope() {
44-
// TODO xFrednet 2021-01-12: This
101+
let x = 18;
102+
103+
// Using a local value in the moved code
104+
if x == 9 {
105+
let y = 18;
106+
println!("y is: `{}`", y);
107+
} else {
108+
let y = "A string";
109+
println!("y is: `{}`", y);
110+
}
111+
112+
// Using a local value in the expression
113+
let _ = if x == 0 {
114+
let mut result = x + 1;
115+
116+
println!("1. Doing some calculations");
117+
println!("2. Some more calculations");
118+
println!("3. Setting result");
119+
120+
result
121+
} else {
122+
let mut result = x - 1;
123+
124+
println!("1. Doing some calculations");
125+
println!("2. Some more calculations");
126+
println!("3. Setting result");
127+
128+
result
129+
};
130+
131+
let _ = if x == 7 {
132+
let z1 = 100;
133+
println!("z1: {}", z1);
134+
135+
let z2 = z1;
136+
println!("z2: {}", z2);
137+
138+
z2
139+
} else {
140+
let z1 = 300;
141+
println!("z1: {}", z1);
142+
143+
let z2 = z1;
144+
println!("z2: {}", z2);
145+
146+
z2
147+
};
45148
}
46149

47150
fn main() {}

tests/ui/shared_code_in_if_blocks/valid_if_blocks.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,16 @@ fn trigger_other_lint() {
152152
":D"
153153
}
154154
};
155+
156+
if x == 0 {
157+
println!("I'm single");
158+
} else if x == 68 {
159+
println!("I'm a doppelgänger");
160+
// Don't listen to my clone below
161+
} else {
162+
// Don't listen to my clone above
163+
println!("I'm a doppelgänger");
164+
}
155165
}
156166

157167
fn main() {}

0 commit comments

Comments
 (0)