Repository: astral-sh/ruff
File: crates/ty_python_semantic/src/types/overrides.rs (Rust)

Code before:
    semantic_index::{
        definition::DefinitionKind, place::ScopedPlaceId, place_table, scope::ScopeId,
        symbol::ScopedSymbolId, use_def_map,
    },
    types::{
        ClassBase, ClassLiteral, ClassType, KnownClass, Type,
        class::CodeGeneratorKind,
        context::InferContext,
        diagnostic::{
            INVALID_EXPLICIT_OVERRIDE, INVALID_METHOD_OVERRIDE, INVALID_NAMED_TUPLE,
            OVERRIDE_OF_FINAL_METHOD, report_invalid_method_override,
            report_overridden_final_method,
        },
        function::{FunctionDecorators, FunctionType, KnownFunction},
        list_members::{Member, MemberWithDefinition, all_end_of_scope_members},
    },
};

/// Prohibited `NamedTuple` attributes that cannot be overwritten.
/// See <https://github.com/python/cpython/blob/main/Lib/typing.py> for the list.
const PROHIBITED_NAMEDTUPLE_ATTRS: &[&str] = &[
    "__new__",
    "__init__",
    "__slots__",
    "__getnewargs__",
    "__replace__",
    "_fields",
    "_field_defaults",
    "_field_types",
    "_make",
    "_replace",
    "_asdict",
    "_source",
];

pub(super) fn check_class<'db>(context: &InferContext<'db, '_>, class: ClassLiteral<'db>) {
    let db = context.db();
    let configuration = OverrideRulesConfig::from(context);
    if configuration.no_rules_enabled() {
        return;
    }

    let class_specialized = class.identity_specialization(db);
    let scope = class.body_scope(db);
    let own_class_members: FxHashSet<_> = all_end_of_scope_members(db, scope).collect();

    for member in own_class_members {
        check_class_declaration(context, configuration, class_specialized, scope, &member);
    }
}


Review comment (performance):
What's the reason for this change? Overriding `__replace__` doesn't seem to cause a runtime error in the same way that overriding `_replace` does:

```pycon
Python 3.13.1 (main, Jan  3 2025, 12:04:03) [Clang 15.0.0 (clang-1500.3.9.4)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from typing import NamedTuple
>>> class Foo(NamedTuple):
...     __replace__ = None
...     
>>> class Foo(NamedTuple):
...     _replace = None
...     
Traceback (most recent call last):
  File "<python-input-2>", line 1, in <module>
    class Foo(NamedTuple):
        _replace = None
  File "/Users/alexw/.pyenv/versions/3.13.1/lib/python3.13/typing.py", line 3021, in __new__
    raise AttributeError("Cannot overwrite NamedTuple attribute " + key)
AttributeError: Cannot overwrite NamedTuple attribute _replace
```

This change also doesn't seem to be tested at all?

Code after:
    semantic_index::{
        definition::DefinitionKind, place::ScopedPlaceId, place_table, scope::ScopeId,
        symbol::ScopedSymbolId, use_def_map,
    },
    types::{
        ClassBase, ClassLiteral, ClassType, KnownClass, Type,
        class::CodeGeneratorKind,
        context::InferContext,
        diagnostic::{
            INVALID_EXPLICIT_OVERRIDE, INVALID_METHOD_OVERRIDE, INVALID_NAMED_TUPLE,
            OVERRIDE_OF_FINAL_METHOD, report_invalid_method_override,
            report_overridden_final_method,
        },
        function::{FunctionDecorators, FunctionType, KnownFunction},
        list_members::{Member, MemberWithDefinition, all_end_of_scope_members},
    },
};

/// Prohibited `NamedTuple` attributes that cannot be overwritten.
/// See <https://github.com/python/cpython/blob/main/Lib/typing.py> for the list.
const PROHIBITED_NAMEDTUPLE_ATTRS: &[&str] = &[
    "__new__",
    "__init__",
    "__slots__",
    "__getnewargs__",
    "_fields",
    "_field_defaults",
    "_field_types",
    "_make",
    "_replace",
    "_asdict",
    "_source",
];

pub(super) fn check_class<'db>(context: &InferContext<'db, '_>, class: ClassLiteral<'db>) {
    let db = context.db();
    let configuration = OverrideRulesConfig::from(context);
    if configuration.no_rules_enabled() {
        return;
    }

    let class_specialized = class.identity_specialization(db);
    let scope = class.body_scope(db);
    let own_class_members: FxHashSet<_> = all_end_of_scope_members(db, scope).collect();

    for member in own_class_members {
        check_class_declaration(context, configuration, class_specialized, scope, &member);
    }
}

fn check_class_declaration<'db>(