diff --git a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs index 89873737a6..cded9e44e6 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs @@ -50,15 +50,6 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) { pylint::rules::nonlocal_and_global(checker, nonlocal); } } - Stmt::Continue(_) => { - if checker.is_rule_enabled(Rule::ContinueOutsideLoop) { - pyflakes::rules::continue_outside_loop( - checker, - stmt, - &mut checker.semantic.current_statements().skip(1), - ); - } - } Stmt::FunctionDef( function_def @ ast::StmtFunctionDef { is_async, diff --git a/crates/ruff_linter/src/checkers/ast/mod.rs b/crates/ruff_linter/src/checkers/ast/mod.rs index d6f5b81199..cdae2bb37d 100644 --- a/crates/ruff_linter/src/checkers/ast/mod.rs +++ b/crates/ruff_linter/src/checkers/ast/mod.rs @@ -711,6 +711,12 @@ impl SemanticSyntaxContext for Checker<'_> { self.report_diagnostic(pyflakes::rules::BreakOutsideLoop, error.range); } } + SemanticSyntaxErrorKind::ContinueOutsideLoop => { + // F702 + if self.is_rule_enabled(Rule::ContinueOutsideLoop) { + self.report_diagnostic(pyflakes::rules::ContinueOutsideLoop, error.range); + } + } SemanticSyntaxErrorKind::ReboundComprehensionVariable | SemanticSyntaxErrorKind::DuplicateTypeParameter | SemanticSyntaxErrorKind::MultipleCaseAssignment(_) diff --git a/crates/ruff_linter/src/rules/pyflakes/rules/continue_outside_loop.rs b/crates/ruff_linter/src/rules/pyflakes/rules/continue_outside_loop.rs index a6e426b9d5..334c64c2a7 100644 --- a/crates/ruff_linter/src/rules/pyflakes/rules/continue_outside_loop.rs +++ b/crates/ruff_linter/src/rules/pyflakes/rules/continue_outside_loop.rs @@ -1,9 +1,6 @@ -use ruff_python_ast::{self as ast, Stmt}; - use ruff_macros::{ViolationMetadata, derive_message_formats}; -use ruff_text_size::Ranged; -use crate::{Violation, checkers::ast::Checker}; +use crate::Violation; /// ## What it does /// Checks for `continue` statements outside of loops. @@ -29,28 +26,3 @@ impl Violation for ContinueOutsideLoop { "`continue` not properly in loop".to_string() } } - -/// F702 -pub(crate) fn continue_outside_loop<'a>( - checker: &Checker, - stmt: &'a Stmt, - parents: &mut impl Iterator, -) { - let mut child = stmt; - for parent in parents { - match parent { - Stmt::For(ast::StmtFor { orelse, .. }) | Stmt::While(ast::StmtWhile { orelse, .. }) => { - if !orelse.contains(child) { - return; - } - } - Stmt::FunctionDef(_) | Stmt::ClassDef(_) => { - break; - } - _ => {} - } - child = parent; - } - - checker.report_diagnostic(ContinueOutsideLoop, stmt.range()); -} diff --git a/crates/ruff_python_parser/src/semantic_errors.rs b/crates/ruff_python_parser/src/semantic_errors.rs index 51949f8bb4..59c5b30b29 100644 --- a/crates/ruff_python_parser/src/semantic_errors.rs +++ b/crates/ruff_python_parser/src/semantic_errors.rs @@ -229,6 +229,11 @@ impl SemanticSyntaxChecker { Self::add_error(ctx, SemanticSyntaxErrorKind::BreakOutsideLoop, *range); } } + Stmt::Continue(ast::StmtContinue { range, .. }) => { + if !ctx.in_loop_context() { + Self::add_error(ctx, SemanticSyntaxErrorKind::ContinueOutsideLoop, *range); + } + } _ => {} } @@ -1131,6 +1136,7 @@ impl Display for SemanticSyntaxError { write!(f, "Future feature `{name}` is not defined") } SemanticSyntaxErrorKind::BreakOutsideLoop => f.write_str("`break` outside loop"), + SemanticSyntaxErrorKind::ContinueOutsideLoop => f.write_str("`continue` outside loop"), } } } @@ -1507,6 +1513,9 @@ pub enum SemanticSyntaxErrorKind { /// Represents the use of a `break` statement outside of a loop. BreakOutsideLoop, + + /// Represents the use of a `continue` statement outside of a loop. + ContinueOutsideLoop, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, get_size2::GetSize)]