Repository: astral-sh/ruff
File: crates/ty_ide/src/completion.rs (Rust)

Code before:
            }
            _ => {}
        }
    }
}

/// Detect and add completions for unset class arguments.
///
/// Some arugments we know are always valid and thus they are easy
/// to provide. The `metaclass` keyword is always valid.
/// For `typing.TypedDict` subclasses, we add
/// `TypedDict` specific keywords like `total`.
fn add_class_arg_completions<'db>(
    model: &SemanticModel<'db>,
    class_def: &ast::StmtClassDef,
    completions: &mut Completions<'db>,
) {
    let is_set = |name| {
        class_def
            .arguments
            .as_ref()
            .is_some_and(|args| args.find_keyword(name).is_some())
    };

    if !is_set("metaclass") {
        let ty = Some(KnownClass::Type.to_instance(model.db()));
        completions.add(Completion::argument("metaclass", ty, None));
    }

    // TODO: Handle PEP 728 that adds two extra keywords,
    // closed and extra_items.
    //
    // See https://peps.python.org/pep-0728/
    if is_typed_dict_class_def(model, class_def) && !is_set("total") {
        let ty = Some(KnownClass::Bool.to_instance(model.db()));
        completions.add(Completion::argument("total", ty, None));
    }
}

/// Detect and add completions for unset function arguments.
///
/// Suggestions are only provided if the cursor is currently inside a
/// function call and the function arguments have not 1) already been
/// set and 2) been defined as positional-only.
fn add_function_arg_completions<'db>(
    db: &'db dyn Db,
    file: File,
    cursor: &ContextCursor<'_>,
    completions: &mut Completions<'db>,
) {
    debug_assert!(

Review comment (suggestion):
While this is an accurate type, I think we can be more specific: the object passed to the `metaclass=` keyword not only needs to be an instance of `type`, it also needs to be a _subclass_ of `type` (it must inhabit the type `type[type]`):

```suggestion
        let ty = Some(KnownClass::Type.to_subclass_of(model.db()));
```

Code after:
    }

    let is_typed_dict = class_def
        .inferred_type(model)
        .and_then(Type::as_class_literal)
        .is_some_and(|t| t.is_typed_dict(model.db()));

    // TODO: Handle PEP 728 that adds two extra keywords,
    // closed and extra_items.
    //
    // See https://peps.python.org/pep-0728/
    if is_typed_dict && !is_set("total") {
        let ty = Some(KnownClass::Bool.to_instance(model.db()));
        completions.add(Completion::argument("total", ty, None));
    }
}

/// Detect and add completions for unset function arguments.
///
/// Suggestions are only provided if the cursor is currently inside a
/// function call and the function arguments have not 1) already been
/// set and 2) been defined as positional-only.
fn add_function_arg_completions<'db>(
    db: &'db dyn Db,
    file: File,
    cursor: &ContextCursor<'_>,
    completions: &mut Completions<'db>,
) {
    debug_assert!(
        cursor
            .covering_node(cursor.range)
            .ancestors()
            .take_while(|node| !node.is_statement())
            .any(|node| node.is_arguments()),
        "Should only be called if we're already certain we're in an arguments node to avoid \
        adding completions for something like `(<CURSOR>)(arg1, arg2)`-style expressions"
    );

    let Some(sig_help) = signature_help(db, file, cursor.offset) else {
        return;
    };
    let set_function_args = detect_set_function_args(cursor);

    for sig in &sig_help.signatures {
        for p in &sig.parameters {
            if p.is_positional_only || set_function_args.contains(&p.name.as_str()) {
                continue;
            }

            completions.add(Completion::argument(
                &p.name,