mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-19 01:50:38 +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_27.py"))]
|
||||||
#[test_case(Rule::RedefinedWhileUnused, Path::new("F811_28.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_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_0.py"))]
|
||||||
#[test_case(Rule::UndefinedName, Path::new("F821_1.py"))]
|
#[test_case(Rule::UndefinedName, Path::new("F821_1.py"))]
|
||||||
#[test_case(Rule::UndefinedName, Path::new("F821_2.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 => {
|
| BindingKind::Builtin => {
|
||||||
return false;
|
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
|
// Otherwise, the shadowed binding must be a class definition, function definition,
|
||||||
// import to be considered a redefinition.
|
// import, or assignment to be considered a redefinition.
|
||||||
matches!(
|
matches!(
|
||||||
existing.kind,
|
existing.kind,
|
||||||
BindingKind::ClassDefinition(_)
|
BindingKind::ClassDefinition(_)
|
||||||
| BindingKind::FunctionDefinition(_)
|
| BindingKind::FunctionDefinition(_)
|
||||||
| BindingKind::Import(_)
|
| BindingKind::Import(_)
|
||||||
| BindingKind::FromImport(_)
|
| BindingKind::FromImport(_)
|
||||||
|
| BindingKind::Assignment
|
||||||
|
| BindingKind::NamedExprAssignment
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue