Skip to content

Commit d2b051e

Browse files
committed
The shared_code_in_if_blocks lint only operats on entire if expr not else ifs
1 parent d7195a8 commit d2b051e

File tree

3 files changed

+141
-19
lines changed

3 files changed

+141
-19
lines changed

clippy_lints/src/copies.rs

+26-17
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

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

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

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

207207
// IF_SAME_THEN_ELSE
208-
// We only lint the first two blocks (index == 0). Further blocks will be linted when that if
209-
// statement is checked
210-
if index == 0 && block_expr_eq && l_stmts.len() == r_stmts.len() && l_stmts.len() == current_start_eq {
208+
if block_expr_eq && l_stmts.len() == r_stmts.len() && l_stmts.len() == current_start_eq {
211209
span_lint_and_note(
212210
cx,
213211
IF_SAME_THEN_ELSE,
@@ -218,16 +216,24 @@ fn lint_same_then_else<'tcx>(
218216
);
219217

220218
return;
219+
} else {
220+
println!(
221+
"{:?}\n - expr_eq: {:10}, l_stmts.len(): {:10}, r_stmts.len(): {:10}",
222+
win[0].span,
223+
block_expr_eq,
224+
l_stmts.len(),
225+
r_stmts.len()
226+
)
221227
}
222228

223229
start_eq = start_eq.min(current_start_eq);
224230
end_eq = end_eq.min(current_end_eq);
225231
expr_eq &= block_expr_eq;
232+
}
226233

227-
// We can return if the eq count is 0 from both sides or if it has no unconditional else case
228-
if !has_unconditional_else || (start_eq == 0 && end_eq == 0 && (has_expr && !expr_eq)) {
229-
return;
230-
}
234+
// SHARED_CODE_IN_IF_BLOCKS prerequisites
235+
if !has_unconditional_else || (start_eq == 0 && end_eq == 0 && (has_expr && !expr_eq)) {
236+
return;
231237
}
232238

233239
if has_expr && !expr_eq {
@@ -278,11 +284,14 @@ fn lint_same_then_else<'tcx>(
278284
end_eq -= moved_start;
279285
}
280286

281-
let mut end_linable = true;
282-
if let Some(expr) = block.expr {
287+
let end_linable = if let Some(expr) = block.expr {
283288
intravisit::walk_expr(&mut walker, expr);
284-
end_linable = walker.uses.iter().any(|x| !block_defs.contains(x));
285-
}
289+
walker.uses.iter().any(|x| !block_defs.contains(x))
290+
} else if end_eq == 0 {
291+
false
292+
} else {
293+
true
294+
};
286295

287296
emit_shared_code_in_if_blocks_lint(cx, start_eq, end_eq, end_linable, blocks, expr);
288297
}
@@ -354,7 +363,7 @@ fn emit_shared_code_in_if_blocks_lint(
354363
SHARED_CODE_IN_IF_BLOCKS,
355364
*span,
356365
"All code blocks contain the same code",
357-
"Consider moving the code out like this",
366+
"Consider moving the statements out like this",
358367
sugg.clone(),
359368
Applicability::Unspecified,
360369
);

tests/ui/shared_code_in_if_blocks/shared_at_bot.rs

+105-2
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

+10
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)