mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-14 15:40:51 +00:00
Use ExprFString
for StringLike::FString
variant (#10311)
## Summary This PR updates the `StringLike::FString` variant to use `ExprFString` instead of `FStringLiteralElement`. For context, the reason it used `FStringLiteralElement` is that the node is actually the string part of an f-string ("foo" in `f"foo{x}"`). But, this is inconsistent with other variants where the captured value is the _entire_ string. This is also problematic w.r.t. implicitly concatenated strings. Any rules which work with `StringLike::FString` doesn't account for the string part in an implicitly concatenated f-strings. For example, we don't flag confusable character in the first part of `"𝐁ad" f"𝐁ad string"`, but only the second part (https://play.ruff.rs/16071c4c-a1dd-4920-b56f-e2ce2f69c843). ### Update `PYI053` _This is included in this PR because otherwise it requires a temporary workaround to be compatible with the old logic._ This PR also updates the `PYI053` (`string-or-bytes-too-long`) rule for f-string to consider _all_ the visible characters in a f-string, including the ones which are implicitly concatenated. This is consistent with implicitly concatenated strings and bytes. For example, ```python def foo( # We count all the characters here arg1: str = '51 character ' 'stringgggggggggggggggggggggggggggggggg', # But not here because of the `{x}` replacement field which _breaks_ them up into two chunks arg2: str = f'51 character {x} stringgggggggggggggggggggggggggggggggggggggggggggg', ) -> None: ... ``` This PR fixes it to consider all _visible_ characters inside an f-string which includes expressions as well. fixes: #10310 fixes: #10307 ## Test Plan Add new test cases and update the snapshots. ## Review To facilitate the review process, the change have been split into two commits: one which has the code change while the other has the test cases and updated snapshots.
This commit is contained in:
parent
f7802ad5de
commit
5f40371ffc
16 changed files with 251 additions and 63 deletions
|
@ -399,35 +399,35 @@ impl LiteralExpressionRef<'_> {
|
|||
/// f-strings.
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum StringLike<'a> {
|
||||
StringLiteral(&'a ast::ExprStringLiteral),
|
||||
BytesLiteral(&'a ast::ExprBytesLiteral),
|
||||
FStringLiteral(&'a ast::FStringLiteralElement),
|
||||
String(&'a ast::ExprStringLiteral),
|
||||
Bytes(&'a ast::ExprBytesLiteral),
|
||||
FString(&'a ast::ExprFString),
|
||||
}
|
||||
|
||||
impl<'a> From<&'a ast::ExprStringLiteral> for StringLike<'a> {
|
||||
fn from(value: &'a ast::ExprStringLiteral) -> Self {
|
||||
StringLike::StringLiteral(value)
|
||||
StringLike::String(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a ast::ExprBytesLiteral> for StringLike<'a> {
|
||||
fn from(value: &'a ast::ExprBytesLiteral) -> Self {
|
||||
StringLike::BytesLiteral(value)
|
||||
StringLike::Bytes(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a ast::FStringLiteralElement> for StringLike<'a> {
|
||||
fn from(value: &'a ast::FStringLiteralElement) -> Self {
|
||||
StringLike::FStringLiteral(value)
|
||||
impl<'a> From<&'a ast::ExprFString> for StringLike<'a> {
|
||||
fn from(value: &'a ast::ExprFString) -> Self {
|
||||
StringLike::FString(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl Ranged for StringLike<'_> {
|
||||
fn range(&self) -> TextRange {
|
||||
match self {
|
||||
StringLike::StringLiteral(literal) => literal.range(),
|
||||
StringLike::BytesLiteral(literal) => literal.range(),
|
||||
StringLike::FStringLiteral(literal) => literal.range(),
|
||||
StringLike::String(literal) => literal.range(),
|
||||
StringLike::Bytes(literal) => literal.range(),
|
||||
StringLike::FString(literal) => literal.range(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue