mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-04 02:38:25 +00:00
Propagate reads on global variables (#11584)
## Summary This PR ensures that if a variable is bound via `global`, and then the `global` is read, the originating variable is also marked as read. It's not perfect, in that it won't detect _rebindings_, like: ```python from app import redis_connection def func(): global redis_connection redis_connection = 1 redis_connection() ``` So, above, `redis_connection` is still marked as unused. But it does avoid flagging `redis_connection` as unused in: ```python from app import redis_connection def func(): global redis_connection redis_connection() ``` Closes https://github.com/astral-sh/ruff/issues/11518.
This commit is contained in:
parent
4a305588e9
commit
69d9212817
6 changed files with 46 additions and 15 deletions
|
@ -470,14 +470,14 @@ pub enum BindingKind<'a> {
|
|||
/// def foo():
|
||||
/// global x
|
||||
/// ```
|
||||
Global,
|
||||
Global(Option<BindingId>),
|
||||
|
||||
/// A binding for a nonlocal variable, like `x` in:
|
||||
/// ```python
|
||||
/// def foo():
|
||||
/// nonlocal x
|
||||
/// ```
|
||||
Nonlocal(ScopeId),
|
||||
Nonlocal(BindingId, ScopeId),
|
||||
|
||||
/// A binding for a builtin, like `print` or `bool`.
|
||||
Builtin,
|
||||
|
@ -670,3 +670,14 @@ impl<'a, 'ast> Imported<'ast> for AnyImport<'a, 'ast> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::BindingKind;
|
||||
|
||||
#[test]
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
fn size() {
|
||||
assert!(std::mem::size_of::<BindingKind>() <= 24);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -540,6 +540,23 @@ impl<'a> SemanticModel<'a> {
|
|||
return ReadResult::Resolved(binding_id);
|
||||
}
|
||||
|
||||
BindingKind::Global(Some(binding_id))
|
||||
| BindingKind::Nonlocal(binding_id, _) => {
|
||||
// Mark the shadowed binding as used.
|
||||
let reference_id = self.resolved_references.push(
|
||||
self.scope_id,
|
||||
self.node_id,
|
||||
ExprContext::Load,
|
||||
self.flags,
|
||||
name.range,
|
||||
);
|
||||
self.bindings[binding_id].references.push(reference_id);
|
||||
|
||||
// Treat it as resolved.
|
||||
self.resolved_names.insert(name.into(), binding_id);
|
||||
return ReadResult::Resolved(binding_id);
|
||||
}
|
||||
|
||||
_ => {
|
||||
// Otherwise, treat it as resolved.
|
||||
self.resolved_names.insert(name.into(), binding_id);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue