mirror of https://github.com/astral-sh/ruff
Preserve global binding kind during reassignments (#2297)
This commit is contained in:
parent
071e3fd196
commit
861df12269
|
|
@ -6,7 +6,7 @@ from typing import NewType
|
|||
GLOBAL: str = "foo"
|
||||
|
||||
|
||||
def f():
|
||||
def assign():
|
||||
global GLOBAL
|
||||
GLOBAL = "bar"
|
||||
lower = 0
|
||||
|
|
@ -18,4 +18,18 @@ def f():
|
|||
MyObj2 = namedtuple("MyObj12", ["a", "b"])
|
||||
|
||||
T = TypeVar("T")
|
||||
UserId = NewType('UserId', int)
|
||||
UserId = NewType("UserId", int)
|
||||
|
||||
|
||||
def aug_assign(rank, world_size):
|
||||
global CURRENT_PORT
|
||||
|
||||
CURRENT_PORT += 1
|
||||
if CURRENT_PORT > MAX_PORT:
|
||||
CURRENT_PORT = START_PORT
|
||||
|
||||
|
||||
def loop_assign():
|
||||
global CURRENT_PORT
|
||||
for CURRENT_PORT in range(5):
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -2,31 +2,37 @@
|
|||
# Errors.
|
||||
###
|
||||
def f():
|
||||
global x
|
||||
global X
|
||||
|
||||
|
||||
def f():
|
||||
global x
|
||||
global X
|
||||
|
||||
print(x)
|
||||
print(X)
|
||||
|
||||
|
||||
###
|
||||
# Non-errors.
|
||||
###
|
||||
def f():
|
||||
global x
|
||||
global X
|
||||
|
||||
x = 1
|
||||
X = 1
|
||||
|
||||
|
||||
def f():
|
||||
global x
|
||||
global X
|
||||
|
||||
(x, y) = (1, 2)
|
||||
(X, y) = (1, 2)
|
||||
|
||||
|
||||
def f():
|
||||
global x
|
||||
global X
|
||||
|
||||
del x
|
||||
del X
|
||||
|
||||
|
||||
def f():
|
||||
global X
|
||||
|
||||
X += 1
|
||||
|
|
|
|||
|
|
@ -3859,11 +3859,31 @@ impl<'a> Checker<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
// Assume the rebound name is used as a global or within a loop.
|
||||
let scope = self.current_scope();
|
||||
let binding = if let Some(index) = scope.values.get(&name) {
|
||||
if matches!(self.bindings[*index].kind, BindingKind::Builtin) {
|
||||
// Avoid overriding builtins.
|
||||
binding
|
||||
} else if matches!(self.bindings[*index].kind, BindingKind::Global) {
|
||||
// If the original binding was a global, and the new binding conflicts within the
|
||||
// current scope, then the new binding is also a global.
|
||||
Binding {
|
||||
runtime_usage: self.bindings[*index].runtime_usage,
|
||||
synthetic_usage: self.bindings[*index].synthetic_usage,
|
||||
typing_usage: self.bindings[*index].typing_usage,
|
||||
kind: BindingKind::Global,
|
||||
..binding
|
||||
}
|
||||
} else if matches!(self.bindings[*index].kind, BindingKind::Nonlocal) {
|
||||
// If the original binding was a nonlocal, and the new binding conflicts within the
|
||||
// current scope, then the new binding is also a nonlocal.
|
||||
Binding {
|
||||
runtime_usage: self.bindings[*index].runtime_usage,
|
||||
synthetic_usage: self.bindings[*index].synthetic_usage,
|
||||
typing_usage: self.bindings[*index].typing_usage,
|
||||
kind: BindingKind::Nonlocal,
|
||||
..binding
|
||||
}
|
||||
} else {
|
||||
Binding {
|
||||
runtime_usage: self.bindings[*index].runtime_usage,
|
||||
|
|
@ -4463,10 +4483,14 @@ impl<'a> Checker<'a> {
|
|||
for (name, index) in &scope.values {
|
||||
let binding = &self.bindings[*index];
|
||||
if matches!(binding.kind, BindingKind::Global) {
|
||||
diagnostics.push(Diagnostic::new(
|
||||
violations::GlobalVariableNotAssigned((*name).to_string()),
|
||||
binding.range,
|
||||
));
|
||||
if let Some(stmt) = &binding.source {
|
||||
if matches!(stmt.node, StmtKind::Global { .. }) {
|
||||
diagnostics.push(Diagnostic::new(
|
||||
violations::GlobalVariableNotAssigned((*name).to_string()),
|
||||
binding.range,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ source: src/rules/pylint/mod.rs
|
|||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
GlobalVariableNotAssigned: x
|
||||
GlobalVariableNotAssigned: X
|
||||
location:
|
||||
row: 5
|
||||
column: 11
|
||||
|
|
@ -13,7 +13,7 @@ expression: diagnostics
|
|||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
GlobalVariableNotAssigned: x
|
||||
GlobalVariableNotAssigned: X
|
||||
location:
|
||||
row: 9
|
||||
column: 11
|
||||
|
|
|
|||
Loading…
Reference in New Issue