Fix f-string interpolation escaping (#18882)

This commit is contained in:
GiGaGon 2025-06-25 01:04:15 -07:00 committed by GitHub
parent 2a0c5669f2
commit d2684a00c6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1419,9 +1419,13 @@ impl<'a> Generator<'a> {
} }
} }
fn unparse_interpolated_string_body(&mut self, values: &[ast::InterpolatedStringElement]) { fn unparse_interpolated_string_body(
&mut self,
values: &[ast::InterpolatedStringElement],
flags: AnyStringFlags,
) {
for value in values { for value in values {
self.unparse_interpolated_string_element(value); self.unparse_interpolated_string_element(value, flags);
} }
} }
@ -1431,6 +1435,7 @@ impl<'a> Generator<'a> {
debug_text: Option<&DebugText>, debug_text: Option<&DebugText>,
conversion: ConversionFlag, conversion: ConversionFlag,
spec: Option<&ast::InterpolatedStringFormatSpec>, spec: Option<&ast::InterpolatedStringFormatSpec>,
flags: AnyStringFlags,
) { ) {
let mut generator = Generator::new(self.indent, self.line_ending); let mut generator = Generator::new(self.indent, self.line_ending);
generator.unparse_expr(val, precedence::FORMATTED_VALUE); generator.unparse_expr(val, precedence::FORMATTED_VALUE);
@ -1460,19 +1465,23 @@ impl<'a> Generator<'a> {
if let Some(spec) = spec { if let Some(spec) = spec {
self.p(":"); self.p(":");
self.unparse_f_string_specifier(&spec.elements); self.unparse_f_string_specifier(&spec.elements, flags);
} }
self.p("}"); self.p("}");
} }
fn unparse_interpolated_string_element(&mut self, element: &ast::InterpolatedStringElement) { fn unparse_interpolated_string_element(
&mut self,
element: &ast::InterpolatedStringElement,
flags: AnyStringFlags,
) {
match element { match element {
ast::InterpolatedStringElement::Literal(ast::InterpolatedStringLiteralElement { ast::InterpolatedStringElement::Literal(ast::InterpolatedStringLiteralElement {
value, value,
.. ..
}) => { }) => {
self.unparse_interpolated_string_literal_element(value); self.unparse_interpolated_string_literal_element(value, flags);
} }
ast::InterpolatedStringElement::Interpolation(ast::InterpolatedElement { ast::InterpolatedStringElement::Interpolation(ast::InterpolatedElement {
expression, expression,
@ -1486,17 +1495,32 @@ impl<'a> Generator<'a> {
debug_text.as_ref(), debug_text.as_ref(),
*conversion, *conversion,
format_spec.as_deref(), format_spec.as_deref(),
flags,
), ),
} }
} }
fn unparse_interpolated_string_literal_element(&mut self, s: &str) { fn unparse_interpolated_string_literal_element(&mut self, s: &str, flags: AnyStringFlags) {
let s = s.replace('{', "{{").replace('}', "}}"); let s = s.replace('{', "{{").replace('}', "}}");
self.p(&s); if flags.prefix().is_raw() {
self.buffer += &s;
return;
}
let escape = UnicodeEscape::with_preferred_quote(&s, flags.quote_style());
if let Some(len) = escape.layout().len {
self.buffer.reserve(len);
}
escape
.write_body(&mut self.buffer)
.expect("Writing to a String buffer should never fail");
} }
fn unparse_f_string_specifier(&mut self, values: &[ast::InterpolatedStringElement]) { fn unparse_f_string_specifier(
self.unparse_interpolated_string_body(values); &mut self,
values: &[ast::InterpolatedStringElement],
flags: AnyStringFlags,
) {
self.unparse_interpolated_string_body(values, flags);
} }
/// Unparse `values` with [`Generator::unparse_f_string_body`], using `quote` as the preferred /// Unparse `values` with [`Generator::unparse_f_string_body`], using `quote` as the preferred
@ -1506,10 +1530,10 @@ impl<'a> Generator<'a> {
values: &[ast::InterpolatedStringElement], values: &[ast::InterpolatedStringElement],
flags: AnyStringFlags, flags: AnyStringFlags,
) { ) {
let mut generator = Generator::new(self.indent, self.line_ending); self.p(flags.prefix().as_str());
generator.unparse_interpolated_string_body(values); self.p(flags.quote_str());
let body = &generator.buffer; self.unparse_interpolated_string_body(values, flags);
self.p_str_repr(body, flags); self.p(flags.quote_str());
} }
fn unparse_t_string_value(&mut self, value: &ast::TStringValue) { fn unparse_t_string_value(&mut self, value: &ast::TStringValue) {
@ -1912,6 +1936,20 @@ class Foo:
assert_round_trip!(r#"f"{ chr(65) = :#x}""#); assert_round_trip!(r#"f"{ chr(65) = :#x}""#);
assert_round_trip!(r#"f"{ ( chr(65) ) = }""#); assert_round_trip!(r#"f"{ ( chr(65) ) = }""#);
assert_round_trip!(r#"f"{a=!r:0.05f}""#); assert_round_trip!(r#"f"{a=!r:0.05f}""#);
// https://github.com/astral-sh/ruff/issues/18742
assert_eq!(
round_trip(
r#"
f"{1=
}"
"#
),
r#"
f"{1=
}"
"#
.trim()
);
} }
#[test] #[test]