Rename AnyStringKind -> AnyStringFlags (#11405)

## Summary

This PR renames `AnyStringKind` to `AnyStringFlags` and `AnyStringFlags`
to `AnyStringFlagsInner`.

The main motivation is to have consistent usage of "kind" and "flags".
For each string kind, it's "flags" like `StringLiteralFlags`,
`BytesLiteralFlags`, and `FStringFlags` but it was `AnyStringKind` for
the "any" variant.
This commit is contained in:
Dhruv Manilawala 2024-05-13 18:48:07 +05:30 committed by GitHub
parent be0ccabbaa
commit 6ecb4776de
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
54 changed files with 378 additions and 371 deletions

View file

@ -1,5 +1,5 @@
use ruff_formatter::write;
use ruff_python_ast::{AnyStringKind, FString};
use ruff_python_ast::{AnyStringFlags, FString};
use ruff_source_file::Locator;
use crate::prelude::*;
@ -56,7 +56,9 @@ impl Format<PyFormatContext<'_>> for FormatFString<'_> {
return result;
}
let string_kind = normalizer.choose_quotes(self.value.into(), &locator).kind();
let string_kind = normalizer
.choose_quotes(self.value.into(), &locator)
.flags();
let context = FStringContext::new(
string_kind,
@ -83,17 +85,17 @@ impl Format<PyFormatContext<'_>> for FormatFString<'_> {
#[derive(Clone, Copy, Debug)]
pub(crate) struct FStringContext {
kind: AnyStringKind,
flags: AnyStringFlags,
layout: FStringLayout,
}
impl FStringContext {
const fn new(kind: AnyStringKind, layout: FStringLayout) -> Self {
Self { kind, layout }
const fn new(flags: AnyStringFlags, layout: FStringLayout) -> Self {
Self { flags, layout }
}
pub(crate) fn kind(self) -> AnyStringKind {
self.kind
pub(crate) fn flags(self) -> AnyStringFlags {
self.flags
}
pub(crate) const fn layout(self) -> FStringLayout {

View file

@ -56,7 +56,7 @@ impl<'a> FormatFStringLiteralElement<'a> {
impl Format<PyFormatContext<'_>> for FormatFStringLiteralElement<'_> {
fn fmt(&self, f: &mut PyFormatter) -> FormatResult<()> {
let literal_content = f.context().locator().slice(self.element.range());
let normalized = normalize_string(literal_content, 0, self.context.kind(), true);
let normalized = normalize_string(literal_content, 0, self.context.flags(), true);
match &normalized {
Cow::Borrowed(_) => source_text_slice(self.element.range()).fmt(f),
Cow::Owned(normalized) => text(normalized).fmt(f),
@ -102,7 +102,7 @@ impl FStringExpressionElementContext {
// But, if the original source code already contained a newline, they'll be preserved.
//
// The Python version is irrelevant in this case.
&& !(self.parent_context.kind().is_triple_quoted() && self.has_format_spec)
&& !(self.parent_context.flags().is_triple_quoted() && self.has_format_spec)
}
}

View file

@ -3,8 +3,8 @@ use std::iter::FusedIterator;
use memchr::memchr2;
use ruff_python_ast::{
self as ast, AnyNodeRef, AnyStringKind, Expr, ExprBytesLiteral, ExprFString, ExprStringLiteral,
ExpressionRef, StringLiteral,
self as ast, AnyNodeRef, AnyStringFlags, Expr, ExprBytesLiteral, ExprFString,
ExprStringLiteral, ExpressionRef, StringLiteral,
};
use ruff_source_file::Locator;
use ruff_text_size::{Ranged, TextRange};
@ -72,7 +72,7 @@ impl<'a> AnyString<'a> {
AnyString::String(_) | AnyString::Bytes(_) => {
self.parts(Quoting::default())
.next()
.is_some_and(|part| part.kind().is_triple_quoted())
.is_some_and(|part| part.flags().is_triple_quoted())
&& memchr2(b'\n', b'\r', source[self.range()].as_bytes()).is_some()
}
AnyString::FString(fstring) => {
@ -176,7 +176,7 @@ pub(super) enum AnyStringPart<'a> {
}
impl AnyStringPart<'_> {
fn kind(&self) -> AnyStringKind {
fn flags(&self) -> AnyStringFlags {
match self {
Self::String { part, .. } => part.flags.into(),
Self::Bytes(bytes_literal) => bytes_literal.flags.into(),

View file

@ -127,7 +127,7 @@ pub(crate) fn format(normalized: &NormalizedString, f: &mut PyFormatter) -> Form
let mut lines = docstring.split('\n').peekable();
// Start the string
let kind = normalized.kind();
let kind = normalized.flags();
let quotes = StringQuotes::from(kind);
write!(f, [kind.prefix(), quotes])?;
// We track where in the source docstring we are (in source code byte offsets)
@ -1573,7 +1573,7 @@ fn docstring_format_source(
/// that avoids `content""""` and `content\"""`. This does only applies to un-escaped backslashes,
/// so `content\\ """` doesn't need a space while `content\\\ """` does.
fn needs_chaperone_space(normalized: &NormalizedString, trim_end: &str) -> bool {
trim_end.ends_with(normalized.kind().quote_style().as_char())
trim_end.ends_with(normalized.flags().quote_style().as_char())
|| trim_end.chars().rev().take_while(|c| *c == '\\').count() % 2 == 1
}

View file

@ -2,7 +2,7 @@ pub(crate) use any::AnyString;
pub(crate) use normalize::{normalize_string, NormalizedString, StringNormalizer};
use ruff_formatter::format_args;
use ruff_python_ast::str::Quote;
use ruff_python_ast::{self as ast, AnyStringKind, AnyStringPrefix};
use ruff_python_ast::{self as ast, AnyStringFlags, AnyStringPrefix};
use ruff_text_size::{Ranged, TextRange};
use crate::comments::{leading_comments, trailing_comments};
@ -87,8 +87,8 @@ impl Format<PyFormatContext<'_>> for StringQuotes {
}
}
impl From<AnyStringKind> for StringQuotes {
fn from(value: AnyStringKind) -> Self {
impl From<AnyStringFlags> for StringQuotes {
fn from(value: AnyStringFlags) -> Self {
Self {
triple: value.is_triple_quoted(),
quote_char: value.quote_style(),
@ -119,7 +119,7 @@ impl From<Quote> for QuoteStyle {
#[derive(Debug, Clone, Copy)]
pub(crate) struct StringPart {
kind: AnyStringKind,
flags: AnyStringFlags,
range: TextRange,
}
@ -131,13 +131,13 @@ impl Ranged for StringPart {
impl StringPart {
/// Use the `kind()` method to retrieve information about the
fn kind(self) -> AnyStringKind {
self.kind
fn flags(self) -> AnyStringFlags {
self.flags
}
/// Returns the range of the string's content in the source (minus prefix and quotes).
fn content_range(self) -> TextRange {
let kind = self.kind();
let kind = self.flags();
TextRange::new(
self.start() + kind.opener_len(),
self.end() - kind.closer_len(),
@ -149,7 +149,7 @@ impl From<&ast::StringLiteral> for StringPart {
fn from(value: &ast::StringLiteral) -> Self {
Self {
range: value.range,
kind: value.flags.into(),
flags: value.flags.into(),
}
}
}
@ -158,7 +158,7 @@ impl From<&ast::BytesLiteral> for StringPart {
fn from(value: &ast::BytesLiteral) -> Self {
Self {
range: value.range,
kind: value.flags.into(),
flags: value.flags.into(),
}
}
}
@ -167,7 +167,7 @@ impl From<&ast::FString> for StringPart {
fn from(value: &ast::FString) -> Self {
Self {
range: value.range,
kind: value.flags.into(),
flags: value.flags.into(),
}
}
}

View file

@ -2,7 +2,7 @@ use std::borrow::Cow;
use std::iter::FusedIterator;
use ruff_formatter::FormatContext;
use ruff_python_ast::{str::Quote, AnyStringKind};
use ruff_python_ast::{str::Quote, AnyStringFlags};
use ruff_source_file::Locator;
use ruff_text_size::{Ranged, TextRange};
@ -60,7 +60,7 @@ impl StringNormalizer {
// The reason to preserve the quotes is based on the assumption that
// the original f-string is valid in terms of quoting, and we don't
// want to change that to make it invalid.
if (context.f_string().kind().is_triple_quoted() && !string.kind().is_triple_quoted())
if (context.f_string().flags().is_triple_quoted() && !string.flags().is_triple_quoted())
|| self.target_version.supports_pep_701()
{
self.quoting
@ -78,14 +78,14 @@ impl StringNormalizer {
let first_quote_or_normalized_char_offset = raw_content
.bytes()
.position(|b| matches!(b, b'\\' | b'"' | b'\'' | b'\r' | b'{'));
let string_kind = string.kind();
let string_flags = string.flags();
let new_kind = match self.quoting(string) {
Quoting::Preserve => string_kind,
Quoting::Preserve => string_flags,
Quoting::CanChange => {
// Per PEP 8, always prefer double quotes for triple-quoted strings.
// Except when using quote-style-preserve.
let preferred_style = if string_kind.is_triple_quoted() {
let preferred_style = if string_flags.is_triple_quoted() {
// ... unless we're formatting a code snippet inside a docstring,
// then we specifically want to invert our quote style to avoid
// writing out invalid Python.
@ -146,30 +146,30 @@ impl StringNormalizer {
if let Some(first_quote_or_normalized_char_offset) =
first_quote_or_normalized_char_offset
{
if string_kind.is_raw_string() {
if string_flags.is_raw_string() {
choose_quotes_for_raw_string(
&raw_content[first_quote_or_normalized_char_offset..],
string_kind,
string_flags,
preferred_quote,
)
} else {
choose_quotes_impl(
&raw_content[first_quote_or_normalized_char_offset..],
string_kind,
string_flags,
preferred_quote,
)
}
} else {
string_kind.with_quote_style(preferred_quote)
string_flags.with_quote_style(preferred_quote)
}
} else {
string_kind
string_flags
}
}
};
QuoteSelection {
kind: new_kind,
flags: new_kind,
first_quote_or_normalized_char_offset,
}
}
@ -189,7 +189,7 @@ impl StringNormalizer {
normalize_string(
raw_content,
first_quote_or_escape_offset,
quote_selection.kind,
quote_selection.flags,
// TODO: Remove the `b'{'` in `choose_quotes` when promoting the
// `format_fstring` preview style
self.format_fstring,
@ -199,7 +199,7 @@ impl StringNormalizer {
};
NormalizedString {
kind: quote_selection.kind,
flags: quote_selection.flags,
content_range: string.content_range(),
text: normalized,
}
@ -208,22 +208,22 @@ impl StringNormalizer {
#[derive(Debug)]
pub(crate) struct QuoteSelection {
kind: AnyStringKind,
flags: AnyStringFlags,
/// Offset to the first quote character or character that needs special handling in [`normalize_string`].
first_quote_or_normalized_char_offset: Option<usize>,
}
impl QuoteSelection {
pub(crate) fn kind(&self) -> AnyStringKind {
self.kind
pub(crate) fn flags(&self) -> AnyStringFlags {
self.flags
}
}
#[derive(Debug)]
pub(crate) struct NormalizedString<'a> {
/// Holds data about the quotes and prefix of the string
kind: AnyStringKind,
flags: AnyStringFlags,
/// The range of the string's content in the source (minus prefix and quotes).
content_range: TextRange,
@ -237,8 +237,8 @@ impl<'a> NormalizedString<'a> {
&self.text
}
pub(crate) fn kind(&self) -> AnyStringKind {
self.kind
pub(crate) fn flags(&self) -> AnyStringFlags {
self.flags
}
}
@ -250,8 +250,8 @@ impl Ranged for NormalizedString<'_> {
impl Format<PyFormatContext<'_>> for NormalizedString<'_> {
fn fmt(&self, f: &mut Formatter<PyFormatContext<'_>>) -> FormatResult<()> {
let quotes = StringQuotes::from(self.kind);
ruff_formatter::write!(f, [self.kind.prefix(), quotes])?;
let quotes = StringQuotes::from(self.flags);
ruff_formatter::write!(f, [self.flags.prefix(), quotes])?;
match &self.text {
Cow::Borrowed(_) => {
source_text_slice(self.range()).fmt(f)?;
@ -271,9 +271,9 @@ impl Format<PyFormatContext<'_>> for NormalizedString<'_> {
/// style is double quotes.
fn choose_quotes_for_raw_string(
input: &str,
kind: AnyStringKind,
flags: AnyStringFlags,
preferred_quote: Quote,
) -> AnyStringKind {
) -> AnyStringFlags {
let preferred_quote_char = preferred_quote.as_char();
let mut chars = input.chars().peekable();
let contains_unescaped_configured_quotes = loop {
@ -284,7 +284,7 @@ fn choose_quotes_for_raw_string(
}
// `"` or `'`
Some(c) if c == preferred_quote_char => {
if !kind.is_triple_quoted() {
if !flags.is_triple_quoted() {
break true;
}
@ -310,9 +310,9 @@ fn choose_quotes_for_raw_string(
}
};
if contains_unescaped_configured_quotes {
kind
flags
} else {
kind.with_quote_style(preferred_quote)
flags.with_quote_style(preferred_quote)
}
}
@ -324,8 +324,12 @@ fn choose_quotes_for_raw_string(
/// For triple quoted strings, the preferred quote style is always used, unless the string contains
/// a triplet of the quote character (e.g., if double quotes are preferred, double quotes will be
/// used unless the string contains `"""`).
fn choose_quotes_impl(input: &str, kind: AnyStringKind, preferred_quote: Quote) -> AnyStringKind {
let quote = if kind.is_triple_quoted() {
fn choose_quotes_impl(
input: &str,
flags: AnyStringFlags,
preferred_quote: Quote,
) -> AnyStringFlags {
let quote = if flags.is_triple_quoted() {
// True if the string contains a triple quote sequence of the configured quote style.
let mut uses_triple_quotes = false;
let mut chars = input.chars().peekable();
@ -379,7 +383,7 @@ fn choose_quotes_impl(input: &str, kind: AnyStringKind, preferred_quote: Quote)
if uses_triple_quotes {
// String contains a triple quote sequence of the configured quote style.
// Keep the existing quote style.
kind.quote_style()
flags.quote_style()
} else {
preferred_quote
}
@ -419,7 +423,7 @@ fn choose_quotes_impl(input: &str, kind: AnyStringKind, preferred_quote: Quote)
}
};
kind.with_quote_style(quote)
flags.with_quote_style(quote)
}
/// Adds the necessary quote escapes and removes unnecessary escape sequences when quoting `input`
@ -429,7 +433,7 @@ fn choose_quotes_impl(input: &str, kind: AnyStringKind, preferred_quote: Quote)
pub(crate) fn normalize_string(
input: &str,
start_offset: usize,
kind: AnyStringKind,
flags: AnyStringFlags,
format_fstring: bool,
) -> Cow<str> {
// The normalized string if `input` is not yet normalized.
@ -439,14 +443,14 @@ pub(crate) fn normalize_string(
// If `last_index` is `0` at the end, then the input is already normalized and can be returned as is.
let mut last_index = 0;
let quote = kind.quote_style();
let quote = flags.quote_style();
let preferred_quote = quote.as_char();
let opposite_quote = quote.opposite().as_char();
let mut chars = CharIndicesWithOffset::new(input, start_offset).peekable();
let is_raw = kind.is_raw_string();
let is_fstring = !format_fstring && kind.is_f_string();
let is_raw = flags.is_raw_string();
let is_fstring = !format_fstring && flags.is_f_string();
let mut formatted_value_nesting = 0u32;
while let Some((index, c)) = chars.next() {
@ -484,7 +488,7 @@ pub(crate) fn normalize_string(
} else {
// Length of the `\` plus the length of the escape sequence character (`u` | `U` | `x`)
let escape_start_len = '\\'.len_utf8() + next.len_utf8();
if let Some(normalised) = UnicodeEscape::new(next, !kind.is_byte_string())
if let Some(normalised) = UnicodeEscape::new(next, !flags.is_byte_string())
.and_then(|escape| escape.normalize(&input[index + escape_start_len..]))
{
let escape_start_offset = index + escape_start_len;
@ -503,7 +507,7 @@ pub(crate) fn normalize_string(
}
}
if !kind.is_triple_quoted() {
if !flags.is_triple_quoted() {
#[allow(clippy::if_same_then_else)]
if next == opposite_quote && formatted_value_nesting == 0 {
// Remove the escape by ending before the backslash and starting again with the quote
@ -516,7 +520,7 @@ pub(crate) fn normalize_string(
}
}
}
} else if !kind.is_triple_quoted()
} else if !flags.is_triple_quoted()
&& c == preferred_quote
&& formatted_value_nesting == 0
{
@ -689,7 +693,7 @@ impl UnicodeEscape {
mod tests {
use std::borrow::Cow;
use ruff_python_ast::{str::Quote, AnyStringKind, AnyStringPrefix, ByteStringPrefix};
use ruff_python_ast::{str::Quote, AnyStringFlags, AnyStringPrefix, ByteStringPrefix};
use super::{normalize_string, UnicodeEscape};
@ -710,7 +714,7 @@ mod tests {
let normalized = normalize_string(
input,
0,
AnyStringKind::new(
AnyStringFlags::new(
AnyStringPrefix::Bytes(ByteStringPrefix::Regular),
Quote::Double,
false,