Repository: astral-sh/ruff
File: crates/ruff_linter/src/rules/refurb/rules/metaclass_abcmeta.rs (Rust)

Code before:
/// The rule's fix is unsafe if the class has base classes. This is because the base classes might
/// be validating the class's other base classes (e.g., `typing.Protocol` does this) or otherwise
/// alter runtime behavior if more base classes are added.
///
/// ## References
/// - [Python documentation: `abc.ABC`](https://docs.python.org/3/library/abc.html#abc.ABC)
/// - [Python documentation: `abc.ABCMeta`](https://docs.python.org/3/library/abc.html#abc.ABCMeta)
#[derive(ViolationMetadata)]
#[violation_metadata(preview_since = "v0.2.0")]
pub(crate) struct MetaClassABCMeta;

impl AlwaysFixableViolation for MetaClassABCMeta {
    #[derive_message_formats]
    fn message(&self) -> String {
        "Use of `metaclass=abc.ABCMeta` to define abstract base class".to_string()
    }

    fn fix_title(&self) -> String {
        "Replace with `abc.ABC`".to_string()
    }
}

/// FURB180
pub(crate) fn metaclass_abcmeta(checker: &Checker, class_def: &StmtClassDef) {

    // Determine whether the class definition contains at least one attribute.
    let Some(arguments) = &class_def.arguments.as_ref() else {
        return;
    };

    // Identify the `metaclass` keyword.
    let Some((position, keyword)) = class_def.keywords().iter().find_position(|&keyword| {
        keyword
            .arg
            .as_ref()
            .is_some_and(|arg| arg.as_str() == "metaclass")
    }) else {
        return;
    };

    // Determine whether it's assigned to `abc.ABCMeta`.
    if !checker
        .semantic()
        .resolve_qualified_name(&keyword.value)
        .is_some_and(|qualified_name| matches!(qualified_name.segments(), ["abc", "ABCMeta"]))
    {
        return;
    }

    let applicability = if class_def.bases().is_empty() {
        Applicability::Safe

Review comment (suggestion):
```suggestion
    // Determine whether the class definition contains at least one argument.
```

Code after:
/// The rule's fix is unsafe if the class has base classes. This is because the base classes might
/// be validating the class's other base classes (e.g., `typing.Protocol` does this) or otherwise
/// alter runtime behavior if more base classes are added.
/// The rule's fix will also be marked as unsafe if the class has
/// comments in its argument list that could be deleted.
///
///
/// ## References
/// - [Python documentation: `abc.ABC`](https://docs.python.org/3/library/abc.html#abc.ABC)
/// - [Python documentation: `abc.ABCMeta`](https://docs.python.org/3/library/abc.html#abc.ABCMeta)
#[derive(ViolationMetadata)]
#[violation_metadata(preview_since = "v0.2.0")]
pub(crate) struct MetaClassABCMeta;

impl AlwaysFixableViolation for MetaClassABCMeta {
    #[derive_message_formats]
    fn message(&self) -> String {
        "Use of `metaclass=abc.ABCMeta` to define abstract base class".to_string()
    }

    fn fix_title(&self) -> String {
        "Replace with `abc.ABC`".to_string()
    }
}

/// FURB180
pub(crate) fn metaclass_abcmeta(checker: &Checker, class_def: &StmtClassDef) {
    // Determine whether the class definition contains at least one argument.
    let Some(arguments) = &class_def.arguments.as_ref() else {
        return;
    };

    // Identify the `metaclass` keyword.
    let Some((position, keyword)) = class_def.keywords().iter().find_position(|&keyword| {
        keyword
            .arg
            .as_ref()
            .is_some_and(|arg| arg.as_str() == "metaclass")
    }) else {
        return;
    };

    // Determine whether it's assigned to `abc.ABCMeta`.
    if !checker
        .semantic()
        .resolve_qualified_name(&keyword.value)
        .is_some_and(|qualified_name| matches!(qualified_name.segments(), ["abc", "ABCMeta"]))
    {
        return;
    }