mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-09 21:28:21 +00:00
Remove SemanticModel#find_binding
(#6546)
## Summary This method is almost never what you actually want, because it doesn't respect Python's scoping semantics. For example, if you call this within a class method, it will return class attributes, whereas Python actually _skips_ symbols in classes unless the load occurs within the class itself. I also want to move away from these kinds of dynamic lookups and more towards `resolve_name`, which performs a lookup based on the stored `BindingId` at the time of symbol resolution, and will make it much easier for us to separate model building from linting in the near future. ## Test Plan `cargo test`
This commit is contained in:
parent
bf4c6473c8
commit
1a9536c4e2
4 changed files with 55 additions and 65 deletions
|
@ -233,13 +233,6 @@ impl<'a> SemanticModel<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
/// Return the current [`Binding`] for a given `name`.
|
||||
pub fn find_binding(&self, member: &str) -> Option<&Binding> {
|
||||
self.current_scopes()
|
||||
.find_map(|scope| scope.get(member))
|
||||
.map(|binding_id| &self.bindings[binding_id])
|
||||
}
|
||||
|
||||
/// Return the [`BindingId`] that the given [`BindingId`] shadows, if any.
|
||||
///
|
||||
/// Note that this will only return bindings that are shadowed by a binding in a parent scope.
|
||||
|
@ -618,6 +611,11 @@ impl<'a> SemanticModel<'a> {
|
|||
Some(binding_id)
|
||||
}
|
||||
|
||||
/// Resolves the [`ast::ExprName`] to the [`BindingId`] of the symbol it refers to, if any.
|
||||
pub fn resolve_name(&self, name: &ast::ExprName) -> Option<BindingId> {
|
||||
self.resolved_names.get(&name.into()).copied()
|
||||
}
|
||||
|
||||
/// Resolves the [`Expr`] to a fully-qualified symbol-name, if `value` resolves to an imported
|
||||
/// or builtin symbol.
|
||||
///
|
||||
|
@ -642,11 +640,10 @@ impl<'a> SemanticModel<'a> {
|
|||
|
||||
// If the name was already resolved, look it up; otherwise, search for the symbol.
|
||||
let head = match_head(value)?;
|
||||
let binding = if let Some(id) = self.resolved_names.get(&head.into()) {
|
||||
self.binding(*id)
|
||||
} else {
|
||||
self.find_binding(&head.id)?
|
||||
};
|
||||
let binding = self
|
||||
.resolve_name(head)
|
||||
.or_else(|| self.lookup_symbol(&head.id))
|
||||
.map(|id| self.binding(id))?;
|
||||
|
||||
match &binding.kind {
|
||||
BindingKind::Import(Import { call_path }) => {
|
||||
|
@ -917,6 +914,11 @@ impl<'a> SemanticModel<'a> {
|
|||
self.scopes.ancestors(self.scope_id)
|
||||
}
|
||||
|
||||
/// Returns an iterator over all scopes IDs, starting from the current [`Scope`].
|
||||
pub fn current_scope_ids(&self) -> impl Iterator<Item = ScopeId> + '_ {
|
||||
self.scopes.ancestor_ids(self.scope_id)
|
||||
}
|
||||
|
||||
/// Returns the parent of the given [`Scope`], if any.
|
||||
pub fn parent_scope(&self, scope: &Scope) -> Option<&Scope<'a>> {
|
||||
scope.parent.map(|scope_id| &self.scopes[scope_id])
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue