[pep8-naming] Avoid false positive for class Bar(type(foo)) (N804) (#14683)

This commit is contained in:
Brent Westbrook 2024-11-30 17:37:28 -05:00 committed by GitHub
parent 56ae73a925
commit 9e017634cb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 43 additions and 16 deletions

View file

@ -12,7 +12,7 @@ pub fn any_qualified_base_class(
semantic: &SemanticModel,
func: &dyn Fn(QualifiedName) -> bool,
) -> bool {
any_base_class(class_def, semantic, &|expr| {
any_base_class(class_def, semantic, &mut |expr| {
semantic
.resolve_qualified_name(map_subscript(expr))
.is_some_and(func)
@ -23,12 +23,12 @@ pub fn any_qualified_base_class(
pub fn any_base_class(
class_def: &ast::StmtClassDef,
semantic: &SemanticModel,
func: &dyn Fn(&Expr) -> bool,
func: &mut dyn FnMut(&Expr) -> bool,
) -> bool {
fn inner(
class_def: &ast::StmtClassDef,
semantic: &SemanticModel,
func: &dyn Fn(&Expr) -> bool,
func: &mut dyn FnMut(&Expr) -> bool,
seen: &mut FxHashSet<BindingId>,
) -> bool {
class_def.bases().iter().any(|expr| {
@ -121,12 +121,30 @@ pub fn is_enumeration(class_def: &ast::StmtClassDef, semantic: &SemanticModel) -
})
}
/// Returns `true` if the given class is a metaclass.
pub fn is_metaclass(class_def: &ast::StmtClassDef, semantic: &SemanticModel) -> bool {
any_base_class(class_def, semantic, &|expr| match expr {
/// Whether or not a class is a metaclass. Constructed by [`is_metaclass`].
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum IsMetaclass {
Yes,
No,
Maybe,
}
impl From<IsMetaclass> for bool {
fn from(value: IsMetaclass) -> Self {
matches!(value, IsMetaclass::Yes)
}
}
/// Returns `IsMetaclass::Yes` if the given class is definitely a metaclass,
/// `IsMetaclass::No` if it's definitely *not* a metaclass, and
/// `IsMetaclass::Maybe` otherwise.
pub fn is_metaclass(class_def: &ast::StmtClassDef, semantic: &SemanticModel) -> IsMetaclass {
let mut maybe = false;
let is_base_class = any_base_class(class_def, semantic, &mut |expr| match expr {
Expr::Call(ast::ExprCall {
func, arguments, ..
}) => {
maybe = true;
// Ex) `class Foo(type(Protocol)): ...`
arguments.len() == 1 && semantic.match_builtin_expr(func.as_ref(), "type")
}
@ -144,5 +162,11 @@ pub fn is_metaclass(class_def: &ast::StmtClassDef, semantic: &SemanticModel) ->
| ["enum", "EnumMeta" | "EnumType"]
)
}),
})
});
match (is_base_class, maybe) {
(true, true) => IsMetaclass::Maybe,
(true, false) => IsMetaclass::Yes,
(false, _) => IsMetaclass::No,
}
}