diff --git a/crates/ruff/src/rules/pyflakes/rules/break_outside_loop.rs b/crates/ruff/src/rules/pyflakes/rules/break_outside_loop.rs index 026a7bfb29..c867a82bf5 100644 --- a/crates/ruff/src/rules/pyflakes/rules/break_outside_loop.rs +++ b/crates/ruff/src/rules/pyflakes/rules/break_outside_loop.rs @@ -3,6 +3,21 @@ use rustpython_parser::ast::{self, Ranged, Stmt}; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; +/// ## What it does +/// Checks for `break` statements outside of loops. +/// +/// ## Why is this bad? +/// The use of a `break` statement outside of a `for` or `while` loop will +/// raise a `SyntaxError`. +/// +/// ## Example +/// ```python +/// def foo(): +/// break +/// ``` +/// +/// ## References +/// - [Python documentation: `break`](https://docs.python.org/3/reference/simple_stmts.html#the-break-statement) #[violation] pub struct BreakOutsideLoop; diff --git a/crates/ruff/src/rules/pyflakes/rules/continue_outside_loop.rs b/crates/ruff/src/rules/pyflakes/rules/continue_outside_loop.rs index e483a6496b..ced5e9c1e0 100644 --- a/crates/ruff/src/rules/pyflakes/rules/continue_outside_loop.rs +++ b/crates/ruff/src/rules/pyflakes/rules/continue_outside_loop.rs @@ -3,6 +3,21 @@ use rustpython_parser::ast::{self, Ranged, Stmt}; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; +/// ## What it does +/// Checks for `continue` statements outside of loops. +/// +/// ## Why is this bad? +/// The use of a `continue` statement outside of a `for` or `while` loop will +/// raise a `SyntaxError`. +/// +/// ## Example +/// ```python +/// def foo(): +/// continue # SyntaxError +/// ``` +/// +/// ## References +/// - [Python documentation: `continue`](https://docs.python.org/3/reference/simple_stmts.html#the-continue-statement) #[violation] pub struct ContinueOutsideLoop; diff --git a/crates/ruff/src/rules/pyflakes/rules/default_except_not_last.rs b/crates/ruff/src/rules/pyflakes/rules/default_except_not_last.rs index 25981d38c3..197f34e349 100644 --- a/crates/ruff/src/rules/pyflakes/rules/default_except_not_last.rs +++ b/crates/ruff/src/rules/pyflakes/rules/default_except_not_last.rs @@ -5,6 +5,44 @@ use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::helpers::except_range; use ruff_python_ast::source_code::Locator; +/// ## What it does +/// Checks for `except` blocks that handle all exceptions, but are not the last +/// `except` block in a `try` statement. +/// +/// ## Why is this bad? +/// When an exception is raised within a `try` block, the `except` blocks are +/// evaluated in order, and the first matching block is executed. If an `except` +/// block handles all exceptions, but isn't the last block, Python will raise a +/// `SyntaxError`, as the following blocks would never be executed. +/// +/// ## Example +/// ```python +/// def reciprocal(n): +/// try: +/// reciprocal = 1 / n +/// except: +/// print("An exception occurred.") +/// except ZeroDivisionError: +/// print("Cannot divide by zero.") +/// else: +/// return reciprocal +/// ``` +/// +/// Use instead: +/// ```python +/// def reciprocal(n): +/// try: +/// reciprocal = 1 / n +/// except ZeroDivisionError: +/// print("Cannot divide by zero.") +/// except: +/// print("An exception occurred.") +/// else: +/// return reciprocal +/// ``` +/// +/// ## References +/// - [Python documentation](https://docs.python.org/3/reference/compound_stmts.html#except-clause) #[violation] pub struct DefaultExceptNotLast; diff --git a/crates/ruff/src/rules/pyflakes/rules/forward_annotation_syntax_error.rs b/crates/ruff/src/rules/pyflakes/rules/forward_annotation_syntax_error.rs index 5c0b3fb304..aa94f3eb0a 100644 --- a/crates/ruff/src/rules/pyflakes/rules/forward_annotation_syntax_error.rs +++ b/crates/ruff/src/rules/pyflakes/rules/forward_annotation_syntax_error.rs @@ -1,6 +1,27 @@ use ruff_diagnostics::Violation; use ruff_macros::{derive_message_formats, violation}; +/// ## What it does +/// Checks for forward annotations that include invalid syntax. +/// +/// +/// ## Why is this bad? +/// In Python, type annotations can be quoted as strings literals to enable +/// references to types that have not yet been defined, known as "forward +/// references". +/// +/// However, these quoted annotations must be valid Python expressions. The use +/// of invalid syntax in a quoted annotation won't raise a `SyntaxError`, but +/// will instead raise an error when type checking is performed. +/// +/// ## Example +/// ```python +/// def foo() -> "/": +/// ... +/// ``` +/// +/// ## References +/// - [PEP 563](https://www.python.org/dev/peps/pep-0563/) #[violation] pub struct ForwardAnnotationSyntaxError { pub body: String, diff --git a/crates/ruff/src/rules/pyflakes/rules/raise_not_implemented.rs b/crates/ruff/src/rules/pyflakes/rules/raise_not_implemented.rs index d639ffa07c..f91e08f0bf 100644 --- a/crates/ruff/src/rules/pyflakes/rules/raise_not_implemented.rs +++ b/crates/ruff/src/rules/pyflakes/rules/raise_not_implemented.rs @@ -6,6 +6,34 @@ use ruff_macros::{derive_message_formats, violation}; use crate::checkers::ast::Checker; use crate::registry::AsRule; +/// ## What it does +/// Checks for `raise` statements that raise `NotImplemented`. +/// +/// ## Why is this bad? +/// `NotImplemented` is an exception used by binary special methods to indicate +/// that an operation is not implemented with respect to a particular type. +/// +/// `NotImplemented` should not be raised directly. Instead, raise +/// `NotImplementedError`, which is used to indicate that the method is +/// abstract or not implemented in the derived class. +/// +/// ## Example +/// ```python +/// class Foo: +/// def bar(self): +/// raise NotImplemented +/// ``` +/// +/// Use instead: +/// ```python +/// class Foo: +/// def bar(self): +/// raise NotImplementedError +/// ``` +/// +/// ## References +/// - [Python documentation: `NotImplemented`](https://docs.python.org/3/library/constants.html#NotImplemented) +/// - [Python documentation: `NotImplementedError`](https://docs.python.org/3/library/exceptions.html#NotImplementedError) #[violation] pub struct RaiseNotImplemented; diff --git a/crates/ruff/src/rules/pyflakes/rules/redefined_while_unused.rs b/crates/ruff/src/rules/pyflakes/rules/redefined_while_unused.rs index b32c762209..e320e607ad 100644 --- a/crates/ruff/src/rules/pyflakes/rules/redefined_while_unused.rs +++ b/crates/ruff/src/rules/pyflakes/rules/redefined_while_unused.rs @@ -2,6 +2,26 @@ use ruff_diagnostics::Violation; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::source_code::OneIndexed; +/// ## What it does +/// Checks for variable definitions that redefine (or "shadow") unused +/// variables. +/// +/// ## Why is this bad? +/// Redefinitions of unused names are unnecessary and often indicative of a +/// mistake. +/// +/// ## Example +/// ```python +/// import foo +/// import bar +/// import foo # Redefinition of unused `foo` from line 1 +/// ``` +/// +/// Use instead: +/// ```python +/// import foo +/// import bar +/// ``` #[violation] pub struct RedefinedWhileUnused { pub name: String, diff --git a/crates/ruff/src/rules/pyflakes/rules/return_outside_function.rs b/crates/ruff/src/rules/pyflakes/rules/return_outside_function.rs index d88d08df0f..c41d3a0aaa 100644 --- a/crates/ruff/src/rules/pyflakes/rules/return_outside_function.rs +++ b/crates/ruff/src/rules/pyflakes/rules/return_outside_function.rs @@ -6,6 +6,21 @@ use ruff_python_semantic::scope::ScopeKind; use crate::checkers::ast::Checker; +/// ## What it does +/// Checks for `return` statements outside of functions. +/// +/// ## Why is this bad? +/// The use of a `return` statement outside of a function will raise a +/// `SyntaxError`. +/// +/// ## Example +/// ```python +/// class Foo: +/// return 1 +/// ``` +/// +/// ## References +/// - [Python documentation: `return`](https://docs.python.org/3/reference/simple_stmts.html#the-return-statement) #[violation] pub struct ReturnOutsideFunction; diff --git a/crates/ruff/src/rules/pyflakes/rules/undefined_export.rs b/crates/ruff/src/rules/pyflakes/rules/undefined_export.rs index bce55367fc..c7c36956c7 100644 --- a/crates/ruff/src/rules/pyflakes/rules/undefined_export.rs +++ b/crates/ruff/src/rules/pyflakes/rules/undefined_export.rs @@ -4,6 +4,36 @@ use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_semantic::scope::Scope; +/// ## What it does +/// Checks for undefined names in `__all__`. +/// +/// ## Why is this bad? +/// In Python, the `__all__` variable is used to define the names that are +/// exported when a module is imported as a wildcard (e.g., +/// `from foo import *`). The names in `__all__` must be defined in the module, +/// but are included as strings. +/// +/// Including an undefined name in `__all__` is likely to raise `NameError` at +/// runtime, when the module is imported. +/// +/// ## Example +/// ```python +/// from foo import bar +/// +/// +/// __all__ = ["bar", "baz"] # undefined name `baz` in `__all__` +/// ``` +/// +/// Use instead: +/// ```python +/// from foo import bar, baz +/// +/// +/// __all__ = ["bar", "baz"] +/// ``` +/// +/// ## References +/// - [Python documentation: `__all__`](https://docs.python.org/3/tutorial/modules.html#importing-from-a-package) #[violation] pub struct UndefinedExport { name: String, diff --git a/crates/ruff/src/rules/pyflakes/rules/undefined_local.rs b/crates/ruff/src/rules/pyflakes/rules/undefined_local.rs index 1a02695da5..1479fdb945 100644 --- a/crates/ruff/src/rules/pyflakes/rules/undefined_local.rs +++ b/crates/ruff/src/rules/pyflakes/rules/undefined_local.rs @@ -5,6 +5,31 @@ use ruff_macros::{derive_message_formats, violation}; use crate::checkers::ast::Checker; +/// ## What it does +/// Checks for undefined local variables. +/// +/// ## Why is this bad? +/// Referencing a local variable before it has been assigned will raise +/// an `UnboundLocalError` at runtime. +/// +/// ## Example +/// ```python +/// x = 1 +/// +/// +/// def foo(): +/// x += 1 +/// ``` +/// +/// Use instead: +/// ```python +/// x = 1 +/// +/// +/// def foo(): +/// global x +/// x += 1 +/// ``` #[violation] pub struct UndefinedLocal { name: String, diff --git a/crates/ruff/src/rules/pyflakes/rules/undefined_name.rs b/crates/ruff/src/rules/pyflakes/rules/undefined_name.rs index b3b94a9928..05b6109a9b 100644 --- a/crates/ruff/src/rules/pyflakes/rules/undefined_name.rs +++ b/crates/ruff/src/rules/pyflakes/rules/undefined_name.rs @@ -1,6 +1,26 @@ use ruff_diagnostics::Violation; use ruff_macros::{derive_message_formats, violation}; +/// ## What it does +/// Checks for uses of undefined names. +/// +/// ## Why is this bad? +/// An undefined name is likely to raise `NameError` at runtime. +/// +/// ## Example +/// ```python +/// def double(): +/// return n * 2 # raises `NameError` if `n` is undefined when `double` is called +/// ``` +/// +/// Use instead: +/// ```python +/// def double(n): +/// return n * 2 +/// ``` +/// +/// ## References +/// - [Python documentation](https://docs.python.org/3/reference/executionmodel.html#naming-and-binding) #[violation] pub struct UndefinedName { pub name: String, diff --git a/crates/ruff/src/rules/pyflakes/rules/unused_annotation.rs b/crates/ruff/src/rules/pyflakes/rules/unused_annotation.rs index 265b463888..44e96c53f6 100644 --- a/crates/ruff/src/rules/pyflakes/rules/unused_annotation.rs +++ b/crates/ruff/src/rules/pyflakes/rules/unused_annotation.rs @@ -4,6 +4,21 @@ use ruff_python_semantic::scope::ScopeId; use crate::checkers::ast::Checker; +/// ## What it does +/// Checks for local variables that are annotated but never used. +/// +/// ## Why is this bad? +/// Annotations are used to provide type hints to static type checkers. If a +/// variable is annotated but never used, the annotation is unnecessary. +/// +/// ## Example +/// ```python +/// def foo(): +/// bar: int +/// ``` +/// +/// ## References +/// - [PEP 484](https://peps.python.org/pep-0484/) #[violation] pub struct UnusedAnnotation { name: String, diff --git a/crates/ruff/src/rules/pyflakes/rules/yield_outside_function.rs b/crates/ruff/src/rules/pyflakes/rules/yield_outside_function.rs index 879118b829..baa6cc3b93 100644 --- a/crates/ruff/src/rules/pyflakes/rules/yield_outside_function.rs +++ b/crates/ruff/src/rules/pyflakes/rules/yield_outside_function.rs @@ -25,6 +25,21 @@ impl fmt::Display for DeferralKeyword { } } +/// ## What it does +/// Checks for `yield` and `yield from` statements outside of functions. +/// +/// ## Why is this bad? +/// The use of a `yield` or `yield from` statement outside of a function will +/// raise a `SyntaxError`. +/// +/// ## Example +/// ```python +/// class Foo: +/// yield 1 +/// ``` +/// +/// ## References +/// - [Python documentation: `yield`](https://docs.python.org/3/reference/simple_stmts.html#the-yield-statement) #[violation] pub struct YieldOutsideFunction { keyword: DeferralKeyword,