Skip to content

Commit

Permalink
Avoid parsing ForwardRef contents as type references
Browse files Browse the repository at this point in the history
  • Loading branch information
charliermarsh committed Mar 23, 2023
1 parent f58345d commit 00f5a19
Show file tree
Hide file tree
Showing 10 changed files with 72 additions and 13 deletions.
8 changes: 8 additions & 0 deletions crates/ruff/resources/test/fixtures/pyflakes/F821_13.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""Test case: ForwardRef."""

from typing import ForwardRef, TypeVar

X = ForwardRef("List[int]")
Y: ForwardRef("List[int]")

Z = TypeVar("X", "List[int]", "int")
7 changes: 7 additions & 0 deletions crates/ruff/resources/test/fixtures/pyflakes/F821_14.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"""Test case: f-strings in type annotations."""

from typing import List

x = 1

x: List[f"i{x}nt"] = []
9 changes: 9 additions & 0 deletions crates/ruff/resources/test/fixtures/pyflakes/F821_15.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"""Test case: f-strings in future type annotations."""

from __future__ import annotations

from typing import List

x = 1

x: List[f"i{x}nt"] = []
20 changes: 8 additions & 12 deletions crates/ruff/src/checkers/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2135,7 +2135,8 @@ where
}

fn visit_expr(&mut self, expr: &'b Expr) {
if !self.ctx.in_deferred_type_definition
if !self.ctx.in_f_string
&& !self.ctx.in_deferred_type_definition
&& self.ctx.in_deferred_string_type_definition.is_none()
&& self.ctx.in_type_definition
&& self.ctx.annotations_future_enabled
Expand Down Expand Up @@ -3288,7 +3289,7 @@ where
value: Constant::Str(value),
kind,
} => {
if self.ctx.in_type_definition && !self.ctx.in_literal {
if self.ctx.in_type_definition && !self.ctx.in_literal && !self.ctx.in_f_string {
self.deferred.string_type_definitions.push((
Range::from(expr),
value,
Expand Down Expand Up @@ -3426,9 +3427,7 @@ where
keywords,
} => {
let callable = self.ctx.resolve_call_path(func).and_then(|call_path| {
if self.ctx.match_typing_call_path(&call_path, "ForwardRef") {
Some(Callable::ForwardRef)
} else if self.ctx.match_typing_call_path(&call_path, "cast") {
if self.ctx.match_typing_call_path(&call_path, "cast") {
Some(Callable::Cast)
} else if self.ctx.match_typing_call_path(&call_path, "NewType") {
Some(Callable::NewType)
Expand All @@ -3455,12 +3454,6 @@ where
}
});
match callable {
Some(Callable::ForwardRef) => {
self.visit_expr(func);
for expr in args {
visit_type_definition!(self, expr);
}
}
Some(Callable::Cast) => {
self.visit_expr(func);
if !args.is_empty() {
Expand Down Expand Up @@ -3569,7 +3562,7 @@ where
}
}
}
None => {
_ => {
// If we're in a type definition, we need to treat the arguments to any
// other callables as non-type definitions (i.e., we don't want to treat
// any strings as deferred type definitions).
Expand Down Expand Up @@ -3637,7 +3630,10 @@ where
self.ctx.in_subscript = prev_in_subscript;
}
ExprKind::JoinedStr { .. } => {
let prev_in_f_string = self.ctx.in_f_string;
self.ctx.in_f_string = true;
visitor::walk_expr(self, expr);
self.ctx.in_f_string = prev_in_f_string;
}
_ => visitor::walk_expr(self, expr),
}
Expand Down
3 changes: 3 additions & 0 deletions crates/ruff/src/rules/pyflakes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ mod tests {
#[test_case(Rule::UndefinedName, Path::new("F821_10.py"); "F821_10")]
#[test_case(Rule::UndefinedName, Path::new("F821_11.py"); "F821_11")]
#[test_case(Rule::UndefinedName, Path::new("F821_12.py"); "F821_12")]
#[test_case(Rule::UndefinedName, Path::new("F821_13.py"); "F821_13")]
#[test_case(Rule::UndefinedName, Path::new("F821_14.py"); "F821_14")]
#[test_case(Rule::UndefinedName, Path::new("F821_15.py"); "F821_15")]
#[test_case(Rule::UndefinedExport, Path::new("F822_0.py"); "F822_0")]
#[test_case(Rule::UndefinedExport, Path::new("F822_1.py"); "F822_1")]
#[test_case(Rule::UndefinedExport, Path::new("F822_2.py"); "F822_2")]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
source: crates/ruff/src/rules/pyflakes/mod.rs
expression: diagnostics
---
- kind:
name: UndefinedName
body: "Undefined name `List`"
suggestion: ~
fixable: false
location:
row: 8
column: 18
end_location:
row: 8
column: 22
fix: ~
parent: ~

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
source: crates/ruff/src/rules/pyflakes/mod.rs
expression: diagnostics
---
[]

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
source: crates/ruff/src/rules/pyflakes/mod.rs
expression: diagnostics
---
[]

2 changes: 2 additions & 0 deletions crates/ruff_python_ast/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ pub struct Context<'a> {
pub in_deferred_string_type_definition: Option<AnnotationKind>,
pub in_deferred_type_definition: bool,
pub in_exception_handler: bool,
pub in_f_string: bool,
pub in_literal: bool,
pub in_subscript: bool,
pub in_type_checking_block: bool,
Expand Down Expand Up @@ -83,6 +84,7 @@ impl<'a> Context<'a> {
in_deferred_string_type_definition: None,
in_deferred_type_definition: false,
in_exception_handler: false,
in_f_string: false,
in_literal: false,
in_subscript: false,
in_type_checking_block: false,
Expand Down
6 changes: 5 additions & 1 deletion crates/ruff_python_ast/src/typing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use crate::str;
use crate::types::Range;

pub enum Callable {
ForwardRef,
Cast,
NewType,
TypeVar,
Expand Down Expand Up @@ -93,6 +92,11 @@ pub fn parse_type_annotation(
range: Range,
locator: &Locator,
) -> Result<(Expr, AnnotationKind)> {
println!(
"parse_type_annotation: value: {}, range: {:?}",
value, range
);

let expression = locator.slice(range);
let body = str::raw_contents(expression);
if body == value {
Expand Down

0 comments on commit 00f5a19

Please sign in to comment.