mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-26 11:59:35 +00:00
Preserve scopes when checking deferred strings (#758)
This commit is contained in:
parent
374d57d822
commit
ff0e5f5cb4
4 changed files with 52 additions and 8 deletions
14
resources/test/fixtures/F821_5.py
vendored
Normal file
14
resources/test/fixtures/F821_5.py
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
"""Test: inner class annotation."""
|
||||
|
||||
|
||||
class RandomClass:
|
||||
def random_func(self) -> "InnerClass":
|
||||
pass
|
||||
|
||||
|
||||
class OuterClass:
|
||||
class InnerClass:
|
||||
pass
|
||||
|
||||
def failing_func(self) -> "InnerClass":
|
||||
return self.InnerClass()
|
|
@ -65,7 +65,7 @@ pub struct Checker<'a> {
|
|||
scopes: Vec<Scope<'a>>,
|
||||
scope_stack: Vec<usize>,
|
||||
dead_scopes: Vec<usize>,
|
||||
deferred_string_annotations: Vec<(Range, &'a str)>,
|
||||
deferred_string_annotations: Vec<(Range, &'a str, Vec<usize>, Vec<usize>)>,
|
||||
deferred_annotations: Vec<(&'a Expr, Vec<usize>, Vec<usize>)>,
|
||||
deferred_functions: Vec<(&'a Stmt, Vec<usize>, Vec<usize>, VisibleScope)>,
|
||||
deferred_lambdas: Vec<(&'a Expr, Vec<usize>, Vec<usize>)>,
|
||||
|
@ -1042,8 +1042,12 @@ where
|
|||
..
|
||||
} = &expr.node
|
||||
{
|
||||
self.deferred_string_annotations
|
||||
.push((Range::from_located(expr), value));
|
||||
self.deferred_string_annotations.push((
|
||||
Range::from_located(expr),
|
||||
value,
|
||||
self.scope_stack.clone(),
|
||||
self.parent_stack.clone(),
|
||||
));
|
||||
} else {
|
||||
self.deferred_annotations.push((
|
||||
expr,
|
||||
|
@ -1569,8 +1573,12 @@ where
|
|||
..
|
||||
} => {
|
||||
if self.in_annotation && !self.in_literal {
|
||||
self.deferred_string_annotations
|
||||
.push((Range::from_located(expr), value));
|
||||
self.deferred_string_annotations.push((
|
||||
Range::from_located(expr),
|
||||
value,
|
||||
self.scope_stack.clone(),
|
||||
self.parent_stack.clone(),
|
||||
));
|
||||
}
|
||||
if self.settings.enabled.contains(&CheckCode::S104) {
|
||||
if let Some(check) = flake8_bandit::plugins::hardcoded_bind_all_interfaces(
|
||||
|
@ -2128,6 +2136,7 @@ impl<'a> Checker<'a> {
|
|||
let mut import_starred = false;
|
||||
for scope_index in self.scope_stack.iter().rev() {
|
||||
let scope = &mut self.scopes[*scope_index];
|
||||
|
||||
if matches!(scope.kind, ScopeKind::Class(_)) {
|
||||
if id == "__class__" {
|
||||
return;
|
||||
|
@ -2344,8 +2353,8 @@ impl<'a> Checker<'a> {
|
|||
|
||||
fn check_deferred_annotations(&mut self) {
|
||||
while let Some((expr, scopes, parents)) = self.deferred_annotations.pop() {
|
||||
self.parent_stack = parents;
|
||||
self.scope_stack = scopes;
|
||||
self.parent_stack = parents;
|
||||
self.visit_expr(expr);
|
||||
}
|
||||
}
|
||||
|
@ -2354,10 +2363,14 @@ impl<'a> Checker<'a> {
|
|||
where
|
||||
'b: 'a,
|
||||
{
|
||||
while let Some((range, expression)) = self.deferred_string_annotations.pop() {
|
||||
let mut stacks = vec![];
|
||||
while let Some((range, expression, scopes, parents)) =
|
||||
self.deferred_string_annotations.pop()
|
||||
{
|
||||
if let Ok(mut expr) = parser::parse_expression(expression, "<filename>") {
|
||||
relocate_expr(&mut expr, range);
|
||||
allocator.push(expr);
|
||||
stacks.push((scopes, parents));
|
||||
} else {
|
||||
if self.settings.enabled.contains(&CheckCode::F722) {
|
||||
self.add_check(Check::new(
|
||||
|
@ -2367,7 +2380,9 @@ impl<'a> Checker<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
for expr in allocator {
|
||||
for (expr, (scopes, parents)) in allocator.iter().zip(stacks) {
|
||||
self.scope_stack = scopes;
|
||||
self.parent_stack = parents;
|
||||
self.visit_expr(expr);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -456,6 +456,7 @@ mod tests {
|
|||
#[test_case(CheckCode::F821, Path::new("F821_2.py"); "F821_2")]
|
||||
#[test_case(CheckCode::F821, Path::new("F821_3.py"); "F821_3")]
|
||||
#[test_case(CheckCode::F821, Path::new("F821_4.py"); "F821_4")]
|
||||
#[test_case(CheckCode::F821, Path::new("F821_5.py"); "F821_5")]
|
||||
#[test_case(CheckCode::F822, Path::new("F822.py"); "F822")]
|
||||
#[test_case(CheckCode::F823, Path::new("F823.py"); "F823")]
|
||||
#[test_case(CheckCode::F831, Path::new("F831.py"); "F831")]
|
||||
|
|
14
src/snapshots/ruff__linter__tests__F821_F821_5.py.snap
Normal file
14
src/snapshots/ruff__linter__tests__F821_F821_5.py.snap
Normal file
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
source: src/linter.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind:
|
||||
UndefinedName: InnerClass
|
||||
location:
|
||||
row: 5
|
||||
column: 29
|
||||
end_location:
|
||||
row: 5
|
||||
column: 41
|
||||
fix: ~
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue