Skip to content

Commit

Permalink
[needless_continue]: lint if the last stmt in for/while/loop is `co…
Browse files Browse the repository at this point in the history
…ntinue`, recursively

fixes: rust-lang#4077
  • Loading branch information
lengyijun committed Sep 21, 2023
1 parent c556695 commit a403969
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 24 deletions.
2 changes: 1 addition & 1 deletion clippy_lints/src/methods/unnecessary_to_owned.rs
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
for (_, node) in cx.tcx.hir().parent_iter(expr.hir_id) {
match node {
Node::Stmt(_) => return true,
Node::Block(..) => continue,
Node::Block(..) => {}
Node::Item(item) => {
if let ItemKind::Fn(_, _, body_id) = &item.kind
&& let output_ty = return_ty(cx, item.owner_id)
Expand Down
76 changes: 60 additions & 16 deletions clippy_lints/src/needless_continue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
//! This lint is **warn** by default.
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::source::{indent_of, snippet, snippet_block};
use rustc_ast::ast;
use rustc_ast::{ast, Block, Label};
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::Span;
Expand Down Expand Up @@ -361,24 +361,68 @@ fn suggestion_snippet_for_continue_inside_else(cx: &EarlyContext<'_>, data: &Lin
)
}

fn check_and_warn(cx: &EarlyContext<'_>, expr: &ast::Expr) {
if_chain! {
if let ast::ExprKind::Loop(loop_block, ..) = &expr.kind;
if let Some(last_stmt) = loop_block.stmts.last();
if let ast::StmtKind::Expr(inner_expr) | ast::StmtKind::Semi(inner_expr) = &last_stmt.kind;
if let ast::ExprKind::Continue(_) = inner_expr.kind;
then {
span_lint_and_help(
cx,
NEEDLESS_CONTINUE,
last_stmt.span,
MSG_REDUNDANT_CONTINUE_EXPRESSION,
None,
DROP_CONTINUE_EXPRESSION_MSG,
);
fn check_last_stmt<F>(b: &Block, func: &F)
where
F: Fn(Option<&ast::Label>, Span),
{
if let Some(last_stmt) = b.stmts.last() &&
let ast::StmtKind::Expr(inner_expr) | ast::StmtKind::Semi(inner_expr) = &last_stmt.kind {
match &inner_expr.kind {
rustc_ast::ExprKind::Continue(continue_label) => {
func(continue_label.as_ref(), last_stmt.span);
},

rustc_ast::ExprKind::If(_, then_block, else_block) => {
check_last_stmt(then_block, func);
if let Some(else_block) = else_block {
match &else_block.kind {
rustc_ast::ExprKind::Continue(continue_label) => {
func(continue_label.as_ref(), else_block.span);
}
rustc_ast::ExprKind::Block(b, _) => {
check_last_stmt(b, func);
}
_ => {}

}
}
}
rustc_ast::ExprKind::Match(_, arms) => {
for arm in arms {
match &arm.body.kind {
rustc_ast::ExprKind::Continue(continue_label) => {
func(continue_label.as_ref(), arm.body.span);
}
rustc_ast::ExprKind::Block(b, _) => {
check_last_stmt(b, func);

}
_ => {}
}

}
}
_ => {},
}
}
}

fn check_and_warn(cx: &EarlyContext<'_>, expr: &ast::Expr) {
with_loop_block(expr, |loop_block, label| {
let p = |continue_label: Option<&Label>, span: Span| {
if compare_labels(label, continue_label) {
span_lint_and_help(
cx,
NEEDLESS_CONTINUE,
span,
MSG_REDUNDANT_CONTINUE_EXPRESSION,
None,
DROP_CONTINUE_EXPRESSION_MSG,
);
}
};
check_last_stmt(loop_block, &p);

for (i, stmt) in loop_block.stmts.iter().enumerate() {
with_if_expr(stmt, |if_expr, cond, then_block, else_expr| {
let data = &LintData {
Expand Down
1 change: 0 additions & 1 deletion clippy_lints/src/redundant_else.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ impl EarlyLintPass for RedundantElse {
ExprKind::If(_, next_then, Some(next_els)) => {
then = next_then;
els = next_els;
continue;
},
// else if without else
ExprKind::If(..) => return,
Expand Down
4 changes: 0 additions & 4 deletions clippy_lints/src/transmute/transmute_undefined_repr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,16 @@ pub(super) fn check<'tcx>(
| (ReducedTy::UnorderedFields(from_sub_ty), ReducedTy::OrderedFields(_, Some(to_sub_ty))) => {
from_ty = from_sub_ty;
to_ty = to_sub_ty;
continue;
},
(ReducedTy::OrderedFields(_, Some(from_sub_ty)), ReducedTy::Other(to_sub_ty)) if reduced_tys.to_fat_ptr => {
from_ty = from_sub_ty;
to_ty = to_sub_ty;
continue;
},
(ReducedTy::Other(from_sub_ty), ReducedTy::OrderedFields(_, Some(to_sub_ty)))
if reduced_tys.from_fat_ptr =>
{
from_ty = from_sub_ty;
to_ty = to_sub_ty;
continue;
},

// ptr <-> ptr
Expand All @@ -52,7 +49,6 @@ pub(super) fn check<'tcx>(
{
from_ty = from_sub_ty;
to_ty = to_sub_ty;
continue;
},

// fat ptr <-> (*size, *size)
Expand Down
2 changes: 1 addition & 1 deletion tests/missing-test-files.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ fn explore_directory(dir: &Path) -> Vec<String> {
missing_files.push(path.to_str().unwrap().to_string());
}
},
_ => continue,
_ => {},
};
}
}
Expand Down
22 changes: 22 additions & 0 deletions tests/ui/needless_continue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,3 +151,25 @@ mod issue_2329 {
}
}
}

mod issue_4077 {
fn main() {
loop {
do_something();
if some_expr() {
continue;
}
}
}

// The contents of these functions are irrelevant, the purpose of this file is
// shown in main.

fn do_something() {
std::process::exit(0);
}

fn some_expr() -> bool {
true
}
}
10 changes: 9 additions & 1 deletion tests/ui/needless_continue.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -136,5 +136,13 @@ LL | | }
println!("bar-5");
}

error: aborting due to 8 previous errors
error: this `continue` expression is redundant
--> $DIR/needless_continue.rs:160:17
|
LL | continue;
| ^^^^^^^^^
|
= help: consider dropping the `continue` expression

error: aborting due to 9 previous errors

0 comments on commit a403969

Please sign in to comment.