mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-17 09:00:26 +00:00
Preserve quote style in generated code (#15726)
## Summary This is a first step toward fixing #7799 by using the quoting style stored in the `flags` field on `ast::StringLiteral`s to select a quoting style. This PR does not include support for f-strings or byte strings. Several rules also needed small updates to pass along existing quoting styles instead of using `StringLiteralFlags::default()`. The remaining snapshot changes are intentional and should preserve the quotes from the input strings. ## Test Plan Existing tests with some accepted updates, plus a few new RUF055 tests for raw strings. --------- Co-authored-by: Alex Waygood <alex.waygood@gmail.com>
This commit is contained in:
parent
e994970538
commit
9bf138c45a
24 changed files with 550 additions and 343 deletions
|
@ -1221,14 +1221,14 @@ impl fmt::Debug for FStringElements {
|
|||
|
||||
/// An AST node that represents either a single string literal or an implicitly
|
||||
/// concatenated string literals.
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct ExprStringLiteral {
|
||||
pub range: TextRange,
|
||||
pub value: StringLiteralValue,
|
||||
}
|
||||
|
||||
/// The value representing a [`ExprStringLiteral`].
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct StringLiteralValue {
|
||||
inner: StringLiteralValueInner,
|
||||
}
|
||||
|
@ -1241,6 +1241,18 @@ impl StringLiteralValue {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns the [`StringLiteralFlags`] associated with this string literal.
|
||||
///
|
||||
/// For an implicitly concatenated string, it returns the flags for the first literal.
|
||||
pub fn flags(&self) -> StringLiteralFlags {
|
||||
self.iter()
|
||||
.next()
|
||||
.expect(
|
||||
"There should always be at least one string literal in an `ExprStringLiteral` node",
|
||||
)
|
||||
.flags
|
||||
}
|
||||
|
||||
/// Creates a new string literal with the given values that represents an
|
||||
/// implicitly concatenated strings.
|
||||
///
|
||||
|
@ -1371,12 +1383,6 @@ enum StringLiteralValueInner {
|
|||
Concatenated(ConcatenatedStringLiteral),
|
||||
}
|
||||
|
||||
impl Default for StringLiteralValueInner {
|
||||
fn default() -> Self {
|
||||
Self::Single(StringLiteral::default())
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
struct StringLiteralFlagsInner: u8 {
|
||||
|
@ -1414,10 +1420,33 @@ bitflags! {
|
|||
|
||||
/// Flags that can be queried to obtain information
|
||||
/// regarding the prefixes and quotes used for a string literal.
|
||||
#[derive(Default, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
///
|
||||
/// ## Notes on usage
|
||||
///
|
||||
/// If you're using a `Generator` from the `ruff_python_codegen` crate to generate a lint-rule fix
|
||||
/// from an existing string literal, consider passing along the [`StringLiteral::flags`] field or
|
||||
/// the result of the [`StringLiteralValue::flags`] method. If you don't have an existing string but
|
||||
/// have a `Checker` from the `ruff_linter` crate available, consider using
|
||||
/// `Checker::default_string_flags` to create instances of this struct; this method will properly
|
||||
/// handle surrounding f-strings. For usage that doesn't fit into one of these categories, the
|
||||
/// public constructor [`StringLiteralFlags::empty`] can be used.
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct StringLiteralFlags(StringLiteralFlagsInner);
|
||||
|
||||
impl StringLiteralFlags {
|
||||
/// Construct a new [`StringLiteralFlags`] with **no flags set**.
|
||||
///
|
||||
/// See [`StringLiteralFlags::with_quote_style`], [`StringLiteralFlags::with_triple_quotes`],
|
||||
/// and [`StringLiteralFlags::with_prefix`] for ways of setting the quote style (single or
|
||||
/// double), enabling triple quotes, and adding prefixes (such as `r` or `u`), respectively.
|
||||
///
|
||||
/// See the documentation for [`StringLiteralFlags`] for additional caveats on this constructor,
|
||||
/// and situations in which alternative ways to construct this struct should be used, especially
|
||||
/// when writing lint rules.
|
||||
pub fn empty() -> Self {
|
||||
Self(StringLiteralFlagsInner::empty())
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_quote_style(mut self, quote_style: Quote) -> Self {
|
||||
self.0
|
||||
|
@ -1520,7 +1549,7 @@ impl fmt::Debug for StringLiteralFlags {
|
|||
|
||||
/// An AST node that represents a single string literal which is part of an
|
||||
/// [`ExprStringLiteral`].
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct StringLiteral {
|
||||
pub range: TextRange,
|
||||
pub value: Box<str>,
|
||||
|
@ -1546,7 +1575,7 @@ impl StringLiteral {
|
|||
Self {
|
||||
range,
|
||||
value: "".into(),
|
||||
flags: StringLiteralFlags::default().with_invalid(),
|
||||
flags: StringLiteralFlags::empty().with_invalid(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2115,7 +2144,7 @@ impl From<AnyStringFlags> for StringLiteralFlags {
|
|||
value.prefix()
|
||||
)
|
||||
};
|
||||
let new = StringLiteralFlags::default()
|
||||
let new = StringLiteralFlags::empty()
|
||||
.with_quote_style(value.quote_style())
|
||||
.with_prefix(prefix);
|
||||
if value.is_triple_quoted() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue