mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-03 10:23:11 +00:00
[pyflakes
] Detect assignments that shadow definitions (F811
) (#11961)
## Summary This PR updates `F811` rule to include assignment as possible shadowed binding. This will fix issue: #11828 . ## Test Plan Add a test file, F811_30.py, which includes a redefinition after an assignment and a verified snapshot file.
This commit is contained in:
parent
c3f61a012e
commit
068b75cc8e
4 changed files with 85 additions and 2 deletions
37
crates/ruff_linter/resources/test/fixtures/pyflakes/F811_30.py
vendored
Normal file
37
crates/ruff_linter/resources/test/fixtures/pyflakes/F811_30.py
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
"""Regression test for: https://github.com/astral-sh/ruff/issues/11828"""
|
||||
|
||||
|
||||
class A:
|
||||
"""A."""
|
||||
|
||||
def foo(self) -> None:
|
||||
"""Foo."""
|
||||
|
||||
bar = foo
|
||||
|
||||
def bar(self) -> None:
|
||||
"""Bar."""
|
||||
|
||||
|
||||
class B:
|
||||
"""B."""
|
||||
def baz(self) -> None:
|
||||
"""Baz."""
|
||||
|
||||
baz = 1
|
||||
|
||||
|
||||
class C:
|
||||
"""C."""
|
||||
def foo(self) -> None:
|
||||
"""Foo."""
|
||||
|
||||
bar = (foo := 1)
|
||||
|
||||
|
||||
class D:
|
||||
"""D."""
|
||||
foo = 1
|
||||
foo = 2
|
||||
bar = (foo := 3)
|
||||
bar = (foo := 4)
|
|
@ -125,6 +125,7 @@ mod tests {
|
|||
#[test_case(Rule::RedefinedWhileUnused, Path::new("F811_27.py"))]
|
||||
#[test_case(Rule::RedefinedWhileUnused, Path::new("F811_28.py"))]
|
||||
#[test_case(Rule::RedefinedWhileUnused, Path::new("F811_29.pyi"))]
|
||||
#[test_case(Rule::RedefinedWhileUnused, Path::new("F811_30.py"))]
|
||||
#[test_case(Rule::UndefinedName, Path::new("F821_0.py"))]
|
||||
#[test_case(Rule::UndefinedName, Path::new("F821_1.py"))]
|
||||
#[test_case(Rule::UndefinedName, Path::new("F821_2.py"))]
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pyflakes/mod.rs
|
||||
---
|
||||
F811_30.py:12:9: F811 Redefinition of unused `bar` from line 10
|
||||
|
|
||||
10 | bar = foo
|
||||
11 |
|
||||
12 | def bar(self) -> None:
|
||||
| ^^^ F811
|
||||
13 | """Bar."""
|
||||
|
|
||||
= help: Remove definition: `bar`
|
||||
|
||||
F811_30.py:21:5: F811 Redefinition of unused `baz` from line 18
|
||||
|
|
||||
19 | """Baz."""
|
||||
20 |
|
||||
21 | baz = 1
|
||||
| ^^^ F811
|
||||
|
|
||||
= help: Remove definition: `baz`
|
||||
|
||||
F811_30.py:29:12: F811 Redefinition of unused `foo` from line 26
|
||||
|
|
||||
27 | """Foo."""
|
||||
28 |
|
||||
29 | bar = (foo := 1)
|
||||
| ^^^ F811
|
||||
|
|
||||
= help: Remove definition: `foo`
|
|
@ -177,16 +177,31 @@ impl<'a> Binding<'a> {
|
|||
| BindingKind::Builtin => {
|
||||
return false;
|
||||
}
|
||||
// Assignment-assignment bindings are not considered redefinitions, as in:
|
||||
// ```python
|
||||
// x = 1
|
||||
// x = 2
|
||||
// ```
|
||||
BindingKind::Assignment | BindingKind::NamedExprAssignment => {
|
||||
if matches!(
|
||||
existing.kind,
|
||||
BindingKind::Assignment | BindingKind::NamedExprAssignment
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
// Otherwise, the shadowed binding must be a class definition, function definition, or
|
||||
// import to be considered a redefinition.
|
||||
// Otherwise, the shadowed binding must be a class definition, function definition,
|
||||
// import, or assignment to be considered a redefinition.
|
||||
matches!(
|
||||
existing.kind,
|
||||
BindingKind::ClassDefinition(_)
|
||||
| BindingKind::FunctionDefinition(_)
|
||||
| BindingKind::Import(_)
|
||||
| BindingKind::FromImport(_)
|
||||
| BindingKind::Assignment
|
||||
| BindingKind::NamedExprAssignment
|
||||
)
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue