Skip to content

Commit 5493578

Browse files
committed
[needless_continue]: lint if the last stmt in for/while/loop is continue, recursively
fixes: #4077
1 parent c556695 commit 5493578

7 files changed

+139
-26
lines changed

clippy_lints/src/methods/unnecessary_to_owned.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
379379
for (_, node) in cx.tcx.hir().parent_iter(expr.hir_id) {
380380
match node {
381381
Node::Stmt(_) => return true,
382-
Node::Block(..) => continue,
382+
Node::Block(..) => {}
383383
Node::Item(item) => {
384384
if let ItemKind::Fn(_, _, body_id) = &item.kind
385385
&& let output_ty = return_ty(cx, item.owner_id)

clippy_lints/src/needless_continue.rs

+71-16
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
//! This lint is **warn** by default.
3636
use clippy_utils::diagnostics::span_lint_and_help;
3737
use clippy_utils::source::{indent_of, snippet, snippet_block};
38-
use rustc_ast::ast;
38+
use rustc_ast::{ast, Block, Label};
3939
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
4040
use rustc_session::{declare_lint_pass, declare_tool_lint};
4141
use rustc_span::Span;
@@ -361,24 +361,79 @@ fn suggestion_snippet_for_continue_inside_else(cx: &EarlyContext<'_>, data: &Lin
361361
)
362362
}
363363

364-
fn check_and_warn(cx: &EarlyContext<'_>, expr: &ast::Expr) {
365-
if_chain! {
366-
if let ast::ExprKind::Loop(loop_block, ..) = &expr.kind;
367-
if let Some(last_stmt) = loop_block.stmts.last();
368-
if let ast::StmtKind::Expr(inner_expr) | ast::StmtKind::Semi(inner_expr) = &last_stmt.kind;
369-
if let ast::ExprKind::Continue(_) = inner_expr.kind;
370-
then {
371-
span_lint_and_help(
372-
cx,
373-
NEEDLESS_CONTINUE,
374-
last_stmt.span,
375-
MSG_REDUNDANT_CONTINUE_EXPRESSION,
376-
None,
377-
DROP_CONTINUE_EXPRESSION_MSG,
378-
);
364+
fn check_last_stmt_in_continue<F>(b: &ast::Expr, func: &F)
365+
where
366+
F: Fn(Option<&ast::Label>, Span),
367+
{
368+
match &b.kind {
369+
ast::ExprKind::If(_, then_block, else_block) => {
370+
check_last_stmt(then_block, func);
371+
if let Some(else_block) = else_block {
372+
check_last_stmt_in_continue(else_block, func);
373+
}
374+
},
375+
ast::ExprKind::Continue(..) => {
376+
unreachable!()
377+
},
378+
ast::ExprKind::Block(b, _) => {
379+
check_last_stmt(b, func);
380+
},
381+
_ => {},
382+
}
383+
}
384+
385+
fn check_last_stmt<F>(b: &Block, func: &F)
386+
where
387+
F: Fn(Option<&ast::Label>, Span),
388+
{
389+
if let Some(last_stmt) = b.stmts.last() &&
390+
let ast::StmtKind::Expr(inner_expr) | ast::StmtKind::Semi(inner_expr) = &last_stmt.kind {
391+
match &inner_expr.kind {
392+
ast::ExprKind::Continue(continue_label) => {
393+
func(continue_label.as_ref(), last_stmt.span);
394+
},
395+
ast::ExprKind::If(_, _, _) => {
396+
check_last_stmt_in_continue(inner_expr, func);
397+
}
398+
ast::ExprKind::Match(_, arms) => {
399+
for arm in arms {
400+
match &arm.body.kind {
401+
ast::ExprKind::Continue(continue_label) => {
402+
func(continue_label.as_ref(), arm.body.span);
403+
}
404+
ast::ExprKind::Block(b, _) => {
405+
check_last_stmt(b, func);
406+
407+
}
408+
_ => {}
409+
}
410+
411+
}
412+
}
413+
ast::ExprKind::Block(b, _) => {
414+
check_last_stmt(b, func);
415+
}
416+
_ => {},
379417
}
380418
}
419+
}
420+
421+
fn check_and_warn(cx: &EarlyContext<'_>, expr: &ast::Expr) {
381422
with_loop_block(expr, |loop_block, label| {
423+
let p = |continue_label: Option<&Label>, span: Span| {
424+
if compare_labels(label, continue_label) {
425+
span_lint_and_help(
426+
cx,
427+
NEEDLESS_CONTINUE,
428+
span,
429+
MSG_REDUNDANT_CONTINUE_EXPRESSION,
430+
None,
431+
DROP_CONTINUE_EXPRESSION_MSG,
432+
);
433+
}
434+
};
435+
check_last_stmt(loop_block, &p);
436+
382437
for (i, stmt) in loop_block.stmts.iter().enumerate() {
383438
with_if_expr(stmt, |if_expr, cond, then_block, else_expr| {
384439
let data = &LintData {

clippy_lints/src/redundant_else.rs

-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ impl EarlyLintPass for RedundantElse {
6969
ExprKind::If(_, next_then, Some(next_els)) => {
7070
then = next_then;
7171
els = next_els;
72-
continue;
7372
},
7473
// else if without else
7574
ExprKind::If(..) => return,

clippy_lints/src/transmute/transmute_undefined_repr.rs

-4
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,16 @@ pub(super) fn check<'tcx>(
3030
| (ReducedTy::UnorderedFields(from_sub_ty), ReducedTy::OrderedFields(_, Some(to_sub_ty))) => {
3131
from_ty = from_sub_ty;
3232
to_ty = to_sub_ty;
33-
continue;
3433
},
3534
(ReducedTy::OrderedFields(_, Some(from_sub_ty)), ReducedTy::Other(to_sub_ty)) if reduced_tys.to_fat_ptr => {
3635
from_ty = from_sub_ty;
3736
to_ty = to_sub_ty;
38-
continue;
3937
},
4038
(ReducedTy::Other(from_sub_ty), ReducedTy::OrderedFields(_, Some(to_sub_ty)))
4139
if reduced_tys.from_fat_ptr =>
4240
{
4341
from_ty = from_sub_ty;
4442
to_ty = to_sub_ty;
45-
continue;
4643
},
4744

4845
// ptr <-> ptr
@@ -52,7 +49,6 @@ pub(super) fn check<'tcx>(
5249
{
5350
from_ty = from_sub_ty;
5451
to_ty = to_sub_ty;
55-
continue;
5652
},
5753

5854
// fat ptr <-> (*size, *size)

tests/missing-test-files.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ fn explore_directory(dir: &Path) -> Vec<String> {
6060
missing_files.push(path.to_str().unwrap().to_string());
6161
}
6262
},
63-
_ => continue,
63+
_ => {},
6464
};
6565
}
6666
}

tests/ui/needless_continue.rs

+39
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,14 @@ fn simple_loop4() {
8787
}
8888
}
8989

90+
fn simple_loop5() {
91+
loop {
92+
println!("bleh");
93+
{ continue }
94+
//~^ ERROR: this `continue` expression is redundant
95+
}
96+
}
97+
9098
mod issue_2329 {
9199
fn condition() -> bool {
92100
unimplemented!()
@@ -151,3 +159,34 @@ mod issue_2329 {
151159
}
152160
}
153161
}
162+
163+
mod issue_4077 {
164+
fn main() {
165+
'outer: loop {
166+
'inner: loop {
167+
do_something();
168+
if some_expr() {
169+
println!("bar-7");
170+
continue 'outer;
171+
} else if !some_expr() {
172+
println!("bar-8");
173+
continue 'inner;
174+
} else {
175+
println!("bar-9");
176+
continue 'inner;
177+
}
178+
}
179+
}
180+
}
181+
182+
// The contents of these functions are irrelevant, the purpose of this file is
183+
// shown in main.
184+
185+
fn do_something() {
186+
std::process::exit(0);
187+
}
188+
189+
fn some_expr() -> bool {
190+
true
191+
}
192+
}

tests/ui/needless_continue.stderr

+27-3
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,16 @@ LL | continue
9191
|
9292
= help: consider dropping the `continue` expression
9393

94+
error: this `continue` expression is redundant
95+
--> $DIR/needless_continue.rs:93:11
96+
|
97+
LL | { continue }
98+
| ^^^^^^^^
99+
|
100+
= help: consider dropping the `continue` expression
101+
94102
error: this `else` block is redundant
95-
--> $DIR/needless_continue.rs:136:24
103+
--> $DIR/needless_continue.rs:144:24
96104
|
97105
LL | } else {
98106
| ________________________^
@@ -117,7 +125,7 @@ LL | | }
117125
}
118126

119127
error: there is no need for an explicit `else` block for this `if` expression
120-
--> $DIR/needless_continue.rs:143:17
128+
--> $DIR/needless_continue.rs:151:17
121129
|
122130
LL | / if condition() {
123131
LL | |
@@ -136,5 +144,21 @@ LL | | }
136144
println!("bar-5");
137145
}
138146

139-
error: aborting due to 8 previous errors
147+
error: this `continue` expression is redundant
148+
--> $DIR/needless_continue.rs:173:21
149+
|
150+
LL | continue 'inner;
151+
| ^^^^^^^^^^^^^^^^
152+
|
153+
= help: consider dropping the `continue` expression
154+
155+
error: this `continue` expression is redundant
156+
--> $DIR/needless_continue.rs:176:21
157+
|
158+
LL | continue 'inner;
159+
| ^^^^^^^^^^^^^^^^
160+
|
161+
= help: consider dropping the `continue` expression
162+
163+
error: aborting due to 11 previous errors
140164

0 commit comments

Comments
 (0)