mirror of https://github.com/astral-sh/ruff
[ty] Improve semantic token classification for names (#21399)
This commit is contained in:
parent
84c3cecad6
commit
43427abb61
|
|
@ -2644,9 +2644,17 @@ def ab(a: int, *, c: int):
|
||||||
|
|
||||||
assert_snapshot!(test.hover(), @r"
|
assert_snapshot!(test.hover(), @r"
|
||||||
int | float
|
int | float
|
||||||
|
---------------------------------------------
|
||||||
|
Convert a string or number to a floating-point number, if possible.
|
||||||
|
|
||||||
---------------------------------------------
|
---------------------------------------------
|
||||||
```python
|
```python
|
||||||
int | float
|
int | float
|
||||||
|
```
|
||||||
|
---
|
||||||
|
```text
|
||||||
|
Convert a string or number to a floating-point number, if possible.
|
||||||
|
|
||||||
```
|
```
|
||||||
---------------------------------------------
|
---------------------------------------------
|
||||||
info[hover]: Hovered content is
|
info[hover]: Hovered content is
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -85,6 +85,7 @@ where
|
||||||
///
|
///
|
||||||
/// This method may panic or produce unspecified results if the provided module is from a
|
/// This method may panic or produce unspecified results if the provided module is from a
|
||||||
/// different file or Salsa revision than the module to which the node belongs.
|
/// different file or Salsa revision than the module to which the node belongs.
|
||||||
|
#[track_caller]
|
||||||
pub fn node<'ast>(&self, module_ref: &'ast ParsedModuleRef) -> &'ast T {
|
pub fn node<'ast>(&self, module_ref: &'ast ParsedModuleRef) -> &'ast T {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
assert_eq!(module_ref.module().addr(), self.module_addr);
|
assert_eq!(module_ref.module().addr(), self.module_addr);
|
||||||
|
|
|
||||||
|
|
@ -1034,7 +1034,7 @@ impl<'db> AssignmentDefinitionKind<'db> {
|
||||||
self.target_kind
|
self.target_kind
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn value<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Expr {
|
pub fn value<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Expr {
|
||||||
self.value.node(module)
|
self.value.node(module)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -761,6 +761,7 @@ pub(crate) struct DeclarationsIterator<'map, 'db> {
|
||||||
inner: LiveDeclarationsIterator<'map>,
|
inner: LiveDeclarationsIterator<'map>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub(crate) struct DeclarationWithConstraint<'db> {
|
pub(crate) struct DeclarationWithConstraint<'db> {
|
||||||
pub(crate) declaration: DefinitionState<'db>,
|
pub(crate) declaration: DefinitionState<'db>,
|
||||||
pub(crate) reachability_constraint: ScopedReachabilityConstraintId,
|
pub(crate) reachability_constraint: ScopedReachabilityConstraintId,
|
||||||
|
|
|
||||||
|
|
@ -869,7 +869,7 @@ impl<'db> Type<'db> {
|
||||||
matches!(self, Type::Dynamic(DynamicType::Todo(_)))
|
matches!(self, Type::Dynamic(DynamicType::Todo(_)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) const fn is_generic_alias(&self) -> bool {
|
pub const fn is_generic_alias(&self) -> bool {
|
||||||
matches!(self, Type::GenericAlias(_))
|
matches!(self, Type::GenericAlias(_))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1080,12 +1080,11 @@ impl<'db> Type<'db> {
|
||||||
.expect("Expected a Type::ClassLiteral variant")
|
.expect("Expected a Type::ClassLiteral variant")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) const fn is_subclass_of(&self) -> bool {
|
pub const fn is_subclass_of(&self) -> bool {
|
||||||
matches!(self, Type::SubclassOf(..))
|
matches!(self, Type::SubclassOf(..))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
pub const fn is_class_literal(&self) -> bool {
|
||||||
pub(crate) const fn is_class_literal(&self) -> bool {
|
|
||||||
matches!(self, Type::ClassLiteral(..))
|
matches!(self, Type::ClassLiteral(..))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -8585,7 +8584,7 @@ impl<'db> TypeVarInstance<'db> {
|
||||||
self.identity(db).definition(db)
|
self.identity(db).definition(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn kind(self, db: &'db dyn Db) -> TypeVarKind {
|
pub fn kind(self, db: &'db dyn Db) -> TypeVarKind {
|
||||||
self.identity(db).kind(db)
|
self.identity(db).kind(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -477,32 +477,17 @@ pub fn all_members<'db>(db: &'db dyn Db, ty: Type<'db>) -> FxHashSet<Member<'db>
|
||||||
/// Get the primary definition kind for a name expression within a specific file.
|
/// Get the primary definition kind for a name expression within a specific file.
|
||||||
/// Returns the first definition kind that is reachable for this name in its scope.
|
/// Returns the first definition kind that is reachable for this name in its scope.
|
||||||
/// This is useful for IDE features like semantic tokens.
|
/// This is useful for IDE features like semantic tokens.
|
||||||
pub fn definition_kind_for_name<'db>(
|
pub fn definition_for_name<'db>(
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
file: File,
|
file: File,
|
||||||
name: &ast::ExprName,
|
name: &ast::ExprName,
|
||||||
) -> Option<DefinitionKind<'db>> {
|
) -> Option<Definition<'db>> {
|
||||||
let index = semantic_index(db, file);
|
let definitions = definitions_for_name(db, file, name);
|
||||||
let name_str = name.id.as_str();
|
|
||||||
|
|
||||||
// Get the scope for this name expression
|
|
||||||
let file_scope = index.expression_scope_id(&ast::ExprRef::from(name));
|
|
||||||
|
|
||||||
// Get the place table for this scope
|
|
||||||
let place_table = index.place_table(file_scope);
|
|
||||||
|
|
||||||
// Look up the place by name
|
|
||||||
let symbol_id = place_table.symbol_id(name_str)?;
|
|
||||||
|
|
||||||
// Get the use-def map and look up definitions for this place
|
|
||||||
let declarations = index
|
|
||||||
.use_def_map(file_scope)
|
|
||||||
.all_reachable_symbol_declarations(symbol_id);
|
|
||||||
|
|
||||||
// Find the first valid definition and return its kind
|
// Find the first valid definition and return its kind
|
||||||
for declaration in declarations {
|
for declaration in definitions {
|
||||||
if let Some(def) = declaration.declaration.definition() {
|
if let Some(def) = declaration.definition() {
|
||||||
return Some(def.kind(db).clone());
|
return Some(def);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -617,7 +602,7 @@ pub fn definitions_for_name<'db>(
|
||||||
// If we didn't find any definitions in scopes, fallback to builtins
|
// If we didn't find any definitions in scopes, fallback to builtins
|
||||||
if resolved_definitions.is_empty() {
|
if resolved_definitions.is_empty() {
|
||||||
let Some(builtins_scope) = builtins_module_scope(db) else {
|
let Some(builtins_scope) = builtins_module_scope(db) else {
|
||||||
return Vec::new();
|
return resolved_definitions;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Special cases for `float` and `complex` in type annotation positions.
|
// Special cases for `float` and `complex` in type annotation positions.
|
||||||
|
|
@ -633,11 +618,14 @@ pub fn definitions_for_name<'db>(
|
||||||
return union
|
return union
|
||||||
.elements(db)
|
.elements(db)
|
||||||
.iter()
|
.iter()
|
||||||
|
// Use `rev` so that `complex` and `float` come first.
|
||||||
|
// This is required for hover to pick up the docstring of `complex` and `float`
|
||||||
|
// instead of `int` (hover only shows the docstring of the first definition).
|
||||||
|
.rev()
|
||||||
.filter_map(|ty| ty.as_nominal_instance())
|
.filter_map(|ty| ty.as_nominal_instance())
|
||||||
.map(|instance| {
|
.map(|instance| {
|
||||||
let definition = instance.class_literal(db).definition(db);
|
let definition = instance.class_literal(db).definition(db);
|
||||||
let parsed = parsed_module(db, definition.file(db));
|
ResolvedDefinition::Definition(definition)
|
||||||
ResolvedDefinition::FileWithRange(definition.focus_range(db, &parsed.load(db)))
|
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
}
|
}
|
||||||
|
|
@ -1243,6 +1231,14 @@ mod resolve_definition {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'db> ResolvedDefinition<'db> {
|
impl<'db> ResolvedDefinition<'db> {
|
||||||
|
pub(crate) fn definition(&self) -> Option<Definition<'db>> {
|
||||||
|
match self {
|
||||||
|
ResolvedDefinition::Definition(definition) => Some(*definition),
|
||||||
|
ResolvedDefinition::Module(_) => None,
|
||||||
|
ResolvedDefinition::FileWithRange(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn file(&self, db: &'db dyn Db) -> File {
|
fn file(&self, db: &'db dyn Db) -> File {
|
||||||
match self {
|
match self {
|
||||||
ResolvedDefinition::Definition(definition) => definition.file(db),
|
ResolvedDefinition::Definition(definition) => definition.file(db),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue