8000 Remove nested f-string flag (#5966) · astral-sh/ruff@86b6a3e · GitHub
[go: up one dir, main page]

Skip to content

Commit 86b6a3e

Browse files
Remove nested f-string flag (#5966)
## Summary Not worth taking up a slot in the semantic model flags.
1 parent f5a2fb5 commit 86b6a3e

File tree

3 files changed

+94
-102
lines changed

3 files changed

+94
-102
lines changed

crates/ruff/src/checkers/ast/mod.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3934,11 +3934,7 @@ where
39343934
}
39353935
}
39363936
Expr::JoinedStr(_) => {
3937-
self.semantic.flags |= if self.semantic.in_f_string() {
3938-
SemanticModelFlags::NESTED_F_STRING
3939-
} else {
3940-
SemanticModelFlags::F_STRING
3941-
};
3937+
self.semantic.flags |= SemanticModelFlags::F_STRING;
39423938
visitor::walk_expr(self, expr);
39433939
}
39443940
_ => visitor::walk_expr(self, expr),

crates/ruff/src/rules/pyupgrade/rules/native_literals.rs

Lines changed: 86 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,6 @@ pub(crate) fn native_literals(
8181
return;
8282
}
8383

84-
// There's no way to rewrite, e.g., `f"{f'{str()}'}"` within a nested f-string.
85-
if checker.semantic().in_nested_f_string() {
86-
return;
87-
}
88-
8984
if !matches!(id.as_str(), "str" | "bytes") {
9085
return;
9186
}
@@ -94,80 +89,95 @@ pub(crate) fn native_literals(
9489
return;
9590
}
9691

97-
let Some(arg) = args.get(0) else {
98-
let mut diagnostic = Diagnostic::new(
99-
NativeLiterals {
100-
literal_type: if id == "str" {
101-
LiteralType::Str
92+
// There's no way to rewrite, e.g., `f"{f'{str()}'}"` within a nested f-string.
93+
if checker.semantic().in_f_string() {
94+
if checker
95+
.semantic()
96+
.expr_ancestors()
97+
.filter(|expr| expr.is_joined_str_expr())
98+
.count()
99+
> 1
100+
{
101+
return;
102+
}
103+
}
104+
105+
match args.get(0) {
106+
None => {
107+
let mut diagnostic = Diagnostic::new(
108+
NativeLiterals {
109+
literal_type: if id == "str" {
110+
LiteralType::Str
111+
} else {
112+
LiteralType::Bytes
113+
},
114+
},
115+
expr.range(),
116+
);
117+
if checker.patch(diagnostic.kind.rule()) {
118+
let constant = if id == "bytes" {
119+
Constant::Bytes(vec![])
102120
} else {
103-
LiteralType::Bytes
121+
Constant::Str(String::new())
122+
};
123+
let content = checker.generator().constant(&constant);
124+
diagnostic.set_fix(Fix::automatic(Edit::range_replacement(
125+
content,
126+
expr.range(),
127+
)));
128+
}
129+
checker.diagnostics.push(diagnostic);
130+
}
131+
Some(arg) => {
132+
// Look for `str("")`.
133+
if id == "str"
134+
&& !matches!(
135+
&arg,
136+
Expr::Constant(ast::ExprConstant {
137+
value: Constant::Str(_),
138+
..
139+
}),
140+
)
141+
{
142+
return;
143+
}
144+
145+
// Look for `bytes(b"")`
146+
if id == "bytes"
147+
&& !matches!(
148+
&arg,
149+
Expr::Constant(ast::ExprConstant {
150+
value: Constant::Bytes(_),
151+
..
152+
}),
153+
)
154+
{
155+
return;
156+
}
157+
158+
// Skip implicit string concatenations.
159+
let arg_code = checker.locator.slice(arg.range());
160+
if is_implicit_concatenation(arg_code) {
161+
return;
162+
}
163+
164+
let mut diagnostic = Diagnostic::new(
165+
NativeLiterals {
166+
literal_type: if id == "str" {
167+
LiteralType::Str
168+
} else {
169+
LiteralType::Bytes
170+
},
104171
},
105-
},
106-
expr.range(),
107-
);
108-
if checker.patch(diagnostic.kind.rule()) {
109-
let constant = if id == "bytes" {
110-
Constant::Bytes(vec![])
111-
} else {
112-
Constant::Str(String::new())
113-
};
114-
let content = checker.generator().constant(&constant);
115-
diagnostic.set_fix(Fix::automatic(Edit::range_replacement(
116-
content,
117172
expr.range(),
118-
)));
173+
);
174+
if checker.patch(diagnostic.kind.rule()) {
175+
diagnostic.set_fix(Fix::automatic(Edit::range_replacement(
176+
arg_code.to_string(),
177+
expr.range(),
178+
)));
179+
}
180+
checker.diagnostics.push(diagnostic);
119181
}
120-
checker.diagnostics.push(diagnostic);
121-
return;
122-
};
123-
124-
// Look for `str("")`.
125-
if id == "str"
126-
&& !matches!(
127-
&arg,
128-
Expr::Constant(ast::ExprConstant {
129-
value: Constant::Str(_),
130-
..
131-
}),
132-
)
133-
{
134-
return;
135-
}
136-
137-
// Look for `bytes(b"")`
138-
if id == "bytes"
139-
&& !matches!(
140-
&arg,
141-
Expr::Constant(ast::ExprConstant {
142-
value: Constant::Bytes(_),
143-
..
144-
}),
145-
)
146-
{
147-
return;
148-
}
149-
150-
// Skip implicit string concatenations.
151-
let arg_code = checker.locator.slice(arg.range());
152-
if is_implicit_concatenation(arg_code) {
153-
return;
154-
}
155-
156-
let mut diagnostic = Diagnostic::new(
157-
NativeLiterals {
158-
literal_type: if id == "str" {
159-
LiteralType::Str
160-
} else {
161-
LiteralType::Bytes
162-
},
163-
},
164-
expr.range(),
165-
);
166-
if checker.patch(diagnostic.kind.rule()) {
167-
diagnostic.set_fix(Fix::automatic(Edit::range_replacement(
168-
arg_code.to_string(),
169-
expr.range(),
170-
)));
171182
}
172-
checker.diagnostics.push(diagnostic);
173183
}

crates/ruff_python_semantic/src/model.rs

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1094,12 +1094,6 @@ impl<'a> SemanticModel<'a> {
10941094
/// Return `true` if the context is in an f-string.
10951095
pub const fn in_f_string(&self) -> bool {
10961096
self.flags.contains(SemanticModelFlags::F_STRING)
1097-
|| self.flags.contains(SemanticModelFlags::NESTED_F_STRING)
1098-
}
1099-
1100-
/// Return `true` if the context is in a nested f-string.
1101-
pub const fn in_nested_f_string(&self) -> bool {
1102-
self.flags.contains(SemanticModelFlags::NESTED_F_STRING)
11031097
}
11041098

11051099
/// Return `true` if the context is in boolean test.
@@ -1304,14 +1298,6 @@ bitflags! {
13041298
/// ```
13051299
const F_STRING = 1 << 7;
13061300

1307-
/// The context is in a nested f-string.
1308-
///
1309-
/// For example, the context could be visiting `x` in:
1310-
/// ```python
1311-
/// f'{f"{x}"}'
1312-
/// ```
1313-
const NESTED_F_STRING = 1 << 8;
1314-
13151301
/// The context is in a boolean test.
13161302
///
13171303
/// For example, the context could be visiting `x` in:
@@ -1322,7 +1308,7 @@ bitflags! {
13221308
///
13231309
/// The implication is that the actual value returned by the current expression is
13241310
/// not used, only its truthiness.
1325-
const BOOLEAN_TEST = 1 << 9;
1311+
const BOOLEAN_TEST = 1 << 8;
13261312

13271313
/// The context is in a `typing::Literal` annotation.
13281314
///
@@ -1331,15 +1317,15 @@ bitflags! {
13311317
/// def f(x: Literal["A", "B", "C"]):
13321318
/// ...
13331319
/// ```
1334-
const LITERAL = 1 << 10;
1320+
const LITERAL = 1 << 9;
13351321

13361322
/// The context is in a subscript expression.
13371323
///
13381324
/// For example, the context could be visiting `x["a"]` in:
13391325
/// ```python
13401326
/// x["a"]["b"]
13411327
/// ```
1342-
const SUBSCRIPT = 1 << 11;
1328+
const SUBSCRIPT = 1 << 10;
13431329

13441330
/// The context is in a type-checking block.
13451331
///
@@ -1351,7 +1337,7 @@ bitflags! {
13511337
/// if TYPE_CHECKING:
13521338
/// x: int = 1
13531339
/// ```
1354-
const TYPE_CHECKING_BLOCK = 1 << 12;
1340+
const TYPE_CHECKING_BLOCK = 1 << 11;
13551341

13561342
/// The context has traversed past the "top-of-file" import boundary.
13571343
///
@@ -1364,7 +1350,7 @@ bitflags! {
13641350
///
13651351
/// x: int = 1
13661352
/// ```
1367-
const IMPORT_BOUNDARY = 1 << 13;
1353+
const IMPORT_BOUNDARY = 1 << 12;
13681354

13691355
/// The context has traversed past the `__future__` import boundary.
13701356
///
@@ -1379,7 +1365,7 @@ bitflags! {
13791365
///
13801366
/// Python considers it a syntax error to import from `__future__` after
13811367
/// any other non-`__future__`-importing statements.
1382-
const FUTURES_BOUNDARY = 1 << 14;
1368+
const FUTURES_BOUNDARY = 1 << 13;
13831369

13841370
/// `__future__`-style type annotations are enabled in this context.
13851371
///
@@ -1391,7 +1377,7 @@ bitflags! {
13911377
/// def f(x: int) -> int:
13921378
/// ...
13931379
/// ```
1394-
const FUTURE_ANNOTATIONS = 1 << 15;
1380+
const FUTURE_ANNOTATIONS = 1 << 14;
13951381
}
13961382
}
13971383

0 commit comments

Comments
 (0)
0