Skip to content

Commit 8a1dde1

Browse files
committed
fix: useless_let_if_seq FN when if is in the last expr of block
1 parent 3c3452a commit 8a1dde1

File tree

3 files changed

+99
-66
lines changed

3 files changed

+99
-66
lines changed

clippy_lints/src/let_if_seq.rs

Lines changed: 76 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -59,80 +59,91 @@ declare_lint_pass!(LetIfSeq => [USELESS_LET_IF_SEQ]);
5959
impl<'tcx> LateLintPass<'tcx> for LetIfSeq {
6060
fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) {
6161
for [stmt, next] in block.stmts.array_windows::<2>() {
62-
if let hir::StmtKind::Let(local) = stmt.kind
63-
&& let hir::PatKind::Binding(mode, canonical_id, ident, None) = local.pat.kind
64-
&& let hir::StmtKind::Expr(if_) = next.kind
65-
&& let hir::ExprKind::If(cond, then, else_) = if_.kind
66-
&& !is_local_used(cx, cond, canonical_id)
67-
&& let hir::ExprKind::Block(then, _) = then.kind
68-
&& let Some(value) = check_assign(cx, canonical_id, then)
69-
&& !is_local_used(cx, value, canonical_id)
70-
{
71-
let span = stmt.span.to(if_.span);
62+
if let hir::StmtKind::Expr(if_) = next.kind {
63+
check_block_inner(cx, stmt, if_);
64+
}
65+
}
7266

73-
let has_interior_mutability = !cx
74-
.typeck_results()
75-
.node_type(canonical_id)
76-
.is_freeze(cx.tcx, cx.typing_env());
77-
if has_interior_mutability {
78-
return;
79-
}
67+
if let Some(expr) = block.expr
68+
&& let Some(stmt) = block.stmts.last()
69+
{
70+
check_block_inner(cx, stmt, expr);
71+
}
72+
}
73+
}
74+
75+
fn check_block_inner<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx hir::Stmt<'tcx>, if_: &'tcx hir::Expr<'tcx>) {
76+
if let hir::StmtKind::Let(local) = stmt.kind
77+
&& let hir::PatKind::Binding(mode, canonical_id, ident, None) = local.pat.kind
78+
&& let hir::ExprKind::If(cond, then, else_) = if_.kind
79+
&& !is_local_used(cx, cond, canonical_id)
80+
&& let hir::ExprKind::Block(then, _) = then.kind
81+
&& let Some(value) = check_assign(cx, canonical_id, then)
82+
&& !is_local_used(cx, value, canonical_id)
83+
{
84+
let span = stmt.span.to(if_.span);
8085

81-
let (default_multi_stmts, default) = if let Some(else_) = else_ {
82-
if let hir::ExprKind::Block(else_, _) = else_.kind {
83-
if let Some(default) = check_assign(cx, canonical_id, else_) {
84-
(else_.stmts.len() > 1, default)
85-
} else if let Some(default) = local.init {
86-
(true, default)
87-
} else {
88-
continue;
89-
}
90-
} else {
91-
continue;
92-
}
86+
let has_interior_mutability = !cx
87+
.typeck_results()
88+
.node_type(canonical_id)
89+
.is_freeze(cx.tcx, cx.typing_env());
90+
if has_interior_mutability {
91+
return;
92+
}
93+
94+
let (default_multi_stmts, default) = if let Some(else_) = else_ {
95+
if let hir::ExprKind::Block(else_, _) = else_.kind {
96+
if let Some(default) = check_assign(cx, canonical_id, else_) {
97+
(else_.stmts.len() > 1, default)
9398
} else if let Some(default) = local.init {
94-
(false, default)
99+
(true, default)
95100
} else {
96-
continue;
97-
};
101+
return;
102+
}
103+
} else {
104+
return;
105+
}
106+
} else if let Some(default) = local.init {
107+
(false, default)
108+
} else {
109+
return;
110+
};
98111

99-
let mutability = match mode {
100-
BindingMode(_, Mutability::Mut) => "<mut> ",
101-
_ => "",
102-
};
112+
let mutability = match mode {
113+
BindingMode(_, Mutability::Mut) => "<mut> ",
114+
_ => "",
115+
};
103116

104-
// FIXME: this should not suggest `mut` if we can detect that the variable is not
105-
// use mutably after the `if`
117+
// FIXME: this should not suggest `mut` if we can detect that the variable is not
118+
// use mutably after the `if`
106119

107-
let sug = format!(
108-
"let {mutability}{name} = if {cond} {{{then} {value} }} else {{{else} {default} }};",
109-
name=ident.name,
110-
cond=snippet(cx, cond.span, "_"),
111-
then=if then.stmts.len() > 1 { " ..;" } else { "" },
112-
else=if default_multi_stmts { " ..;" } else { "" },
113-
value=snippet(cx, value.span, "<value>"),
114-
default=snippet(cx, default.span, "<default>"),
115-
);
116-
span_lint_hir_and_then(
117-
cx,
118-
USELESS_LET_IF_SEQ,
119-
local.hir_id,
120+
let sug = format!(
121+
"let {mutability}{name} = if {cond} {{{then} {value} }} else {{{else} {default} }};",
122+
name=ident.name,
123+
cond=snippet(cx, cond.span, "_"),
124+
then=if then.stmts.len() > 1 { " ..;" } else { "" },
125+
else=if default_multi_stmts { " ..;" } else { "" },
126+
value=snippet(cx, value.span, "<value>"),
127+
default=snippet(cx, default.span, "<default>"),
128+
);
129+
span_lint_hir_and_then(
130+
cx,
131+
USELESS_LET_IF_SEQ,
132+
local.hir_id,
133+
span,
134+
"`if _ { .. } else { .. }` is an expression",
135+
|diag| {
136+
diag.span_suggestion(
120137
span,
121-
"`if _ { .. } else { .. }` is an expression",
122-
|diag| {
123-
diag.span_suggestion(
124-
span,
125-
"it is more idiomatic to write",
126-
sug,
127-
Applicability::HasPlaceholders,
128-
);
129-
if !mutability.is_empty() {
130-
diag.note("you might not need `mut` at all");
131-
}
132-
},
138+
"it is more idiomatic to write",
139+
sug,
140+
Applicability::HasPlaceholders,
133141
);
134-
}
135-
}
142+
if !mutability.is_empty() {
143+
diag.note("you might not need `mut` at all");
144+
}
145+
},
146+
);
136147
}
137148
}
138149

tests/ui/let_if_seq.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,3 +139,13 @@ fn main() {
139139
}
140140
println!("{}", val.get());
141141
}
142+
143+
fn issue16062(bar: fn() -> bool) {
144+
let foo;
145+
//~^ useless_let_if_seq
146+
if bar() {
147+
foo = 42;
148+
} else {
149+
foo = 0;
150+
}
151+
}

tests/ui/let_if_seq.stderr

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,5 +52,17 @@ LL | | }
5252
|
5353
= note: you might not need `mut` at all
5454

55-
error: aborting due to 4 previous errors
55+
error: `if _ { .. } else { .. }` is an expression
56+
--> tests/ui/let_if_seq.rs:144:5
57+
|
58+
LL | / let foo;
59+
LL | |
60+
LL | | if bar() {
61+
LL | | foo = 42;
62+
LL | | } else {
63+
LL | | foo = 0;
64+
LL | | }
65+
| |_____^ help: it is more idiomatic to write: `let foo = if bar() { 42 } else { 0 };`
66+
67+
error: aborting due to 5 previous errors
5668

0 commit comments

Comments
 (0)