Recognize all symbols named TYPE_CHECKING for in_type_checking_block (#15719)

Closes #15681

## Summary

This changes `analyze::typing::is_type_checking_block` to recognize all
symbols named "TYPE_CHECKING".
This matches the current behavior of mypy and pyright as well as
`flake8-type-checking`.

It also drops support for detecting `if False:` and `if 0:` as type
checking blocks. This used to be an option for
providing backwards compatibility with Python versions that did not have
a `typing` module, but has since
been removed from the typing spec and is no longer supported by any of
the mainstream type checkers.

## Test Plan

`cargo nextest run`

---------

Co-authored-by: Micha Reiser <micha@reiser.io>
This commit is contained in:
David Salvisberg 2025-02-06 14:45:12 +01:00 committed by GitHub
parent 81059d05fc
commit 8fcac0ff36
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 192 additions and 15 deletions

View file

@ -382,6 +382,22 @@ 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"
// 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 False:`
if is_const_false(test) {
return true;