X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=clippy_lints%2Fsrc%2Fneedless_continue.rs;h=98a3bce1ff38a1e9d107b54d8f725af240156c9a;hb=eb688958d3d87fb1c91d181dc5fbfbef7cfa634d;hp=603071a5f4ac4659fef61816e436507b54fc5ada;hpb=299ff49667c213a87c22e371298a87a5b4f874a6;p=rust.git diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs index 603071a5f4a..98a3bce1ff3 100644 --- a/clippy_lints/src/needless_continue.rs +++ b/clippy_lints/src/needless_continue.rs @@ -33,29 +33,28 @@ //! ``` //! //! 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_lint::{EarlyContext, EarlyLintPass}; +use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::{original_sp, DUMMY_SP}; use rustc_span::Span; -use crate::utils::{indent_of, snippet, snippet_block, span_lint_and_help}; - declare_clippy_lint! { - /// **What it does:** The lint checks for `if`-statements appearing in loops + /// ### What it does + /// The lint checks for `if`-statements appearing in loops /// that contain a `continue` statement in either their main blocks or their /// `else`-blocks, when omitting the `else`-block possibly with some /// rearrangement of code can make the code easier to understand. /// - /// **Why is this bad?** Having explicit `else` blocks for `if` statements + /// ### Why is this bad? + /// Having explicit `else` blocks for `if` statements /// containing `continue` in their THEN branch adds unnecessary branching and /// nesting to the code. Having an else block containing just `continue` can /// also be better written by grouping the statements following the whole `if` /// statement within the THEN block and omitting the else block completely. /// - /// **Known problems:** None - /// - /// **Example:** + /// ### Example /// ```rust /// # fn condition() -> bool { false } /// # fn update_condition() {} @@ -111,6 +110,7 @@ /// # break; /// } /// ``` + #[clippy::version = "pre 1.29.0"] pub NEEDLESS_CONTINUE, pedantic, "`continue` statements that can be replaced by a rearrangement of code" @@ -270,9 +270,11 @@ struct LintData<'a> { /// The 0-based index of the `if` statement in the containing loop block. stmt_idx: usize, /// The statements of the loop block. - block_stmts: &'a [ast::Stmt], + loop_block: &'a ast::Block, } +const MSG_REDUNDANT_CONTINUE_EXPRESSION: &str = "this `continue` expression is redundant"; + const MSG_REDUNDANT_ELSE_BLOCK: &str = "this `else` block is redundant"; const MSG_ELSE_BLOCK_NOT_NEEDED: &str = "there is no need for an explicit `else` block for this `if` \ @@ -283,6 +285,8 @@ struct LintData<'a> { const DROP_ELSE_BLOCK_MSG: &str = "consider dropping the `else` clause"; +const DROP_CONTINUE_EXPRESSION_MSG: &str = "consider dropping the `continue` expression"; + fn emit_warning<'a>(cx: &EarlyContext<'_>, data: &'a LintData<'_>, header: &str, typ: LintType) { // snip is the whole *help* message that appears after the warning. // message is the warning message. @@ -339,10 +343,10 @@ fn suggestion_snippet_for_continue_inside_else<'a>(cx: &EarlyContext<'_>, data: let indent = span_of_first_expr_in_block(data.if_block) .and_then(|span| indent_of(cx, span)) .unwrap_or(0); - let to_annex = data.block_stmts[data.stmt_idx + 1..] + let to_annex = data.loop_block.stmts[data.stmt_idx + 1..] .iter() - .map(|stmt| original_sp(stmt.span, DUMMY_SP)) - .map(|span| { + .map(|stmt| { + let span = cx.sess().source_map().stmt_span(stmt.span, data.loop_block.span); let snip = snippet_block(cx, span, "..", None).into_owned(); snip.lines() .map(|line| format!("{}{}", " ".repeat(indent), line)) @@ -364,6 +368,22 @@ fn suggestion_snippet_for_continue_inside_else<'a>(cx: &EarlyContext<'_>, data: } fn check_and_warn<'a>(cx: &EarlyContext<'_>, expr: &'a 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, + ); + } + } with_loop_block(expr, |loop_block, label| { for (i, stmt) in loop_block.stmts.iter().enumerate() { with_if_expr(stmt, |if_expr, cond, then_block, else_expr| { @@ -373,7 +393,7 @@ fn check_and_warn<'a>(cx: &EarlyContext<'_>, expr: &'a ast::Expr) { if_cond: cond, if_block: then_block, else_expr, - block_stmts: &loop_block.stmts, + loop_block, }; if needless_continue_in_else(else_expr, label) { emit_warning( @@ -402,7 +422,7 @@ fn check_and_warn<'a>(cx: &EarlyContext<'_>, expr: &'a ast::Expr) { /// /// is transformed to /// -/// ```ignore +/// ```text /// { /// let x = 5; /// ``` @@ -416,11 +436,7 @@ fn erode_from_back(s: &str) -> String { break; } } - if ret.is_empty() { - s.to_string() - } else { - ret - } + if ret.is_empty() { s.to_string() } else { ret } } fn span_of_first_expr_in_block(block: &ast::Block) -> Option {