diff --git a/crates/ruff/src/checkers/ast/mod.rs b/crates/ruff/src/checkers/ast/mod.rs index 6fa683363c..b11002cfd1 100644 --- a/crates/ruff/src/checkers/ast/mod.rs +++ b/crates/ruff/src/checkers/ast/mod.rs @@ -4808,7 +4808,7 @@ impl<'a> Checker<'a> { let exports: Vec<(&str, TextRange)> = { self.semantic_model .global_scope() - .bindings_for_name("__all__") + .get_all("__all__") .map(|binding_id| &self.semantic_model.bindings[binding_id]) .filter_map(|binding| match &binding.kind { BindingKind::Export(Export { names }) => { @@ -5069,7 +5069,7 @@ impl<'a> Checker<'a> { let exports: Option> = { let global_scope = self.semantic_model.global_scope(); global_scope - .bindings_for_name("__all__") + .get_all("__all__") .map(|binding_id| &self.semantic_model.bindings[binding_id]) .filter_map(|binding| match &binding.kind { BindingKind::Export(Export { names }) => Some(names.iter().copied()), diff --git a/crates/ruff/src/rules/flake8_bugbear/rules/unused_loop_control_variable.rs b/crates/ruff/src/rules/flake8_bugbear/rules/unused_loop_control_variable.rs index 6d813426a1..380628fc25 100644 --- a/crates/ruff/src/rules/flake8_bugbear/rules/unused_loop_control_variable.rs +++ b/crates/ruff/src/rules/flake8_bugbear/rules/unused_loop_control_variable.rs @@ -156,7 +156,7 @@ pub(crate) fn unused_loop_control_variable(checker: &mut Checker, target: &Expr, // used _after_ the loop. let scope = checker.semantic_model().scope(); if scope - .bindings_for_name(name) + .get_all(name) .map(|binding_id| checker.semantic_model().binding(binding_id)) .all(|binding| !binding.is_used()) { diff --git a/crates/ruff_python_semantic/src/scope.rs b/crates/ruff_python_semantic/src/scope.rs index e5100b3859..69f9cca6d8 100644 --- a/crates/ruff_python_semantic/src/scope.rs +++ b/crates/ruff_python_semantic/src/scope.rs @@ -90,24 +90,41 @@ impl<'a> Scope<'a> { self.bindings.contains_key(name) } - /// Returns the ids of all bindings defined in this scope. + /// Returns the IDs of all bindings defined in this scope. pub fn binding_ids(&self) -> impl Iterator + '_ { self.bindings.values().copied() } - /// Returns a tuple of the name and id of all bindings defined in this scope. + /// Returns a tuple of the name and ID of all bindings defined in this scope. pub fn bindings(&self) -> impl Iterator + '_ { self.bindings.iter().map(|(&name, &id)| (name, id)) } - /// Returns an iterator over all [bindings](BindingId) bound to the given name, including + /// Like [`Scope::get`], but returns all bindings with the given name, including /// those that were shadowed by later bindings. - pub fn bindings_for_name(&self, name: &str) -> impl Iterator + '_ { + pub fn get_all(&self, name: &str) -> impl Iterator + '_ { std::iter::successors(self.bindings.get(name).copied(), |id| { self.shadowed_bindings.get(id).copied() }) } + /// Like [`Scope::binding_ids`], but returns all bindings that were added to the scope, + /// including those that were shadowed by later bindings. + pub fn all_binding_ids(&self) -> impl Iterator + '_ { + self.bindings.values().copied().flat_map(|id| { + std::iter::successors(Some(id), |id| self.shadowed_bindings.get(id).copied()) + }) + } + + /// Like [`Scope::bindings`], but returns all bindings added to the scope, including those that + /// were shadowed by later bindings. + pub fn all_bindings(&self) -> impl Iterator + '_ { + self.bindings.iter().flat_map(|(&name, &id)| { + std::iter::successors(Some(id), |id| self.shadowed_bindings.get(id).copied()) + .map(move |id| (name, id)) + }) + } + /// Adds a reference to a star import (e.g., `from sys import *`) to this scope. pub fn add_star_import(&mut self, import: StarImportation<'a>) { self.star_imports.push(import);