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

Code before:
    }

    /// Whether the completion that would be built from the
    /// given builder should be excluded based on this context.
    ///
    /// This only returns `true` when it is definitively known that the
    /// completion would never be valid for this context.
    fn exclude(&self, db: &dyn Db, builder: &CompletionBuilder<'_>) -> bool {
        if self.is_raising_exception && builder.is_notimplemented(db) {
            return true;
        }
        if builder.kind == Some(CompletionKind::Keyword)
            && let Some(ref valid_keywords) = self.valid_keywords
        {
            return !valid_keywords.contains(builder.name.as_str());
        }
        // Exclude classes that are already listed as base classes in the class definition.
        if self.is_in_class_def {
            // For in-scope completions, check if the simple name matches.
            if builder.import.is_none() && self.existing_class_bases.contains(&builder.name) {
                return true;
            }
            // For auto-import completions, check if the qualified name matches.
            // This handles cases like `class Foo(mod.Bar, ...)` where we want to
            // filter out auto-import suggestions for `Bar` from module `mod`.
            if let Some(module_name) = builder.module_name {
                let qualified = Name::new(format!("{}.{}", module_name, builder.name));
                if self.existing_class_bases.contains(&qualified) {
                    return true;
                }
            }
        }
        false
    }
}

/// Extracts the names of base classes from a class definition.
///
/// For simple name references (e.g., `Foo`), returns the name as-is.
/// For attribute accesses (e.g., `mod.Foo`), returns the full dotted path.
fn extract_base_class_names(class_def: &ast::StmtClassDef) -> FxHashSet<Name> {
    class_def
        .bases()
        .iter()
        .filter_map(|expr| UnqualifiedName::from_expr(expr).map(|name| Name::new(name.to_string())))
        .collect()
}

/// Relevance information assigned to a single completion.
///
/// A "lesser" rank means the completion appears higher in the

Review comment (suggestion):
Hmmm I'm not sure this is quite correct. e.g.,

```python
import foo

class MyClass(foo.Bar, foo.B<CURSOR>): pass
```

The completions returned on `foo.B<CURSOR>` won't have an import attached to them (because `foo` is already in scope). But the name on the completions won't be qualified. And indeed, the completions returned in that case won't have a module name associated with them at all. So you'll end up searching for `Bar` against `foo.Bar` and thus not find a match.

With that said, I don't think this will hide completions that it shouldn't. I think it just won't hide some completions that it should. So this is not really making anything worse.

I think fixing this particular issue is a bigger change so I'd be okay landing with this flaw personally.

Code after:

    /// Whether we're in a class definition context.
    fn is_in_class_def(&self) -> bool {
        self.existing_class_bases.is_some()
    }

    /// Whether the completion that would be built from the
    /// given builder should be excluded based on this context.
    ///
    /// This only returns `true` when it is definitively known that the
    /// completion would never be valid for this context.
    fn exclude(&self, db: &dyn Db, builder: &CompletionBuilder<'_>) -> bool {
        if self.is_raising_exception && builder.is_notimplemented(db) {
            return true;
        }
        if builder.kind == Some(CompletionKind::Keyword)
            && let Some(ref valid_keywords) = self.valid_keywords
        {
            return !valid_keywords.contains(builder.name.as_str());
        }
        // Exclude classes that are already listed as base classes in the class definition.
        if let Some(ref existing_class_bases) = self.existing_class_bases {
            // For in-scope completions, check if the simple name matches.
            if builder.import.is_none() && existing_class_bases.contains(&builder.name) {
                return true;
            }
            // For auto-import completions, check if the qualified name matches.
            // This handles cases like `class Foo(mod.Bar, ...)` where we want to
            // filter out auto-import suggestions for `Bar` from module `mod`.
            if let Some(ref qualified) = builder.qualified
                && existing_class_bases.contains(qualified)
            {
                return true;
            }
        }
        false
    }
}

/// Extracts the names of base classes from a class definition.
///
/// For simple name references (e.g., `Foo`), returns the name as-is.
/// For attribute accesses (e.g., `mod.Foo`), returns the full dotted path.
fn extract_base_class_names(class_def: &ast::StmtClassDef) -> FxHashSet<Name> {
    class_def
        .bases()
        .iter()
        .filter_map(|expr| UnqualifiedName::from_expr(expr).map(|name| Name::new(name.to_string())))
        .collect()
}