diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_type_checking/TC005.py b/crates/ruff_linter/resources/test/fixtures/flake8_type_checking/TC005.py index dc5ce7c75e..1030f6aaf5 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_type_checking/TC005.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_type_checking/TC005.py @@ -4,13 +4,6 @@ if TYPE_CHECKING: pass # TC005 -if False: - pass # TC005 - -if 0: - pass # TC005 - - def example(): if TYPE_CHECKING: pass # TC005 @@ -32,13 +25,6 @@ if TYPE_CHECKING: x: List -if False: - x: List - -if 0: - x: List - - from typing_extensions import TYPE_CHECKING if TYPE_CHECKING: diff --git a/crates/ruff_linter/src/checkers/ast/mod.rs b/crates/ruff_linter/src/checkers/ast/mod.rs index 6d195e41bf..fc72c1d1a3 100644 --- a/crates/ruff_linter/src/checkers/ast/mod.rs +++ b/crates/ruff_linter/src/checkers/ast/mod.rs @@ -246,11 +246,7 @@ impl<'a> Checker<'a> { notebook_index: Option<&'a NotebookIndex>, target_version: PythonVersion, ) -> Checker<'a> { - let mut semantic = SemanticModel::new(&settings.typing_modules, path, module); - if settings.preview.is_enabled() { - // Set the feature flag to test `TYPE_CHECKING` semantic changes - semantic.flags |= SemanticModelFlags::NEW_TYPE_CHECKING_BLOCK_DETECTION; - } + let semantic = SemanticModel::new(&settings.typing_modules, path, module); Self { parsed, parsed_type_annotation: None, diff --git a/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM108_SIM108.py.snap b/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM108_SIM108.py.snap index 3306802cce..a18c5fdac5 100644 --- a/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM108_SIM108.py.snap +++ b/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM108_SIM108.py.snap @@ -226,6 +226,33 @@ SIM108.py:167:1: SIM108 [*] Use ternary operator `z = 1 if True else other` inst 172 169 | if False: 173 170 | z = 1 +SIM108.py:172:1: SIM108 [*] Use ternary operator `z = 1 if False else other` instead of `if`-`else`-block + | +170 | z = other +171 | +172 | / if False: +173 | | z = 1 +174 | | else: +175 | | z = other + | |_____________^ SIM108 +176 | +177 | if 1: + | + = help: Replace `if`-`else`-block with `z = 1 if False else other` + +ℹ Unsafe fix +169 169 | else: +170 170 | z = other +171 171 | +172 |-if False: +173 |- z = 1 +174 |-else: +175 |- z = other + 172 |+z = 1 if False else other +176 173 | +177 174 | if 1: +178 175 | z = True + SIM108.py:177:1: SIM108 [*] Use ternary operator `z = True if 1 else other` instead of `if`-`else`-block | 175 | z = other diff --git a/crates/ruff_linter/src/rules/flake8_type_checking/snapshots/ruff_linter__rules__flake8_type_checking__tests__empty-type-checking-block_TC005.py.snap b/crates/ruff_linter/src/rules/flake8_type_checking/snapshots/ruff_linter__rules__flake8_type_checking__tests__empty-type-checking-block_TC005.py.snap index 137f000062..5486cdfa4c 100644 --- a/crates/ruff_linter/src/rules/flake8_type_checking/snapshots/ruff_linter__rules__flake8_type_checking__tests__empty-type-checking-block_TC005.py.snap +++ b/crates/ruff_linter/src/rules/flake8_type_checking/snapshots/ruff_linter__rules__flake8_type_checking__tests__empty-type-checking-block_TC005.py.snap @@ -16,102 +16,64 @@ TC005.py:4:5: TC005 [*] Found empty type-checking block 4 |- pass # TC005 5 3 | 6 4 | -7 5 | if False: +7 5 | def example(): -TC005.py:8:5: TC005 [*] Found empty type-checking block +TC005.py:9:9: TC005 [*] Found empty type-checking block | - 7 | if False: - 8 | pass # TC005 - | ^^^^ TC005 - 9 | -10 | if 0: + 7 | def example(): + 8 | if TYPE_CHECKING: + 9 | pass # TC005 + | ^^^^ TC005 +10 | return | = help: Delete empty type-checking block ℹ Safe fix -4 4 | pass # TC005 -5 5 | -6 6 | -7 |-if False: -8 |- pass # TC005 -9 7 | -10 8 | if 0: -11 9 | pass # TC005 - -TC005.py:11:5: TC005 [*] Found empty type-checking block - | -10 | if 0: -11 | pass # TC005 - | ^^^^ TC005 - | - = help: Delete empty type-checking block - -ℹ Safe fix -7 7 | if False: -8 8 | pass # TC005 -9 9 | -10 |-if 0: -11 |- pass # TC005 +5 5 | +6 6 | +7 7 | def example(): +8 |- if TYPE_CHECKING: +9 |- pass # TC005 +10 8 | return +11 9 | 12 10 | -13 11 | -14 12 | def example(): -TC005.py:16:9: TC005 [*] Found empty type-checking block +TC005.py:15:9: TC005 [*] Found empty type-checking block | -14 | def example(): -15 | if TYPE_CHECKING: -16 | pass # TC005 +13 | class Test: +14 | if TYPE_CHECKING: +15 | pass # TC005 | ^^^^ TC005 -17 | return +16 | x = 2 | = help: Delete empty type-checking block ℹ Safe fix +11 11 | 12 12 | -13 13 | -14 14 | def example(): -15 |- if TYPE_CHECKING: -16 |- pass # TC005 -17 15 | return +13 13 | class Test: +14 |- if TYPE_CHECKING: +15 |- pass # TC005 +16 14 | x = 2 +17 15 | 18 16 | -19 17 | -TC005.py:22:9: TC005 [*] Found empty type-checking block +TC005.py:31:5: TC005 [*] Found empty type-checking block | -20 | class Test: -21 | if TYPE_CHECKING: -22 | pass # TC005 - | ^^^^ TC005 -23 | x = 2 - | - = help: Delete empty type-checking block - -ℹ Safe fix -18 18 | -19 19 | -20 20 | class Test: -21 |- if TYPE_CHECKING: -22 |- pass # TC005 -23 21 | x = 2 -24 22 | -25 23 | - -TC005.py:45:5: TC005 [*] Found empty type-checking block - | -44 | if TYPE_CHECKING: -45 | pass # TC005 +30 | if TYPE_CHECKING: +31 | pass # TC005 | ^^^^ TC005 -46 | -47 | # https://github.com/astral-sh/ruff/issues/11368 +32 | +33 | # https://github.com/astral-sh/ruff/issues/11368 | = help: Delete empty type-checking block ℹ Safe fix -41 41 | -42 42 | from typing_extensions import TYPE_CHECKING -43 43 | -44 |-if TYPE_CHECKING: -45 |- pass # TC005 -46 44 | -47 45 | # https://github.com/astral-sh/ruff/issues/11368 -48 46 | if TYPE_CHECKING: +27 27 | +28 28 | from typing_extensions import TYPE_CHECKING +29 29 | +30 |-if TYPE_CHECKING: +31 |- pass # TC005 +32 30 | +33 31 | # https://github.com/astral-sh/ruff/issues/11368 +34 32 | if TYPE_CHECKING: diff --git a/crates/ruff_python_semantic/src/analyze/typing.rs b/crates/ruff_python_semantic/src/analyze/typing.rs index fc801c40ca..2c2be80283 100644 --- a/crates/ruff_python_semantic/src/analyze/typing.rs +++ b/crates/ruff_python_semantic/src/analyze/typing.rs @@ -1,10 +1,10 @@ //! Analysis rules for the `typing` module. -use ruff_python_ast::helpers::{any_over_expr, is_const_false, map_subscript}; +use ruff_python_ast::helpers::{any_over_expr, map_subscript}; use ruff_python_ast::identifier::Identifier; use ruff_python_ast::name::QualifiedName; use ruff_python_ast::{ - self as ast, Expr, ExprCall, ExprName, Int, Operator, ParameterWithDefault, Parameters, Stmt, + self as ast, Expr, ExprCall, ExprName, Operator, ParameterWithDefault, Parameters, Stmt, StmtAssign, }; use ruff_python_stdlib::typing::{ @@ -391,44 +391,19 @@ pub fn is_mutable_expr(expr: &Expr, semantic: &SemanticModel) -> bool { pub fn is_type_checking_block(stmt: &ast::StmtIf, semantic: &SemanticModel) -> bool { let ast::StmtIf { test, .. } = stmt; - if semantic.use_new_type_checking_block_detection_semantics() { - return match test.as_ref() { - // As long as the symbol's name is "TYPE_CHECKING" we will treat it like `typing.TYPE_CHECKING` - // for this specific check even if it's defined somewhere else, like the current module. - // Ex) `if TYPE_CHECKING:` - Expr::Name(ast::ExprName { id, .. }) => { - id == "TYPE_CHECKING" + match test.as_ref() { + // As long as the symbol's name is "TYPE_CHECKING" we will treat it like `typing.TYPE_CHECKING` + // for this specific check even if it's defined somewhere else, like the current module. + // Ex) `if TYPE_CHECKING:` + Expr::Name(ast::ExprName { id, .. }) => { + id == "TYPE_CHECKING" // Ex) `if TC:` with `from typing import TYPE_CHECKING as TC` || semantic.match_typing_expr(test, "TYPE_CHECKING") - } - // Ex) `if typing.TYPE_CHECKING:` - Expr::Attribute(ast::ExprAttribute { attr, .. }) => attr == "TYPE_CHECKING", - _ => false, - }; + } + // Ex) `if typing.TYPE_CHECKING:` + Expr::Attribute(ast::ExprAttribute { attr, .. }) => attr == "TYPE_CHECKING", + _ => false, } - - // Ex) `if False:` - if is_const_false(test) { - return true; - } - - // Ex) `if 0:` - if matches!( - test.as_ref(), - Expr::NumberLiteral(ast::ExprNumberLiteral { - value: ast::Number::Int(Int::ZERO), - .. - }) - ) { - return true; - } - - // Ex) `if typing.TYPE_CHECKING:` - if semantic.match_typing_expr(test, "TYPE_CHECKING") { - return true; - } - - false } /// Returns `true` if the [`ast::StmtIf`] is a version-checking block (e.g., `if sys.version_info >= ...:`). diff --git a/crates/ruff_python_semantic/src/model.rs b/crates/ruff_python_semantic/src/model.rs index 62145f4234..e1b25670d5 100644 --- a/crates/ruff_python_semantic/src/model.rs +++ b/crates/ruff_python_semantic/src/model.rs @@ -2014,18 +2014,6 @@ impl<'a> SemanticModel<'a> { .intersects(SemanticModelFlags::DEFERRED_CLASS_BASE) } - /// Return `true` if we should use the new semantics to recognize - /// type checking blocks. Previously we only recognized type checking - /// blocks if `TYPE_CHECKING` was imported from a typing module. - /// - /// With this feature flag enabled we recognize any symbol named - /// `TYPE_CHECKING`, regardless of where it comes from to mirror - /// what mypy and pyright do. - pub const fn use_new_type_checking_block_detection_semantics(&self) -> bool { - self.flags - .intersects(SemanticModelFlags::NEW_TYPE_CHECKING_BLOCK_DETECTION) - } - /// Return an iterator over all bindings shadowed by the given [`BindingId`], within the /// containing scope, and across scopes. pub fn shadowed_bindings( @@ -2557,14 +2545,6 @@ bitflags! { /// [#13824]: https://github.com/astral-sh/ruff/issues/13824 const NO_TYPE_CHECK = 1 << 30; - /// The model special-cases any symbol named `TYPE_CHECKING`. - /// - /// Previously we only recognized `TYPE_CHECKING` if it was part of - /// one of the configured `typing` modules. This flag exists to - /// test out the semantic change only in preview. This flag will go - /// away once this change has been stabilized. - const NEW_TYPE_CHECKING_BLOCK_DETECTION = 1 << 31; - /// The context is in any type annotation. const ANNOTATION = Self::TYPING_ONLY_ANNOTATION.bits() | Self::RUNTIME_EVALUATED_ANNOTATION.bits() | Self::RUNTIME_REQUIRED_ANNOTATION.bits();