Skip to content

Commit 1d97f27

Browse files
authored
Start tracking quoting style in the AST (#10298)
This PR modifies our AST so that nodes for string literals, bytes literals and f-strings all retain the following information: - The quoting style used (double or single quotes) - Whether the string is triple-quoted or not - Whether the string is raw or not This PR is a followup to #10256. Like with that PR, this PR does not, in itself, fix any bugs. However, it means that we will have the necessary information to preserve quoting style and rawness of strings in the `ExprGenerator` in a followup PR, which will allow us to provide a fix for #7799. The information is recorded on the AST nodes using a bitflag field on each node, similarly to how we recorded the information on `Tok::String`, `Tok::FStringStart` and `Tok::FStringMiddle` tokens in #10298. Rather than reusing the bitflag I used for the tokens, however, I decided to create a custom bitflag for each AST node. Using different bitflags for each node allows us to make invalid states unrepresentable: it is valid to set a `u` prefix on a string literal, but not on a bytes literal or an f-string. It also allows us to have better debug representations for each AST node modified in this PR.
1 parent 965adbe commit 1d97f27

File tree

81 files changed

+4150
-3173
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+4150
-3173
lines changed

crates/ruff_linter/src/rules/flake8_quotes/settings.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ impl Default for Quote {
2222
}
2323
}
2424

25-
impl From<ruff_python_parser::QuoteStyle> for Quote {
26-
fn from(value: ruff_python_parser::QuoteStyle) -> Self {
25+
impl From<ruff_python_ast::str::QuoteStyle> for Quote {
26+
fn from(value: ruff_python_ast::str::QuoteStyle) -> Self {
2727
match value {
28-
ruff_python_parser::QuoteStyle::Double => Self::Double,
29-
ruff_python_parser::QuoteStyle::Single => Self::Single,
28+
ruff_python_ast::str::QuoteStyle::Double => Self::Double,
29+
ruff_python_ast::str::QuoteStyle::Single => Self::Single,
3030
}
3131
}
3232
}

crates/ruff_linter/src/rules/flake8_simplify/rules/ast_expr.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use ast::{StringLiteralFlags, StringLiteralPrefix};
12
use ruff_python_ast::{self as ast, Arguments, Expr};
23
use ruff_text_size::Ranged;
34

@@ -218,7 +219,13 @@ fn check_os_environ_subscript(checker: &mut Checker, expr: &Expr) {
218219
);
219220
let node = ast::StringLiteral {
220221
value: capital_env_var.into_boxed_str(),
221-
unicode: env_var.is_unicode(),
222+
flags: StringLiteralFlags::default().with_prefix({
223+
if env_var.is_unicode() {
224+
StringLiteralPrefix::UString
225+
} else {
226+
StringLiteralPrefix::None
227+
}
228+
}),
222229
..ast::StringLiteral::default()
223230
};
224231
let new_env_var = node.into();

crates/ruff_linter/src/rules/flynt/rules/static_join_to_fstring.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use ast::FStringFlags;
12
use itertools::Itertools;
23

34
use crate::fix::edits::pad;
@@ -97,6 +98,7 @@ fn build_fstring(joiner: &str, joinees: &[Expr]) -> Option<Expr> {
9798
let node = ast::FString {
9899
elements: f_string_elements,
99100
range: TextRange::default(),
101+
flags: FStringFlags::default(),
100102
};
101103
Some(node.into())
102104
}

crates/ruff_linter/src/rules/pylint/rules/unspecified_encoding.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use anyhow::Result;
22

3+
use ast::StringLiteralFlags;
34
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Fix};
45
use ruff_macros::{derive_message_formats, violation};
56
use ruff_python_ast as ast;
@@ -106,7 +107,7 @@ fn generate_keyword_fix(checker: &Checker, call: &ast::ExprCall) -> Fix {
106107
.expr(&Expr::StringLiteral(ast::ExprStringLiteral {
107108
value: ast::StringLiteralValue::single(ast::StringLiteral {
108109
value: "locale".to_string().into_boxed_str(),
109-
unicode: false,
110+
flags: StringLiteralFlags::default(),
110111
range: TextRange::default(),
111112
}),
112113
range: TextRange::default(),

crates/ruff_linter/src/rules/pyupgrade/rules/unicode_kind_prefix.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ impl AlwaysFixableViolation for UnicodeKindPrefix {
4040

4141
/// UP025
4242
pub(crate) fn unicode_kind_prefix(checker: &mut Checker, string: &StringLiteral) {
43-
if string.unicode {
43+
if string.flags.is_u_string() {
4444
let mut diagnostic = Diagnostic::new(UnicodeKindPrefix, string.range);
4545
diagnostic.set_fix(Fix::safe_edit(Edit::range_deletion(TextRange::at(
4646
string.start(),

crates/ruff_python_ast/src/node.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -4430,7 +4430,11 @@ impl AstNode for ast::FString {
44304430
where
44314431
V: PreorderVisitor<'a> + ?Sized,
44324432
{
4433-
let ast::FString { elements, range: _ } = self;
4433+
let ast::FString {
4434+
elements,
4435+
range: _,
4436+
flags: _,
4437+
} = self;
44344438

44354439
for fstring_element in elements {
44364440
visitor.visit_f_string_element(fstring_element);

0 commit comments

Comments
 (0)