From 50044bf8178d0b0f7e121b6dc53d147777c9c89a Mon Sep 17 00:00:00 2001 From: David Szotten Date: Tue, 8 Aug 2023 15:26:19 +0100 Subject: [PATCH 01/17] ast for JoinedStringPart --- crates/ruff_python_ast/src/comparable.rs | 48 +++++++---- crates/ruff_python_ast/src/expression.rs | 9 --- crates/ruff_python_ast/src/helpers.rs | 48 ++++++----- crates/ruff_python_ast/src/node.rs | 81 +------------------ crates/ruff_python_ast/src/nodes.rs | 50 ++++++++---- crates/ruff_python_ast/src/relocate.rs | 36 +++++---- crates/ruff_python_ast/src/visitor.rs | 41 ++++++---- .../ruff_python_ast/src/visitor/preorder.rs | 30 ++++++- 8 files changed, 171 insertions(+), 172 deletions(-) diff --git a/crates/ruff_python_ast/src/comparable.rs b/crates/ruff_python_ast/src/comparable.rs index a3bfd8eea2cc7..89166670e7c49 100644 --- a/crates/ruff_python_ast/src/comparable.rs +++ b/crates/ruff_python_ast/src/comparable.rs @@ -519,6 +519,36 @@ impl<'a> From<&'a ast::ExceptHandler> for ComparableExceptHandler<'a> { } } +#[derive(Debug, PartialEq, Eq, Hash)] +pub enum ComparableFStringPart<'a> { + String(&'a str), + FormattedValue(FormattedValue<'a>), +} + +#[derive(Debug, PartialEq, Eq, Hash)] +pub struct FormattedValue<'a> { + expression: ComparableExpr<'a>, + debug_text: Option<&'a ast::DebugText>, + pub conversion: ast::ConversionFlag, + pub format_spec: Option>>, +} + +impl<'a> From<&'a ast::FStringPart> for ComparableFStringPart<'a> { + fn from(fstring_part: &'a ast::FStringPart) -> Self { + match fstring_part { + ast::FStringPart::String(ast::StringTodoName { value, .. }) => Self::String(value), + ast::FStringPart::FormattedValue(formatted_value) => { + Self::FormattedValue(FormattedValue { + expression: (&formatted_value.expression).into(), + debug_text: formatted_value.debug_text.as_ref(), + conversion: formatted_value.conversion, + format_spec: formatted_value.format_spec.as_ref().map(Into::into), + }) + } + } + } +} + #[derive(Debug, PartialEq, Eq, Hash)] pub struct ComparableElifElseClause<'a> { test: Option>, @@ -651,7 +681,7 @@ pub struct ExprFormattedValue<'a> { #[derive(Debug, PartialEq, Eq, Hash)] pub struct ExprFString<'a> { - values: Vec>, + parts: Vec>, } #[derive(Debug, PartialEq, Eq, Hash)] @@ -880,24 +910,12 @@ impl<'a> From<&'a ast::Expr> for ComparableExpr<'a> { func: func.into(), arguments: arguments.into(), }), - ast::Expr::FormattedValue(ast::ExprFormattedValue { - value, - conversion, - debug_text, - format_spec, - range: _, - }) => Self::FormattedValue(ExprFormattedValue { - value: value.into(), - conversion: *conversion, - debug_text: debug_text.as_ref(), - format_spec: format_spec.as_ref().map(Into::into), - }), ast::Expr::FString(ast::ExprFString { - values, + parts, implicit_concatenated: _, range: _, }) => Self::FString(ExprFString { - values: values.iter().map(Into::into).collect(), + parts: parts.iter().map(Into::into).collect(), }), ast::Expr::Constant(ast::ExprConstant { value, range: _ }) => { Self::Constant(ExprConstant { diff --git a/crates/ruff_python_ast/src/expression.rs b/crates/ruff_python_ast/src/expression.rs index 562c68495281d..8182b3da31222 100644 --- a/crates/ruff_python_ast/src/expression.rs +++ b/crates/ruff_python_ast/src/expression.rs @@ -23,7 +23,6 @@ pub enum ExpressionRef<'a> { YieldFrom(&'a ast::ExprYieldFrom), Compare(&'a ast::ExprCompare), Call(&'a ast::ExprCall), - FormattedValue(&'a ast::ExprFormattedValue), FString(&'a ast::ExprFString), Constant(&'a ast::ExprConstant), Attribute(&'a ast::ExprAttribute), @@ -62,7 +61,6 @@ impl<'a> From<&'a Expr> for ExpressionRef<'a> { Expr::YieldFrom(value) => ExpressionRef::YieldFrom(value), Expr::Compare(value) => ExpressionRef::Compare(value), Expr::Call(value) => ExpressionRef::Call(value), - Expr::FormattedValue(value) => ExpressionRef::FormattedValue(value), Expr::FString(value) => ExpressionRef::FString(value), Expr::Constant(value) => ExpressionRef::Constant(value), Expr::Attribute(value) => ExpressionRef::Attribute(value), @@ -162,11 +160,6 @@ impl<'a> From<&'a ast::ExprCall> for ExpressionRef<'a> { Self::Call(value) } } -impl<'a> From<&'a ast::ExprFormattedValue> for ExpressionRef<'a> { - fn from(value: &'a ast::ExprFormattedValue) -> Self { - Self::FormattedValue(value) - } -} impl<'a> From<&'a ast::ExprFString> for ExpressionRef<'a> { fn from(value: &'a ast::ExprFString) -> Self { Self::FString(value) @@ -238,7 +231,6 @@ impl<'a> From> for AnyNodeRef<'a> { ExpressionRef::YieldFrom(expression) => AnyNodeRef::ExprYieldFrom(expression), ExpressionRef::Compare(expression) => AnyNodeRef::ExprCompare(expression), ExpressionRef::Call(expression) => AnyNodeRef::ExprCall(expression), - ExpressionRef::FormattedValue(expression) => AnyNodeRef::ExprFormattedValue(expression), ExpressionRef::FString(expression) => AnyNodeRef::ExprFString(expression), ExpressionRef::Constant(expression) => AnyNodeRef::ExprConstant(expression), ExpressionRef::Attribute(expression) => AnyNodeRef::ExprAttribute(expression), @@ -275,7 +267,6 @@ impl Ranged for ExpressionRef<'_> { ExpressionRef::YieldFrom(expression) => expression.range(), ExpressionRef::Compare(expression) => expression.range(), ExpressionRef::Call(expression) => expression.range(), - ExpressionRef::FormattedValue(expression) => expression.range(), ExpressionRef::FString(expression) => expression.range(), ExpressionRef::Constant(expression) => expression.range(), ExpressionRef::Attribute(expression) => expression.range(), diff --git a/crates/ruff_python_ast/src/helpers.rs b/crates/ruff_python_ast/src/helpers.rs index 9e9ce3179cd75..5bebca42ec27c 100644 --- a/crates/ruff_python_ast/src/helpers.rs +++ b/crates/ruff_python_ast/src/helpers.rs @@ -9,7 +9,8 @@ use ruff_text_size::{Ranged, TextRange}; use crate::call_path::CallPath; use crate::statement_visitor::{walk_body, walk_stmt, StatementVisitor}; use crate::{ - self as ast, Arguments, Constant, ExceptHandler, Expr, MatchCase, Pattern, Stmt, TypeParam, + self as ast, Arguments, Constant, ExceptHandler, Expr, FStringPart, MatchCase, Pattern, Stmt, + TypeParam, }; /// Return `true` if the `Stmt` is a compound statement (as opposed to a simple statement). @@ -118,10 +119,12 @@ pub fn any_over_expr(expr: &Expr, func: &dyn Fn(&Expr) -> bool) -> bool { return true; } match expr { - Expr::BoolOp(ast::ExprBoolOp { values, .. }) - | Expr::FString(ast::ExprFString { values, .. }) => { + Expr::BoolOp(ast::ExprBoolOp { values, .. }) => { values.iter().any(|expr| any_over_expr(expr, func)) } + Expr::FString(ast::ExprFString { parts, .. }) => { + parts.iter().any(|part| any_over_fstring_part(part, func)) + } Expr::NamedExpr(ast::ExprNamedExpr { target, value, @@ -214,14 +217,6 @@ pub fn any_over_expr(expr: &Expr, func: &dyn Fn(&Expr) -> bool) -> bool { .iter() .any(|keyword| any_over_expr(&keyword.value, func)) } - Expr::FormattedValue(ast::ExprFormattedValue { - value, format_spec, .. - }) => { - any_over_expr(value, func) - || format_spec - .as_ref() - .is_some_and(|value| any_over_expr(value, func)) - } Expr::Subscript(ast::ExprSubscript { value, slice, .. }) => { any_over_expr(value, func) || any_over_expr(slice, func) } @@ -292,6 +287,22 @@ pub fn any_over_pattern(pattern: &Pattern, func: &dyn Fn(&Expr) -> bool) -> bool } } +pub fn any_over_fstring_part(part: &FStringPart, func: &dyn Fn(&Expr) -> bool) -> bool { + match part { + FStringPart::String(_) => false, + FStringPart::FormattedValue(ast::FormattedValue { + expression, + format_spec, + .. + }) => { + any_over_expr(expression, func) + || format_spec + .as_ref() + .map_or(false, |format_spec| any_over_expr(format_spec, func)) + } + } +} + pub fn any_over_stmt(stmt: &Stmt, func: &dyn Fn(&Expr) -> bool) -> bool { match stmt { Stmt::FunctionDef(ast::StmtFunctionDef { @@ -1078,19 +1089,14 @@ impl Truthiness { Constant::Complex { real, imag } => Some(*real != 0.0 || *imag != 0.0), Constant::Ellipsis => Some(true), }, - Expr::FString(ast::ExprFString { values, .. }) => { - if values.is_empty() { + Expr::FString(ast::ExprFString { parts, .. }) => { + if parts.is_empty() { Some(false) - } else if values.iter().any(|value| { - if let Expr::Constant(ast::ExprConstant { - value: Constant::Str(ast::StringConstant { value, .. }), - .. - }) = &value - { + } else if parts.iter().any(|part| match part { + ast::FStringPart::String(ast::StringTodoName { value, .. }) => { !value.is_empty() - } else { - false } + ast::FStringPart::FormattedValue(_) => true, }) { Some(true) } else { diff --git a/crates/ruff_python_ast/src/node.rs b/crates/ruff_python_ast/src/node.rs index 35cfb9147cd81..b7827d86a3858 100644 --- a/crates/ruff_python_ast/src/node.rs +++ b/crates/ruff_python_ast/src/node.rs @@ -71,7 +71,6 @@ pub enum AnyNode { ExprYieldFrom(ast::ExprYieldFrom), ExprCompare(ast::ExprCompare), ExprCall(ast::ExprCall), - ExprFormattedValue(ast::ExprFormattedValue), ExprFString(ast::ExprFString), ExprConstant(ast::ExprConstant), ExprAttribute(ast::ExprAttribute), @@ -158,7 +157,6 @@ impl AnyNode { | AnyNode::ExprYieldFrom(_) | AnyNode::ExprCompare(_) | AnyNode::ExprCall(_) - | AnyNode::ExprFormattedValue(_) | AnyNode::ExprFString(_) | AnyNode::ExprConstant(_) | AnyNode::ExprAttribute(_) @@ -217,7 +215,6 @@ impl AnyNode { AnyNode::ExprYieldFrom(node) => Some(Expr::YieldFrom(node)), AnyNode::ExprCompare(node) => Some(Expr::Compare(node)), AnyNode::ExprCall(node) => Some(Expr::Call(node)), - AnyNode::ExprFormattedValue(node) => Some(Expr::FormattedValue(node)), AnyNode::ExprFString(node) => Some(Expr::FString(node)), AnyNode::ExprConstant(node) => Some(Expr::Constant(node)), AnyNode::ExprAttribute(node) => Some(Expr::Attribute(node)), @@ -332,7 +329,6 @@ impl AnyNode { | AnyNode::ExprYieldFrom(_) | AnyNode::ExprCompare(_) | AnyNode::ExprCall(_) - | AnyNode::ExprFormattedValue(_) | AnyNode::ExprFString(_) | AnyNode::ExprConstant(_) | AnyNode::ExprAttribute(_) @@ -427,7 +423,6 @@ impl AnyNode { | AnyNode::ExprYieldFrom(_) | AnyNode::ExprCompare(_) | AnyNode::ExprCall(_) - | AnyNode::ExprFormattedValue(_) | AnyNode::ExprFString(_) | AnyNode::ExprConstant(_) | AnyNode::ExprAttribute(_) @@ -507,7 +502,6 @@ impl AnyNode { | AnyNode::ExprYieldFrom(_) | AnyNode::ExprCompare(_) | AnyNode::ExprCall(_) - | AnyNode::ExprFormattedValue(_) | AnyNode::ExprFString(_) | AnyNode::ExprConstant(_) | AnyNode::ExprAttribute(_) @@ -612,7 +606,6 @@ impl AnyNode { Self::ExprYieldFrom(node) => AnyNodeRef::ExprYieldFrom(node), Self::ExprCompare(node) => AnyNodeRef::ExprCompare(node), Self::ExprCall(node) => AnyNodeRef::ExprCall(node), - Self::ExprFormattedValue(node) => AnyNodeRef::ExprFormattedValue(node), Self::ExprFString(node) => AnyNodeRef::ExprFString(node), Self::ExprConstant(node) => AnyNodeRef::ExprConstant(node), Self::ExprAttribute(node) => AnyNodeRef::ExprAttribute(node), @@ -2565,48 +2558,6 @@ impl AstNode for ast::ExprCall { visitor.visit_arguments(arguments); } } -impl AstNode for ast::ExprFormattedValue { - fn cast(kind: AnyNode) -> Option - where - Self: Sized, - { - if let AnyNode::ExprFormattedValue(node) = kind { - Some(node) - } else { - None - } - } - - fn cast_ref(kind: AnyNodeRef) -> Option<&Self> { - if let AnyNodeRef::ExprFormattedValue(node) = kind { - Some(node) - } else { - None - } - } - - fn as_any_node_ref(&self) -> AnyNodeRef { - AnyNodeRef::from(self) - } - - fn into_any_node(self) -> AnyNode { - AnyNode::from(self) - } - - fn visit_preorder<'a, V>(&'a self, visitor: &mut V) - where - V: PreorderVisitor<'a> + ?Sized, - { - let ast::ExprFormattedValue { - value, format_spec, .. - } = self; - visitor.visit_expr(value); - - if let Some(expr) = format_spec { - visitor.visit_format_spec(expr); - } - } -} impl AstNode for ast::ExprFString { fn cast(kind: AnyNode) -> Option where @@ -2640,13 +2591,13 @@ impl AstNode for ast::ExprFString { V: PreorderVisitor<'a> + ?Sized, { let ast::ExprFString { - values, + parts, implicit_concatenated: _, range: _, } = self; - for expr in values { - visitor.visit_expr(expr); + for part in parts { + visitor.visit_fstring_part(part); } } } @@ -4122,7 +4073,6 @@ impl From for AnyNode { Expr::YieldFrom(node) => AnyNode::ExprYieldFrom(node), Expr::Compare(node) => AnyNode::ExprCompare(node), Expr::Call(node) => AnyNode::ExprCall(node), - Expr::FormattedValue(node) => AnyNode::ExprFormattedValue(node), Expr::FString(node) => AnyNode::ExprFString(node), Expr::Constant(node) => AnyNode::ExprConstant(node), Expr::Attribute(node) => AnyNode::ExprAttribute(node), @@ -4439,12 +4389,6 @@ impl From for AnyNode { } } -impl From for AnyNode { - fn from(node: ast::ExprFormattedValue) -> Self { - AnyNode::ExprFormattedValue(node) - } -} - impl From for AnyNode { fn from(node: ast::ExprFString) -> Self { AnyNode::ExprFString(node) @@ -4691,7 +4635,6 @@ impl Ranged for AnyNode { AnyNode::ExprYieldFrom(node) => node.range(), AnyNode::ExprCompare(node) => node.range(), AnyNode::ExprCall(node) => node.range(), - AnyNode::ExprFormattedValue(node) => node.range(), AnyNode::ExprFString(node) => node.range(), AnyNode::ExprConstant(node) => node.range(), AnyNode::ExprAttribute(node) => node.range(), @@ -4778,7 +4721,6 @@ pub enum AnyNodeRef<'a> { ExprYieldFrom(&'a ast::ExprYieldFrom), ExprCompare(&'a ast::ExprCompare), ExprCall(&'a ast::ExprCall), - ExprFormattedValue(&'a ast::ExprFormattedValue), ExprFString(&'a ast::ExprFString), ExprConstant(&'a ast::ExprConstant), ExprAttribute(&'a ast::ExprAttribute), @@ -4864,7 +4806,6 @@ impl AnyNodeRef<'_> { AnyNodeRef::ExprYieldFrom(node) => NonNull::from(*node).cast(), AnyNodeRef::ExprCompare(node) => NonNull::from(*node).cast(), AnyNodeRef::ExprCall(node) => NonNull::from(*node).cast(), - AnyNodeRef::ExprFormattedValue(node) => NonNull::from(*node).cast(), AnyNodeRef::ExprFString(node) => NonNull::from(*node).cast(), AnyNodeRef::ExprConstant(node) => NonNull::from(*node).cast(), AnyNodeRef::ExprAttribute(node) => NonNull::from(*node).cast(), @@ -4956,7 +4897,6 @@ impl AnyNodeRef<'_> { AnyNodeRef::ExprYieldFrom(_) => NodeKind::ExprYieldFrom, AnyNodeRef::ExprCompare(_) => NodeKind::ExprCompare, AnyNodeRef::ExprCall(_) => NodeKind::ExprCall, - AnyNodeRef::ExprFormattedValue(_) => NodeKind::ExprFormattedValue, AnyNodeRef::ExprFString(_) => NodeKind::ExprFString, AnyNodeRef::ExprConstant(_) => NodeKind::ExprConstant, AnyNodeRef::ExprAttribute(_) => NodeKind::ExprAttribute, @@ -5043,7 +4983,6 @@ impl AnyNodeRef<'_> { | AnyNodeRef::ExprYieldFrom(_) | AnyNodeRef::ExprCompare(_) | AnyNodeRef::ExprCall(_) - | AnyNodeRef::ExprFormattedValue(_) | AnyNodeRef::ExprFString(_) | AnyNodeRef::ExprConstant(_) | AnyNodeRef::ExprAttribute(_) @@ -5102,7 +5041,6 @@ impl AnyNodeRef<'_> { | AnyNodeRef::ExprYieldFrom(_) | AnyNodeRef::ExprCompare(_) | AnyNodeRef::ExprCall(_) - | AnyNodeRef::ExprFormattedValue(_) | AnyNodeRef::ExprFString(_) | AnyNodeRef::ExprConstant(_) | AnyNodeRef::ExprAttribute(_) @@ -5216,7 +5154,6 @@ impl AnyNodeRef<'_> { | AnyNodeRef::ExprYieldFrom(_) | AnyNodeRef::ExprCompare(_) | AnyNodeRef::ExprCall(_) - | AnyNodeRef::ExprFormattedValue(_) | AnyNodeRef::ExprFString(_) | AnyNodeRef::ExprConstant(_) | AnyNodeRef::ExprAttribute(_) @@ -5311,7 +5248,6 @@ impl AnyNodeRef<'_> { | AnyNodeRef::ExprYieldFrom(_) | AnyNodeRef::ExprCompare(_) | AnyNodeRef::ExprCall(_) - | AnyNodeRef::ExprFormattedValue(_) | AnyNodeRef::ExprFString(_) | AnyNodeRef::ExprConstant(_) | AnyNodeRef::ExprAttribute(_) @@ -5391,7 +5327,6 @@ impl AnyNodeRef<'_> { | AnyNodeRef::ExprYieldFrom(_) | AnyNodeRef::ExprCompare(_) | AnyNodeRef::ExprCall(_) - | AnyNodeRef::ExprFormattedValue(_) | AnyNodeRef::ExprFString(_) | AnyNodeRef::ExprConstant(_) | AnyNodeRef::ExprAttribute(_) @@ -5505,7 +5440,6 @@ impl AnyNodeRef<'_> { AnyNodeRef::ExprYieldFrom(node) => node.visit_preorder(visitor), AnyNodeRef::ExprCompare(node) => node.visit_preorder(visitor), AnyNodeRef::ExprCall(node) => node.visit_preorder(visitor), - AnyNodeRef::ExprFormattedValue(node) => node.visit_preorder(visitor), AnyNodeRef::ExprFString(node) => node.visit_preorder(visitor), AnyNodeRef::ExprConstant(node) => node.visit_preorder(visitor), AnyNodeRef::ExprAttribute(node) => node.visit_preorder(visitor), @@ -5816,12 +5750,6 @@ impl<'a> From<&'a ast::ExprCall> for AnyNodeRef<'a> { } } -impl<'a> From<&'a ast::ExprFormattedValue> for AnyNodeRef<'a> { - fn from(node: &'a ast::ExprFormattedValue) -> Self { - AnyNodeRef::ExprFormattedValue(node) - } -} - impl<'a> From<&'a ast::ExprFString> for AnyNodeRef<'a> { fn from(node: &'a ast::ExprFString) -> Self { AnyNodeRef::ExprFString(node) @@ -6029,7 +5957,6 @@ impl<'a> From<&'a Expr> for AnyNodeRef<'a> { Expr::YieldFrom(node) => AnyNodeRef::ExprYieldFrom(node), Expr::Compare(node) => AnyNodeRef::ExprCompare(node), Expr::Call(node) => AnyNodeRef::ExprCall(node), - Expr::FormattedValue(node) => AnyNodeRef::ExprFormattedValue(node), Expr::FString(node) => AnyNodeRef::ExprFString(node), Expr::Constant(node) => AnyNodeRef::ExprConstant(node), Expr::Attribute(node) => AnyNodeRef::ExprAttribute(node), @@ -6181,7 +6108,6 @@ impl Ranged for AnyNodeRef<'_> { AnyNodeRef::ExprYieldFrom(node) => node.range(), AnyNodeRef::ExprCompare(node) => node.range(), AnyNodeRef::ExprCall(node) => node.range(), - AnyNodeRef::ExprFormattedValue(node) => node.range(), AnyNodeRef::ExprFString(node) => node.range(), AnyNodeRef::ExprConstant(node) => node.range(), AnyNodeRef::ExprAttribute(node) => node.range(), @@ -6270,7 +6196,6 @@ pub enum NodeKind { ExprYieldFrom, ExprCompare, ExprCall, - ExprFormattedValue, ExprFString, ExprConstant, ExprAttribute, diff --git a/crates/ruff_python_ast/src/nodes.rs b/crates/ruff_python_ast/src/nodes.rs index ad42a51428d2b..3b38aba3e90b4 100644 --- a/crates/ruff_python_ast/src/nodes.rs +++ b/crates/ruff_python_ast/src/nodes.rs @@ -587,8 +587,6 @@ pub enum Expr { Compare(ExprCompare), #[is(name = "call_expr")] Call(ExprCall), - #[is(name = "formatted_value_expr")] - FormattedValue(ExprFormattedValue), #[is(name = "f_string_expr")] FString(ExprFString), #[is(name = "constant_expr")] @@ -877,18 +875,19 @@ impl From for Expr { /// See also [FormattedValue](https://docs.python.org/3/library/ast.html#ast.FormattedValue) #[derive(Clone, Debug, PartialEq)] -pub struct ExprFormattedValue { +pub struct FormattedValue { pub range: TextRange, - pub value: Box, + pub expression: Box, pub debug_text: Option, pub conversion: ConversionFlag, + // TODO: is this Option>? pub format_spec: Option>, } -impl From for Expr { - fn from(payload: ExprFormattedValue) -> Self { - Expr::FormattedValue(payload) - } +#[derive(Clone, Debug, PartialEq)] +pub struct StringTodoName { + pub range: TextRange, + pub value: String, } /// Transforms a value prior to formatting it. @@ -930,9 +929,9 @@ pub struct DebugText { #[derive(Clone, Debug, PartialEq)] pub struct ExprFString { pub range: TextRange, - pub values: Vec, /// Whether the f-string contains multiple string tokens that were implicitly concatenated. pub implicit_concatenated: bool, + pub parts: Vec, } impl From for Expr { @@ -941,6 +940,12 @@ impl From for Expr { } } +#[derive(Clone, Debug, PartialEq)] +pub enum FStringPart { + String(StringTodoName), + FormattedValue(FormattedValue), +} + /// See also [Constant](https://docs.python.org/3/library/ast.html#ast.Constant) #[derive(Clone, Debug, PartialEq)] pub struct ExprConstant { @@ -2953,11 +2958,6 @@ impl Ranged for crate::nodes::ExprCall { self.range } } -impl Ranged for crate::nodes::ExprFormattedValue { - fn range(&self) -> TextRange { - self.range - } -} impl Ranged for crate::nodes::ExprFString { fn range(&self) -> TextRange { self.range @@ -3028,7 +3028,6 @@ impl Ranged for crate::Expr { Self::YieldFrom(node) => node.range(), Self::Compare(node) => node.range(), Self::Call(node) => node.range(), - Self::FormattedValue(node) => node.range(), Self::FString(node) => node.range(), Self::Constant(node) => node.range(), Self::Attribute(node) => node.range(), @@ -3382,3 +3381,24 @@ mod size_assertions { assert_eq_size!(Pattern, [u8; 96]); assert_eq_size!(Mod, [u8; 32]); } + +impl Ranged for crate::nodes::FormattedValue { + fn range(&self) -> TextRange { + self.range + } +} + +impl Ranged for crate::nodes::FStringPart { + fn range(&self) -> TextRange { + match self { + FStringPart::String(node) => node.range(), + FStringPart::FormattedValue(node) => node.range(), + } + } +} + +impl Ranged for crate::nodes::StringTodoName { + fn range(&self) -> TextRange { + self.range + } +} diff --git a/crates/ruff_python_ast/src/relocate.rs b/crates/ruff_python_ast/src/relocate.rs index 122cdbc259ba0..a5743f1cb691c 100644 --- a/crates/ruff_python_ast/src/relocate.rs +++ b/crates/ruff_python_ast/src/relocate.rs @@ -128,22 +128,26 @@ pub fn relocate_expr(expr: &mut Expr, location: TextRange) { relocate_keyword(keyword, location); } } - Expr::FormattedValue(nodes::ExprFormattedValue { - value, - format_spec, - range, - .. - }) => { - *range = location; - relocate_expr(value, location); - if let Some(expr) = format_spec { - relocate_expr(expr, location); - } - } - Expr::FString(nodes::ExprFString { values, range, .. }) => { - *range = location; - for expr in values { - relocate_expr(expr, location); + Expr::FString(nodes::ExprFString { parts, range, .. }) => { + *range = location; + for part in parts { + match part { + nodes::FStringPart::String(nodes::StringTodoName { range, .. }) => { + *range = location; + } + nodes::FStringPart::FormattedValue(nodes::FormattedValue { + range, + expression, + format_spec, + .. + }) => { + *range = location; + relocate_expr(expression, location); + if let Some(format_spec) = format_spec { + relocate_expr(format_spec, location); + } + } + } } } Expr::Constant(nodes::ExprConstant { range, .. }) => { diff --git a/crates/ruff_python_ast/src/visitor.rs b/crates/ruff_python_ast/src/visitor.rs index d0b62fa7af9eb..038d9ea07f84f 100644 --- a/crates/ruff_python_ast/src/visitor.rs +++ b/crates/ruff_python_ast/src/visitor.rs @@ -4,9 +4,9 @@ pub mod preorder; use crate::{ self as ast, Alias, Arguments, BoolOp, CmpOp, Comprehension, Decorator, ElifElseClause, - ExceptHandler, Expr, ExprContext, Keyword, MatchCase, Operator, Parameter, Parameters, Pattern, - PatternArguments, PatternKeyword, Stmt, TypeParam, TypeParamTypeVar, TypeParams, UnaryOp, - WithItem, + ExceptHandler, Expr, ExprContext, FStringPart, Keyword, MatchCase, Operator, Parameter, + Parameters, Pattern, PatternArguments, PatternKeyword, Stmt, TypeParam, TypeParamTypeVar, + TypeParams, UnaryOp, WithItem, }; /// A trait for AST visitors. Visits all nodes in the AST recursively in evaluation-order. @@ -95,6 +95,9 @@ pub trait Visitor<'a> { fn visit_elif_else_clause(&mut self, elif_else_clause: &'a ElifElseClause) { walk_elif_else_clause(self, elif_else_clause); } + fn visit_fstring_part(&mut self, fstring_part: &'a FStringPart) { + walk_fstring_part(self, fstring_part); + } } pub fn walk_body<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, body: &'a [Stmt]) { @@ -464,17 +467,9 @@ pub fn walk_expr<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, expr: &'a Expr) { visitor.visit_expr(func); visitor.visit_arguments(arguments); } - Expr::FormattedValue(ast::ExprFormattedValue { - value, format_spec, .. - }) => { - visitor.visit_expr(value); - if let Some(expr) = format_spec { - visitor.visit_format_spec(expr); - } - } - Expr::FString(ast::ExprFString { values, .. }) => { - for expr in values { - visitor.visit_expr(expr); + Expr::FString(ast::ExprFString { parts, .. }) => { + for part in parts { + visitor.visit_fstring_part(part); } } Expr::Constant(_) => {} @@ -721,6 +716,24 @@ pub fn walk_pattern_keyword<'a, V: Visitor<'a> + ?Sized>( visitor.visit_pattern(&pattern_keyword.pattern); } +pub fn walk_fstring_part<'a, V: Visitor<'a> + ?Sized>( + visitor: &mut V, + fstring_part: &'a FStringPart, +) { + if let ast::FStringPart::FormattedValue(ast::FormattedValue { + expression, + format_spec, + .. + }) = fstring_part + { + visitor.visit_expr(expression); + if let Some(expr) = format_spec { + // TODO: why go via `visit_format_spec` as opposed to just straight to `visit_expr`? + visitor.visit_format_spec(expr); + } + } +} + #[allow(unused_variables)] pub fn walk_expr_context<'a, V: Visitor<'a> + ?Sized>(visitor: &V, expr_context: &'a ExprContext) {} diff --git a/crates/ruff_python_ast/src/visitor/preorder.rs b/crates/ruff_python_ast/src/visitor/preorder.rs index 6a64d1daa3a87..7a9f175766b9d 100644 --- a/crates/ruff_python_ast/src/visitor/preorder.rs +++ b/crates/ruff_python_ast/src/visitor/preorder.rs @@ -1,9 +1,9 @@ use crate::node::{AnyNodeRef, AstNode}; use crate::{ Alias, Arguments, BoolOp, CmpOp, Comprehension, Constant, Decorator, ElifElseClause, - ExceptHandler, Expr, Keyword, MatchCase, Mod, Operator, Parameter, ParameterWithDefault, - Parameters, Pattern, PatternArguments, PatternKeyword, Stmt, TypeParam, TypeParams, UnaryOp, - WithItem, + ExceptHandler, Expr, FStringPart, FormattedValue, Keyword, MatchCase, Mod, Operator, Parameter, + ParameterWithDefault, Parameters, Pattern, PatternArguments, PatternKeyword, Stmt, TypeParam, + TypeParams, UnaryOp, WithItem, }; /// Visitor that traverses all nodes recursively in pre-order. @@ -153,6 +153,11 @@ pub trait PreorderVisitor<'a> { fn visit_elif_else_clause(&mut self, elif_else_clause: &'a ElifElseClause) { walk_elif_else_clause(self, elif_else_clause); } + + #[inline] + fn visit_fstring_part(&mut self, fstring_part: &'a FStringPart) { + walk_fstring_part(self, fstring_part); + } } pub fn walk_module<'a, V>(visitor: &mut V, module: &'a Mod) @@ -275,7 +280,6 @@ where Expr::YieldFrom(expr) => expr.visit_preorder(visitor), Expr::Compare(expr) => expr.visit_preorder(visitor), Expr::Call(expr) => expr.visit_preorder(visitor), - Expr::FormattedValue(expr) => expr.visit_preorder(visitor), Expr::FString(expr) => expr.visit_preorder(visitor), Expr::Constant(expr) => expr.visit_preorder(visitor), Expr::Attribute(expr) => expr.visit_preorder(visitor), @@ -499,6 +503,24 @@ where visitor.leave_node(node); } +pub fn walk_fstring_part<'a, V: PreorderVisitor<'a> + ?Sized>( + visitor: &mut V, + fstring_part: &'a FStringPart, +) { + if let FStringPart::FormattedValue(FormattedValue { + expression, + format_spec, + .. + }) = fstring_part + { + visitor.visit_expr(expression); + if let Some(expr) = format_spec { + // TODO: why go via `visit_format_spec` as opposed to just straight to `visit_expr`? + visitor.visit_format_spec(expr); + } + } +} + pub fn walk_bool_op<'a, V>(_visitor: &mut V, _bool_op: &'a BoolOp) where V: PreorderVisitor<'a> + ?Sized, From 0077dfac1d1d7b40f95a2a33698e2f4888022318 Mon Sep 17 00:00:00 2001 From: David Szotten Date: Sat, 5 Aug 2023 09:32:23 +0100 Subject: [PATCH 02/17] FStringPart for parser/string.rs --- crates/ruff_python_ast/src/nodes.rs | 5 - .../src/expression/mod.rs | 2 - ...parser__parser__tests__parse_f_string.snap | 16 +- ...uff_python_parser__parser__tests__try.snap | 40 ++-- ...ython_parser__parser__tests__try_star.snap | 72 +++---- ...string__tests__fstring_constant_range.snap | 48 ++--- ...ing__tests__fstring_escaped_character.snap | 20 +- ...tring__tests__fstring_escaped_newline.snap | 20 +- ...ing__tests__fstring_line_continuation.snap | 20 +- ...__fstring_parse_self_documenting_base.snap | 46 +++-- ...ring_parse_self_documenting_base_more.snap | 106 +++++------ ...fstring_parse_self_documenting_format.snap | 78 ++++---- ...ing__tests__fstring_unescaped_newline.snap | 20 +- ...r__string__tests__parse_empty_fstring.snap | 8 +- ...tring__tests__parse_f_string_concat_1.snap | 16 +- ...tring__tests__parse_f_string_concat_2.snap | 16 +- ...tring__tests__parse_f_string_concat_3.snap | 20 +- ...tring__tests__parse_f_string_concat_4.snap | 32 +--- ..._parser__string__tests__parse_fstring.snap | 74 ++++---- ...__string__tests__parse_fstring_equals.snap | 68 +++---- ...ring_nested_concatenation_string_spec.snap | 88 +++++---- ...ing__tests__parse_fstring_nested_spec.snap | 82 ++++---- ...sts__parse_fstring_nested_string_spec.snap | 88 +++++---- ...ring__tests__parse_fstring_not_equals.snap | 68 +++---- ..._tests__parse_fstring_not_nested_spec.snap | 68 +++---- ...ts__parse_fstring_self_doc_prec_space.snap | 46 +++-- ...parse_fstring_self_doc_trailing_space.snap | 46 +++-- ...ring__tests__parse_fstring_yield_expr.snap | 34 ++-- ...ing__tests__parse_u_f_string_concat_1.snap | 16 +- ...ing__tests__parse_u_f_string_concat_2.snap | 16 +- ...on_parser__string__tests__raw_fstring.snap | 8 +- ...ing__tests__triple_quoted_raw_fstring.snap | 8 +- crates/ruff_python_parser/src/string.rs | 175 ++++++++++-------- 33 files changed, 704 insertions(+), 766 deletions(-) diff --git a/crates/ruff_python_ast/src/nodes.rs b/crates/ruff_python_ast/src/nodes.rs index 3b38aba3e90b4..bbd16b1977416 100644 --- a/crates/ruff_python_ast/src/nodes.rs +++ b/crates/ruff_python_ast/src/nodes.rs @@ -3314,11 +3314,6 @@ impl From for ParenthesizedExpr { Expr::Call(payload).into() } } -impl From for ParenthesizedExpr { - fn from(payload: ExprFormattedValue) -> Self { - Expr::FormattedValue(payload).into() - } -} impl From for ParenthesizedExpr { fn from(payload: ExprFString) -> Self { Expr::FString(payload).into() diff --git a/crates/ruff_python_formatter/src/expression/mod.rs b/crates/ruff_python_formatter/src/expression/mod.rs index 6cae0c2973f3c..a1dc38ba17178 100644 --- a/crates/ruff_python_formatter/src/expression/mod.rs +++ b/crates/ruff_python_formatter/src/expression/mod.rs @@ -302,7 +302,6 @@ impl NeedsParentheses for Expr { Expr::YieldFrom(expr) => expr.needs_parentheses(parent, context), Expr::Compare(expr) => expr.needs_parentheses(parent, context), Expr::Call(expr) => expr.needs_parentheses(parent, context), - Expr::FormattedValue(expr) => expr.needs_parentheses(parent, context), Expr::FString(expr) => expr.needs_parentheses(parent, context), Expr::Constant(expr) => expr.needs_parentheses(parent, context), Expr::Attribute(expr) => expr.needs_parentheses(parent, context), @@ -534,7 +533,6 @@ impl<'input> CanOmitOptionalParenthesesVisitor<'input> { | Expr::Await(_) | Expr::Yield(_) | Expr::YieldFrom(_) - | Expr::FormattedValue(_) | Expr::FString(_) | Expr::Constant(_) | Expr::Starred(_) diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_f_string.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_f_string.snap index edf6c9b3a7edc..0697d8f731176 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_f_string.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_f_string.snap @@ -9,21 +9,15 @@ expression: parse_ast value: FString( ExprFString { range: 0..14, - values: [ - Constant( - ExprConstant { + implicit_concatenated: false, + parts: [ + String( + StringTodoName { range: 2..13, - value: Str( - StringConstant { - value: "Hello world", - unicode: false, - implicit_concatenated: false, - }, - ), + value: "Hello world", }, ), ], - implicit_concatenated: false, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try.snap index b9aab97c0d967..464a7f31fe8cf 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try.snap @@ -81,23 +81,18 @@ expression: parse_ast FString( ExprFString { range: 62..81, - values: [ - Constant( - ExprConstant { + implicit_concatenated: false, + parts: [ + String( + StringTodoName { range: 64..71, - value: Str( - StringConstant { - value: "caught ", - unicode: false, - implicit_concatenated: false, - }, - ), + value: "caught ", }, ), FormattedValue( - ExprFormattedValue { + FormattedValue { range: 71..80, - value: Call( + expression: Call( ExprCall { range: 72..79, func: Name( @@ -128,7 +123,6 @@ expression: parse_ast }, ), ], - implicit_concatenated: false, }, ), ], @@ -179,23 +173,18 @@ expression: parse_ast FString( ExprFString { range: 114..133, - values: [ - Constant( - ExprConstant { + implicit_concatenated: false, + parts: [ + String( + StringTodoName { range: 116..123, - value: Str( - StringConstant { - value: "caught ", - unicode: false, - implicit_concatenated: false, - }, - ), + value: "caught ", }, ), FormattedValue( - ExprFormattedValue { + FormattedValue { range: 123..132, - value: Call( + expression: Call( ExprCall { range: 124..131, func: Name( @@ -226,7 +215,6 @@ expression: parse_ast }, ), ], - implicit_concatenated: false, }, ), ], diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try_star.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try_star.snap index 5f691af0cf773..9563bb76da920 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try_star.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try_star.snap @@ -197,23 +197,18 @@ expression: parse_ast FString( ExprFString { range: 133..179, - values: [ - Constant( - ExprConstant { + implicit_concatenated: false, + parts: [ + String( + StringTodoName { range: 135..142, - value: Str( - StringConstant { - value: "caught ", - unicode: false, - implicit_concatenated: false, - }, - ), + value: "caught ", }, ), FormattedValue( - ExprFormattedValue { + FormattedValue { range: 142..151, - value: Call( + expression: Call( ExprCall { range: 143..150, func: Name( @@ -243,22 +238,16 @@ expression: parse_ast format_spec: None, }, ), - Constant( - ExprConstant { + String( + StringTodoName { range: 151..164, - value: Str( - StringConstant { - value: " with nested ", - unicode: false, - implicit_concatenated: false, - }, - ), + value: " with nested ", }, ), FormattedValue( - ExprFormattedValue { + FormattedValue { range: 164..178, - value: Attribute( + expression: Attribute( ExprAttribute { range: 165..177, value: Name( @@ -281,7 +270,6 @@ expression: parse_ast }, ), ], - implicit_concatenated: false, }, ), ], @@ -332,23 +320,18 @@ expression: parse_ast FString( ExprFString { range: 213..259, - values: [ - Constant( - ExprConstant { + implicit_concatenated: false, + parts: [ + String( + StringTodoName { range: 215..222, - value: Str( - StringConstant { - value: "caught ", - unicode: false, - implicit_concatenated: false, - }, - ), + value: "caught ", }, ), FormattedValue( - ExprFormattedValue { + FormattedValue { range: 222..231, - value: Call( + expression: Call( ExprCall { range: 223..230, func: Name( @@ -378,22 +361,16 @@ expression: parse_ast format_spec: None, }, ), - Constant( - ExprConstant { + String( + StringTodoName { range: 231..244, - value: Str( - StringConstant { - value: " with nested ", - unicode: false, - implicit_concatenated: false, - }, - ), + value: " with nested ", }, ), FormattedValue( - ExprFormattedValue { + FormattedValue { range: 244..258, - value: Attribute( + expression: Attribute( ExprAttribute { range: 245..257, value: Name( @@ -416,7 +393,6 @@ expression: parse_ast }, ), ], - implicit_concatenated: false, }, ), ], diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_constant_range.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_constant_range.snap index 245d664aa8756..ab3919c96632b 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_constant_range.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_constant_range.snap @@ -9,23 +9,18 @@ expression: parse_ast value: FString( ExprFString { range: 0..22, - values: [ - Constant( - ExprConstant { + implicit_concatenated: false, + parts: [ + String( + StringTodoName { range: 2..5, - value: Str( - StringConstant { - value: "aaa", - unicode: false, - implicit_concatenated: false, - }, - ), + value: "aaa", }, ), FormattedValue( - ExprFormattedValue { + FormattedValue { range: 5..10, - value: Name( + expression: Name( ExprName { range: 6..9, id: "bbb", @@ -37,22 +32,16 @@ expression: parse_ast format_spec: None, }, ), - Constant( - ExprConstant { + String( + StringTodoName { range: 10..13, - value: Str( - StringConstant { - value: "ccc", - unicode: false, - implicit_concatenated: false, - }, - ), + value: "ccc", }, ), FormattedValue( - ExprFormattedValue { + FormattedValue { range: 13..18, - value: Name( + expression: Name( ExprName { range: 14..17, id: "ddd", @@ -64,20 +53,13 @@ expression: parse_ast format_spec: None, }, ), - Constant( - ExprConstant { + String( + StringTodoName { range: 18..21, - value: Str( - StringConstant { - value: "eee", - unicode: false, - implicit_concatenated: false, - }, - ), + value: "eee", }, ), ], - implicit_concatenated: false, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_character.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_character.snap index 796b97b9eac02..1a0a57367b7b5 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_character.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_character.snap @@ -9,23 +9,18 @@ expression: parse_ast value: FString( ExprFString { range: 0..8, - values: [ - Constant( - ExprConstant { + implicit_concatenated: false, + parts: [ + String( + StringTodoName { range: 2..4, - value: Str( - StringConstant { - value: "\\", - unicode: false, - implicit_concatenated: false, - }, - ), + value: "\\", }, ), FormattedValue( - ExprFormattedValue { + FormattedValue { range: 4..7, - value: Name( + expression: Name( ExprName { range: 5..6, id: "x", @@ -38,7 +33,6 @@ expression: parse_ast }, ), ], - implicit_concatenated: false, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_newline.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_newline.snap index 17dc9dbe2bd73..fedbfdfe5b12a 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_newline.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_newline.snap @@ -9,23 +9,18 @@ expression: parse_ast value: FString( ExprFString { range: 0..8, - values: [ - Constant( - ExprConstant { + implicit_concatenated: false, + parts: [ + String( + StringTodoName { range: 2..4, - value: Str( - StringConstant { - value: "\n", - unicode: false, - implicit_concatenated: false, - }, - ), + value: "\n", }, ), FormattedValue( - ExprFormattedValue { + FormattedValue { range: 4..7, - value: Name( + expression: Name( ExprName { range: 5..6, id: "x", @@ -38,7 +33,6 @@ expression: parse_ast }, ), ], - implicit_concatenated: false, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_line_continuation.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_line_continuation.snap index fcf985cc79c3c..89e29bb052e97 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_line_continuation.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_line_continuation.snap @@ -9,23 +9,18 @@ expression: parse_ast value: FString( ExprFString { range: 0..9, - values: [ - Constant( - ExprConstant { + implicit_concatenated: false, + parts: [ + String( + StringTodoName { range: 3..5, - value: Str( - StringConstant { - value: "\\\n", - unicode: false, - implicit_concatenated: false, - }, - ), + value: "\\\n", }, ), FormattedValue( - ExprFormattedValue { + FormattedValue { range: 5..8, - value: Name( + expression: Name( ExprName { range: 6..7, id: "x", @@ -38,7 +33,6 @@ expression: parse_ast }, ), ], - implicit_concatenated: false, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base.snap index 2ea0c26e91d2d..1d1751726ff70 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base.snap @@ -2,25 +2,31 @@ source: crates/ruff_python_parser/src/string.rs expression: parse_ast --- -[ - FormattedValue( - ExprFormattedValue { - range: 2..9, - value: Name( - ExprName { - range: 3..7, - id: "user", - ctx: Load, +FString( + ExprFString { + range: 2..9, + implicit_concatenated: false, + parts: [ + FormattedValue( + FormattedValue { + range: 2..9, + expression: Name( + ExprName { + range: 3..7, + id: "user", + ctx: Load, + }, + ), + debug_text: Some( + DebugText { + leading: "", + trailing: "=", + }, + ), + conversion: None, + format_spec: None, }, ), - debug_text: Some( - DebugText { - leading: "", - trailing: "=", - }, - ), - conversion: None, - format_spec: None, - }, - ), -] + ], + }, +) diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base_more.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base_more.snap index 346124137fa71..c9c8e8d8801f8 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base_more.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base_more.snap @@ -2,69 +2,63 @@ source: crates/ruff_python_parser/src/string.rs expression: parse_ast --- -[ - Constant( - ExprConstant { - range: 2..6, - value: Str( - StringConstant { +FString( + ExprFString { + range: 2..37, + implicit_concatenated: false, + parts: [ + String( + StringTodoName { + range: 2..6, value: "mix ", - unicode: false, - implicit_concatenated: false, }, ), - }, - ), - FormattedValue( - ExprFormattedValue { - range: 6..13, - value: Name( - ExprName { - range: 7..11, - id: "user", - ctx: Load, + FormattedValue( + FormattedValue { + range: 6..13, + expression: Name( + ExprName { + range: 7..11, + id: "user", + ctx: Load, + }, + ), + debug_text: Some( + DebugText { + leading: "", + trailing: "=", + }, + ), + conversion: None, + format_spec: None, }, ), - debug_text: Some( - DebugText { - leading: "", - trailing: "=", - }, - ), - conversion: None, - format_spec: None, - }, - ), - Constant( - ExprConstant { - range: 13..28, - value: Str( - StringConstant { + String( + StringTodoName { + range: 13..28, value: " with text and ", - unicode: false, - implicit_concatenated: false, - }, - ), - }, - ), - FormattedValue( - ExprFormattedValue { - range: 28..37, - value: Name( - ExprName { - range: 29..35, - id: "second", - ctx: Load, }, ), - debug_text: Some( - DebugText { - leading: "", - trailing: "=", + FormattedValue( + FormattedValue { + range: 28..37, + expression: Name( + ExprName { + range: 29..35, + id: "second", + ctx: Load, + }, + ), + debug_text: Some( + DebugText { + leading: "", + trailing: "=", + }, + ), + conversion: None, + format_spec: None, }, ), - conversion: None, - format_spec: None, - }, - ), -] + ], + }, +) diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_format.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_format.snap index e22f1f70ae5f6..42d790c2b4518 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_format.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_format.snap @@ -2,46 +2,46 @@ source: crates/ruff_python_parser/src/string.rs expression: parse_ast --- -[ - FormattedValue( - ExprFormattedValue { - range: 2..13, - value: Name( - ExprName { - range: 3..7, - id: "user", - ctx: Load, - }, - ), - debug_text: Some( - DebugText { - leading: "", - trailing: "=", - }, - ), - conversion: None, - format_spec: Some( - FString( - ExprFString { - range: 9..12, - values: [ - Constant( - ExprConstant { - range: 9..12, - value: Str( - StringConstant { +FString( + ExprFString { + range: 2..13, + implicit_concatenated: false, + parts: [ + FormattedValue( + FormattedValue { + range: 2..13, + expression: Name( + ExprName { + range: 3..7, + id: "user", + ctx: Load, + }, + ), + debug_text: Some( + DebugText { + leading: "", + trailing: "=", + }, + ), + conversion: None, + format_spec: Some( + FString( + ExprFString { + range: 9..12, + implicit_concatenated: false, + parts: [ + String( + StringTodoName { + range: 9..12, value: ">10", - unicode: false, - implicit_concatenated: false, }, ), - }, - ), - ], - implicit_concatenated: false, - }, - ), + ], + }, + ), + ), + }, ), - }, - ), -] + ], + }, +) diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_unescaped_newline.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_unescaped_newline.snap index 654b947387a38..1fbcf587f6804 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_unescaped_newline.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_unescaped_newline.snap @@ -9,23 +9,18 @@ expression: parse_ast value: FString( ExprFString { range: 0..11, - values: [ - Constant( - ExprConstant { + implicit_concatenated: false, + parts: [ + String( + StringTodoName { range: 4..5, - value: Str( - StringConstant { - value: "\n", - unicode: false, - implicit_concatenated: false, - }, - ), + value: "\n", }, ), FormattedValue( - ExprFormattedValue { + FormattedValue { range: 5..8, - value: Name( + expression: Name( ExprName { range: 6..7, id: "x", @@ -38,7 +33,6 @@ expression: parse_ast }, ), ], - implicit_concatenated: false, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_empty_fstring.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_empty_fstring.snap index a1435da1835d3..c704373b44aed 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_empty_fstring.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_empty_fstring.snap @@ -2,4 +2,10 @@ source: crates/ruff_python_parser/src/string.rs expression: "parse_fstring(\"\").unwrap()" --- -[] +FString( + ExprFString { + range: 2..2, + implicit_concatenated: false, + parts: [], + }, +) diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_1.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_1.snap index db3c59a6385ea..6ecd1e632a65d 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_1.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_1.snap @@ -9,21 +9,15 @@ expression: parse_ast value: FString( ExprFString { range: 0..17, - values: [ - Constant( - ExprConstant { + implicit_concatenated: true, + parts: [ + String( + StringTodoName { range: 1..16, - value: Str( - StringConstant { - value: "Hello world", - unicode: false, - implicit_concatenated: true, - }, - ), + value: "Hello world", }, ), ], - implicit_concatenated: true, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_2.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_2.snap index db3c59a6385ea..6ecd1e632a65d 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_2.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_2.snap @@ -9,21 +9,15 @@ expression: parse_ast value: FString( ExprFString { range: 0..17, - values: [ - Constant( - ExprConstant { + implicit_concatenated: true, + parts: [ + String( + StringTodoName { range: 1..16, - value: Str( - StringConstant { - value: "Hello world", - unicode: false, - implicit_concatenated: true, - }, - ), + value: "Hello world", }, ), ], - implicit_concatenated: true, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_3.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_3.snap index d7887a62aae9c..48623c07e7c3d 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_3.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_3.snap @@ -9,23 +9,18 @@ expression: parse_ast value: FString( ExprFString { range: 0..22, - values: [ - Constant( - ExprConstant { + implicit_concatenated: true, + parts: [ + String( + StringTodoName { range: 1..16, - value: Str( - StringConstant { - value: "Hello world", - unicode: false, - implicit_concatenated: true, - }, - ), + value: "Hello world", }, ), FormattedValue( - ExprFormattedValue { + FormattedValue { range: 16..21, - value: Constant( + expression: Constant( ExprConstant { range: 17..20, value: Str( @@ -43,7 +38,6 @@ expression: parse_ast }, ), ], - implicit_concatenated: true, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_4.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_4.snap index 86e8c4f5b8514..5d609b5ef4209 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_4.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_4.snap @@ -9,23 +9,18 @@ expression: parse_ast value: FString( ExprFString { range: 0..31, - values: [ - Constant( - ExprConstant { + implicit_concatenated: true, + parts: [ + String( + StringTodoName { range: 1..16, - value: Str( - StringConstant { - value: "Hello world", - unicode: false, - implicit_concatenated: true, - }, - ), + value: "Hello world", }, ), FormattedValue( - ExprFormattedValue { + FormattedValue { range: 16..21, - value: Constant( + expression: Constant( ExprConstant { range: 17..20, value: Str( @@ -42,20 +37,13 @@ expression: parse_ast format_spec: None, }, ), - Constant( - ExprConstant { + String( + StringTodoName { range: 24..30, - value: Str( - StringConstant { - value: "again!", - unicode: false, - implicit_concatenated: true, - }, - ), + value: "again!", }, ), ], - implicit_concatenated: true, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring.snap index ea76fa6ad48eb..2292afbcbf79a 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring.snap @@ -2,47 +2,47 @@ source: crates/ruff_python_parser/src/string.rs expression: parse_ast --- -[ - FormattedValue( - ExprFormattedValue { - range: 2..5, - value: Name( - ExprName { - range: 3..4, - id: "a", - ctx: Load, +FString( + ExprFString { + range: 2..17, + implicit_concatenated: false, + parts: [ + FormattedValue( + FormattedValue { + range: 2..5, + expression: Name( + ExprName { + range: 3..4, + id: "a", + ctx: Load, + }, + ), + debug_text: None, + conversion: None, + format_spec: None, }, ), - debug_text: None, - conversion: None, - format_spec: None, - }, - ), - FormattedValue( - ExprFormattedValue { - range: 5..10, - value: Name( - ExprName { - range: 7..8, - id: "b", - ctx: Load, + FormattedValue( + FormattedValue { + range: 5..10, + expression: Name( + ExprName { + range: 7..8, + id: "b", + ctx: Load, + }, + ), + debug_text: None, + conversion: None, + format_spec: None, }, ), - debug_text: None, - conversion: None, - format_spec: None, - }, - ), - Constant( - ExprConstant { - range: 10..17, - value: Str( - StringConstant { + String( + StringTodoName { + range: 10..17, value: "{foo}", - unicode: false, - implicit_concatenated: false, }, ), - }, - ), -] + ], + }, +) diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_equals.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_equals.snap index 8a4ae20ea4575..4b91169c9deca 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_equals.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_equals.snap @@ -2,39 +2,45 @@ source: crates/ruff_python_parser/src/string.rs expression: parse_ast --- -[ - FormattedValue( - ExprFormattedValue { - range: 2..12, - value: Compare( - ExprCompare { - range: 3..11, - left: Constant( - ExprConstant { - range: 3..5, - value: Int( - 42, +FString( + ExprFString { + range: 2..12, + implicit_concatenated: false, + parts: [ + FormattedValue( + FormattedValue { + range: 2..12, + expression: Compare( + ExprCompare { + range: 3..11, + left: Constant( + ExprConstant { + range: 3..5, + value: Int( + 42, + ), + }, ), + ops: [ + Eq, + ], + comparators: [ + Constant( + ExprConstant { + range: 9..11, + value: Int( + 42, + ), + }, + ), + ], }, ), - ops: [ - Eq, - ], - comparators: [ - Constant( - ExprConstant { - range: 9..11, - value: Int( - 42, - ), - }, - ), - ], + debug_text: None, + conversion: None, + format_spec: None, }, ), - debug_text: None, - conversion: None, - format_spec: None, - }, - ), -] + ], + }, +) diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_concatenation_string_spec.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_concatenation_string_spec.snap index 752f06e9b23b0..3674eafb2d9f2 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_concatenation_string_spec.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_concatenation_string_spec.snap @@ -2,49 +2,55 @@ source: crates/ruff_python_parser/src/string.rs expression: parse_ast --- -[ - FormattedValue( - ExprFormattedValue { - range: 2..15, - value: Name( - ExprName { - range: 3..6, - id: "foo", - ctx: Load, - }, - ), - debug_text: None, - conversion: None, - format_spec: Some( - FString( - ExprFString { - range: 7..14, - values: [ - FormattedValue( - ExprFormattedValue { - range: 7..14, - value: Constant( - ExprConstant { - range: 8..13, - value: Str( - StringConstant { - value: "", - unicode: false, - implicit_concatenated: true, +FString( + ExprFString { + range: 2..15, + implicit_concatenated: false, + parts: [ + FormattedValue( + FormattedValue { + range: 2..15, + expression: Name( + ExprName { + range: 3..6, + id: "foo", + ctx: Load, + }, + ), + debug_text: None, + conversion: None, + format_spec: Some( + FString( + ExprFString { + range: 7..14, + implicit_concatenated: false, + parts: [ + FormattedValue( + FormattedValue { + range: 7..14, + expression: Constant( + ExprConstant { + range: 8..13, + value: Str( + StringConstant { + value: "", + unicode: false, + implicit_concatenated: true, + }, + ), }, ), + debug_text: None, + conversion: None, + format_spec: None, }, ), - debug_text: None, - conversion: None, - format_spec: None, - }, - ), - ], - implicit_concatenated: false, - }, - ), + ], + }, + ), + ), + }, ), - }, - ), -] + ], + }, +) diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_spec.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_spec.snap index d93be4602f04e..bc9ae45975235 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_spec.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_spec.snap @@ -2,44 +2,50 @@ source: crates/ruff_python_parser/src/string.rs expression: parse_ast --- -[ - FormattedValue( - ExprFormattedValue { - range: 2..14, - value: Name( - ExprName { - range: 3..6, - id: "foo", - ctx: Load, - }, - ), - debug_text: None, - conversion: None, - format_spec: Some( - FString( - ExprFString { - range: 7..13, - values: [ - FormattedValue( - ExprFormattedValue { - range: 7..13, - value: Name( - ExprName { - range: 8..12, - id: "spec", - ctx: Load, +FString( + ExprFString { + range: 2..14, + implicit_concatenated: false, + parts: [ + FormattedValue( + FormattedValue { + range: 2..14, + expression: Name( + ExprName { + range: 3..6, + id: "foo", + ctx: Load, + }, + ), + debug_text: None, + conversion: None, + format_spec: Some( + FString( + ExprFString { + range: 7..13, + implicit_concatenated: false, + parts: [ + FormattedValue( + FormattedValue { + range: 7..13, + expression: Name( + ExprName { + range: 8..12, + id: "spec", + ctx: Load, + }, + ), + debug_text: None, + conversion: None, + format_spec: None, }, ), - debug_text: None, - conversion: None, - format_spec: None, - }, - ), - ], - implicit_concatenated: false, - }, - ), + ], + }, + ), + ), + }, ), - }, - ), -] + ], + }, +) diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_string_spec.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_string_spec.snap index 8a1149aa5c66f..c0eccf2a4587d 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_string_spec.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_string_spec.snap @@ -2,49 +2,55 @@ source: crates/ruff_python_parser/src/string.rs expression: parse_ast --- -[ - FormattedValue( - ExprFormattedValue { - range: 2..12, - value: Name( - ExprName { - range: 3..6, - id: "foo", - ctx: Load, - }, - ), - debug_text: None, - conversion: None, - format_spec: Some( - FString( - ExprFString { - range: 7..11, - values: [ - FormattedValue( - ExprFormattedValue { - range: 7..11, - value: Constant( - ExprConstant { - range: 8..10, - value: Str( - StringConstant { - value: "", - unicode: false, - implicit_concatenated: false, +FString( + ExprFString { + range: 2..12, + implicit_concatenated: false, + parts: [ + FormattedValue( + FormattedValue { + range: 2..12, + expression: Name( + ExprName { + range: 3..6, + id: "foo", + ctx: Load, + }, + ), + debug_text: None, + conversion: None, + format_spec: Some( + FString( + ExprFString { + range: 7..11, + implicit_concatenated: false, + parts: [ + FormattedValue( + FormattedValue { + range: 7..11, + expression: Constant( + ExprConstant { + range: 8..10, + value: Str( + StringConstant { + value: "", + unicode: false, + implicit_concatenated: false, + }, + ), }, ), + debug_text: None, + conversion: None, + format_spec: None, }, ), - debug_text: None, - conversion: None, - format_spec: None, - }, - ), - ], - implicit_concatenated: false, - }, - ), + ], + }, + ), + ), + }, ), - }, - ), -] + ], + }, +) diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_equals.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_equals.snap index 759c8bc9ad50f..278f861740a9e 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_equals.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_equals.snap @@ -2,39 +2,45 @@ source: crates/ruff_python_parser/src/string.rs expression: parse_ast --- -[ - FormattedValue( - ExprFormattedValue { - range: 2..10, - value: Compare( - ExprCompare { - range: 3..9, - left: Constant( - ExprConstant { - range: 3..4, - value: Int( - 1, +FString( + ExprFString { + range: 2..10, + implicit_concatenated: false, + parts: [ + FormattedValue( + FormattedValue { + range: 2..10, + expression: Compare( + ExprCompare { + range: 3..9, + left: Constant( + ExprConstant { + range: 3..4, + value: Int( + 1, + ), + }, ), + ops: [ + NotEq, + ], + comparators: [ + Constant( + ExprConstant { + range: 8..9, + value: Int( + 2, + ), + }, + ), + ], }, ), - ops: [ - NotEq, - ], - comparators: [ - Constant( - ExprConstant { - range: 8..9, - value: Int( - 2, - ), - }, - ), - ], + debug_text: None, + conversion: None, + format_spec: None, }, ), - debug_text: None, - conversion: None, - format_spec: None, - }, - ), -] + ], + }, +) diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_nested_spec.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_nested_spec.snap index f4294c5bb328b..fa5ef7eff419f 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_nested_spec.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_nested_spec.snap @@ -2,41 +2,41 @@ source: crates/ruff_python_parser/src/string.rs expression: parse_ast --- -[ - FormattedValue( - ExprFormattedValue { - range: 2..12, - value: Name( - ExprName { - range: 3..6, - id: "foo", - ctx: Load, - }, - ), - debug_text: None, - conversion: None, - format_spec: Some( - FString( - ExprFString { - range: 7..11, - values: [ - Constant( - ExprConstant { - range: 7..11, - value: Str( - StringConstant { +FString( + ExprFString { + range: 2..12, + implicit_concatenated: false, + parts: [ + FormattedValue( + FormattedValue { + range: 2..12, + expression: Name( + ExprName { + range: 3..6, + id: "foo", + ctx: Load, + }, + ), + debug_text: None, + conversion: None, + format_spec: Some( + FString( + ExprFString { + range: 7..11, + implicit_concatenated: false, + parts: [ + String( + StringTodoName { + range: 7..11, value: "spec", - unicode: false, - implicit_concatenated: false, }, ), - }, - ), - ], - implicit_concatenated: false, - }, - ), + ], + }, + ), + ), + }, ), - }, - ), -] + ], + }, +) diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_self_doc_prec_space.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_self_doc_prec_space.snap index 1891d37330dd0..24fa34110b1e4 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_self_doc_prec_space.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_self_doc_prec_space.snap @@ -2,25 +2,31 @@ source: crates/ruff_python_parser/src/string.rs expression: parse_ast --- -[ - FormattedValue( - ExprFormattedValue { - range: 2..9, - value: Name( - ExprName { - range: 3..4, - id: "x", - ctx: Load, +FString( + ExprFString { + range: 2..9, + implicit_concatenated: false, + parts: [ + FormattedValue( + FormattedValue { + range: 2..9, + expression: Name( + ExprName { + range: 3..4, + id: "x", + ctx: Load, + }, + ), + debug_text: Some( + DebugText { + leading: "", + trailing: " =", + }, + ), + conversion: None, + format_spec: None, }, ), - debug_text: Some( - DebugText { - leading: "", - trailing: " =", - }, - ), - conversion: None, - format_spec: None, - }, - ), -] + ], + }, +) diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_self_doc_trailing_space.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_self_doc_trailing_space.snap index aa84db5f3f4fa..118ebe2da6550 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_self_doc_trailing_space.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_self_doc_trailing_space.snap @@ -2,25 +2,31 @@ source: crates/ruff_python_parser/src/string.rs expression: parse_ast --- -[ - FormattedValue( - ExprFormattedValue { - range: 2..9, - value: Name( - ExprName { - range: 3..4, - id: "x", - ctx: Load, +FString( + ExprFString { + range: 2..9, + implicit_concatenated: false, + parts: [ + FormattedValue( + FormattedValue { + range: 2..9, + expression: Name( + ExprName { + range: 3..4, + id: "x", + ctx: Load, + }, + ), + debug_text: Some( + DebugText { + leading: "", + trailing: "= ", + }, + ), + conversion: None, + format_spec: None, }, ), - debug_text: Some( - DebugText { - leading: "", - trailing: "= ", - }, - ), - conversion: None, - format_spec: None, - }, - ), -] + ], + }, +) diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_yield_expr.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_yield_expr.snap index d52ab525d43db..b671f97c9feba 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_yield_expr.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_yield_expr.snap @@ -2,19 +2,25 @@ source: crates/ruff_python_parser/src/string.rs expression: parse_ast --- -[ - FormattedValue( - ExprFormattedValue { - range: 2..9, - value: Yield( - ExprYield { - range: 3..8, - value: None, +FString( + ExprFString { + range: 2..9, + implicit_concatenated: false, + parts: [ + FormattedValue( + FormattedValue { + range: 2..9, + expression: Yield( + ExprYield { + range: 3..8, + value: None, + }, + ), + debug_text: None, + conversion: None, + format_spec: None, }, ), - debug_text: None, - conversion: None, - format_spec: None, - }, - ), -] + ], + }, +) diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_f_string_concat_1.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_f_string_concat_1.snap index 5f0ecabfed2a9..837ba4718c78b 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_f_string_concat_1.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_f_string_concat_1.snap @@ -9,21 +9,15 @@ expression: parse_ast value: FString( ExprFString { range: 0..18, - values: [ - Constant( - ExprConstant { + implicit_concatenated: true, + parts: [ + String( + StringTodoName { range: 2..17, - value: Str( - StringConstant { - value: "Hello world", - unicode: true, - implicit_concatenated: true, - }, - ), + value: "Hello world", }, ), ], - implicit_concatenated: true, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_f_string_concat_2.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_f_string_concat_2.snap index 39610847fe217..2479e73bece35 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_f_string_concat_2.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_f_string_concat_2.snap @@ -9,21 +9,15 @@ expression: parse_ast value: FString( ExprFString { range: 0..22, - values: [ - Constant( - ExprConstant { + implicit_concatenated: true, + parts: [ + String( + StringTodoName { range: 2..21, - value: Str( - StringConstant { - value: "Hello world!", - unicode: true, - implicit_concatenated: true, - }, - ), + value: "Hello world!", }, ), ], - implicit_concatenated: true, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__raw_fstring.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__raw_fstring.snap index 65f4daf83d8d7..dcd954c4e1860 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__raw_fstring.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__raw_fstring.snap @@ -9,11 +9,12 @@ expression: parse_ast value: FString( ExprFString { range: 0..7, - values: [ + implicit_concatenated: false, + parts: [ FormattedValue( - ExprFormattedValue { + FormattedValue { range: 3..6, - value: Name( + expression: Name( ExprName { range: 4..5, id: "x", @@ -26,7 +27,6 @@ expression: parse_ast }, ), ], - implicit_concatenated: false, }, ), }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__triple_quoted_raw_fstring.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__triple_quoted_raw_fstring.snap index 6793e65f73804..c28615bf2c573 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__triple_quoted_raw_fstring.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__triple_quoted_raw_fstring.snap @@ -9,11 +9,12 @@ expression: parse_ast value: FString( ExprFString { range: 0..11, - values: [ + implicit_concatenated: false, + parts: [ FormattedValue( - ExprFormattedValue { + FormattedValue { range: 5..8, - value: Name( + expression: Name( ExprName { range: 6..7, id: "x", @@ -26,7 +27,6 @@ expression: parse_ast }, ), ], - implicit_concatenated: false, }, ), }, diff --git a/crates/ruff_python_parser/src/string.rs b/crates/ruff_python_parser/src/string.rs index 0524473f1252e..4b3e6edaaa755 100644 --- a/crates/ruff_python_parser/src/string.rs +++ b/crates/ruff_python_parser/src/string.rs @@ -173,12 +173,16 @@ impl<'a> StringParser<'a> { } } - fn parse_formatted_value(&mut self, nested: u8) -> Result, LexicalError> { + fn parse_formatted_value(&mut self, nested: u8) -> Result, LexicalError> { use FStringErrorType::{ - EmptyExpression, InvalidConversionFlag, InvalidExpression, MismatchedDelimiter, - UnclosedLbrace, Unmatched, UnterminatedString, + EmptyExpression, ExpressionNestedTooDeeply, InvalidConversionFlag, InvalidExpression, + MismatchedDelimiter, UnclosedLbrace, Unmatched, UnterminatedString, }; + if nested >= 2 { + return Err(FStringError::new(ExpressionNestedTooDeeply, self.get_pos()).into()); + } + let mut expression = String::new(); // for self-documenting strings we also store the `=` and any trailing space inside // expression (because we want to combine it with any trailing spaces before the equal @@ -242,7 +246,7 @@ impl<'a> StringParser<'a> { let parsed_spec = self.parse_spec(nested)?; spec = Some(Box::new(Expr::from(ast::ExprFString { - values: parsed_spec, + parts: parsed_spec, implicit_concatenated: false, range: self.range(start_location), }))); @@ -320,8 +324,8 @@ impl<'a> StringParser<'a> { let leading = &expression[..usize::from(value.start() - start_location) - 1]; let trailing = &expression[usize::from(value.end() - start_location) - 1..]; - vec![Expr::from(ast::ExprFormattedValue { - value: Box::new(value), + vec![ast::FStringPart::FormattedValue(ast::FormattedValue { + expression: Box::new(value), debug_text: Some(ast::DebugText { leading: leading.to_string(), trailing: trailing.to_string(), @@ -331,8 +335,8 @@ impl<'a> StringParser<'a> { range: self.range(start_location), })] } else { - vec![Expr::from(ast::ExprFormattedValue { - value: Box::new( + vec![ast::FStringPart::FormattedValue(ast::FormattedValue { + expression: Box::new( parse_fstring_expr(&expression, start_location).map_err(|e| { FStringError::new( InvalidExpression(Box::new(e.error)), @@ -376,7 +380,7 @@ impl<'a> StringParser<'a> { Err(FStringError::new(UnclosedLbrace, self.get_pos()).into()) } - fn parse_spec(&mut self, nested: u8) -> Result, LexicalError> { + fn parse_spec(&mut self, nested: u8) -> Result, LexicalError> { let mut spec_constructor = Vec::new(); let mut constant_piece = String::new(); let mut start_location = self.get_pos(); @@ -384,12 +388,12 @@ impl<'a> StringParser<'a> { match next { '{' => { if !constant_piece.is_empty() { - spec_constructor.push(Expr::from(ast::ExprConstant { - value: std::mem::take(&mut constant_piece).into(), + spec_constructor.push(ast::FStringPart::String(ast::StringTodoName { + value: std::mem::take(&mut constant_piece), range: self.range(start_location), })); } - let parsed_expr = self.parse_fstring(nested + 1)?; + let parsed_expr = self.parse_formatted_value(nested + 1)?; spec_constructor.extend(parsed_expr); start_location = self.get_pos(); continue; @@ -404,24 +408,21 @@ impl<'a> StringParser<'a> { self.next_char(); } if !constant_piece.is_empty() { - spec_constructor.push(Expr::from(ast::ExprConstant { - value: std::mem::take(&mut constant_piece).into(), + spec_constructor.push(ast::FStringPart::String(ast::StringTodoName { + value: std::mem::take(&mut constant_piece), range: self.range(start_location), })); } Ok(spec_constructor) } - fn parse_fstring(&mut self, nested: u8) -> Result, LexicalError> { - use FStringErrorType::{ExpressionNestedTooDeeply, SingleRbrace, UnclosedLbrace}; - - if nested >= 2 { - return Err(FStringError::new(ExpressionNestedTooDeeply, self.get_pos()).into()); - } + fn parse_fstring(&mut self, nested: u8) -> Result { + use FStringErrorType::{SingleRbrace, UnclosedLbrace}; let mut content = String::new(); - let mut start_location = self.get_pos(); - let mut values = vec![]; + let start_location = self.get_pos(); + let mut part_start_location = self.get_pos(); + let mut parts = vec![]; while let Some(ch) = self.peek() { match ch { @@ -441,15 +442,15 @@ impl<'a> StringParser<'a> { } } if !content.is_empty() { - values.push(Expr::from(ast::ExprConstant { - value: std::mem::take(&mut content).into(), - range: self.range(start_location), + parts.push(ast::FStringPart::String(ast::StringTodoName { + value: std::mem::take(&mut content), + range: self.range(part_start_location), })); } - let parsed_values = self.parse_formatted_value(nested)?; - values.extend(parsed_values); - start_location = self.get_pos(); + let parsed_parts = self.parse_formatted_value(nested)?; + parts.extend(parsed_parts); + part_start_location = self.get_pos(); } '}' => { if nested > 0 { @@ -475,13 +476,17 @@ impl<'a> StringParser<'a> { } if !content.is_empty() { - values.push(Expr::from(ast::ExprConstant { - value: content.into(), - range: self.range(start_location), + parts.push(ast::FStringPart::String(ast::StringTodoName { + value: content, + range: self.range(part_start_location), })); } - Ok(values) + Ok(Expr::from(ast::ExprFString { + parts, + implicit_concatenated: false, + range: self.range(start_location), + })) } fn parse_bytes(&mut self) -> Result { @@ -533,13 +538,13 @@ impl<'a> StringParser<'a> { })) } - fn parse(&mut self) -> Result, LexicalError> { + fn parse(&mut self) -> Result { if self.kind.is_any_fstring() { self.parse_fstring(0) } else if self.kind.is_any_bytes() { - self.parse_bytes().map(|expr| vec![expr]) + self.parse_bytes() } else { - self.parse_string().map(|expr| vec![expr]) + self.parse_string() } } } @@ -554,7 +559,7 @@ fn parse_string( kind: StringKind, triple_quoted: bool, start: TextSize, -) -> Result, LexicalError> { +) -> Result { StringParser::new(source, kind, triple_quoted, start).parse() } @@ -587,14 +592,13 @@ pub(crate) fn parse_strings( if has_bytes { let mut content: Vec = vec![]; for (start, (source, kind, triple_quoted), _) in values { - for value in parse_string(&source, kind, triple_quoted, start)? { - match value { - Expr::Constant(ast::ExprConstant { - value: Constant::Bytes(BytesConstant { value, .. }), - .. - }) => content.extend(value), - _ => unreachable!("Unexpected non-bytes expression."), - } + let value = parse_string(&source, kind, triple_quoted, start)?; + match value { + Expr::Constant(ast::ExprConstant { + value: Constant::Bytes(BytesConstant { value, .. }), + .. + }) => content.extend(value), + _ => unreachable!("Unexpected non-bytes expression."), } } return Ok(ast::ExprConstant { @@ -610,14 +614,13 @@ pub(crate) fn parse_strings( if !has_fstring { let mut content: Vec = vec![]; for (start, (source, kind, triple_quoted), _) in values { - for value in parse_string(&source, kind, triple_quoted, start)? { - match value { - Expr::Constant(ast::ExprConstant { - value: Constant::Str(StringConstant { value, .. }), - .. - }) => content.push(value), - _ => unreachable!("Unexpected non-string expression."), - } + let value = parse_string(&source, kind, triple_quoted, start)?; + match value { + Expr::Constant(ast::ExprConstant { + value: Constant::Str(StringConstant { value, .. }), + .. + }) => content.push(value), + _ => unreachable!("Unexpected non-string expression."), } } return Ok(ast::ExprConstant { @@ -632,44 +635,58 @@ pub(crate) fn parse_strings( } // De-duplicate adjacent constants. - let mut deduped: Vec = vec![]; + let mut deduped: Vec = vec![]; let mut current: Vec = vec![]; let mut current_start = initial_start; let mut current_end = last_end; - let take_current = |current: &mut Vec, start, end| -> Expr { - Expr::Constant(ast::ExprConstant { - value: Constant::Str(StringConstant { - value: current.drain(..).collect::(), - unicode: is_initial_kind_unicode, - implicit_concatenated, - }), + let take_current = |current: &mut Vec, start, end| -> ast::FStringPart { + ast::FStringPart::String(ast::StringTodoName { + value: current.drain(..).collect::(), range: TextRange::new(start, end), }) }; for (start, (source, kind, triple_quoted), _) in values { - for value in parse_string(&source, kind, triple_quoted, start)? { - let value_range = value.range(); - match value { - Expr::FormattedValue { .. } => { - if !current.is_empty() { - deduped.push(take_current(&mut current, current_start, current_end)); + let value = parse_string(&source, kind, triple_quoted, start)?; + match value { + Expr::FString(ast::ExprFString { parts, .. }) => { + for part in parts { + match part { + ast::FStringPart::String(ast::StringTodoName { + value: inner, + range, + }) => { + if current.is_empty() { + current_start = range.start(); + } + current_end = range.end(); + current.push(inner); + } + ast::FStringPart::FormattedValue(ast::FormattedValue { .. }) => { + if !current.is_empty() { + deduped.push(take_current( + &mut current, + current_start, + current_end, + )); + } + deduped.push(part); + } } - deduped.push(value); } - Expr::Constant(ast::ExprConstant { - value: Constant::Str(StringConstant { value, .. }), - .. - }) => { - if current.is_empty() { - current_start = value_range.start(); - } - current_end = value_range.end(); - current.push(value); + } + Expr::Constant(ast::ExprConstant { + value: Constant::Str(StringConstant { value, .. }), + range, + }) => { + if current.is_empty() { + current_start = range.start(); } - _ => unreachable!("Unexpected non-string expression."), + current_end = range.end(); + current.push(value); } + expr => unreachable!("Unexpected non-string expression: `{expr:?}`."), } } if !current.is_empty() { @@ -677,7 +694,7 @@ pub(crate) fn parse_strings( } Ok(Expr::FString(ast::ExprFString { - values: deduped, + parts: deduped, implicit_concatenated, range: TextRange::new(initial_start, last_end), })) @@ -788,7 +805,7 @@ mod tests { use super::*; use crate::parser::parse_suite; - fn parse_fstring(source: &str) -> Result, LexicalError> { + fn parse_fstring(source: &str) -> Result { StringParser::new(source, StringKind::FString, false, TextSize::default()).parse() } From 3847a14e920b936171253711fa58692c788c8c9a Mon Sep 17 00:00:00 2001 From: David Szotten Date: Sat, 5 Aug 2023 14:29:07 +0100 Subject: [PATCH 03/17] FStringPart for formatter (no change yet; formatter only uses FString atm) --- .../src/expression/expr_formatted_value.rs | 24 ------------- .../src/expression/mod.rs | 2 -- .../src/expression/string.rs | 8 ++--- crates/ruff_python_formatter/src/generated.rs | 36 ------------------- 4 files changed, 4 insertions(+), 66 deletions(-) delete mode 100644 crates/ruff_python_formatter/src/expression/expr_formatted_value.rs diff --git a/crates/ruff_python_formatter/src/expression/expr_formatted_value.rs b/crates/ruff_python_formatter/src/expression/expr_formatted_value.rs deleted file mode 100644 index 5133cb86e5845..0000000000000 --- a/crates/ruff_python_formatter/src/expression/expr_formatted_value.rs +++ /dev/null @@ -1,24 +0,0 @@ -use ruff_python_ast::node::AnyNodeRef; -use ruff_python_ast::ExprFormattedValue; - -use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses}; -use crate::prelude::*; - -#[derive(Default)] -pub struct FormatExprFormattedValue; - -impl FormatNodeRule for FormatExprFormattedValue { - fn fmt_fields(&self, _item: &ExprFormattedValue, _f: &mut PyFormatter) -> FormatResult<()> { - unreachable!("Handled inside of `FormatExprFString"); - } -} - -impl NeedsParentheses for ExprFormattedValue { - fn needs_parentheses( - &self, - _parent: AnyNodeRef, - _context: &PyFormatContext, - ) -> OptionalParentheses { - OptionalParentheses::Multiline - } -} diff --git a/crates/ruff_python_formatter/src/expression/mod.rs b/crates/ruff_python_formatter/src/expression/mod.rs index a1dc38ba17178..0c069ec7395ee 100644 --- a/crates/ruff_python_formatter/src/expression/mod.rs +++ b/crates/ruff_python_formatter/src/expression/mod.rs @@ -31,7 +31,6 @@ pub(crate) mod expr_constant; pub(crate) mod expr_dict; pub(crate) mod expr_dict_comp; pub(crate) mod expr_f_string; -pub(crate) mod expr_formatted_value; pub(crate) mod expr_generator_exp; pub(crate) mod expr_if_exp; pub(crate) mod expr_ipy_escape_command; @@ -90,7 +89,6 @@ impl FormatRule> for FormatExpr { Expr::YieldFrom(expr) => expr.format().fmt(f), Expr::Compare(expr) => expr.format().fmt(f), Expr::Call(expr) => expr.format().fmt(f), - Expr::FormattedValue(expr) => expr.format().fmt(f), Expr::FString(expr) => expr.format().fmt(f), Expr::Constant(expr) => expr.format().fmt(f), Expr::Attribute(expr) => expr.format().fmt(f), diff --git a/crates/ruff_python_formatter/src/expression/string.rs b/crates/ruff_python_formatter/src/expression/string.rs index 3bd7bdb12982b..51d52f9e7ab7f 100644 --- a/crates/ruff_python_formatter/src/expression/string.rs +++ b/crates/ruff_python_formatter/src/expression/string.rs @@ -47,13 +47,13 @@ impl<'a> AnyString<'a> { fn quoting(&self, locator: &Locator) -> Quoting { match self { Self::Constant(_) => Quoting::CanChange, - Self::FString(f_string) => { - if f_string.values.iter().any(|value| match value { - Expr::FormattedValue(ast::ExprFormattedValue { range, .. }) => { + Self::FString(f_str) => { + if f_str.parts.iter().any(|value| match value { + ast::FStringPart::FormattedValue(ast::FormattedValue { range, .. }) => { let string_content = locator.slice(*range); string_content.contains(['"', '\'']) } - _ => false, + ast::FStringPart::String(_) => false, }) { Quoting::Preserve } else { diff --git a/crates/ruff_python_formatter/src/generated.rs b/crates/ruff_python_formatter/src/generated.rs index 08c248e221e5c..5f10ad4cc5167 100644 --- a/crates/ruff_python_formatter/src/generated.rs +++ b/crates/ruff_python_formatter/src/generated.rs @@ -1534,42 +1534,6 @@ impl<'ast> IntoFormat> for ast::ExprCall { } } -impl FormatRule> - for crate::expression::expr_formatted_value::FormatExprFormattedValue -{ - #[inline] - fn fmt(&self, node: &ast::ExprFormattedValue, f: &mut PyFormatter) -> FormatResult<()> { - FormatNodeRule::::fmt(self, node, f) - } -} -impl<'ast> AsFormat> for ast::ExprFormattedValue { - type Format<'a> = FormatRefWithRule< - 'a, - ast::ExprFormattedValue, - crate::expression::expr_formatted_value::FormatExprFormattedValue, - PyFormatContext<'ast>, - >; - fn format(&self) -> Self::Format<'_> { - FormatRefWithRule::new( - self, - crate::expression::expr_formatted_value::FormatExprFormattedValue::default(), - ) - } -} -impl<'ast> IntoFormat> for ast::ExprFormattedValue { - type Format = FormatOwnedWithRule< - ast::ExprFormattedValue, - crate::expression::expr_formatted_value::FormatExprFormattedValue, - PyFormatContext<'ast>, - >; - fn into_format(self) -> Self::Format { - FormatOwnedWithRule::new( - self, - crate::expression::expr_formatted_value::FormatExprFormattedValue::default(), - ) - } -} - impl FormatRule> for crate::expression::expr_f_string::FormatExprFString { From e7037954bdc042c3cdcb12fd70a3900328d1fd34 Mon Sep 17 00:00:00 2001 From: David Szotten Date: Sat, 5 Aug 2023 22:28:54 +0100 Subject: [PATCH 04/17] format_spec -> FStringPart instead of Expr --- crates/ruff_linter/src/checkers/ast/mod.rs | 11 ----- crates/ruff_python_ast/src/comparable.rs | 6 +-- crates/ruff_python_ast/src/helpers.rs | 4 +- crates/ruff_python_ast/src/nodes.rs | 3 +- crates/ruff_python_ast/src/relocate.rs | 40 +++++++++------- crates/ruff_python_ast/src/visitor.rs | 12 +---- .../ruff_python_ast/src/visitor/preorder.rs | 10 +--- crates/ruff_python_ast/tests/preorder.rs | 6 --- crates/ruff_python_ast/tests/visitor.rs | 6 --- ...uff_python_parser__parser__tests__try.snap | 4 +- ...ython_parser__parser__tests__try_star.snap | 8 ++-- ...string__tests__fstring_constant_range.snap | 4 +- ...ing__tests__fstring_escaped_character.snap | 2 +- ...tring__tests__fstring_escaped_newline.snap | 2 +- ...ing__tests__fstring_line_continuation.snap | 2 +- ...__fstring_parse_self_documenting_base.snap | 2 +- ...ring_parse_self_documenting_base_more.snap | 4 +- ...fstring_parse_self_documenting_format.snap | 18 ++------ ...ing__tests__fstring_unescaped_newline.snap | 2 +- ...tring__tests__parse_f_string_concat_3.snap | 2 +- ...tring__tests__parse_f_string_concat_4.snap | 2 +- ..._parser__string__tests__parse_fstring.snap | 4 +- ...__string__tests__parse_fstring_equals.snap | 2 +- ...ring_nested_concatenation_string_spec.snap | 46 ++++++++----------- ...ing__tests__parse_fstring_nested_spec.snap | 36 ++++++--------- ...sts__parse_fstring_nested_string_spec.snap | 46 ++++++++----------- ...ring__tests__parse_fstring_not_equals.snap | 2 +- ..._tests__parse_fstring_not_nested_spec.snap | 18 ++------ ...ts__parse_fstring_self_doc_prec_space.snap | 2 +- ...parse_fstring_self_doc_trailing_space.snap | 2 +- ...ring__tests__parse_fstring_yield_expr.snap | 2 +- ...on_parser__string__tests__raw_fstring.snap | 2 +- ...ing__tests__triple_quoted_raw_fstring.snap | 2 +- crates/ruff_python_parser/src/string.rs | 11 +---- 34 files changed, 123 insertions(+), 202 deletions(-) diff --git a/crates/ruff_linter/src/checkers/ast/mod.rs b/crates/ruff_linter/src/checkers/ast/mod.rs index 19663bbeff139..577a0451778a5 100644 --- a/crates/ruff_linter/src/checkers/ast/mod.rs +++ b/crates/ruff_linter/src/checkers/ast/mod.rs @@ -1278,17 +1278,6 @@ where self.semantic.flags = flags_snapshot; } - fn visit_format_spec(&mut self, format_spec: &'b Expr) { - match format_spec { - Expr::FString(ast::ExprFString { values, .. }) => { - for value in values { - self.visit_expr(value); - } - } - _ => unreachable!("Unexpected expression for format_spec"), - } - } - fn visit_parameters(&mut self, parameters: &'b Parameters) { // Step 1: Binding. // Bind, but intentionally avoid walking default expressions, as we handle them diff --git a/crates/ruff_python_ast/src/comparable.rs b/crates/ruff_python_ast/src/comparable.rs index 89166670e7c49..18af63ee4ef0c 100644 --- a/crates/ruff_python_ast/src/comparable.rs +++ b/crates/ruff_python_ast/src/comparable.rs @@ -530,7 +530,7 @@ pub struct FormattedValue<'a> { expression: ComparableExpr<'a>, debug_text: Option<&'a ast::DebugText>, pub conversion: ast::ConversionFlag, - pub format_spec: Option>>, + pub format_spec: Vec>, } impl<'a> From<&'a ast::FStringPart> for ComparableFStringPart<'a> { @@ -542,7 +542,7 @@ impl<'a> From<&'a ast::FStringPart> for ComparableFStringPart<'a> { expression: (&formatted_value.expression).into(), debug_text: formatted_value.debug_text.as_ref(), conversion: formatted_value.conversion, - format_spec: formatted_value.format_spec.as_ref().map(Into::into), + format_spec: formatted_value.format_spec.iter().map(Into::into).collect(), }) } } @@ -676,7 +676,7 @@ pub struct ExprFormattedValue<'a> { value: Box>, debug_text: Option<&'a ast::DebugText>, conversion: ast::ConversionFlag, - format_spec: Option>>, + format_spec: Vec>, } #[derive(Debug, PartialEq, Eq, Hash)] diff --git a/crates/ruff_python_ast/src/helpers.rs b/crates/ruff_python_ast/src/helpers.rs index 5bebca42ec27c..afed041f58d41 100644 --- a/crates/ruff_python_ast/src/helpers.rs +++ b/crates/ruff_python_ast/src/helpers.rs @@ -297,8 +297,8 @@ pub fn any_over_fstring_part(part: &FStringPart, func: &dyn Fn(&Expr) -> bool) - }) => { any_over_expr(expression, func) || format_spec - .as_ref() - .map_or(false, |format_spec| any_over_expr(format_spec, func)) + .iter() + .any(|spec_part| any_over_fstring_part(spec_part, func)) } } } diff --git a/crates/ruff_python_ast/src/nodes.rs b/crates/ruff_python_ast/src/nodes.rs index bbd16b1977416..7aebce0b49084 100644 --- a/crates/ruff_python_ast/src/nodes.rs +++ b/crates/ruff_python_ast/src/nodes.rs @@ -880,8 +880,7 @@ pub struct FormattedValue { pub expression: Box, pub debug_text: Option, pub conversion: ConversionFlag, - // TODO: is this Option>? - pub format_spec: Option>, + pub format_spec: Vec, } #[derive(Clone, Debug, PartialEq)] diff --git a/crates/ruff_python_ast/src/relocate.rs b/crates/ruff_python_ast/src/relocate.rs index a5743f1cb691c..86a793ff67317 100644 --- a/crates/ruff_python_ast/src/relocate.rs +++ b/crates/ruff_python_ast/src/relocate.rs @@ -131,23 +131,7 @@ pub fn relocate_expr(expr: &mut Expr, location: TextRange) { Expr::FString(nodes::ExprFString { parts, range, .. }) => { *range = location; for part in parts { - match part { - nodes::FStringPart::String(nodes::StringTodoName { range, .. }) => { - *range = location; - } - nodes::FStringPart::FormattedValue(nodes::FormattedValue { - range, - expression, - format_spec, - .. - }) => { - *range = location; - relocate_expr(expression, location); - if let Some(format_spec) = format_spec { - relocate_expr(format_spec, location); - } - } - } + relocate_fstring_part(part, location); } } Expr::Constant(nodes::ExprConstant { range, .. }) => { @@ -208,3 +192,25 @@ pub fn relocate_expr(expr: &mut Expr, location: TextRange) { } } } + +/// Change a f-string part's location (recursively) to match a desired, fixed +/// location. +fn relocate_fstring_part(part: &mut nodes::FStringPart, location: TextRange) { + match part { + nodes::FStringPart::String(nodes::StringTodoName { range, .. }) => { + *range = location; + } + nodes::FStringPart::FormattedValue(nodes::FormattedValue { + range, + expression, + format_spec, + .. + }) => { + *range = location; + relocate_expr(expression, location); + for spec_part in format_spec { + relocate_fstring_part(spec_part, location); + } + } + } +} diff --git a/crates/ruff_python_ast/src/visitor.rs b/crates/ruff_python_ast/src/visitor.rs index 038d9ea07f84f..45ba3b62a36a6 100644 --- a/crates/ruff_python_ast/src/visitor.rs +++ b/crates/ruff_python_ast/src/visitor.rs @@ -50,9 +50,6 @@ pub trait Visitor<'a> { fn visit_except_handler(&mut self, except_handler: &'a ExceptHandler) { walk_except_handler(self, except_handler); } - fn visit_format_spec(&mut self, format_spec: &'a Expr) { - walk_format_spec(self, format_spec); - } fn visit_arguments(&mut self, arguments: &'a Arguments) { walk_arguments(self, arguments); } @@ -563,10 +560,6 @@ pub fn walk_except_handler<'a, V: Visitor<'a> + ?Sized>( } } -pub fn walk_format_spec<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, format_spec: &'a Expr) { - visitor.visit_expr(format_spec); -} - pub fn walk_arguments<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, arguments: &'a Arguments) { // Note that the there might be keywords before the last arg, e.g. in // f(*args, a=2, *args2, **kwargs)`, but we follow Python in evaluating first `args` and then @@ -727,9 +720,8 @@ pub fn walk_fstring_part<'a, V: Visitor<'a> + ?Sized>( }) = fstring_part { visitor.visit_expr(expression); - if let Some(expr) = format_spec { - // TODO: why go via `visit_format_spec` as opposed to just straight to `visit_expr`? - visitor.visit_format_spec(expr); + for spec_part in format_spec { + walk_fstring_part(visitor, spec_part); } } } diff --git a/crates/ruff_python_ast/src/visitor/preorder.rs b/crates/ruff_python_ast/src/visitor/preorder.rs index 7a9f175766b9d..04c9b182ca616 100644 --- a/crates/ruff_python_ast/src/visitor/preorder.rs +++ b/crates/ruff_python_ast/src/visitor/preorder.rs @@ -74,11 +74,6 @@ pub trait PreorderVisitor<'a> { walk_except_handler(self, except_handler); } - #[inline] - fn visit_format_spec(&mut self, format_spec: &'a Expr) { - walk_format_spec(self, format_spec); - } - #[inline] fn visit_arguments(&mut self, arguments: &'a Arguments) { walk_arguments(self, arguments); @@ -514,9 +509,8 @@ pub fn walk_fstring_part<'a, V: PreorderVisitor<'a> + ?Sized>( }) = fstring_part { visitor.visit_expr(expression); - if let Some(expr) = format_spec { - // TODO: why go via `visit_format_spec` as opposed to just straight to `visit_expr`? - visitor.visit_format_spec(expr); + for spec_part in format_spec { + walk_fstring_part(visitor, spec_part); } } } diff --git a/crates/ruff_python_ast/tests/preorder.rs b/crates/ruff_python_ast/tests/preorder.rs index 8c6cba2f30250..663a204ecfa58 100644 --- a/crates/ruff_python_ast/tests/preorder.rs +++ b/crates/ruff_python_ast/tests/preorder.rs @@ -225,12 +225,6 @@ impl PreorderVisitor<'_> for RecordVisitor { self.exit_node(); } - fn visit_format_spec(&mut self, format_spec: &Expr) { - self.enter_node(format_spec); - walk_expr(self, format_spec); - self.exit_node(); - } - fn visit_parameters(&mut self, parameters: &Parameters) { self.enter_node(parameters); walk_parameters(self, parameters); diff --git a/crates/ruff_python_ast/tests/visitor.rs b/crates/ruff_python_ast/tests/visitor.rs index b44cf55ce0324..4d733eb57436b 100644 --- a/crates/ruff_python_ast/tests/visitor.rs +++ b/crates/ruff_python_ast/tests/visitor.rs @@ -228,12 +228,6 @@ impl Visitor<'_> for RecordVisitor { self.exit_node(); } - fn visit_format_spec(&mut self, format_spec: &Expr) { - self.enter_node(format_spec); - walk_expr(self, format_spec); - self.exit_node(); - } - fn visit_parameters(&mut self, parameters: &Parameters) { self.enter_node(parameters); walk_parameters(self, parameters); diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try.snap index 464a7f31fe8cf..7143d62f05d65 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try.snap @@ -119,7 +119,7 @@ expression: parse_ast ), debug_text: None, conversion: None, - format_spec: None, + format_spec: [], }, ), ], @@ -211,7 +211,7 @@ expression: parse_ast ), debug_text: None, conversion: None, - format_spec: None, + format_spec: [], }, ), ], diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try_star.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try_star.snap index 9563bb76da920..2d56073a34c9b 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try_star.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try_star.snap @@ -235,7 +235,7 @@ expression: parse_ast ), debug_text: None, conversion: None, - format_spec: None, + format_spec: [], }, ), String( @@ -266,7 +266,7 @@ expression: parse_ast ), debug_text: None, conversion: None, - format_spec: None, + format_spec: [], }, ), ], @@ -358,7 +358,7 @@ expression: parse_ast ), debug_text: None, conversion: None, - format_spec: None, + format_spec: [], }, ), String( @@ -389,7 +389,7 @@ expression: parse_ast ), debug_text: None, conversion: None, - format_spec: None, + format_spec: [], }, ), ], diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_constant_range.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_constant_range.snap index ab3919c96632b..fdaf136baba7c 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_constant_range.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_constant_range.snap @@ -29,7 +29,7 @@ expression: parse_ast ), debug_text: None, conversion: None, - format_spec: None, + format_spec: [], }, ), String( @@ -50,7 +50,7 @@ expression: parse_ast ), debug_text: None, conversion: None, - format_spec: None, + format_spec: [], }, ), String( diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_character.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_character.snap index 1a0a57367b7b5..7f62fbef9b8cb 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_character.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_character.snap @@ -29,7 +29,7 @@ expression: parse_ast ), debug_text: None, conversion: None, - format_spec: None, + format_spec: [], }, ), ], diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_newline.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_newline.snap index fedbfdfe5b12a..48f33d11d570c 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_newline.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_newline.snap @@ -29,7 +29,7 @@ expression: parse_ast ), debug_text: None, conversion: None, - format_spec: None, + format_spec: [], }, ), ], diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_line_continuation.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_line_continuation.snap index 89e29bb052e97..c195c8a97acb7 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_line_continuation.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_line_continuation.snap @@ -29,7 +29,7 @@ expression: parse_ast ), debug_text: None, conversion: None, - format_spec: None, + format_spec: [], }, ), ], diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base.snap index 1d1751726ff70..bb257fdc4349b 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base.snap @@ -24,7 +24,7 @@ FString( }, ), conversion: None, - format_spec: None, + format_spec: [], }, ), ], diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base_more.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base_more.snap index c9c8e8d8801f8..b85d6c805d226 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base_more.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base_more.snap @@ -30,7 +30,7 @@ FString( }, ), conversion: None, - format_spec: None, + format_spec: [], }, ), String( @@ -56,7 +56,7 @@ FString( }, ), conversion: None, - format_spec: None, + format_spec: [], }, ), ], diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_format.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_format.snap index 42d790c2b4518..8176c2891506a 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_format.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_format.snap @@ -24,22 +24,14 @@ FString( }, ), conversion: None, - format_spec: Some( - FString( - ExprFString { + format_spec: [ + String( + StringTodoName { range: 9..12, - implicit_concatenated: false, - parts: [ - String( - StringTodoName { - range: 9..12, - value: ">10", - }, - ), - ], + value: ">10", }, ), - ), + ], }, ), ], diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_unescaped_newline.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_unescaped_newline.snap index 1fbcf587f6804..ca370d78e70e1 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_unescaped_newline.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_unescaped_newline.snap @@ -29,7 +29,7 @@ expression: parse_ast ), debug_text: None, conversion: None, - format_spec: None, + format_spec: [], }, ), ], diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_3.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_3.snap index 48623c07e7c3d..48de12a8bf867 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_3.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_3.snap @@ -34,7 +34,7 @@ expression: parse_ast ), debug_text: None, conversion: None, - format_spec: None, + format_spec: [], }, ), ], diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_4.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_4.snap index 5d609b5ef4209..8c2012e7c0b77 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_4.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_4.snap @@ -34,7 +34,7 @@ expression: parse_ast ), debug_text: None, conversion: None, - format_spec: None, + format_spec: [], }, ), String( diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring.snap index 2292afbcbf79a..5daca143ae92a 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring.snap @@ -19,7 +19,7 @@ FString( ), debug_text: None, conversion: None, - format_spec: None, + format_spec: [], }, ), FormattedValue( @@ -34,7 +34,7 @@ FString( ), debug_text: None, conversion: None, - format_spec: None, + format_spec: [], }, ), String( diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_equals.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_equals.snap index 4b91169c9deca..ef20767fb833b 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_equals.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_equals.snap @@ -38,7 +38,7 @@ FString( ), debug_text: None, conversion: None, - format_spec: None, + format_spec: [], }, ), ], diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_concatenation_string_spec.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_concatenation_string_spec.snap index 3674eafb2d9f2..ca0f544e27a09 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_concatenation_string_spec.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_concatenation_string_spec.snap @@ -19,36 +19,28 @@ FString( ), debug_text: None, conversion: None, - format_spec: Some( - FString( - ExprFString { + format_spec: [ + FormattedValue( + FormattedValue { range: 7..14, - implicit_concatenated: false, - parts: [ - FormattedValue( - FormattedValue { - range: 7..14, - expression: Constant( - ExprConstant { - range: 8..13, - value: Str( - StringConstant { - value: "", - unicode: false, - implicit_concatenated: true, - }, - ), - }, - ), - debug_text: None, - conversion: None, - format_spec: None, - }, - ), - ], + expression: Constant( + ExprConstant { + range: 8..13, + value: Str( + StringConstant { + value: "", + unicode: false, + implicit_concatenated: true, + }, + ), + }, + ), + debug_text: None, + conversion: None, + format_spec: [], }, ), - ), + ], }, ), ], diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_spec.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_spec.snap index bc9ae45975235..9fd8c07f5abce 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_spec.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_spec.snap @@ -19,31 +19,23 @@ FString( ), debug_text: None, conversion: None, - format_spec: Some( - FString( - ExprFString { + format_spec: [ + FormattedValue( + FormattedValue { range: 7..13, - implicit_concatenated: false, - parts: [ - FormattedValue( - FormattedValue { - range: 7..13, - expression: Name( - ExprName { - range: 8..12, - id: "spec", - ctx: Load, - }, - ), - debug_text: None, - conversion: None, - format_spec: None, - }, - ), - ], + expression: Name( + ExprName { + range: 8..12, + id: "spec", + ctx: Load, + }, + ), + debug_text: None, + conversion: None, + format_spec: [], }, ), - ), + ], }, ), ], diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_string_spec.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_string_spec.snap index c0eccf2a4587d..267bfb58a5565 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_string_spec.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_string_spec.snap @@ -19,36 +19,28 @@ FString( ), debug_text: None, conversion: None, - format_spec: Some( - FString( - ExprFString { + format_spec: [ + FormattedValue( + FormattedValue { range: 7..11, - implicit_concatenated: false, - parts: [ - FormattedValue( - FormattedValue { - range: 7..11, - expression: Constant( - ExprConstant { - range: 8..10, - value: Str( - StringConstant { - value: "", - unicode: false, - implicit_concatenated: false, - }, - ), - }, - ), - debug_text: None, - conversion: None, - format_spec: None, - }, - ), - ], + expression: Constant( + ExprConstant { + range: 8..10, + value: Str( + StringConstant { + value: "", + unicode: false, + implicit_concatenated: false, + }, + ), + }, + ), + debug_text: None, + conversion: None, + format_spec: [], }, ), - ), + ], }, ), ], diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_equals.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_equals.snap index 278f861740a9e..06ae95d28278e 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_equals.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_equals.snap @@ -38,7 +38,7 @@ FString( ), debug_text: None, conversion: None, - format_spec: None, + format_spec: [], }, ), ], diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_nested_spec.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_nested_spec.snap index fa5ef7eff419f..a5ac0620aad2d 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_nested_spec.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_nested_spec.snap @@ -19,22 +19,14 @@ FString( ), debug_text: None, conversion: None, - format_spec: Some( - FString( - ExprFString { + format_spec: [ + String( + StringTodoName { range: 7..11, - implicit_concatenated: false, - parts: [ - String( - StringTodoName { - range: 7..11, - value: "spec", - }, - ), - ], + value: "spec", }, ), - ), + ], }, ), ], diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_self_doc_prec_space.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_self_doc_prec_space.snap index 24fa34110b1e4..d74d5dc69b35d 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_self_doc_prec_space.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_self_doc_prec_space.snap @@ -24,7 +24,7 @@ FString( }, ), conversion: None, - format_spec: None, + format_spec: [], }, ), ], diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_self_doc_trailing_space.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_self_doc_trailing_space.snap index 118ebe2da6550..721aea1ca9ff2 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_self_doc_trailing_space.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_self_doc_trailing_space.snap @@ -24,7 +24,7 @@ FString( }, ), conversion: None, - format_spec: None, + format_spec: [], }, ), ], diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_yield_expr.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_yield_expr.snap index b671f97c9feba..a9f2af8c6e21c 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_yield_expr.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_yield_expr.snap @@ -18,7 +18,7 @@ FString( ), debug_text: None, conversion: None, - format_spec: None, + format_spec: [], }, ), ], diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__raw_fstring.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__raw_fstring.snap index dcd954c4e1860..e8b37db3235b0 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__raw_fstring.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__raw_fstring.snap @@ -23,7 +23,7 @@ expression: parse_ast ), debug_text: None, conversion: None, - format_spec: None, + format_spec: [], }, ), ], diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__triple_quoted_raw_fstring.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__triple_quoted_raw_fstring.snap index c28615bf2c573..f81548a8a85d8 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__triple_quoted_raw_fstring.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__triple_quoted_raw_fstring.snap @@ -23,7 +23,7 @@ expression: parse_ast ), debug_text: None, conversion: None, - format_spec: None, + format_spec: [], }, ), ], diff --git a/crates/ruff_python_parser/src/string.rs b/crates/ruff_python_parser/src/string.rs index 4b3e6edaaa755..f5148ddd99248 100644 --- a/crates/ruff_python_parser/src/string.rs +++ b/crates/ruff_python_parser/src/string.rs @@ -189,7 +189,7 @@ impl<'a> StringParser<'a> { // sign). the expression_length is the length of the actual expression part that we pass to // `parse_fstring_expr` let mut expression_length = 0; - let mut spec = None; + let mut spec = vec![]; let mut delimiters = Vec::new(); let mut conversion = ConversionFlag::None; let mut self_documenting = false; @@ -242,14 +242,7 @@ impl<'a> StringParser<'a> { } ':' if delimiters.is_empty() => { - let start_location = self.get_pos(); - let parsed_spec = self.parse_spec(nested)?; - - spec = Some(Box::new(Expr::from(ast::ExprFString { - parts: parsed_spec, - implicit_concatenated: false, - range: self.range(start_location), - }))); + spec = self.parse_spec(nested)?; } '(' | '{' | '[' => { expression.push(ch); From 62b428496c4e0a46f70c1f2a2d68193571b7d97e Mon Sep 17 00:00:00 2001 From: David Szotten Date: Sat, 5 Aug 2023 22:29:30 +0100 Subject: [PATCH 05/17] FStringPart for generator --- crates/ruff_python_codegen/src/generator.rs | 63 +++++++-------------- 1 file changed, 19 insertions(+), 44 deletions(-) diff --git a/crates/ruff_python_codegen/src/generator.rs b/crates/ruff_python_codegen/src/generator.rs index 0bd53c94db3ee..f29175e35d3ba 100644 --- a/crates/ruff_python_codegen/src/generator.rs +++ b/crates/ruff_python_codegen/src/generator.rs @@ -1075,20 +1075,8 @@ impl<'a> Generator<'a> { } self.p(")"); } - Expr::FormattedValue(ast::ExprFormattedValue { - value, - debug_text, - conversion, - format_spec, - range: _, - }) => self.unparse_formatted( - value, - debug_text.as_ref(), - *conversion, - format_spec.as_deref(), - ), - Expr::FString(ast::ExprFString { values, .. }) => { - self.unparse_f_string(values, false); + Expr::FString(ast::ExprFString { parts, .. }) => { + self.unparse_fstring(parts, false); } Expr::Constant(ast::ExprConstant { value, range: _ }) => { self.unparse_constant(value); @@ -1268,9 +1256,9 @@ impl<'a> Generator<'a> { } } - fn unparse_f_string_body(&mut self, values: &[Expr], is_spec: bool) { + fn unparse_fstring_body(&mut self, values: &[ast::FStringPart]) { for value in values { - self.unparse_f_string_elem(value, is_spec); + self.unparse_fstring_elem(value); } } @@ -1279,7 +1267,7 @@ impl<'a> Generator<'a> { val: &Expr, debug_text: Option<&DebugText>, conversion: ConversionFlag, - spec: Option<&Expr>, + spec: &[ast::FStringPart], ) { let mut generator = Generator::new(self.indent, self.quote, self.line_ending); generator.unparse_expr(val, precedence::FORMATTED_VALUE); @@ -1307,50 +1295,37 @@ impl<'a> Generator<'a> { self.p(&format!("{}", conversion as u8 as char)); } - if let Some(spec) = spec { + if !spec.is_empty() { self.p(":"); - self.unparse_f_string_elem(spec, true); + self.unparse_fstring(spec, true); } self.p("}"); } - fn unparse_f_string_elem(&mut self, expr: &Expr, is_spec: bool) { - match expr { - Expr::Constant(ast::ExprConstant { value, .. }) => { - if let Constant::Str(ast::StringConstant { value, .. }) = value { - self.unparse_f_string_literal(value); - } else { - unreachable!() - } - } - Expr::FString(ast::ExprFString { values, .. }) => { - self.unparse_f_string(values, is_spec); + fn unparse_fstring_elem(&mut self, part: &ast::FStringPart) { + match part { + ast::FStringPart::String(ast::StringTodoName { value, .. }) => { + self.unparse_fstring_literal(value); } - Expr::FormattedValue(ast::ExprFormattedValue { - value, + ast::FStringPart::FormattedValue(ast::FormattedValue { + expression, debug_text, conversion, format_spec, range: _, - }) => self.unparse_formatted( - value, - debug_text.as_ref(), - *conversion, - format_spec.as_deref(), - ), - _ => unreachable!(), + }) => self.unparse_formatted(expression, debug_text.as_ref(), *conversion, format_spec), } } - fn unparse_f_string_literal(&mut self, s: &str) { + fn unparse_fstring_literal(&mut self, s: &str) { let s = s.replace('{', "{{").replace('}', "}}"); self.p(&s); } - fn unparse_f_string(&mut self, values: &[Expr], is_spec: bool) { + fn unparse_fstring(&mut self, values: &[ast::FStringPart], is_spec: bool) { if is_spec { - self.unparse_f_string_body(values, is_spec); + self.unparse_fstring_body(values); } else { self.p("f"); let mut generator = Generator::new( @@ -1361,7 +1336,7 @@ impl<'a> Generator<'a> { }, self.line_ending, ); - generator.unparse_f_string_body(values, is_spec); + generator.unparse_fstring_body(values); let body = &generator.buffer; self.p_str_repr(body); } @@ -1682,7 +1657,7 @@ class Foo: } #[test] - fn self_documenting_f_string() { + fn self_documenting_fstring() { assert_round_trip!(r#"f"{ chr(65) = }""#); assert_round_trip!(r#"f"{ chr(65) = !s}""#); assert_round_trip!(r#"f"{ chr(65) = !r}""#); From c27cd5994c3a0a22641532ab85db2d8159512a52 Mon Sep 17 00:00:00 2001 From: David Szotten Date: Sat, 5 Aug 2023 22:29:45 +0100 Subject: [PATCH 06/17] wip fixing ruff rules --- .../src/checkers/ast/analyze/expression.rs | 6 ++-- .../src/rules/flake8_comprehensions/fixes.rs | 2 +- .../flake8_pytest_style/rules/helpers.rs | 13 ++++++-- crates/ruff_linter/src/rules/flynt/helpers.rs | 33 +++++++++---------- .../flynt/rules/static_join_to_fstring.rs | 8 ++--- .../rules/f_string_missing_placeholders.rs | 10 ++++-- .../pylint/rules/assert_on_string_literal.rs | 26 +++++++-------- .../pyupgrade/rules/use_pep604_annotation.rs | 1 - .../explicit_f_string_type_conversion.rs | 14 ++++---- .../tryceratops/rules/raise_vanilla_args.rs | 10 +++--- .../src/analyze/type_inference.rs | 1 - 11 files changed, 67 insertions(+), 57 deletions(-) diff --git a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs index f2ed2125a5851..d8a8b0d5be19a 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs @@ -957,15 +957,15 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { pylint::rules::await_outside_async(checker, expr); } } - Expr::FString(ast::ExprFString { values, .. }) => { + Expr::FString(ast::ExprFString { parts, .. }) => { if checker.enabled(Rule::FStringMissingPlaceholders) { - pyflakes::rules::f_string_missing_placeholders(expr, values, checker); + pyflakes::rules::f_string_missing_placeholders(expr, parts, checker); } if checker.enabled(Rule::HardcodedSQLExpression) { flake8_bandit::rules::hardcoded_sql_expression(checker, expr); } if checker.enabled(Rule::ExplicitFStringTypeConversion) { - ruff::rules::explicit_f_string_type_conversion(checker, expr, values); + ruff::rules::explicit_f_string_type_conversion(checker, expr, parts); } } Expr::BinOp(ast::ExprBinOp { diff --git a/crates/ruff_linter/src/rules/flake8_comprehensions/fixes.rs b/crates/ruff_linter/src/rules/flake8_comprehensions/fixes.rs index 6ede08874185e..01471858628dd 100644 --- a/crates/ruff_linter/src/rules/flake8_comprehensions/fixes.rs +++ b/crates/ruff_linter/src/rules/flake8_comprehensions/fixes.rs @@ -1076,7 +1076,7 @@ pub(crate) fn fix_unnecessary_map( // If the expression is embedded in an f-string, surround it with spaces to avoid // syntax errors. if matches!(object_type, ObjectType::Set | ObjectType::Dict) { - if parent.is_some_and(Expr::is_formatted_value_expr) { + if parent.is_some_and(Expr::is_f_string_expr) { content = format!(" {content} "); } } diff --git a/crates/ruff_linter/src/rules/flake8_pytest_style/rules/helpers.rs b/crates/ruff_linter/src/rules/flake8_pytest_style/rules/helpers.rs index 43a183267fa78..fca0b3e07a5f4 100644 --- a/crates/ruff_linter/src/rules/flake8_pytest_style/rules/helpers.rs +++ b/crates/ruff_linter/src/rules/flake8_pytest_style/rules/helpers.rs @@ -63,13 +63,22 @@ pub(super) fn is_empty_or_null_string(expr: &Expr) -> bool { .. }) => string.is_empty(), Expr::Constant(constant) if constant.value.is_none() => true, - Expr::FString(ast::ExprFString { values, .. }) => { - values.iter().all(is_empty_or_null_string) + Expr::FString(ast::ExprFString { parts, .. }) => { + parts.iter().all(is_empty_or_null_string_part) } _ => false, } } +fn is_empty_or_null_string_part(part: &ast::FStringPart) -> bool { + match part { + ast::FStringPart::String(ast::StringTodoName { value, .. }) => value.is_empty(), + ast::FStringPart::FormattedValue(ast::FormattedValue { expression, .. }) => { + is_empty_or_null_string(expression) + } + } +} + pub(super) fn split_names(names: &str) -> Vec<&str> { // Match the following pytest code: // [x.strip() for x in argnames.split(",") if x.strip()] diff --git a/crates/ruff_linter/src/rules/flynt/helpers.rs b/crates/ruff_linter/src/rules/flynt/helpers.rs index bc2e18197a0a2..12eda4ae1c39e 100644 --- a/crates/ruff_linter/src/rules/flynt/helpers.rs +++ b/crates/ruff_linter/src/rules/flynt/helpers.rs @@ -2,24 +2,22 @@ use ruff_python_ast::{self as ast, Arguments, Constant, ConversionFlag, Expr}; use ruff_text_size::TextRange; /// Wrap an expression in a `FormattedValue` with no special formatting. -fn to_formatted_value_expr(inner: &Expr) -> Expr { - let node = ast::ExprFormattedValue { - value: Box::new(inner.clone()), +fn to_formatted_value_expr(inner: &Expr) -> ast::FStringPart { + ast::FStringPart::FormattedValue(ast::FormattedValue { + expression: Box::new(inner.clone()), debug_text: None, conversion: ConversionFlag::None, - format_spec: None, + format_spec: vec![], range: TextRange::default(), - }; - node.into() + }) } /// Convert a string to a constant string expression. -pub(super) fn to_constant_string(s: &str) -> Expr { - let node = ast::ExprConstant { - value: s.to_owned().into(), +pub(super) fn to_constant_string(s: &str) -> ast::FStringPart { + ast::FStringPart::String(ast::StringTodoName { + value: s.to_owned(), range: TextRange::default(), - }; - node.into() + }) } /// Figure out if `expr` represents a "simple" call @@ -51,15 +49,16 @@ fn is_simple_callee(func: &Expr) -> bool { } /// Convert an expression to a f-string element (if it looks like a good idea). -pub(super) fn to_f_string_element(expr: &Expr) -> Option { +pub(super) fn to_fstring_part(expr: &Expr) -> Option { match expr { // These are directly handled by `unparse_f_string_element`: Expr::Constant(ast::ExprConstant { - value: Constant::Str(_), - .. - }) - | Expr::FString(_) - | Expr::FormattedValue(_) => Some(expr.clone()), + value: Constant::Str(value), + range, + }) => Some(ast::FStringPart::String(ast::StringTodoName { + value: value.to_string(), + range: *range, + })), // These should be pretty safe to wrap in a formatted value. Expr::Constant(ast::ExprConstant { value: diff --git a/crates/ruff_linter/src/rules/flynt/rules/static_join_to_fstring.rs b/crates/ruff_linter/src/rules/flynt/rules/static_join_to_fstring.rs index 969b7cf94bed0..3ecdbe58b9885 100644 --- a/crates/ruff_linter/src/rules/flynt/rules/static_join_to_fstring.rs +++ b/crates/ruff_linter/src/rules/flynt/rules/static_join_to_fstring.rs @@ -91,7 +91,7 @@ fn build_fstring(joiner: &str, joinees: &[Expr]) -> Option { return Some(node.into()); } - let mut fstring_elems = Vec::with_capacity(joinees.len() * 2); + let mut fstring_parts = Vec::with_capacity(joinees.len() * 2); let mut first = true; for expr in joinees { @@ -101,13 +101,13 @@ fn build_fstring(joiner: &str, joinees: &[Expr]) -> Option { return None; } if !std::mem::take(&mut first) { - fstring_elems.push(helpers::to_constant_string(joiner)); + fstring_parts.push(helpers::to_constant_string(joiner)); } - fstring_elems.push(helpers::to_f_string_element(expr)?); + fstring_parts.push(helpers::to_fstring_part(expr)?); } let node = ast::ExprFString { - values: fstring_elems, + parts: fstring_parts, implicit_concatenated: false, range: TextRange::default(), }; diff --git a/crates/ruff_linter/src/rules/pyflakes/rules/f_string_missing_placeholders.rs b/crates/ruff_linter/src/rules/pyflakes/rules/f_string_missing_placeholders.rs index 779ed539bb7c1..2bd90fb748d13 100644 --- a/crates/ruff_linter/src/rules/pyflakes/rules/f_string_missing_placeholders.rs +++ b/crates/ruff_linter/src/rules/pyflakes/rules/f_string_missing_placeholders.rs @@ -1,6 +1,6 @@ use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::{Expr, PySourceType}; +use ruff_python_ast::{Expr, FStringPart, PySourceType}; use ruff_python_parser::{lexer, AsMode, StringKind, Tok}; use ruff_source_file::Locator; use ruff_text_size::{Ranged, TextRange, TextSize}; @@ -79,10 +79,14 @@ fn find_useless_f_strings<'a>( } /// F541 -pub(crate) fn f_string_missing_placeholders(expr: &Expr, values: &[Expr], checker: &mut Checker) { +pub(crate) fn f_string_missing_placeholders( + expr: &Expr, + values: &[FStringPart], + checker: &mut Checker, +) { if !values .iter() - .any(|value| matches!(value, Expr::FormattedValue(_))) + .any(|value| matches!(value, FStringPart::FormattedValue(_))) { for (prefix_range, tok_range) in find_useless_f_strings(expr, checker.locator(), checker.source_type) diff --git a/crates/ruff_linter/src/rules/pylint/rules/assert_on_string_literal.rs b/crates/ruff_linter/src/rules/pylint/rules/assert_on_string_literal.rs index 50589bc6ec95e..c31a2027db230 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/assert_on_string_literal.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/assert_on_string_literal.rs @@ -72,25 +72,21 @@ pub(crate) fn assert_on_string_literal(checker: &mut Checker, test: &Expr) { } _ => {} }, - Expr::FString(ast::ExprFString { values, .. }) => { + Expr::FString(ast::ExprFString { parts, .. }) => { checker.diagnostics.push(Diagnostic::new( AssertOnStringLiteral { - kind: if values.iter().all(|value| match value { - Expr::Constant(ast::ExprConstant { value, .. }) => match value { - Constant::Str(value) => value.is_empty(), - Constant::Bytes(value) => value.is_empty(), - _ => false, - }, - _ => false, + kind: if parts.iter().all(|part| match part { + ast::FStringPart::String(ast::StringTodoName { value, .. }) => { + value.is_empty() + } + ast::FStringPart::FormattedValue(_) => false, }) { Kind::Empty - } else if values.iter().any(|value| match value { - Expr::Constant(ast::ExprConstant { value, .. }) => match value { - Constant::Str(value) => !value.is_empty(), - Constant::Bytes(value) => !value.is_empty(), - _ => false, - }, - _ => false, + } else if parts.iter().any(|part| match part { + ast::FStringPart::String(ast::StringTodoName { value, .. }) => { + !value.is_empty() + } + ast::FStringPart::FormattedValue(_) => false, }) { Kind::NonEmpty } else { diff --git a/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep604_annotation.rs b/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep604_annotation.rs index c1fbbfa6cec22..0edaf468c87e0 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep604_annotation.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep604_annotation.rs @@ -188,7 +188,6 @@ fn is_allowed_value(expr: &Expr) -> bool { | Expr::GeneratorExp(_) | Expr::Compare(_) | Expr::Call(_) - | Expr::FormattedValue(_) | Expr::FString(_) | Expr::Constant(_) | Expr::Attribute(_) diff --git a/crates/ruff_linter/src/rules/ruff/rules/explicit_f_string_type_conversion.rs b/crates/ruff_linter/src/rules/ruff/rules/explicit_f_string_type_conversion.rs index 11302f4ba295d..54299734f376d 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/explicit_f_string_type_conversion.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/explicit_f_string_type_conversion.rs @@ -56,12 +56,12 @@ impl AlwaysAutofixableViolation for ExplicitFStringTypeConversion { pub(crate) fn explicit_f_string_type_conversion( checker: &mut Checker, expr: &Expr, - values: &[Expr], + values: &[ast::FStringPart], ) { for (index, formatted_value) in values .iter() .filter_map(|expr| { - if let Expr::FormattedValue(expr) = &expr { + if let ast::FStringPart::FormattedValue(expr) = &expr { Some(expr) } else { None @@ -69,8 +69,10 @@ pub(crate) fn explicit_f_string_type_conversion( }) .enumerate() { - let ast::ExprFormattedValue { - value, conversion, .. + let ast::FormattedValue { + expression, + conversion, + .. } = formatted_value; // Skip if there's already a conversion flag. @@ -87,7 +89,7 @@ pub(crate) fn explicit_f_string_type_conversion( range: _, }, .. - }) = value.as_ref() + }) = expression.as_ref() else { continue; }; @@ -122,7 +124,7 @@ pub(crate) fn explicit_f_string_type_conversion( continue; } - let mut diagnostic = Diagnostic::new(ExplicitFStringTypeConversion, value.range()); + let mut diagnostic = Diagnostic::new(ExplicitFStringTypeConversion, expression.range()); if checker.patch(diagnostic.kind.rule()) { diagnostic.try_set_fix(|| { convert_call_to_conversion_flag(expr, index, checker.locator(), checker.stylist()) diff --git a/crates/ruff_linter/src/rules/tryceratops/rules/raise_vanilla_args.rs b/crates/ruff_linter/src/rules/tryceratops/rules/raise_vanilla_args.rs index bb07a670b1b02..53b9021129e04 100644 --- a/crates/ruff_linter/src/rules/tryceratops/rules/raise_vanilla_args.rs +++ b/crates/ruff_linter/src/rules/tryceratops/rules/raise_vanilla_args.rs @@ -89,10 +89,12 @@ pub(crate) fn raise_vanilla_args(checker: &mut Checker, expr: &Expr) { /// some whitespace). fn contains_message(expr: &Expr) -> bool { match expr { - Expr::FString(ast::ExprFString { values, .. }) => { - for value in values { - if contains_message(value) { - return true; + Expr::FString(ast::ExprFString { parts, .. }) => { + for part in parts { + if let ast::FStringPart::String(ast::StringTodoName { value, .. }) = part { + if value.chars().any(char::is_whitespace) { + return true; + } } } } diff --git a/crates/ruff_python_semantic/src/analyze/type_inference.rs b/crates/ruff_python_semantic/src/analyze/type_inference.rs index 4bba5b9826010..890e2a8e952e1 100644 --- a/crates/ruff_python_semantic/src/analyze/type_inference.rs +++ b/crates/ruff_python_semantic/src/analyze/type_inference.rs @@ -302,7 +302,6 @@ impl From<&Expr> for ResolvedPythonType { | Expr::YieldFrom(_) | Expr::Compare(_) | Expr::Call(_) - | Expr::FormattedValue(_) | Expr::Attribute(_) | Expr::Subscript(_) | Expr::Starred(_) From d1daf36a025bf9301b0ed4ada3fe64657de8e422 Mon Sep 17 00:00:00 2001 From: David Szotten Date: Sun, 6 Aug 2023 18:03:33 +0100 Subject: [PATCH 07/17] fix with feature=unreachable-code --- crates/ruff_linter/src/rules/ruff/rules/unreachable.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/ruff_linter/src/rules/ruff/rules/unreachable.rs b/crates/ruff_linter/src/rules/ruff/rules/unreachable.rs index e52fe4889bf27..e8696d7208588 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/unreachable.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/unreachable.rs @@ -625,7 +625,6 @@ impl<'stmt> BasicBlocksBuilder<'stmt> { | Expr::Set(_) | Expr::Compare(_) | Expr::Call(_) - | Expr::FormattedValue(_) | Expr::FString(_) | Expr::Constant(_) | Expr::Attribute(_) From 2827c3846dad4b845fc8470961dc021c0a398462 Mon Sep 17 00:00:00 2001 From: David Szotten Date: Thu, 17 Aug 2023 09:04:14 +0100 Subject: [PATCH 08/17] FormattedValue is a node --- crates/ruff_python_ast/src/node.rs | 75 ++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/crates/ruff_python_ast/src/node.rs b/crates/ruff_python_ast/src/node.rs index b7827d86a3858..ae2c7c81d0c77 100644 --- a/crates/ruff_python_ast/src/node.rs +++ b/crates/ruff_python_ast/src/node.rs @@ -82,6 +82,7 @@ pub enum AnyNode { ExprSlice(ast::ExprSlice), ExprIpyEscapeCommand(ast::ExprIpyEscapeCommand), ExceptHandlerExceptHandler(ast::ExceptHandlerExceptHandler), + FormattedValue(ast::FormattedValue), PatternMatchValue(ast::PatternMatchValue), PatternMatchSingleton(ast::PatternMatchSingleton), PatternMatchSequence(ast::PatternMatchSequence), @@ -157,6 +158,7 @@ impl AnyNode { | AnyNode::ExprYieldFrom(_) | AnyNode::ExprCompare(_) | AnyNode::ExprCall(_) + | AnyNode::FormattedValue(_) | AnyNode::ExprFString(_) | AnyNode::ExprConstant(_) | AnyNode::ExprAttribute(_) @@ -254,6 +256,7 @@ impl AnyNode { | AnyNode::StmtContinue(_) | AnyNode::StmtIpyEscapeCommand(_) | AnyNode::ExceptHandlerExceptHandler(_) + | AnyNode::FormattedValue(_) | AnyNode::PatternMatchValue(_) | AnyNode::PatternMatchSingleton(_) | AnyNode::PatternMatchSequence(_) @@ -329,6 +332,7 @@ impl AnyNode { | AnyNode::ExprYieldFrom(_) | AnyNode::ExprCompare(_) | AnyNode::ExprCall(_) + | AnyNode::FormattedValue(_) | AnyNode::ExprFString(_) | AnyNode::ExprConstant(_) | AnyNode::ExprAttribute(_) @@ -423,6 +427,7 @@ impl AnyNode { | AnyNode::ExprYieldFrom(_) | AnyNode::ExprCompare(_) | AnyNode::ExprCall(_) + | AnyNode::FormattedValue(_) | AnyNode::ExprFString(_) | AnyNode::ExprConstant(_) | AnyNode::ExprAttribute(_) @@ -502,6 +507,7 @@ impl AnyNode { | AnyNode::ExprYieldFrom(_) | AnyNode::ExprCompare(_) | AnyNode::ExprCall(_) + | AnyNode::FormattedValue(_) | AnyNode::ExprFString(_) | AnyNode::ExprConstant(_) | AnyNode::ExprAttribute(_) @@ -606,6 +612,7 @@ impl AnyNode { Self::ExprYieldFrom(node) => AnyNodeRef::ExprYieldFrom(node), Self::ExprCompare(node) => AnyNodeRef::ExprCompare(node), Self::ExprCall(node) => AnyNodeRef::ExprCall(node), + Self::FormattedValue(node) => AnyNodeRef::FormattedValue(node), Self::ExprFString(node) => AnyNodeRef::ExprFString(node), Self::ExprConstant(node) => AnyNodeRef::ExprConstant(node), Self::ExprAttribute(node) => AnyNodeRef::ExprAttribute(node), @@ -2558,6 +2565,50 @@ impl AstNode for ast::ExprCall { visitor.visit_arguments(arguments); } } +impl AstNode for ast::FormattedValue { + fn cast(kind: AnyNode) -> Option + where + Self: Sized, + { + if let AnyNode::FormattedValue(node) = kind { + Some(node) + } else { + None + } + } + + fn cast_ref(kind: AnyNodeRef) -> Option<&Self> { + if let AnyNodeRef::FormattedValue(node) = kind { + Some(node) + } else { + None + } + } + + fn as_any_node_ref(&self) -> AnyNodeRef { + AnyNodeRef::from(self) + } + + fn into_any_node(self) -> AnyNode { + AnyNode::from(self) + } + + fn visit_preorder<'a, V>(&'a self, visitor: &mut V) + where + V: PreorderVisitor<'a> + ?Sized, + { + let ast::FormattedValue { + expression, + format_spec, + .. + } = self; + visitor.visit_expr(expression); + + for spec_part in format_spec { + visitor.visit_fstring_part(spec_part); + } + } +} impl AstNode for ast::ExprFString { fn cast(kind: AnyNode) -> Option where @@ -4389,6 +4440,12 @@ impl From for AnyNode { } } +impl From for AnyNode { + fn from(node: ast::FormattedValue) -> Self { + AnyNode::FormattedValue(node) + } +} + impl From for AnyNode { fn from(node: ast::ExprFString) -> Self { AnyNode::ExprFString(node) @@ -4635,6 +4692,7 @@ impl Ranged for AnyNode { AnyNode::ExprYieldFrom(node) => node.range(), AnyNode::ExprCompare(node) => node.range(), AnyNode::ExprCall(node) => node.range(), + AnyNode::FormattedValue(node) => node.range(), AnyNode::ExprFString(node) => node.range(), AnyNode::ExprConstant(node) => node.range(), AnyNode::ExprAttribute(node) => node.range(), @@ -4721,6 +4779,7 @@ pub enum AnyNodeRef<'a> { ExprYieldFrom(&'a ast::ExprYieldFrom), ExprCompare(&'a ast::ExprCompare), ExprCall(&'a ast::ExprCall), + FormattedValue(&'a ast::FormattedValue), ExprFString(&'a ast::ExprFString), ExprConstant(&'a ast::ExprConstant), ExprAttribute(&'a ast::ExprAttribute), @@ -4806,6 +4865,7 @@ impl AnyNodeRef<'_> { AnyNodeRef::ExprYieldFrom(node) => NonNull::from(*node).cast(), AnyNodeRef::ExprCompare(node) => NonNull::from(*node).cast(), AnyNodeRef::ExprCall(node) => NonNull::from(*node).cast(), + AnyNodeRef::FormattedValue(node) => NonNull::from(*node).cast(), AnyNodeRef::ExprFString(node) => NonNull::from(*node).cast(), AnyNodeRef::ExprConstant(node) => NonNull::from(*node).cast(), AnyNodeRef::ExprAttribute(node) => NonNull::from(*node).cast(), @@ -4897,6 +4957,7 @@ impl AnyNodeRef<'_> { AnyNodeRef::ExprYieldFrom(_) => NodeKind::ExprYieldFrom, AnyNodeRef::ExprCompare(_) => NodeKind::ExprCompare, AnyNodeRef::ExprCall(_) => NodeKind::ExprCall, + AnyNodeRef::FormattedValue(_) => NodeKind::FormattedValue, AnyNodeRef::ExprFString(_) => NodeKind::ExprFString, AnyNodeRef::ExprConstant(_) => NodeKind::ExprConstant, AnyNodeRef::ExprAttribute(_) => NodeKind::ExprAttribute, @@ -4983,6 +5044,7 @@ impl AnyNodeRef<'_> { | AnyNodeRef::ExprYieldFrom(_) | AnyNodeRef::ExprCompare(_) | AnyNodeRef::ExprCall(_) + | AnyNodeRef::FormattedValue(_) | AnyNodeRef::ExprFString(_) | AnyNodeRef::ExprConstant(_) | AnyNodeRef::ExprAttribute(_) @@ -5041,6 +5103,7 @@ impl AnyNodeRef<'_> { | AnyNodeRef::ExprYieldFrom(_) | AnyNodeRef::ExprCompare(_) | AnyNodeRef::ExprCall(_) + | AnyNodeRef::FormattedValue(_) | AnyNodeRef::ExprFString(_) | AnyNodeRef::ExprConstant(_) | AnyNodeRef::ExprAttribute(_) @@ -5154,6 +5217,7 @@ impl AnyNodeRef<'_> { | AnyNodeRef::ExprYieldFrom(_) | AnyNodeRef::ExprCompare(_) | AnyNodeRef::ExprCall(_) + | AnyNodeRef::FormattedValue(_) | AnyNodeRef::ExprFString(_) | AnyNodeRef::ExprConstant(_) | AnyNodeRef::ExprAttribute(_) @@ -5248,6 +5312,7 @@ impl AnyNodeRef<'_> { | AnyNodeRef::ExprYieldFrom(_) | AnyNodeRef::ExprCompare(_) | AnyNodeRef::ExprCall(_) + | AnyNodeRef::FormattedValue(_) | AnyNodeRef::ExprFString(_) | AnyNodeRef::ExprConstant(_) | AnyNodeRef::ExprAttribute(_) @@ -5327,6 +5392,7 @@ impl AnyNodeRef<'_> { | AnyNodeRef::ExprYieldFrom(_) | AnyNodeRef::ExprCompare(_) | AnyNodeRef::ExprCall(_) + | AnyNodeRef::FormattedValue(_) | AnyNodeRef::ExprFString(_) | AnyNodeRef::ExprConstant(_) | AnyNodeRef::ExprAttribute(_) @@ -5440,6 +5506,7 @@ impl AnyNodeRef<'_> { AnyNodeRef::ExprYieldFrom(node) => node.visit_preorder(visitor), AnyNodeRef::ExprCompare(node) => node.visit_preorder(visitor), AnyNodeRef::ExprCall(node) => node.visit_preorder(visitor), + AnyNodeRef::FormattedValue(node) => node.visit_preorder(visitor), AnyNodeRef::ExprFString(node) => node.visit_preorder(visitor), AnyNodeRef::ExprConstant(node) => node.visit_preorder(visitor), AnyNodeRef::ExprAttribute(node) => node.visit_preorder(visitor), @@ -5750,6 +5817,12 @@ impl<'a> From<&'a ast::ExprCall> for AnyNodeRef<'a> { } } +impl<'a> From<&'a ast::FormattedValue> for AnyNodeRef<'a> { + fn from(node: &'a ast::FormattedValue) -> Self { + AnyNodeRef::FormattedValue(node) + } +} + impl<'a> From<&'a ast::ExprFString> for AnyNodeRef<'a> { fn from(node: &'a ast::ExprFString) -> Self { AnyNodeRef::ExprFString(node) @@ -6108,6 +6181,7 @@ impl Ranged for AnyNodeRef<'_> { AnyNodeRef::ExprYieldFrom(node) => node.range(), AnyNodeRef::ExprCompare(node) => node.range(), AnyNodeRef::ExprCall(node) => node.range(), + AnyNodeRef::FormattedValue(node) => node.range(), AnyNodeRef::ExprFString(node) => node.range(), AnyNodeRef::ExprConstant(node) => node.range(), AnyNodeRef::ExprAttribute(node) => node.range(), @@ -6196,6 +6270,7 @@ pub enum NodeKind { ExprYieldFrom, ExprCompare, ExprCall, + FormattedValue, ExprFString, ExprConstant, ExprAttribute, From 76573bc663f0917be9104d0a600d275510559c17 Mon Sep 17 00:00:00 2001 From: David Szotten Date: Thu, 17 Aug 2023 09:26:42 +0100 Subject: [PATCH 09/17] StringTodoName is a node --- crates/ruff_python_ast/src/node.rs | 68 +++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/crates/ruff_python_ast/src/node.rs b/crates/ruff_python_ast/src/node.rs index ae2c7c81d0c77..09ffeefe2bebf 100644 --- a/crates/ruff_python_ast/src/node.rs +++ b/crates/ruff_python_ast/src/node.rs @@ -83,6 +83,7 @@ pub enum AnyNode { ExprIpyEscapeCommand(ast::ExprIpyEscapeCommand), ExceptHandlerExceptHandler(ast::ExceptHandlerExceptHandler), FormattedValue(ast::FormattedValue), + StringTodoName(ast::StringTodoName), PatternMatchValue(ast::PatternMatchValue), PatternMatchSingleton(ast::PatternMatchSingleton), PatternMatchSequence(ast::PatternMatchSequence), @@ -159,6 +160,7 @@ impl AnyNode { | AnyNode::ExprCompare(_) | AnyNode::ExprCall(_) | AnyNode::FormattedValue(_) + | AnyNode::StringTodoName(_) | AnyNode::ExprFString(_) | AnyNode::ExprConstant(_) | AnyNode::ExprAttribute(_) @@ -257,6 +259,7 @@ impl AnyNode { | AnyNode::StmtIpyEscapeCommand(_) | AnyNode::ExceptHandlerExceptHandler(_) | AnyNode::FormattedValue(_) + | AnyNode::StringTodoName(_) | AnyNode::PatternMatchValue(_) | AnyNode::PatternMatchSingleton(_) | AnyNode::PatternMatchSequence(_) @@ -333,6 +336,7 @@ impl AnyNode { | AnyNode::ExprCompare(_) | AnyNode::ExprCall(_) | AnyNode::FormattedValue(_) + | AnyNode::StringTodoName(_) | AnyNode::ExprFString(_) | AnyNode::ExprConstant(_) | AnyNode::ExprAttribute(_) @@ -428,6 +432,7 @@ impl AnyNode { | AnyNode::ExprCompare(_) | AnyNode::ExprCall(_) | AnyNode::FormattedValue(_) + | AnyNode::StringTodoName(_) | AnyNode::ExprFString(_) | AnyNode::ExprConstant(_) | AnyNode::ExprAttribute(_) @@ -508,6 +513,7 @@ impl AnyNode { | AnyNode::ExprCompare(_) | AnyNode::ExprCall(_) | AnyNode::FormattedValue(_) + | AnyNode::StringTodoName(_) | AnyNode::ExprFString(_) | AnyNode::ExprConstant(_) | AnyNode::ExprAttribute(_) @@ -613,6 +619,7 @@ impl AnyNode { Self::ExprCompare(node) => AnyNodeRef::ExprCompare(node), Self::ExprCall(node) => AnyNodeRef::ExprCall(node), Self::FormattedValue(node) => AnyNodeRef::FormattedValue(node), + Self::StringTodoName(node) => AnyNodeRef::StringTodoName(node), Self::ExprFString(node) => AnyNodeRef::ExprFString(node), Self::ExprConstant(node) => AnyNodeRef::ExprConstant(node), Self::ExprAttribute(node) => AnyNodeRef::ExprAttribute(node), @@ -2609,6 +2616,41 @@ impl AstNode for ast::FormattedValue { } } } +impl AstNode for ast::StringTodoName { + fn cast(kind: AnyNode) -> Option + where + Self: Sized, + { + if let AnyNode::StringTodoName(node) = kind { + Some(node) + } else { + None + } + } + + fn cast_ref(kind: AnyNodeRef) -> Option<&Self> { + if let AnyNodeRef::StringTodoName(node) = kind { + Some(node) + } else { + None + } + } + + fn as_any_node_ref(&self) -> AnyNodeRef { + AnyNodeRef::from(self) + } + + fn into_any_node(self) -> AnyNode { + AnyNode::from(self) + } + + fn visit_preorder<'a, V>(&'a self, _visitor: &mut V) + where + V: PreorderVisitor<'a> + ?Sized, + { + // TODO: is this correct? + } +} impl AstNode for ast::ExprFString { fn cast(kind: AnyNode) -> Option where @@ -4446,6 +4488,12 @@ impl From for AnyNode { } } +impl From for AnyNode { + fn from(node: ast::StringTodoName) -> Self { + AnyNode::StringTodoName(node) + } +} + impl From for AnyNode { fn from(node: ast::ExprFString) -> Self { AnyNode::ExprFString(node) @@ -4693,6 +4741,7 @@ impl Ranged for AnyNode { AnyNode::ExprCompare(node) => node.range(), AnyNode::ExprCall(node) => node.range(), AnyNode::FormattedValue(node) => node.range(), + AnyNode::StringTodoName(node) => node.range(), AnyNode::ExprFString(node) => node.range(), AnyNode::ExprConstant(node) => node.range(), AnyNode::ExprAttribute(node) => node.range(), @@ -4780,6 +4829,7 @@ pub enum AnyNodeRef<'a> { ExprCompare(&'a ast::ExprCompare), ExprCall(&'a ast::ExprCall), FormattedValue(&'a ast::FormattedValue), + StringTodoName(&'a ast::StringTodoName), ExprFString(&'a ast::ExprFString), ExprConstant(&'a ast::ExprConstant), ExprAttribute(&'a ast::ExprAttribute), @@ -4866,6 +4916,7 @@ impl AnyNodeRef<'_> { AnyNodeRef::ExprCompare(node) => NonNull::from(*node).cast(), AnyNodeRef::ExprCall(node) => NonNull::from(*node).cast(), AnyNodeRef::FormattedValue(node) => NonNull::from(*node).cast(), + AnyNodeRef::StringTodoName(node) => NonNull::from(*node).cast(), AnyNodeRef::ExprFString(node) => NonNull::from(*node).cast(), AnyNodeRef::ExprConstant(node) => NonNull::from(*node).cast(), AnyNodeRef::ExprAttribute(node) => NonNull::from(*node).cast(), @@ -4958,6 +5009,7 @@ impl AnyNodeRef<'_> { AnyNodeRef::ExprCompare(_) => NodeKind::ExprCompare, AnyNodeRef::ExprCall(_) => NodeKind::ExprCall, AnyNodeRef::FormattedValue(_) => NodeKind::FormattedValue, + AnyNodeRef::StringTodoName(_) => NodeKind::StringTodoName, AnyNodeRef::ExprFString(_) => NodeKind::ExprFString, AnyNodeRef::ExprConstant(_) => NodeKind::ExprConstant, AnyNodeRef::ExprAttribute(_) => NodeKind::ExprAttribute, @@ -5045,6 +5097,7 @@ impl AnyNodeRef<'_> { | AnyNodeRef::ExprCompare(_) | AnyNodeRef::ExprCall(_) | AnyNodeRef::FormattedValue(_) + | AnyNodeRef::StringTodoName(_) | AnyNodeRef::ExprFString(_) | AnyNodeRef::ExprConstant(_) | AnyNodeRef::ExprAttribute(_) @@ -5103,7 +5156,6 @@ impl AnyNodeRef<'_> { | AnyNodeRef::ExprYieldFrom(_) | AnyNodeRef::ExprCompare(_) | AnyNodeRef::ExprCall(_) - | AnyNodeRef::FormattedValue(_) | AnyNodeRef::ExprFString(_) | AnyNodeRef::ExprConstant(_) | AnyNodeRef::ExprAttribute(_) @@ -5143,6 +5195,8 @@ impl AnyNodeRef<'_> { | AnyNodeRef::StmtContinue(_) | AnyNodeRef::StmtIpyEscapeCommand(_) | AnyNodeRef::ExceptHandlerExceptHandler(_) + | AnyNodeRef::FormattedValue(_) + | AnyNodeRef::StringTodoName(_) | AnyNodeRef::PatternMatchValue(_) | AnyNodeRef::PatternMatchSingleton(_) | AnyNodeRef::PatternMatchSequence(_) @@ -5218,6 +5272,7 @@ impl AnyNodeRef<'_> { | AnyNodeRef::ExprCompare(_) | AnyNodeRef::ExprCall(_) | AnyNodeRef::FormattedValue(_) + | AnyNodeRef::StringTodoName(_) | AnyNodeRef::ExprFString(_) | AnyNodeRef::ExprConstant(_) | AnyNodeRef::ExprAttribute(_) @@ -5313,6 +5368,7 @@ impl AnyNodeRef<'_> { | AnyNodeRef::ExprCompare(_) | AnyNodeRef::ExprCall(_) | AnyNodeRef::FormattedValue(_) + | AnyNodeRef::StringTodoName(_) | AnyNodeRef::ExprFString(_) | AnyNodeRef::ExprConstant(_) | AnyNodeRef::ExprAttribute(_) @@ -5393,6 +5449,7 @@ impl AnyNodeRef<'_> { | AnyNodeRef::ExprCompare(_) | AnyNodeRef::ExprCall(_) | AnyNodeRef::FormattedValue(_) + | AnyNodeRef::StringTodoName(_) | AnyNodeRef::ExprFString(_) | AnyNodeRef::ExprConstant(_) | AnyNodeRef::ExprAttribute(_) @@ -5507,6 +5564,7 @@ impl AnyNodeRef<'_> { AnyNodeRef::ExprCompare(node) => node.visit_preorder(visitor), AnyNodeRef::ExprCall(node) => node.visit_preorder(visitor), AnyNodeRef::FormattedValue(node) => node.visit_preorder(visitor), + AnyNodeRef::StringTodoName(node) => node.visit_preorder(visitor), AnyNodeRef::ExprFString(node) => node.visit_preorder(visitor), AnyNodeRef::ExprConstant(node) => node.visit_preorder(visitor), AnyNodeRef::ExprAttribute(node) => node.visit_preorder(visitor), @@ -5823,6 +5881,12 @@ impl<'a> From<&'a ast::FormattedValue> for AnyNodeRef<'a> { } } +impl<'a> From<&'a ast::StringTodoName> for AnyNodeRef<'a> { + fn from(node: &'a ast::StringTodoName) -> Self { + AnyNodeRef::StringTodoName(node) + } +} + impl<'a> From<&'a ast::ExprFString> for AnyNodeRef<'a> { fn from(node: &'a ast::ExprFString) -> Self { AnyNodeRef::ExprFString(node) @@ -6182,6 +6246,7 @@ impl Ranged for AnyNodeRef<'_> { AnyNodeRef::ExprCompare(node) => node.range(), AnyNodeRef::ExprCall(node) => node.range(), AnyNodeRef::FormattedValue(node) => node.range(), + AnyNodeRef::StringTodoName(node) => node.range(), AnyNodeRef::ExprFString(node) => node.range(), AnyNodeRef::ExprConstant(node) => node.range(), AnyNodeRef::ExprAttribute(node) => node.range(), @@ -6271,6 +6336,7 @@ pub enum NodeKind { ExprCompare, ExprCall, FormattedValue, + StringTodoName, ExprFString, ExprConstant, ExprAttribute, From 82471487a540422e8627a3a9414254401ab0b4ee Mon Sep 17 00:00:00 2001 From: David Szotten Date: Sun, 20 Aug 2023 07:57:41 +0100 Subject: [PATCH 10/17] FStringPart: String(StringTodoName) -> Literal(PartialString) --- .../flake8_pytest_style/rules/helpers.rs | 2 +- crates/ruff_linter/src/rules/flynt/helpers.rs | 4 +- .../pylint/rules/assert_on_string_literal.rs | 4 +- .../tryceratops/rules/raise_vanilla_args.rs | 2 +- crates/ruff_python_ast/src/comparable.rs | 4 +- crates/ruff_python_ast/src/helpers.rs | 4 +- crates/ruff_python_ast/src/node.rs | 56 +++++++++---------- crates/ruff_python_ast/src/nodes.rs | 8 +-- crates/ruff_python_ast/src/relocate.rs | 2 +- crates/ruff_python_codegen/src/generator.rs | 2 +- .../src/expression/string.rs | 2 +- ...parser__parser__tests__parse_f_string.snap | 4 +- ...uff_python_parser__parser__tests__try.snap | 8 +-- ...ython_parser__parser__tests__try_star.snap | 16 +++--- ...string__tests__fstring_constant_range.snap | 12 ++-- ...ing__tests__fstring_escaped_character.snap | 4 +- ...tring__tests__fstring_escaped_newline.snap | 4 +- ...ing__tests__fstring_line_continuation.snap | 4 +- ...ring_parse_self_documenting_base_more.snap | 8 +-- ...fstring_parse_self_documenting_format.snap | 4 +- ...ing__tests__fstring_unescaped_newline.snap | 4 +- ...tring__tests__parse_f_string_concat_1.snap | 4 +- ...tring__tests__parse_f_string_concat_2.snap | 4 +- ...tring__tests__parse_f_string_concat_3.snap | 4 +- ...tring__tests__parse_f_string_concat_4.snap | 8 +-- ..._parser__string__tests__parse_fstring.snap | 4 +- ..._tests__parse_fstring_not_nested_spec.snap | 4 +- ...ing__tests__parse_u_f_string_concat_1.snap | 4 +- ...ing__tests__parse_u_f_string_concat_2.snap | 4 +- crates/ruff_python_parser/src/string.rs | 12 ++-- 30 files changed, 103 insertions(+), 103 deletions(-) diff --git a/crates/ruff_linter/src/rules/flake8_pytest_style/rules/helpers.rs b/crates/ruff_linter/src/rules/flake8_pytest_style/rules/helpers.rs index fca0b3e07a5f4..015a4971a733a 100644 --- a/crates/ruff_linter/src/rules/flake8_pytest_style/rules/helpers.rs +++ b/crates/ruff_linter/src/rules/flake8_pytest_style/rules/helpers.rs @@ -72,7 +72,7 @@ pub(super) fn is_empty_or_null_string(expr: &Expr) -> bool { fn is_empty_or_null_string_part(part: &ast::FStringPart) -> bool { match part { - ast::FStringPart::String(ast::StringTodoName { value, .. }) => value.is_empty(), + ast::FStringPart::Literal(ast::PartialString { value, .. }) => value.is_empty(), ast::FStringPart::FormattedValue(ast::FormattedValue { expression, .. }) => { is_empty_or_null_string(expression) } diff --git a/crates/ruff_linter/src/rules/flynt/helpers.rs b/crates/ruff_linter/src/rules/flynt/helpers.rs index 12eda4ae1c39e..781a5435da552 100644 --- a/crates/ruff_linter/src/rules/flynt/helpers.rs +++ b/crates/ruff_linter/src/rules/flynt/helpers.rs @@ -14,7 +14,7 @@ fn to_formatted_value_expr(inner: &Expr) -> ast::FStringPart { /// Convert a string to a constant string expression. pub(super) fn to_constant_string(s: &str) -> ast::FStringPart { - ast::FStringPart::String(ast::StringTodoName { + ast::FStringPart::Literal(ast::PartialString { value: s.to_owned(), range: TextRange::default(), }) @@ -55,7 +55,7 @@ pub(super) fn to_fstring_part(expr: &Expr) -> Option { Expr::Constant(ast::ExprConstant { value: Constant::Str(value), range, - }) => Some(ast::FStringPart::String(ast::StringTodoName { + }) => Some(ast::FStringPart::Literal(ast::PartialString { value: value.to_string(), range: *range, })), diff --git a/crates/ruff_linter/src/rules/pylint/rules/assert_on_string_literal.rs b/crates/ruff_linter/src/rules/pylint/rules/assert_on_string_literal.rs index c31a2027db230..3de2af76e71cb 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/assert_on_string_literal.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/assert_on_string_literal.rs @@ -76,14 +76,14 @@ pub(crate) fn assert_on_string_literal(checker: &mut Checker, test: &Expr) { checker.diagnostics.push(Diagnostic::new( AssertOnStringLiteral { kind: if parts.iter().all(|part| match part { - ast::FStringPart::String(ast::StringTodoName { value, .. }) => { + ast::FStringPart::Literal(ast::PartialString { value, .. }) => { value.is_empty() } ast::FStringPart::FormattedValue(_) => false, }) { Kind::Empty } else if parts.iter().any(|part| match part { - ast::FStringPart::String(ast::StringTodoName { value, .. }) => { + ast::FStringPart::Literal(ast::PartialString { value, .. }) => { !value.is_empty() } ast::FStringPart::FormattedValue(_) => false, diff --git a/crates/ruff_linter/src/rules/tryceratops/rules/raise_vanilla_args.rs b/crates/ruff_linter/src/rules/tryceratops/rules/raise_vanilla_args.rs index 53b9021129e04..d426c07d8f34b 100644 --- a/crates/ruff_linter/src/rules/tryceratops/rules/raise_vanilla_args.rs +++ b/crates/ruff_linter/src/rules/tryceratops/rules/raise_vanilla_args.rs @@ -91,7 +91,7 @@ fn contains_message(expr: &Expr) -> bool { match expr { Expr::FString(ast::ExprFString { parts, .. }) => { for part in parts { - if let ast::FStringPart::String(ast::StringTodoName { value, .. }) = part { + if let ast::FStringPart::Literal(ast::PartialString { value, .. }) = part { if value.chars().any(char::is_whitespace) { return true; } diff --git a/crates/ruff_python_ast/src/comparable.rs b/crates/ruff_python_ast/src/comparable.rs index 18af63ee4ef0c..f5bf453c1c14e 100644 --- a/crates/ruff_python_ast/src/comparable.rs +++ b/crates/ruff_python_ast/src/comparable.rs @@ -521,7 +521,7 @@ impl<'a> From<&'a ast::ExceptHandler> for ComparableExceptHandler<'a> { #[derive(Debug, PartialEq, Eq, Hash)] pub enum ComparableFStringPart<'a> { - String(&'a str), + Literal(&'a str), FormattedValue(FormattedValue<'a>), } @@ -536,7 +536,7 @@ pub struct FormattedValue<'a> { impl<'a> From<&'a ast::FStringPart> for ComparableFStringPart<'a> { fn from(fstring_part: &'a ast::FStringPart) -> Self { match fstring_part { - ast::FStringPart::String(ast::StringTodoName { value, .. }) => Self::String(value), + ast::FStringPart::Literal(ast::PartialString { value, .. }) => Self::Literal(value), ast::FStringPart::FormattedValue(formatted_value) => { Self::FormattedValue(FormattedValue { expression: (&formatted_value.expression).into(), diff --git a/crates/ruff_python_ast/src/helpers.rs b/crates/ruff_python_ast/src/helpers.rs index afed041f58d41..84d40e570d2f6 100644 --- a/crates/ruff_python_ast/src/helpers.rs +++ b/crates/ruff_python_ast/src/helpers.rs @@ -289,7 +289,7 @@ pub fn any_over_pattern(pattern: &Pattern, func: &dyn Fn(&Expr) -> bool) -> bool pub fn any_over_fstring_part(part: &FStringPart, func: &dyn Fn(&Expr) -> bool) -> bool { match part { - FStringPart::String(_) => false, + FStringPart::Literal(_) => false, FStringPart::FormattedValue(ast::FormattedValue { expression, format_spec, @@ -1093,7 +1093,7 @@ impl Truthiness { if parts.is_empty() { Some(false) } else if parts.iter().any(|part| match part { - ast::FStringPart::String(ast::StringTodoName { value, .. }) => { + ast::FStringPart::Literal(ast::PartialString { value, .. }) => { !value.is_empty() } ast::FStringPart::FormattedValue(_) => true, diff --git a/crates/ruff_python_ast/src/node.rs b/crates/ruff_python_ast/src/node.rs index 09ffeefe2bebf..0663ce7abf920 100644 --- a/crates/ruff_python_ast/src/node.rs +++ b/crates/ruff_python_ast/src/node.rs @@ -83,7 +83,7 @@ pub enum AnyNode { ExprIpyEscapeCommand(ast::ExprIpyEscapeCommand), ExceptHandlerExceptHandler(ast::ExceptHandlerExceptHandler), FormattedValue(ast::FormattedValue), - StringTodoName(ast::StringTodoName), + PartialString(ast::PartialString), PatternMatchValue(ast::PatternMatchValue), PatternMatchSingleton(ast::PatternMatchSingleton), PatternMatchSequence(ast::PatternMatchSequence), @@ -160,7 +160,7 @@ impl AnyNode { | AnyNode::ExprCompare(_) | AnyNode::ExprCall(_) | AnyNode::FormattedValue(_) - | AnyNode::StringTodoName(_) + | AnyNode::PartialString(_) | AnyNode::ExprFString(_) | AnyNode::ExprConstant(_) | AnyNode::ExprAttribute(_) @@ -259,7 +259,7 @@ impl AnyNode { | AnyNode::StmtIpyEscapeCommand(_) | AnyNode::ExceptHandlerExceptHandler(_) | AnyNode::FormattedValue(_) - | AnyNode::StringTodoName(_) + | AnyNode::PartialString(_) | AnyNode::PatternMatchValue(_) | AnyNode::PatternMatchSingleton(_) | AnyNode::PatternMatchSequence(_) @@ -336,7 +336,7 @@ impl AnyNode { | AnyNode::ExprCompare(_) | AnyNode::ExprCall(_) | AnyNode::FormattedValue(_) - | AnyNode::StringTodoName(_) + | AnyNode::PartialString(_) | AnyNode::ExprFString(_) | AnyNode::ExprConstant(_) | AnyNode::ExprAttribute(_) @@ -432,7 +432,7 @@ impl AnyNode { | AnyNode::ExprCompare(_) | AnyNode::ExprCall(_) | AnyNode::FormattedValue(_) - | AnyNode::StringTodoName(_) + | AnyNode::PartialString(_) | AnyNode::ExprFString(_) | AnyNode::ExprConstant(_) | AnyNode::ExprAttribute(_) @@ -513,7 +513,7 @@ impl AnyNode { | AnyNode::ExprCompare(_) | AnyNode::ExprCall(_) | AnyNode::FormattedValue(_) - | AnyNode::StringTodoName(_) + | AnyNode::PartialString(_) | AnyNode::ExprFString(_) | AnyNode::ExprConstant(_) | AnyNode::ExprAttribute(_) @@ -619,7 +619,7 @@ impl AnyNode { Self::ExprCompare(node) => AnyNodeRef::ExprCompare(node), Self::ExprCall(node) => AnyNodeRef::ExprCall(node), Self::FormattedValue(node) => AnyNodeRef::FormattedValue(node), - Self::StringTodoName(node) => AnyNodeRef::StringTodoName(node), + Self::PartialString(node) => AnyNodeRef::PartialString(node), Self::ExprFString(node) => AnyNodeRef::ExprFString(node), Self::ExprConstant(node) => AnyNodeRef::ExprConstant(node), Self::ExprAttribute(node) => AnyNodeRef::ExprAttribute(node), @@ -2616,12 +2616,12 @@ impl AstNode for ast::FormattedValue { } } } -impl AstNode for ast::StringTodoName { +impl AstNode for ast::PartialString { fn cast(kind: AnyNode) -> Option where Self: Sized, { - if let AnyNode::StringTodoName(node) = kind { + if let AnyNode::PartialString(node) = kind { Some(node) } else { None @@ -2629,7 +2629,7 @@ impl AstNode for ast::StringTodoName { } fn cast_ref(kind: AnyNodeRef) -> Option<&Self> { - if let AnyNodeRef::StringTodoName(node) = kind { + if let AnyNodeRef::PartialString(node) = kind { Some(node) } else { None @@ -4488,9 +4488,9 @@ impl From for AnyNode { } } -impl From for AnyNode { - fn from(node: ast::StringTodoName) -> Self { - AnyNode::StringTodoName(node) +impl From for AnyNode { + fn from(node: ast::PartialString) -> Self { + AnyNode::PartialString(node) } } @@ -4741,7 +4741,7 @@ impl Ranged for AnyNode { AnyNode::ExprCompare(node) => node.range(), AnyNode::ExprCall(node) => node.range(), AnyNode::FormattedValue(node) => node.range(), - AnyNode::StringTodoName(node) => node.range(), + AnyNode::PartialString(node) => node.range(), AnyNode::ExprFString(node) => node.range(), AnyNode::ExprConstant(node) => node.range(), AnyNode::ExprAttribute(node) => node.range(), @@ -4829,7 +4829,7 @@ pub enum AnyNodeRef<'a> { ExprCompare(&'a ast::ExprCompare), ExprCall(&'a ast::ExprCall), FormattedValue(&'a ast::FormattedValue), - StringTodoName(&'a ast::StringTodoName), + PartialString(&'a ast::PartialString), ExprFString(&'a ast::ExprFString), ExprConstant(&'a ast::ExprConstant), ExprAttribute(&'a ast::ExprAttribute), @@ -4916,7 +4916,7 @@ impl AnyNodeRef<'_> { AnyNodeRef::ExprCompare(node) => NonNull::from(*node).cast(), AnyNodeRef::ExprCall(node) => NonNull::from(*node).cast(), AnyNodeRef::FormattedValue(node) => NonNull::from(*node).cast(), - AnyNodeRef::StringTodoName(node) => NonNull::from(*node).cast(), + AnyNodeRef::PartialString(node) => NonNull::from(*node).cast(), AnyNodeRef::ExprFString(node) => NonNull::from(*node).cast(), AnyNodeRef::ExprConstant(node) => NonNull::from(*node).cast(), AnyNodeRef::ExprAttribute(node) => NonNull::from(*node).cast(), @@ -5009,7 +5009,7 @@ impl AnyNodeRef<'_> { AnyNodeRef::ExprCompare(_) => NodeKind::ExprCompare, AnyNodeRef::ExprCall(_) => NodeKind::ExprCall, AnyNodeRef::FormattedValue(_) => NodeKind::FormattedValue, - AnyNodeRef::StringTodoName(_) => NodeKind::StringTodoName, + AnyNodeRef::PartialString(_) => NodeKind::PartialString, AnyNodeRef::ExprFString(_) => NodeKind::ExprFString, AnyNodeRef::ExprConstant(_) => NodeKind::ExprConstant, AnyNodeRef::ExprAttribute(_) => NodeKind::ExprAttribute, @@ -5097,7 +5097,7 @@ impl AnyNodeRef<'_> { | AnyNodeRef::ExprCompare(_) | AnyNodeRef::ExprCall(_) | AnyNodeRef::FormattedValue(_) - | AnyNodeRef::StringTodoName(_) + | AnyNodeRef::PartialString(_) | AnyNodeRef::ExprFString(_) | AnyNodeRef::ExprConstant(_) | AnyNodeRef::ExprAttribute(_) @@ -5196,7 +5196,7 @@ impl AnyNodeRef<'_> { | AnyNodeRef::StmtIpyEscapeCommand(_) | AnyNodeRef::ExceptHandlerExceptHandler(_) | AnyNodeRef::FormattedValue(_) - | AnyNodeRef::StringTodoName(_) + | AnyNodeRef::PartialString(_) | AnyNodeRef::PatternMatchValue(_) | AnyNodeRef::PatternMatchSingleton(_) | AnyNodeRef::PatternMatchSequence(_) @@ -5272,7 +5272,7 @@ impl AnyNodeRef<'_> { | AnyNodeRef::ExprCompare(_) | AnyNodeRef::ExprCall(_) | AnyNodeRef::FormattedValue(_) - | AnyNodeRef::StringTodoName(_) + | AnyNodeRef::PartialString(_) | AnyNodeRef::ExprFString(_) | AnyNodeRef::ExprConstant(_) | AnyNodeRef::ExprAttribute(_) @@ -5368,7 +5368,7 @@ impl AnyNodeRef<'_> { | AnyNodeRef::ExprCompare(_) | AnyNodeRef::ExprCall(_) | AnyNodeRef::FormattedValue(_) - | AnyNodeRef::StringTodoName(_) + | AnyNodeRef::PartialString(_) | AnyNodeRef::ExprFString(_) | AnyNodeRef::ExprConstant(_) | AnyNodeRef::ExprAttribute(_) @@ -5449,7 +5449,7 @@ impl AnyNodeRef<'_> { | AnyNodeRef::ExprCompare(_) | AnyNodeRef::ExprCall(_) | AnyNodeRef::FormattedValue(_) - | AnyNodeRef::StringTodoName(_) + | AnyNodeRef::PartialString(_) | AnyNodeRef::ExprFString(_) | AnyNodeRef::ExprConstant(_) | AnyNodeRef::ExprAttribute(_) @@ -5564,7 +5564,7 @@ impl AnyNodeRef<'_> { AnyNodeRef::ExprCompare(node) => node.visit_preorder(visitor), AnyNodeRef::ExprCall(node) => node.visit_preorder(visitor), AnyNodeRef::FormattedValue(node) => node.visit_preorder(visitor), - AnyNodeRef::StringTodoName(node) => node.visit_preorder(visitor), + AnyNodeRef::PartialString(node) => node.visit_preorder(visitor), AnyNodeRef::ExprFString(node) => node.visit_preorder(visitor), AnyNodeRef::ExprConstant(node) => node.visit_preorder(visitor), AnyNodeRef::ExprAttribute(node) => node.visit_preorder(visitor), @@ -5881,9 +5881,9 @@ impl<'a> From<&'a ast::FormattedValue> for AnyNodeRef<'a> { } } -impl<'a> From<&'a ast::StringTodoName> for AnyNodeRef<'a> { - fn from(node: &'a ast::StringTodoName) -> Self { - AnyNodeRef::StringTodoName(node) +impl<'a> From<&'a ast::PartialString> for AnyNodeRef<'a> { + fn from(node: &'a ast::PartialString) -> Self { + AnyNodeRef::PartialString(node) } } @@ -6246,7 +6246,7 @@ impl Ranged for AnyNodeRef<'_> { AnyNodeRef::ExprCompare(node) => node.range(), AnyNodeRef::ExprCall(node) => node.range(), AnyNodeRef::FormattedValue(node) => node.range(), - AnyNodeRef::StringTodoName(node) => node.range(), + AnyNodeRef::PartialString(node) => node.range(), AnyNodeRef::ExprFString(node) => node.range(), AnyNodeRef::ExprConstant(node) => node.range(), AnyNodeRef::ExprAttribute(node) => node.range(), @@ -6336,7 +6336,7 @@ pub enum NodeKind { ExprCompare, ExprCall, FormattedValue, - StringTodoName, + PartialString, ExprFString, ExprConstant, ExprAttribute, diff --git a/crates/ruff_python_ast/src/nodes.rs b/crates/ruff_python_ast/src/nodes.rs index 7aebce0b49084..449fe9ab7efb7 100644 --- a/crates/ruff_python_ast/src/nodes.rs +++ b/crates/ruff_python_ast/src/nodes.rs @@ -884,7 +884,7 @@ pub struct FormattedValue { } #[derive(Clone, Debug, PartialEq)] -pub struct StringTodoName { +pub struct PartialString { pub range: TextRange, pub value: String, } @@ -941,7 +941,7 @@ impl From for Expr { #[derive(Clone, Debug, PartialEq)] pub enum FStringPart { - String(StringTodoName), + Literal(PartialString), FormattedValue(FormattedValue), } @@ -3385,13 +3385,13 @@ impl Ranged for crate::nodes::FormattedValue { impl Ranged for crate::nodes::FStringPart { fn range(&self) -> TextRange { match self { - FStringPart::String(node) => node.range(), + FStringPart::Literal(node) => node.range(), FStringPart::FormattedValue(node) => node.range(), } } } -impl Ranged for crate::nodes::StringTodoName { +impl Ranged for crate::nodes::PartialString { fn range(&self) -> TextRange { self.range } diff --git a/crates/ruff_python_ast/src/relocate.rs b/crates/ruff_python_ast/src/relocate.rs index 86a793ff67317..e6712f859dda0 100644 --- a/crates/ruff_python_ast/src/relocate.rs +++ b/crates/ruff_python_ast/src/relocate.rs @@ -197,7 +197,7 @@ pub fn relocate_expr(expr: &mut Expr, location: TextRange) { /// location. fn relocate_fstring_part(part: &mut nodes::FStringPart, location: TextRange) { match part { - nodes::FStringPart::String(nodes::StringTodoName { range, .. }) => { + nodes::FStringPart::Literal(nodes::PartialString { range, .. }) => { *range = location; } nodes::FStringPart::FormattedValue(nodes::FormattedValue { diff --git a/crates/ruff_python_codegen/src/generator.rs b/crates/ruff_python_codegen/src/generator.rs index f29175e35d3ba..e52ccc0fa838b 100644 --- a/crates/ruff_python_codegen/src/generator.rs +++ b/crates/ruff_python_codegen/src/generator.rs @@ -1305,7 +1305,7 @@ impl<'a> Generator<'a> { fn unparse_fstring_elem(&mut self, part: &ast::FStringPart) { match part { - ast::FStringPart::String(ast::StringTodoName { value, .. }) => { + ast::FStringPart::Literal(ast::PartialString { value, .. }) => { self.unparse_fstring_literal(value); } ast::FStringPart::FormattedValue(ast::FormattedValue { diff --git a/crates/ruff_python_formatter/src/expression/string.rs b/crates/ruff_python_formatter/src/expression/string.rs index 51d52f9e7ab7f..7c6b563d465f5 100644 --- a/crates/ruff_python_formatter/src/expression/string.rs +++ b/crates/ruff_python_formatter/src/expression/string.rs @@ -53,7 +53,7 @@ impl<'a> AnyString<'a> { let string_content = locator.slice(*range); string_content.contains(['"', '\'']) } - ast::FStringPart::String(_) => false, + ast::FStringPart::Literal(_) => false, }) { Quoting::Preserve } else { diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_f_string.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_f_string.snap index 0697d8f731176..f80a93face317 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_f_string.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_f_string.snap @@ -11,8 +11,8 @@ expression: parse_ast range: 0..14, implicit_concatenated: false, parts: [ - String( - StringTodoName { + Literal( + PartialString { range: 2..13, value: "Hello world", }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try.snap index 7143d62f05d65..918f4b9f30395 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try.snap @@ -83,8 +83,8 @@ expression: parse_ast range: 62..81, implicit_concatenated: false, parts: [ - String( - StringTodoName { + Literal( + PartialString { range: 64..71, value: "caught ", }, @@ -175,8 +175,8 @@ expression: parse_ast range: 114..133, implicit_concatenated: false, parts: [ - String( - StringTodoName { + Literal( + PartialString { range: 116..123, value: "caught ", }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try_star.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try_star.snap index 2d56073a34c9b..ecacb9205f3b5 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try_star.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try_star.snap @@ -199,8 +199,8 @@ expression: parse_ast range: 133..179, implicit_concatenated: false, parts: [ - String( - StringTodoName { + Literal( + PartialString { range: 135..142, value: "caught ", }, @@ -238,8 +238,8 @@ expression: parse_ast format_spec: [], }, ), - String( - StringTodoName { + Literal( + PartialString { range: 151..164, value: " with nested ", }, @@ -322,8 +322,8 @@ expression: parse_ast range: 213..259, implicit_concatenated: false, parts: [ - String( - StringTodoName { + Literal( + PartialString { range: 215..222, value: "caught ", }, @@ -361,8 +361,8 @@ expression: parse_ast format_spec: [], }, ), - String( - StringTodoName { + Literal( + PartialString { range: 231..244, value: " with nested ", }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_constant_range.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_constant_range.snap index fdaf136baba7c..2b55b4e275eee 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_constant_range.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_constant_range.snap @@ -11,8 +11,8 @@ expression: parse_ast range: 0..22, implicit_concatenated: false, parts: [ - String( - StringTodoName { + Literal( + PartialString { range: 2..5, value: "aaa", }, @@ -32,8 +32,8 @@ expression: parse_ast format_spec: [], }, ), - String( - StringTodoName { + Literal( + PartialString { range: 10..13, value: "ccc", }, @@ -53,8 +53,8 @@ expression: parse_ast format_spec: [], }, ), - String( - StringTodoName { + Literal( + PartialString { range: 18..21, value: "eee", }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_character.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_character.snap index 7f62fbef9b8cb..9adcbf6008b5f 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_character.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_character.snap @@ -11,8 +11,8 @@ expression: parse_ast range: 0..8, implicit_concatenated: false, parts: [ - String( - StringTodoName { + Literal( + PartialString { range: 2..4, value: "\\", }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_newline.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_newline.snap index 48f33d11d570c..9800251950494 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_newline.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_newline.snap @@ -11,8 +11,8 @@ expression: parse_ast range: 0..8, implicit_concatenated: false, parts: [ - String( - StringTodoName { + Literal( + PartialString { range: 2..4, value: "\n", }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_line_continuation.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_line_continuation.snap index c195c8a97acb7..a8b64fb64af0c 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_line_continuation.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_line_continuation.snap @@ -11,8 +11,8 @@ expression: parse_ast range: 0..9, implicit_concatenated: false, parts: [ - String( - StringTodoName { + Literal( + PartialString { range: 3..5, value: "\\\n", }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base_more.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base_more.snap index b85d6c805d226..5d2f649895b45 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base_more.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base_more.snap @@ -7,8 +7,8 @@ FString( range: 2..37, implicit_concatenated: false, parts: [ - String( - StringTodoName { + Literal( + PartialString { range: 2..6, value: "mix ", }, @@ -33,8 +33,8 @@ FString( format_spec: [], }, ), - String( - StringTodoName { + Literal( + PartialString { range: 13..28, value: " with text and ", }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_format.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_format.snap index 8176c2891506a..0a6dad037ecd8 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_format.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_format.snap @@ -25,8 +25,8 @@ FString( ), conversion: None, format_spec: [ - String( - StringTodoName { + Literal( + PartialString { range: 9..12, value: ">10", }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_unescaped_newline.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_unescaped_newline.snap index ca370d78e70e1..f4dfd26711c8a 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_unescaped_newline.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_unescaped_newline.snap @@ -11,8 +11,8 @@ expression: parse_ast range: 0..11, implicit_concatenated: false, parts: [ - String( - StringTodoName { + Literal( + PartialString { range: 4..5, value: "\n", }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_1.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_1.snap index 6ecd1e632a65d..3d4fb7e40b1b3 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_1.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_1.snap @@ -11,8 +11,8 @@ expression: parse_ast range: 0..17, implicit_concatenated: true, parts: [ - String( - StringTodoName { + Literal( + PartialString { range: 1..16, value: "Hello world", }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_2.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_2.snap index 6ecd1e632a65d..3d4fb7e40b1b3 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_2.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_2.snap @@ -11,8 +11,8 @@ expression: parse_ast range: 0..17, implicit_concatenated: true, parts: [ - String( - StringTodoName { + Literal( + PartialString { range: 1..16, value: "Hello world", }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_3.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_3.snap index 48de12a8bf867..de8c04740e639 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_3.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_3.snap @@ -11,8 +11,8 @@ expression: parse_ast range: 0..22, implicit_concatenated: true, parts: [ - String( - StringTodoName { + Literal( + PartialString { range: 1..16, value: "Hello world", }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_4.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_4.snap index 8c2012e7c0b77..30ff989893e69 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_4.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_4.snap @@ -11,8 +11,8 @@ expression: parse_ast range: 0..31, implicit_concatenated: true, parts: [ - String( - StringTodoName { + Literal( + PartialString { range: 1..16, value: "Hello world", }, @@ -37,8 +37,8 @@ expression: parse_ast format_spec: [], }, ), - String( - StringTodoName { + Literal( + PartialString { range: 24..30, value: "again!", }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring.snap index 5daca143ae92a..9e387b6f4f4fc 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring.snap @@ -37,8 +37,8 @@ FString( format_spec: [], }, ), - String( - StringTodoName { + Literal( + PartialString { range: 10..17, value: "{foo}", }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_nested_spec.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_nested_spec.snap index a5ac0620aad2d..572ca3349f858 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_nested_spec.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_nested_spec.snap @@ -20,8 +20,8 @@ FString( debug_text: None, conversion: None, format_spec: [ - String( - StringTodoName { + Literal( + PartialString { range: 7..11, value: "spec", }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_f_string_concat_1.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_f_string_concat_1.snap index 837ba4718c78b..564dfb67bd0b2 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_f_string_concat_1.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_f_string_concat_1.snap @@ -11,8 +11,8 @@ expression: parse_ast range: 0..18, implicit_concatenated: true, parts: [ - String( - StringTodoName { + Literal( + PartialString { range: 2..17, value: "Hello world", }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_f_string_concat_2.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_f_string_concat_2.snap index 2479e73bece35..c9b8a9b34007d 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_f_string_concat_2.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_f_string_concat_2.snap @@ -11,8 +11,8 @@ expression: parse_ast range: 0..22, implicit_concatenated: true, parts: [ - String( - StringTodoName { + Literal( + PartialString { range: 2..21, value: "Hello world!", }, diff --git a/crates/ruff_python_parser/src/string.rs b/crates/ruff_python_parser/src/string.rs index f5148ddd99248..c0bde09ba9eba 100644 --- a/crates/ruff_python_parser/src/string.rs +++ b/crates/ruff_python_parser/src/string.rs @@ -381,7 +381,7 @@ impl<'a> StringParser<'a> { match next { '{' => { if !constant_piece.is_empty() { - spec_constructor.push(ast::FStringPart::String(ast::StringTodoName { + spec_constructor.push(ast::FStringPart::Literal(ast::PartialString { value: std::mem::take(&mut constant_piece), range: self.range(start_location), })); @@ -401,7 +401,7 @@ impl<'a> StringParser<'a> { self.next_char(); } if !constant_piece.is_empty() { - spec_constructor.push(ast::FStringPart::String(ast::StringTodoName { + spec_constructor.push(ast::FStringPart::Literal(ast::PartialString { value: std::mem::take(&mut constant_piece), range: self.range(start_location), })); @@ -435,7 +435,7 @@ impl<'a> StringParser<'a> { } } if !content.is_empty() { - parts.push(ast::FStringPart::String(ast::StringTodoName { + parts.push(ast::FStringPart::Literal(ast::PartialString { value: std::mem::take(&mut content), range: self.range(part_start_location), })); @@ -469,7 +469,7 @@ impl<'a> StringParser<'a> { } if !content.is_empty() { - parts.push(ast::FStringPart::String(ast::StringTodoName { + parts.push(ast::FStringPart::Literal(ast::PartialString { value: content, range: self.range(part_start_location), })); @@ -634,7 +634,7 @@ pub(crate) fn parse_strings( let mut current_end = last_end; let take_current = |current: &mut Vec, start, end| -> ast::FStringPart { - ast::FStringPart::String(ast::StringTodoName { + ast::FStringPart::Literal(ast::PartialString { value: current.drain(..).collect::(), range: TextRange::new(start, end), }) @@ -646,7 +646,7 @@ pub(crate) fn parse_strings( Expr::FString(ast::ExprFString { parts, .. }) => { for part in parts { match part { - ast::FStringPart::String(ast::StringTodoName { + ast::FStringPart::Literal(ast::PartialString { value: inner, range, }) => { From c7f4a3ffc4e91a8d8083651576ce8178bc994468 Mon Sep 17 00:00:00 2001 From: David Szotten Date: Sun, 20 Aug 2023 12:06:11 +0100 Subject: [PATCH 11/17] generate AsFormat and friends --- crates/ruff_python_formatter/src/generated.rs | 72 +++++++++++++++++++ .../src/other/formatted_value.rs | 12 ++++ crates/ruff_python_formatter/src/other/mod.rs | 2 + .../src/other/partial_string.rs | 12 ++++ 4 files changed, 98 insertions(+) create mode 100644 crates/ruff_python_formatter/src/other/formatted_value.rs create mode 100644 crates/ruff_python_formatter/src/other/partial_string.rs diff --git a/crates/ruff_python_formatter/src/generated.rs b/crates/ruff_python_formatter/src/generated.rs index 5f10ad4cc5167..fbfb5cad58689 100644 --- a/crates/ruff_python_formatter/src/generated.rs +++ b/crates/ruff_python_formatter/src/generated.rs @@ -1932,6 +1932,78 @@ impl<'ast> IntoFormat> for ast::ExceptHandlerExceptHandler } } +impl FormatRule> + for crate::other::formatted_value::FormatFormattedValue +{ + #[inline] + fn fmt(&self, node: &ast::FormattedValue, f: &mut PyFormatter) -> FormatResult<()> { + FormatNodeRule::::fmt(self, node, f) + } +} +impl<'ast> AsFormat> for ast::FormattedValue { + type Format<'a> = FormatRefWithRule< + 'a, + ast::FormattedValue, + crate::other::formatted_value::FormatFormattedValue, + PyFormatContext<'ast>, + >; + fn format(&self) -> Self::Format<'_> { + FormatRefWithRule::new( + self, + crate::other::formatted_value::FormatFormattedValue::default(), + ) + } +} +impl<'ast> IntoFormat> for ast::FormattedValue { + type Format = FormatOwnedWithRule< + ast::FormattedValue, + crate::other::formatted_value::FormatFormattedValue, + PyFormatContext<'ast>, + >; + fn into_format(self) -> Self::Format { + FormatOwnedWithRule::new( + self, + crate::other::formatted_value::FormatFormattedValue::default(), + ) + } +} + +impl FormatRule> + for crate::other::partial_string::FormatPartialString +{ + #[inline] + fn fmt(&self, node: &ast::PartialString, f: &mut PyFormatter) -> FormatResult<()> { + FormatNodeRule::::fmt(self, node, f) + } +} +impl<'ast> AsFormat> for ast::PartialString { + type Format<'a> = FormatRefWithRule< + 'a, + ast::PartialString, + crate::other::partial_string::FormatPartialString, + PyFormatContext<'ast>, + >; + fn format(&self) -> Self::Format<'_> { + FormatRefWithRule::new( + self, + crate::other::partial_string::FormatPartialString::default(), + ) + } +} +impl<'ast> IntoFormat> for ast::PartialString { + type Format = FormatOwnedWithRule< + ast::PartialString, + crate::other::partial_string::FormatPartialString, + PyFormatContext<'ast>, + >; + fn into_format(self) -> Self::Format { + FormatOwnedWithRule::new( + self, + crate::other::partial_string::FormatPartialString::default(), + ) + } +} + impl FormatRule> for crate::pattern::pattern_match_value::FormatPatternMatchValue { diff --git a/crates/ruff_python_formatter/src/other/formatted_value.rs b/crates/ruff_python_formatter/src/other/formatted_value.rs new file mode 100644 index 0000000000000..3f56c8b38e5e4 --- /dev/null +++ b/crates/ruff_python_formatter/src/other/formatted_value.rs @@ -0,0 +1,12 @@ +use crate::{FormatNodeRule, PyFormatter}; +use ruff_formatter::FormatResult; +use ruff_python_ast::FormattedValue; + +#[derive(Default)] +pub struct FormatFormattedValue; + +impl FormatNodeRule for FormatFormattedValue { + fn fmt_fields(&self, _item: &FormattedValue, _f: &mut PyFormatter) -> FormatResult<()> { + unreachable!("Handled inside of `FormatExprFString"); + } +} diff --git a/crates/ruff_python_formatter/src/other/mod.rs b/crates/ruff_python_formatter/src/other/mod.rs index e7eb28ae7f4fd..dd7904005178e 100644 --- a/crates/ruff_python_formatter/src/other/mod.rs +++ b/crates/ruff_python_formatter/src/other/mod.rs @@ -5,10 +5,12 @@ pub(crate) mod comprehension; pub(crate) mod decorator; pub(crate) mod elif_else_clause; pub(crate) mod except_handler_except_handler; +pub(crate) mod formatted_value; pub(crate) mod identifier; pub(crate) mod keyword; pub(crate) mod match_case; pub(crate) mod parameter; pub(crate) mod parameter_with_default; pub(crate) mod parameters; +pub(crate) mod partial_string; pub(crate) mod with_item; diff --git a/crates/ruff_python_formatter/src/other/partial_string.rs b/crates/ruff_python_formatter/src/other/partial_string.rs new file mode 100644 index 0000000000000..9605d93d0d5e0 --- /dev/null +++ b/crates/ruff_python_formatter/src/other/partial_string.rs @@ -0,0 +1,12 @@ +use crate::{FormatNodeRule, PyFormatter}; +use ruff_formatter::FormatResult; +use ruff_python_ast::PartialString; + +#[derive(Default)] +pub struct FormatPartialString; + +impl FormatNodeRule for FormatPartialString { + fn fmt_fields(&self, _item: &PartialString, _f: &mut PyFormatter) -> FormatResult<()> { + unreachable!("Handled inside of `FormatExprFString"); + } +} From 0ebea36e58ad77f8006ae57c5fbbf9fc234b5178 Mon Sep 17 00:00:00 2001 From: David Szotten Date: Mon, 21 Aug 2023 13:30:19 +0100 Subject: [PATCH 12/17] remove accidental pub --- crates/ruff_python_ast/src/comparable.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ruff_python_ast/src/comparable.rs b/crates/ruff_python_ast/src/comparable.rs index f5bf453c1c14e..4a2630e7f63f7 100644 --- a/crates/ruff_python_ast/src/comparable.rs +++ b/crates/ruff_python_ast/src/comparable.rs @@ -529,8 +529,8 @@ pub enum ComparableFStringPart<'a> { pub struct FormattedValue<'a> { expression: ComparableExpr<'a>, debug_text: Option<&'a ast::DebugText>, - pub conversion: ast::ConversionFlag, - pub format_spec: Vec>, + conversion: ast::ConversionFlag, + format_spec: Vec>, } impl<'a> From<&'a ast::FStringPart> for ComparableFStringPart<'a> { From 917195d8ddd91ecfa7ad97493e6f6884e1459c72 Mon Sep 17 00:00:00 2001 From: David Szotten Date: Mon, 28 Aug 2023 13:31:26 +0100 Subject: [PATCH 13/17] FStringPart -> FStringElement etc --- .../src/checkers/ast/analyze/expression.rs | 6 +- .../flake8_pytest_style/rules/helpers.rs | 12 +- crates/ruff_linter/src/rules/flynt/helpers.rs | 14 +- .../flynt/rules/static_join_to_fstring.rs | 10 +- .../rules/f_string_missing_placeholders.rs | 6 +- .../pylint/rules/assert_on_string_literal.rs | 22 ++-- .../explicit_f_string_type_conversion.rs | 6 +- .../tryceratops/rules/raise_vanilla_args.rs | 8 +- crates/ruff_python_ast/src/comparable.rs | 32 ++--- crates/ruff_python_ast/src/helpers.rs | 30 ++--- crates/ruff_python_ast/src/node.rs | 122 +++++++++--------- crates/ruff_python_ast/src/nodes.rs | 24 ++-- crates/ruff_python_ast/src/relocate.rs | 22 ++-- crates/ruff_python_ast/src/visitor.rs | 24 ++-- .../ruff_python_ast/src/visitor/preorder.rs | 22 ++-- crates/ruff_python_codegen/src/generator.rs | 18 +-- .../src/expression/string.rs | 9 +- crates/ruff_python_formatter/src/generated.rs | 48 +++---- .../src/other/formatted_value.rs | 12 +- .../src/other/partial_string.rs | 8 +- ...parser__parser__tests__parse_f_string.snap | 4 +- ...uff_python_parser__parser__tests__try.snap | 16 +-- ...ython_parser__parser__tests__try_star.snap | 28 ++-- ...string__tests__fstring_constant_range.snap | 16 +-- ...ing__tests__fstring_escaped_character.snap | 8 +- ...tring__tests__fstring_escaped_newline.snap | 8 +- ...ing__tests__fstring_line_continuation.snap | 8 +- ...__fstring_parse_self_documenting_base.snap | 6 +- ...ring_parse_self_documenting_base_more.snap | 14 +- ...fstring_parse_self_documenting_format.snap | 8 +- ...ing__tests__fstring_unescaped_newline.snap | 8 +- ...r__string__tests__parse_empty_fstring.snap | 2 +- ...tring__tests__parse_f_string_concat_1.snap | 4 +- ...tring__tests__parse_f_string_concat_2.snap | 4 +- ...tring__tests__parse_f_string_concat_3.snap | 8 +- ...tring__tests__parse_f_string_concat_4.snap | 10 +- ..._parser__string__tests__parse_fstring.snap | 12 +- ...__string__tests__parse_fstring_equals.snap | 6 +- ...ring_nested_concatenation_string_spec.snap | 10 +- ...ing__tests__parse_fstring_nested_spec.snap | 10 +- ...sts__parse_fstring_nested_string_spec.snap | 10 +- ...ring__tests__parse_fstring_not_equals.snap | 6 +- ..._tests__parse_fstring_not_nested_spec.snap | 8 +- ...ts__parse_fstring_self_doc_prec_space.snap | 6 +- ...parse_fstring_self_doc_trailing_space.snap | 6 +- ...ring__tests__parse_fstring_yield_expr.snap | 6 +- ...ing__tests__parse_u_f_string_concat_1.snap | 4 +- ...ing__tests__parse_u_f_string_concat_2.snap | 4 +- ...on_parser__string__tests__raw_fstring.snap | 6 +- ...ing__tests__triple_quoted_raw_fstring.snap | 6 +- crates/ruff_python_parser/src/string.rs | 115 +++++++++-------- 51 files changed, 424 insertions(+), 398 deletions(-) diff --git a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs index d8a8b0d5be19a..3f10860a1b51d 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs @@ -957,15 +957,15 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { pylint::rules::await_outside_async(checker, expr); } } - Expr::FString(ast::ExprFString { parts, .. }) => { + Expr::FString(ast::ExprFString { elements, .. }) => { if checker.enabled(Rule::FStringMissingPlaceholders) { - pyflakes::rules::f_string_missing_placeholders(expr, parts, checker); + pyflakes::rules::f_string_missing_placeholders(expr, elements, checker); } if checker.enabled(Rule::HardcodedSQLExpression) { flake8_bandit::rules::hardcoded_sql_expression(checker, expr); } if checker.enabled(Rule::ExplicitFStringTypeConversion) { - ruff::rules::explicit_f_string_type_conversion(checker, expr, parts); + ruff::rules::explicit_f_string_type_conversion(checker, expr, elements); } } Expr::BinOp(ast::ExprBinOp { diff --git a/crates/ruff_linter/src/rules/flake8_pytest_style/rules/helpers.rs b/crates/ruff_linter/src/rules/flake8_pytest_style/rules/helpers.rs index 015a4971a733a..70c236ba49b52 100644 --- a/crates/ruff_linter/src/rules/flake8_pytest_style/rules/helpers.rs +++ b/crates/ruff_linter/src/rules/flake8_pytest_style/rules/helpers.rs @@ -63,17 +63,17 @@ pub(super) fn is_empty_or_null_string(expr: &Expr) -> bool { .. }) => string.is_empty(), Expr::Constant(constant) if constant.value.is_none() => true, - Expr::FString(ast::ExprFString { parts, .. }) => { - parts.iter().all(is_empty_or_null_string_part) + Expr::FString(ast::ExprFString { elements, .. }) => { + elements.iter().all(is_empty_or_null_fstring_element) } _ => false, } } -fn is_empty_or_null_string_part(part: &ast::FStringPart) -> bool { - match part { - ast::FStringPart::Literal(ast::PartialString { value, .. }) => value.is_empty(), - ast::FStringPart::FormattedValue(ast::FormattedValue { expression, .. }) => { +fn is_empty_or_null_fstring_element(element: &ast::FStringElement) -> bool { + match element { + ast::FStringElement::Literal(ast::FStringLiteralElement { value, .. }) => value.is_empty(), + ast::FStringElement::Expression(ast::FStringExpressionElement { expression, .. }) => { is_empty_or_null_string(expression) } } diff --git a/crates/ruff_linter/src/rules/flynt/helpers.rs b/crates/ruff_linter/src/rules/flynt/helpers.rs index 781a5435da552..56b1cbac653cb 100644 --- a/crates/ruff_linter/src/rules/flynt/helpers.rs +++ b/crates/ruff_linter/src/rules/flynt/helpers.rs @@ -1,9 +1,9 @@ use ruff_python_ast::{self as ast, Arguments, Constant, ConversionFlag, Expr}; use ruff_text_size::TextRange; -/// Wrap an expression in a `FormattedValue` with no special formatting. -fn to_formatted_value_expr(inner: &Expr) -> ast::FStringPart { - ast::FStringPart::FormattedValue(ast::FormattedValue { +/// Wrap an expression in a `FStringExpressionElement` with no special formatting. +fn to_formatted_value_expr(inner: &Expr) -> ast::FStringElement { + ast::FStringElement::Expression(ast::FStringExpressionElement { expression: Box::new(inner.clone()), debug_text: None, conversion: ConversionFlag::None, @@ -13,8 +13,8 @@ fn to_formatted_value_expr(inner: &Expr) -> ast::FStringPart { } /// Convert a string to a constant string expression. -pub(super) fn to_constant_string(s: &str) -> ast::FStringPart { - ast::FStringPart::Literal(ast::PartialString { +pub(super) fn to_constant_string(s: &str) -> ast::FStringElement { + ast::FStringElement::Literal(ast::FStringLiteralElement { value: s.to_owned(), range: TextRange::default(), }) @@ -49,13 +49,13 @@ fn is_simple_callee(func: &Expr) -> bool { } /// Convert an expression to a f-string element (if it looks like a good idea). -pub(super) fn to_fstring_part(expr: &Expr) -> Option { +pub(super) fn to_fstring_element(expr: &Expr) -> Option { match expr { // These are directly handled by `unparse_f_string_element`: Expr::Constant(ast::ExprConstant { value: Constant::Str(value), range, - }) => Some(ast::FStringPart::Literal(ast::PartialString { + }) => Some(ast::FStringElement::Literal(ast::FStringLiteralElement { value: value.to_string(), range: *range, })), diff --git a/crates/ruff_linter/src/rules/flynt/rules/static_join_to_fstring.rs b/crates/ruff_linter/src/rules/flynt/rules/static_join_to_fstring.rs index 3ecdbe58b9885..8d557fd57edc9 100644 --- a/crates/ruff_linter/src/rules/flynt/rules/static_join_to_fstring.rs +++ b/crates/ruff_linter/src/rules/flynt/rules/static_join_to_fstring.rs @@ -91,7 +91,7 @@ fn build_fstring(joiner: &str, joinees: &[Expr]) -> Option { return Some(node.into()); } - let mut fstring_parts = Vec::with_capacity(joinees.len() * 2); + let mut fstring_elements = Vec::with_capacity(joinees.len() * 2); let mut first = true; for expr in joinees { @@ -101,13 +101,13 @@ fn build_fstring(joiner: &str, joinees: &[Expr]) -> Option { return None; } if !std::mem::take(&mut first) { - fstring_parts.push(helpers::to_constant_string(joiner)); + fstring_elements.push(helpers::to_constant_string(joiner)); } - fstring_parts.push(helpers::to_fstring_part(expr)?); + fstring_elements.push(helpers::to_fstring_element(expr)?); } let node = ast::ExprFString { - parts: fstring_parts, + elements: fstring_elements, implicit_concatenated: false, range: TextRange::default(), }; @@ -141,7 +141,7 @@ pub(crate) fn static_join_to_fstring(checker: &mut Checker, expr: &Expr, joiner: }; // Try to build the fstring (internally checks whether e.g. the elements are - // convertible to f-string parts). + // convertible to f-string elements). let Some(new_expr) = build_fstring(joiner, joinees) else { return; }; diff --git a/crates/ruff_linter/src/rules/pyflakes/rules/f_string_missing_placeholders.rs b/crates/ruff_linter/src/rules/pyflakes/rules/f_string_missing_placeholders.rs index 2bd90fb748d13..8c87d858966c7 100644 --- a/crates/ruff_linter/src/rules/pyflakes/rules/f_string_missing_placeholders.rs +++ b/crates/ruff_linter/src/rules/pyflakes/rules/f_string_missing_placeholders.rs @@ -1,6 +1,6 @@ use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::{Expr, FStringPart, PySourceType}; +use ruff_python_ast::{Expr, FStringElement, PySourceType}; use ruff_python_parser::{lexer, AsMode, StringKind, Tok}; use ruff_source_file::Locator; use ruff_text_size::{Ranged, TextRange, TextSize}; @@ -81,12 +81,12 @@ fn find_useless_f_strings<'a>( /// F541 pub(crate) fn f_string_missing_placeholders( expr: &Expr, - values: &[FStringPart], + values: &[FStringElement], checker: &mut Checker, ) { if !values .iter() - .any(|value| matches!(value, FStringPart::FormattedValue(_))) + .any(|value| matches!(value, FStringElement::Expression(_))) { for (prefix_range, tok_range) in find_useless_f_strings(expr, checker.locator(), checker.source_type) diff --git a/crates/ruff_linter/src/rules/pylint/rules/assert_on_string_literal.rs b/crates/ruff_linter/src/rules/pylint/rules/assert_on_string_literal.rs index 3de2af76e71cb..d57f403eb27cd 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/assert_on_string_literal.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/assert_on_string_literal.rs @@ -72,21 +72,21 @@ pub(crate) fn assert_on_string_literal(checker: &mut Checker, test: &Expr) { } _ => {} }, - Expr::FString(ast::ExprFString { parts, .. }) => { + Expr::FString(ast::ExprFString { elements, .. }) => { checker.diagnostics.push(Diagnostic::new( AssertOnStringLiteral { - kind: if parts.iter().all(|part| match part { - ast::FStringPart::Literal(ast::PartialString { value, .. }) => { - value.is_empty() - } - ast::FStringPart::FormattedValue(_) => false, + kind: if elements.iter().all(|element| match element { + ast::FStringElement::Literal(ast::FStringLiteralElement { + value, .. + }) => value.is_empty(), + ast::FStringElement::Expression(_) => false, }) { Kind::Empty - } else if parts.iter().any(|part| match part { - ast::FStringPart::Literal(ast::PartialString { value, .. }) => { - !value.is_empty() - } - ast::FStringPart::FormattedValue(_) => false, + } else if elements.iter().any(|element| match element { + ast::FStringElement::Literal(ast::FStringLiteralElement { + value, .. + }) => !value.is_empty(), + ast::FStringElement::Expression(_) => false, }) { Kind::NonEmpty } else { diff --git a/crates/ruff_linter/src/rules/ruff/rules/explicit_f_string_type_conversion.rs b/crates/ruff_linter/src/rules/ruff/rules/explicit_f_string_type_conversion.rs index 54299734f376d..96f5b8f7ba0db 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/explicit_f_string_type_conversion.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/explicit_f_string_type_conversion.rs @@ -56,12 +56,12 @@ impl AlwaysAutofixableViolation for ExplicitFStringTypeConversion { pub(crate) fn explicit_f_string_type_conversion( checker: &mut Checker, expr: &Expr, - values: &[ast::FStringPart], + values: &[ast::FStringElement], ) { for (index, formatted_value) in values .iter() .filter_map(|expr| { - if let ast::FStringPart::FormattedValue(expr) = &expr { + if let ast::FStringElement::Expression(expr) = &expr { Some(expr) } else { None @@ -69,7 +69,7 @@ pub(crate) fn explicit_f_string_type_conversion( }) .enumerate() { - let ast::FormattedValue { + let ast::FStringExpressionElement { expression, conversion, .. diff --git a/crates/ruff_linter/src/rules/tryceratops/rules/raise_vanilla_args.rs b/crates/ruff_linter/src/rules/tryceratops/rules/raise_vanilla_args.rs index d426c07d8f34b..d3b9a7f012938 100644 --- a/crates/ruff_linter/src/rules/tryceratops/rules/raise_vanilla_args.rs +++ b/crates/ruff_linter/src/rules/tryceratops/rules/raise_vanilla_args.rs @@ -89,9 +89,11 @@ pub(crate) fn raise_vanilla_args(checker: &mut Checker, expr: &Expr) { /// some whitespace). fn contains_message(expr: &Expr) -> bool { match expr { - Expr::FString(ast::ExprFString { parts, .. }) => { - for part in parts { - if let ast::FStringPart::Literal(ast::PartialString { value, .. }) = part { + Expr::FString(ast::ExprFString { elements, .. }) => { + for element in elements { + if let ast::FStringElement::Literal(ast::FStringLiteralElement { value, .. }) = + element + { if value.chars().any(char::is_whitespace) { return true; } diff --git a/crates/ruff_python_ast/src/comparable.rs b/crates/ruff_python_ast/src/comparable.rs index 4a2630e7f63f7..f69347ce19478 100644 --- a/crates/ruff_python_ast/src/comparable.rs +++ b/crates/ruff_python_ast/src/comparable.rs @@ -520,25 +520,27 @@ impl<'a> From<&'a ast::ExceptHandler> for ComparableExceptHandler<'a> { } #[derive(Debug, PartialEq, Eq, Hash)] -pub enum ComparableFStringPart<'a> { +pub enum ComparableFStringElement<'a> { Literal(&'a str), - FormattedValue(FormattedValue<'a>), + FStringExpressionElement(FStringExpressionElement<'a>), } #[derive(Debug, PartialEq, Eq, Hash)] -pub struct FormattedValue<'a> { +pub struct FStringExpressionElement<'a> { expression: ComparableExpr<'a>, debug_text: Option<&'a ast::DebugText>, conversion: ast::ConversionFlag, - format_spec: Vec>, + format_spec: Vec>, } -impl<'a> From<&'a ast::FStringPart> for ComparableFStringPart<'a> { - fn from(fstring_part: &'a ast::FStringPart) -> Self { +impl<'a> From<&'a ast::FStringElement> for ComparableFStringElement<'a> { + fn from(fstring_part: &'a ast::FStringElement) -> Self { match fstring_part { - ast::FStringPart::Literal(ast::PartialString { value, .. }) => Self::Literal(value), - ast::FStringPart::FormattedValue(formatted_value) => { - Self::FormattedValue(FormattedValue { + ast::FStringElement::Literal(ast::FStringLiteralElement { value, .. }) => { + Self::Literal(value) + } + ast::FStringElement::Expression(formatted_value) => { + Self::FStringExpressionElement(FStringExpressionElement { expression: (&formatted_value.expression).into(), debug_text: formatted_value.debug_text.as_ref(), conversion: formatted_value.conversion, @@ -672,16 +674,16 @@ pub struct ExprCall<'a> { } #[derive(Debug, PartialEq, Eq, Hash)] -pub struct ExprFormattedValue<'a> { +pub struct ExprFStringExpressionElement<'a> { value: Box>, debug_text: Option<&'a ast::DebugText>, conversion: ast::ConversionFlag, - format_spec: Vec>, + format_spec: Vec>, } #[derive(Debug, PartialEq, Eq, Hash)] pub struct ExprFString<'a> { - parts: Vec>, + elements: Vec>, } #[derive(Debug, PartialEq, Eq, Hash)] @@ -753,7 +755,7 @@ pub enum ComparableExpr<'a> { YieldFrom(ExprYieldFrom<'a>), Compare(ExprCompare<'a>), Call(ExprCall<'a>), - FormattedValue(ExprFormattedValue<'a>), + FStringExpressionElement(ExprFStringExpressionElement<'a>), FString(ExprFString<'a>), Constant(ExprConstant<'a>), Attribute(ExprAttribute<'a>), @@ -911,11 +913,11 @@ impl<'a> From<&'a ast::Expr> for ComparableExpr<'a> { arguments: arguments.into(), }), ast::Expr::FString(ast::ExprFString { - parts, + elements, implicit_concatenated: _, range: _, }) => Self::FString(ExprFString { - parts: parts.iter().map(Into::into).collect(), + elements: elements.iter().map(Into::into).collect(), }), ast::Expr::Constant(ast::ExprConstant { value, range: _ }) => { Self::Constant(ExprConstant { diff --git a/crates/ruff_python_ast/src/helpers.rs b/crates/ruff_python_ast/src/helpers.rs index 84d40e570d2f6..94d36c7adfe80 100644 --- a/crates/ruff_python_ast/src/helpers.rs +++ b/crates/ruff_python_ast/src/helpers.rs @@ -9,8 +9,8 @@ use ruff_text_size::{Ranged, TextRange}; use crate::call_path::CallPath; use crate::statement_visitor::{walk_body, walk_stmt, StatementVisitor}; use crate::{ - self as ast, Arguments, Constant, ExceptHandler, Expr, FStringPart, MatchCase, Pattern, Stmt, - TypeParam, + self as ast, Arguments, Constant, ExceptHandler, Expr, FStringElement, MatchCase, Pattern, + Stmt, TypeParam, }; /// Return `true` if the `Stmt` is a compound statement (as opposed to a simple statement). @@ -122,9 +122,9 @@ pub fn any_over_expr(expr: &Expr, func: &dyn Fn(&Expr) -> bool) -> bool { Expr::BoolOp(ast::ExprBoolOp { values, .. }) => { values.iter().any(|expr| any_over_expr(expr, func)) } - Expr::FString(ast::ExprFString { parts, .. }) => { - parts.iter().any(|part| any_over_fstring_part(part, func)) - } + Expr::FString(ast::ExprFString { elements, .. }) => elements + .iter() + .any(|element| any_over_fstring_element(element, func)), Expr::NamedExpr(ast::ExprNamedExpr { target, value, @@ -287,10 +287,10 @@ pub fn any_over_pattern(pattern: &Pattern, func: &dyn Fn(&Expr) -> bool) -> bool } } -pub fn any_over_fstring_part(part: &FStringPart, func: &dyn Fn(&Expr) -> bool) -> bool { - match part { - FStringPart::Literal(_) => false, - FStringPart::FormattedValue(ast::FormattedValue { +pub fn any_over_fstring_element(element: &FStringElement, func: &dyn Fn(&Expr) -> bool) -> bool { + match element { + FStringElement::Literal(_) => false, + FStringElement::Expression(ast::FStringExpressionElement { expression, format_spec, .. @@ -298,7 +298,7 @@ pub fn any_over_fstring_part(part: &FStringPart, func: &dyn Fn(&Expr) -> bool) - any_over_expr(expression, func) || format_spec .iter() - .any(|spec_part| any_over_fstring_part(spec_part, func)) + .any(|spec_element| any_over_fstring_element(spec_element, func)) } } } @@ -1089,14 +1089,14 @@ impl Truthiness { Constant::Complex { real, imag } => Some(*real != 0.0 || *imag != 0.0), Constant::Ellipsis => Some(true), }, - Expr::FString(ast::ExprFString { parts, .. }) => { - if parts.is_empty() { + Expr::FString(ast::ExprFString { elements, .. }) => { + if elements.is_empty() { Some(false) - } else if parts.iter().any(|part| match part { - ast::FStringPart::Literal(ast::PartialString { value, .. }) => { + } else if elements.iter().any(|element| match element { + ast::FStringElement::Literal(ast::FStringLiteralElement { value, .. }) => { !value.is_empty() } - ast::FStringPart::FormattedValue(_) => true, + ast::FStringElement::Expression(_) => true, }) { Some(true) } else { diff --git a/crates/ruff_python_ast/src/node.rs b/crates/ruff_python_ast/src/node.rs index 0663ce7abf920..14b84a5f54d21 100644 --- a/crates/ruff_python_ast/src/node.rs +++ b/crates/ruff_python_ast/src/node.rs @@ -82,8 +82,8 @@ pub enum AnyNode { ExprSlice(ast::ExprSlice), ExprIpyEscapeCommand(ast::ExprIpyEscapeCommand), ExceptHandlerExceptHandler(ast::ExceptHandlerExceptHandler), - FormattedValue(ast::FormattedValue), - PartialString(ast::PartialString), + FStringExpressionElement(ast::FStringExpressionElement), + FStringLiteralElement(ast::FStringLiteralElement), PatternMatchValue(ast::PatternMatchValue), PatternMatchSingleton(ast::PatternMatchSingleton), PatternMatchSequence(ast::PatternMatchSequence), @@ -159,8 +159,8 @@ impl AnyNode { | AnyNode::ExprYieldFrom(_) | AnyNode::ExprCompare(_) | AnyNode::ExprCall(_) - | AnyNode::FormattedValue(_) - | AnyNode::PartialString(_) + | AnyNode::FStringExpressionElement(_) + | AnyNode::FStringLiteralElement(_) | AnyNode::ExprFString(_) | AnyNode::ExprConstant(_) | AnyNode::ExprAttribute(_) @@ -258,8 +258,8 @@ impl AnyNode { | AnyNode::StmtContinue(_) | AnyNode::StmtIpyEscapeCommand(_) | AnyNode::ExceptHandlerExceptHandler(_) - | AnyNode::FormattedValue(_) - | AnyNode::PartialString(_) + | AnyNode::FStringExpressionElement(_) + | AnyNode::FStringLiteralElement(_) | AnyNode::PatternMatchValue(_) | AnyNode::PatternMatchSingleton(_) | AnyNode::PatternMatchSequence(_) @@ -335,8 +335,8 @@ impl AnyNode { | AnyNode::ExprYieldFrom(_) | AnyNode::ExprCompare(_) | AnyNode::ExprCall(_) - | AnyNode::FormattedValue(_) - | AnyNode::PartialString(_) + | AnyNode::FStringExpressionElement(_) + | AnyNode::FStringLiteralElement(_) | AnyNode::ExprFString(_) | AnyNode::ExprConstant(_) | AnyNode::ExprAttribute(_) @@ -431,8 +431,8 @@ impl AnyNode { | AnyNode::ExprYieldFrom(_) | AnyNode::ExprCompare(_) | AnyNode::ExprCall(_) - | AnyNode::FormattedValue(_) - | AnyNode::PartialString(_) + | AnyNode::FStringExpressionElement(_) + | AnyNode::FStringLiteralElement(_) | AnyNode::ExprFString(_) | AnyNode::ExprConstant(_) | AnyNode::ExprAttribute(_) @@ -512,8 +512,8 @@ impl AnyNode { | AnyNode::ExprYieldFrom(_) | AnyNode::ExprCompare(_) | AnyNode::ExprCall(_) - | AnyNode::FormattedValue(_) - | AnyNode::PartialString(_) + | AnyNode::FStringExpressionElement(_) + | AnyNode::FStringLiteralElement(_) | AnyNode::ExprFString(_) | AnyNode::ExprConstant(_) | AnyNode::ExprAttribute(_) @@ -618,8 +618,8 @@ impl AnyNode { Self::ExprYieldFrom(node) => AnyNodeRef::ExprYieldFrom(node), Self::ExprCompare(node) => AnyNodeRef::ExprCompare(node), Self::ExprCall(node) => AnyNodeRef::ExprCall(node), - Self::FormattedValue(node) => AnyNodeRef::FormattedValue(node), - Self::PartialString(node) => AnyNodeRef::PartialString(node), + Self::FStringExpressionElement(node) => AnyNodeRef::FStringExpressionElement(node), + Self::FStringLiteralElement(node) => AnyNodeRef::FStringLiteralElement(node), Self::ExprFString(node) => AnyNodeRef::ExprFString(node), Self::ExprConstant(node) => AnyNodeRef::ExprConstant(node), Self::ExprAttribute(node) => AnyNodeRef::ExprAttribute(node), @@ -2572,12 +2572,12 @@ impl AstNode for ast::ExprCall { visitor.visit_arguments(arguments); } } -impl AstNode for ast::FormattedValue { +impl AstNode for ast::FStringExpressionElement { fn cast(kind: AnyNode) -> Option where Self: Sized, { - if let AnyNode::FormattedValue(node) = kind { + if let AnyNode::FStringExpressionElement(node) = kind { Some(node) } else { None @@ -2585,7 +2585,7 @@ impl AstNode for ast::FormattedValue { } fn cast_ref(kind: AnyNodeRef) -> Option<&Self> { - if let AnyNodeRef::FormattedValue(node) = kind { + if let AnyNodeRef::FStringExpressionElement(node) = kind { Some(node) } else { None @@ -2604,7 +2604,7 @@ impl AstNode for ast::FormattedValue { where V: PreorderVisitor<'a> + ?Sized, { - let ast::FormattedValue { + let ast::FStringExpressionElement { expression, format_spec, .. @@ -2612,16 +2612,16 @@ impl AstNode for ast::FormattedValue { visitor.visit_expr(expression); for spec_part in format_spec { - visitor.visit_fstring_part(spec_part); + visitor.visit_fstring_element(spec_part); } } } -impl AstNode for ast::PartialString { +impl AstNode for ast::FStringLiteralElement { fn cast(kind: AnyNode) -> Option where Self: Sized, { - if let AnyNode::PartialString(node) = kind { + if let AnyNode::FStringLiteralElement(node) = kind { Some(node) } else { None @@ -2629,7 +2629,7 @@ impl AstNode for ast::PartialString { } fn cast_ref(kind: AnyNodeRef) -> Option<&Self> { - if let AnyNodeRef::PartialString(node) = kind { + if let AnyNodeRef::FStringLiteralElement(node) = kind { Some(node) } else { None @@ -2684,13 +2684,13 @@ impl AstNode for ast::ExprFString { V: PreorderVisitor<'a> + ?Sized, { let ast::ExprFString { - parts, + elements, implicit_concatenated: _, range: _, } = self; - for part in parts { - visitor.visit_fstring_part(part); + for element in elements { + visitor.visit_fstring_element(element); } } } @@ -4482,15 +4482,15 @@ impl From for AnyNode { } } -impl From for AnyNode { - fn from(node: ast::FormattedValue) -> Self { - AnyNode::FormattedValue(node) +impl From for AnyNode { + fn from(node: ast::FStringExpressionElement) -> Self { + AnyNode::FStringExpressionElement(node) } } -impl From for AnyNode { - fn from(node: ast::PartialString) -> Self { - AnyNode::PartialString(node) +impl From for AnyNode { + fn from(node: ast::FStringLiteralElement) -> Self { + AnyNode::FStringLiteralElement(node) } } @@ -4740,8 +4740,8 @@ impl Ranged for AnyNode { AnyNode::ExprYieldFrom(node) => node.range(), AnyNode::ExprCompare(node) => node.range(), AnyNode::ExprCall(node) => node.range(), - AnyNode::FormattedValue(node) => node.range(), - AnyNode::PartialString(node) => node.range(), + AnyNode::FStringExpressionElement(node) => node.range(), + AnyNode::FStringLiteralElement(node) => node.range(), AnyNode::ExprFString(node) => node.range(), AnyNode::ExprConstant(node) => node.range(), AnyNode::ExprAttribute(node) => node.range(), @@ -4828,8 +4828,8 @@ pub enum AnyNodeRef<'a> { ExprYieldFrom(&'a ast::ExprYieldFrom), ExprCompare(&'a ast::ExprCompare), ExprCall(&'a ast::ExprCall), - FormattedValue(&'a ast::FormattedValue), - PartialString(&'a ast::PartialString), + FStringExpressionElement(&'a ast::FStringExpressionElement), + FStringLiteralElement(&'a ast::FStringLiteralElement), ExprFString(&'a ast::ExprFString), ExprConstant(&'a ast::ExprConstant), ExprAttribute(&'a ast::ExprAttribute), @@ -4915,8 +4915,8 @@ impl AnyNodeRef<'_> { AnyNodeRef::ExprYieldFrom(node) => NonNull::from(*node).cast(), AnyNodeRef::ExprCompare(node) => NonNull::from(*node).cast(), AnyNodeRef::ExprCall(node) => NonNull::from(*node).cast(), - AnyNodeRef::FormattedValue(node) => NonNull::from(*node).cast(), - AnyNodeRef::PartialString(node) => NonNull::from(*node).cast(), + AnyNodeRef::FStringExpressionElement(node) => NonNull::from(*node).cast(), + AnyNodeRef::FStringLiteralElement(node) => NonNull::from(*node).cast(), AnyNodeRef::ExprFString(node) => NonNull::from(*node).cast(), AnyNodeRef::ExprConstant(node) => NonNull::from(*node).cast(), AnyNodeRef::ExprAttribute(node) => NonNull::from(*node).cast(), @@ -5008,8 +5008,8 @@ impl AnyNodeRef<'_> { AnyNodeRef::ExprYieldFrom(_) => NodeKind::ExprYieldFrom, AnyNodeRef::ExprCompare(_) => NodeKind::ExprCompare, AnyNodeRef::ExprCall(_) => NodeKind::ExprCall, - AnyNodeRef::FormattedValue(_) => NodeKind::FormattedValue, - AnyNodeRef::PartialString(_) => NodeKind::PartialString, + AnyNodeRef::FStringExpressionElement(_) => NodeKind::FStringExpressionElement, + AnyNodeRef::FStringLiteralElement(_) => NodeKind::FStringLiteralElement, AnyNodeRef::ExprFString(_) => NodeKind::ExprFString, AnyNodeRef::ExprConstant(_) => NodeKind::ExprConstant, AnyNodeRef::ExprAttribute(_) => NodeKind::ExprAttribute, @@ -5096,8 +5096,8 @@ impl AnyNodeRef<'_> { | AnyNodeRef::ExprYieldFrom(_) | AnyNodeRef::ExprCompare(_) | AnyNodeRef::ExprCall(_) - | AnyNodeRef::FormattedValue(_) - | AnyNodeRef::PartialString(_) + | AnyNodeRef::FStringExpressionElement(_) + | AnyNodeRef::FStringLiteralElement(_) | AnyNodeRef::ExprFString(_) | AnyNodeRef::ExprConstant(_) | AnyNodeRef::ExprAttribute(_) @@ -5195,8 +5195,8 @@ impl AnyNodeRef<'_> { | AnyNodeRef::StmtContinue(_) | AnyNodeRef::StmtIpyEscapeCommand(_) | AnyNodeRef::ExceptHandlerExceptHandler(_) - | AnyNodeRef::FormattedValue(_) - | AnyNodeRef::PartialString(_) + | AnyNodeRef::FStringExpressionElement(_) + | AnyNodeRef::FStringLiteralElement(_) | AnyNodeRef::PatternMatchValue(_) | AnyNodeRef::PatternMatchSingleton(_) | AnyNodeRef::PatternMatchSequence(_) @@ -5271,8 +5271,8 @@ impl AnyNodeRef<'_> { | AnyNodeRef::ExprYieldFrom(_) | AnyNodeRef::ExprCompare(_) | AnyNodeRef::ExprCall(_) - | AnyNodeRef::FormattedValue(_) - | AnyNodeRef::PartialString(_) + | AnyNodeRef::FStringExpressionElement(_) + | AnyNodeRef::FStringLiteralElement(_) | AnyNodeRef::ExprFString(_) | AnyNodeRef::ExprConstant(_) | AnyNodeRef::ExprAttribute(_) @@ -5367,8 +5367,8 @@ impl AnyNodeRef<'_> { | AnyNodeRef::ExprYieldFrom(_) | AnyNodeRef::ExprCompare(_) | AnyNodeRef::ExprCall(_) - | AnyNodeRef::FormattedValue(_) - | AnyNodeRef::PartialString(_) + | AnyNodeRef::FStringExpressionElement(_) + | AnyNodeRef::FStringLiteralElement(_) | AnyNodeRef::ExprFString(_) | AnyNodeRef::ExprConstant(_) | AnyNodeRef::ExprAttribute(_) @@ -5448,8 +5448,8 @@ impl AnyNodeRef<'_> { | AnyNodeRef::ExprYieldFrom(_) | AnyNodeRef::ExprCompare(_) | AnyNodeRef::ExprCall(_) - | AnyNodeRef::FormattedValue(_) - | AnyNodeRef::PartialString(_) + | AnyNodeRef::FStringExpressionElement(_) + | AnyNodeRef::FStringLiteralElement(_) | AnyNodeRef::ExprFString(_) | AnyNodeRef::ExprConstant(_) | AnyNodeRef::ExprAttribute(_) @@ -5563,8 +5563,8 @@ impl AnyNodeRef<'_> { AnyNodeRef::ExprYieldFrom(node) => node.visit_preorder(visitor), AnyNodeRef::ExprCompare(node) => node.visit_preorder(visitor), AnyNodeRef::ExprCall(node) => node.visit_preorder(visitor), - AnyNodeRef::FormattedValue(node) => node.visit_preorder(visitor), - AnyNodeRef::PartialString(node) => node.visit_preorder(visitor), + AnyNodeRef::FStringExpressionElement(node) => node.visit_preorder(visitor), + AnyNodeRef::FStringLiteralElement(node) => node.visit_preorder(visitor), AnyNodeRef::ExprFString(node) => node.visit_preorder(visitor), AnyNodeRef::ExprConstant(node) => node.visit_preorder(visitor), AnyNodeRef::ExprAttribute(node) => node.visit_preorder(visitor), @@ -5875,15 +5875,15 @@ impl<'a> From<&'a ast::ExprCall> for AnyNodeRef<'a> { } } -impl<'a> From<&'a ast::FormattedValue> for AnyNodeRef<'a> { - fn from(node: &'a ast::FormattedValue) -> Self { - AnyNodeRef::FormattedValue(node) +impl<'a> From<&'a ast::FStringExpressionElement> for AnyNodeRef<'a> { + fn from(node: &'a ast::FStringExpressionElement) -> Self { + AnyNodeRef::FStringExpressionElement(node) } } -impl<'a> From<&'a ast::PartialString> for AnyNodeRef<'a> { - fn from(node: &'a ast::PartialString) -> Self { - AnyNodeRef::PartialString(node) +impl<'a> From<&'a ast::FStringLiteralElement> for AnyNodeRef<'a> { + fn from(node: &'a ast::FStringLiteralElement) -> Self { + AnyNodeRef::FStringLiteralElement(node) } } @@ -6245,8 +6245,8 @@ impl Ranged for AnyNodeRef<'_> { AnyNodeRef::ExprYieldFrom(node) => node.range(), AnyNodeRef::ExprCompare(node) => node.range(), AnyNodeRef::ExprCall(node) => node.range(), - AnyNodeRef::FormattedValue(node) => node.range(), - AnyNodeRef::PartialString(node) => node.range(), + AnyNodeRef::FStringExpressionElement(node) => node.range(), + AnyNodeRef::FStringLiteralElement(node) => node.range(), AnyNodeRef::ExprFString(node) => node.range(), AnyNodeRef::ExprConstant(node) => node.range(), AnyNodeRef::ExprAttribute(node) => node.range(), @@ -6335,8 +6335,8 @@ pub enum NodeKind { ExprYieldFrom, ExprCompare, ExprCall, - FormattedValue, - PartialString, + FStringExpressionElement, + FStringLiteralElement, ExprFString, ExprConstant, ExprAttribute, diff --git a/crates/ruff_python_ast/src/nodes.rs b/crates/ruff_python_ast/src/nodes.rs index 449fe9ab7efb7..a9065d49dc01e 100644 --- a/crates/ruff_python_ast/src/nodes.rs +++ b/crates/ruff_python_ast/src/nodes.rs @@ -875,16 +875,16 @@ impl From for Expr { /// See also [FormattedValue](https://docs.python.org/3/library/ast.html#ast.FormattedValue) #[derive(Clone, Debug, PartialEq)] -pub struct FormattedValue { +pub struct FStringExpressionElement { pub range: TextRange, pub expression: Box, pub debug_text: Option, pub conversion: ConversionFlag, - pub format_spec: Vec, + pub format_spec: Vec, } #[derive(Clone, Debug, PartialEq)] -pub struct PartialString { +pub struct FStringLiteralElement { pub range: TextRange, pub value: String, } @@ -930,7 +930,7 @@ pub struct ExprFString { pub range: TextRange, /// Whether the f-string contains multiple string tokens that were implicitly concatenated. pub implicit_concatenated: bool, - pub parts: Vec, + pub elements: Vec, } impl From for Expr { @@ -940,9 +940,9 @@ impl From for Expr { } #[derive(Clone, Debug, PartialEq)] -pub enum FStringPart { - Literal(PartialString), - FormattedValue(FormattedValue), +pub enum FStringElement { + Literal(FStringLiteralElement), + Expression(FStringExpressionElement), } /// See also [Constant](https://docs.python.org/3/library/ast.html#ast.Constant) @@ -3376,22 +3376,22 @@ mod size_assertions { assert_eq_size!(Mod, [u8; 32]); } -impl Ranged for crate::nodes::FormattedValue { +impl Ranged for crate::nodes::FStringExpressionElement { fn range(&self) -> TextRange { self.range } } -impl Ranged for crate::nodes::FStringPart { +impl Ranged for crate::nodes::FStringElement { fn range(&self) -> TextRange { match self { - FStringPart::Literal(node) => node.range(), - FStringPart::FormattedValue(node) => node.range(), + FStringElement::Literal(node) => node.range(), + FStringElement::Expression(node) => node.range(), } } } -impl Ranged for crate::nodes::PartialString { +impl Ranged for crate::nodes::FStringLiteralElement { fn range(&self) -> TextRange { self.range } diff --git a/crates/ruff_python_ast/src/relocate.rs b/crates/ruff_python_ast/src/relocate.rs index e6712f859dda0..52425b4dd08cd 100644 --- a/crates/ruff_python_ast/src/relocate.rs +++ b/crates/ruff_python_ast/src/relocate.rs @@ -128,10 +128,12 @@ pub fn relocate_expr(expr: &mut Expr, location: TextRange) { relocate_keyword(keyword, location); } } - Expr::FString(nodes::ExprFString { parts, range, .. }) => { + Expr::FString(nodes::ExprFString { + elements, range, .. + }) => { *range = location; - for part in parts { - relocate_fstring_part(part, location); + for element in elements { + relocate_fstring_element(element, location); } } Expr::Constant(nodes::ExprConstant { range, .. }) => { @@ -193,14 +195,14 @@ pub fn relocate_expr(expr: &mut Expr, location: TextRange) { } } -/// Change a f-string part's location (recursively) to match a desired, fixed +/// Change a f-string element's location (recursively) to match a desired, fixed /// location. -fn relocate_fstring_part(part: &mut nodes::FStringPart, location: TextRange) { - match part { - nodes::FStringPart::Literal(nodes::PartialString { range, .. }) => { +fn relocate_fstring_element(element: &mut nodes::FStringElement, location: TextRange) { + match element { + nodes::FStringElement::Literal(nodes::FStringLiteralElement { range, .. }) => { *range = location; } - nodes::FStringPart::FormattedValue(nodes::FormattedValue { + nodes::FStringElement::Expression(nodes::FStringExpressionElement { range, expression, format_spec, @@ -208,8 +210,8 @@ fn relocate_fstring_part(part: &mut nodes::FStringPart, location: TextRange) { }) => { *range = location; relocate_expr(expression, location); - for spec_part in format_spec { - relocate_fstring_part(spec_part, location); + for spec_element in format_spec { + relocate_fstring_element(spec_element, location); } } } diff --git a/crates/ruff_python_ast/src/visitor.rs b/crates/ruff_python_ast/src/visitor.rs index 45ba3b62a36a6..ac49e624b5bc9 100644 --- a/crates/ruff_python_ast/src/visitor.rs +++ b/crates/ruff_python_ast/src/visitor.rs @@ -4,7 +4,7 @@ pub mod preorder; use crate::{ self as ast, Alias, Arguments, BoolOp, CmpOp, Comprehension, Decorator, ElifElseClause, - ExceptHandler, Expr, ExprContext, FStringPart, Keyword, MatchCase, Operator, Parameter, + ExceptHandler, Expr, ExprContext, FStringElement, Keyword, MatchCase, Operator, Parameter, Parameters, Pattern, PatternArguments, PatternKeyword, Stmt, TypeParam, TypeParamTypeVar, TypeParams, UnaryOp, WithItem, }; @@ -92,8 +92,8 @@ pub trait Visitor<'a> { fn visit_elif_else_clause(&mut self, elif_else_clause: &'a ElifElseClause) { walk_elif_else_clause(self, elif_else_clause); } - fn visit_fstring_part(&mut self, fstring_part: &'a FStringPart) { - walk_fstring_part(self, fstring_part); + fn visit_fstring_element(&mut self, fstring_element: &'a FStringElement) { + walk_fstring_element(self, fstring_element); } } @@ -464,9 +464,9 @@ pub fn walk_expr<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, expr: &'a Expr) { visitor.visit_expr(func); visitor.visit_arguments(arguments); } - Expr::FString(ast::ExprFString { parts, .. }) => { - for part in parts { - visitor.visit_fstring_part(part); + Expr::FString(ast::ExprFString { elements, .. }) => { + for element in elements { + visitor.visit_fstring_element(element); } } Expr::Constant(_) => {} @@ -709,19 +709,19 @@ pub fn walk_pattern_keyword<'a, V: Visitor<'a> + ?Sized>( visitor.visit_pattern(&pattern_keyword.pattern); } -pub fn walk_fstring_part<'a, V: Visitor<'a> + ?Sized>( +pub fn walk_fstring_element<'a, V: Visitor<'a> + ?Sized>( visitor: &mut V, - fstring_part: &'a FStringPart, + fstring_element: &'a FStringElement, ) { - if let ast::FStringPart::FormattedValue(ast::FormattedValue { + if let ast::FStringElement::Expression(ast::FStringExpressionElement { expression, format_spec, .. - }) = fstring_part + }) = fstring_element { visitor.visit_expr(expression); - for spec_part in format_spec { - walk_fstring_part(visitor, spec_part); + for spec_element in format_spec { + walk_fstring_element(visitor, spec_element); } } } diff --git a/crates/ruff_python_ast/src/visitor/preorder.rs b/crates/ruff_python_ast/src/visitor/preorder.rs index 04c9b182ca616..026877254f6be 100644 --- a/crates/ruff_python_ast/src/visitor/preorder.rs +++ b/crates/ruff_python_ast/src/visitor/preorder.rs @@ -1,9 +1,9 @@ use crate::node::{AnyNodeRef, AstNode}; use crate::{ Alias, Arguments, BoolOp, CmpOp, Comprehension, Constant, Decorator, ElifElseClause, - ExceptHandler, Expr, FStringPart, FormattedValue, Keyword, MatchCase, Mod, Operator, Parameter, - ParameterWithDefault, Parameters, Pattern, PatternArguments, PatternKeyword, Stmt, TypeParam, - TypeParams, UnaryOp, WithItem, + ExceptHandler, Expr, FStringElement, FStringExpressionElement, Keyword, MatchCase, Mod, + Operator, Parameter, ParameterWithDefault, Parameters, Pattern, PatternArguments, + PatternKeyword, Stmt, TypeParam, TypeParams, UnaryOp, WithItem, }; /// Visitor that traverses all nodes recursively in pre-order. @@ -150,8 +150,8 @@ pub trait PreorderVisitor<'a> { } #[inline] - fn visit_fstring_part(&mut self, fstring_part: &'a FStringPart) { - walk_fstring_part(self, fstring_part); + fn visit_fstring_element(&mut self, fstring_element: &'a FStringElement) { + walk_fstring_element(self, fstring_element); } } @@ -498,19 +498,19 @@ where visitor.leave_node(node); } -pub fn walk_fstring_part<'a, V: PreorderVisitor<'a> + ?Sized>( +pub fn walk_fstring_element<'a, V: PreorderVisitor<'a> + ?Sized>( visitor: &mut V, - fstring_part: &'a FStringPart, + fstring_element: &'a FStringElement, ) { - if let FStringPart::FormattedValue(FormattedValue { + if let FStringElement::Expression(FStringExpressionElement { expression, format_spec, .. - }) = fstring_part + }) = fstring_element { visitor.visit_expr(expression); - for spec_part in format_spec { - walk_fstring_part(visitor, spec_part); + for spec_element in format_spec { + walk_fstring_element(visitor, spec_element); } } } diff --git a/crates/ruff_python_codegen/src/generator.rs b/crates/ruff_python_codegen/src/generator.rs index e52ccc0fa838b..b1cd767f83f59 100644 --- a/crates/ruff_python_codegen/src/generator.rs +++ b/crates/ruff_python_codegen/src/generator.rs @@ -1075,8 +1075,8 @@ impl<'a> Generator<'a> { } self.p(")"); } - Expr::FString(ast::ExprFString { parts, .. }) => { - self.unparse_fstring(parts, false); + Expr::FString(ast::ExprFString { elements, .. }) => { + self.unparse_fstring(elements, false); } Expr::Constant(ast::ExprConstant { value, range: _ }) => { self.unparse_constant(value); @@ -1256,7 +1256,7 @@ impl<'a> Generator<'a> { } } - fn unparse_fstring_body(&mut self, values: &[ast::FStringPart]) { + fn unparse_fstring_body(&mut self, values: &[ast::FStringElement]) { for value in values { self.unparse_fstring_elem(value); } @@ -1267,7 +1267,7 @@ impl<'a> Generator<'a> { val: &Expr, debug_text: Option<&DebugText>, conversion: ConversionFlag, - spec: &[ast::FStringPart], + spec: &[ast::FStringElement], ) { let mut generator = Generator::new(self.indent, self.quote, self.line_ending); generator.unparse_expr(val, precedence::FORMATTED_VALUE); @@ -1303,12 +1303,12 @@ impl<'a> Generator<'a> { self.p("}"); } - fn unparse_fstring_elem(&mut self, part: &ast::FStringPart) { - match part { - ast::FStringPart::Literal(ast::PartialString { value, .. }) => { + fn unparse_fstring_elem(&mut self, element: &ast::FStringElement) { + match element { + ast::FStringElement::Literal(ast::FStringLiteralElement { value, .. }) => { self.unparse_fstring_literal(value); } - ast::FStringPart::FormattedValue(ast::FormattedValue { + ast::FStringElement::Expression(ast::FStringExpressionElement { expression, debug_text, conversion, @@ -1323,7 +1323,7 @@ impl<'a> Generator<'a> { self.p(&s); } - fn unparse_fstring(&mut self, values: &[ast::FStringPart], is_spec: bool) { + fn unparse_fstring(&mut self, values: &[ast::FStringElement], is_spec: bool) { if is_spec { self.unparse_fstring_body(values); } else { diff --git a/crates/ruff_python_formatter/src/expression/string.rs b/crates/ruff_python_formatter/src/expression/string.rs index 7c6b563d465f5..d3b36c694f3c6 100644 --- a/crates/ruff_python_formatter/src/expression/string.rs +++ b/crates/ruff_python_formatter/src/expression/string.rs @@ -48,12 +48,15 @@ impl<'a> AnyString<'a> { match self { Self::Constant(_) => Quoting::CanChange, Self::FString(f_str) => { - if f_str.parts.iter().any(|value| match value { - ast::FStringPart::FormattedValue(ast::FormattedValue { range, .. }) => { + if f_str.elements.iter().any(|value| match value { + ast::FStringElement::Expression(ast::FStringExpressionElement { + range, + .. + }) => { let string_content = locator.slice(*range); string_content.contains(['"', '\'']) } - ast::FStringPart::Literal(_) => false, + ast::FStringElement::Literal(_) => false, }) { Quoting::Preserve } else { diff --git a/crates/ruff_python_formatter/src/generated.rs b/crates/ruff_python_formatter/src/generated.rs index fbfb5cad58689..f217bb4447fa9 100644 --- a/crates/ruff_python_formatter/src/generated.rs +++ b/crates/ruff_python_formatter/src/generated.rs @@ -1932,74 +1932,74 @@ impl<'ast> IntoFormat> for ast::ExceptHandlerExceptHandler } } -impl FormatRule> - for crate::other::formatted_value::FormatFormattedValue +impl FormatRule> + for crate::other::formatted_value::FormatFStringExpressionElement { #[inline] - fn fmt(&self, node: &ast::FormattedValue, f: &mut PyFormatter) -> FormatResult<()> { - FormatNodeRule::::fmt(self, node, f) + fn fmt(&self, node: &ast::FStringExpressionElement, f: &mut PyFormatter) -> FormatResult<()> { + FormatNodeRule::::fmt(self, node, f) } } -impl<'ast> AsFormat> for ast::FormattedValue { +impl<'ast> AsFormat> for ast::FStringExpressionElement { type Format<'a> = FormatRefWithRule< 'a, - ast::FormattedValue, - crate::other::formatted_value::FormatFormattedValue, + ast::FStringExpressionElement, + crate::other::formatted_value::FormatFStringExpressionElement, PyFormatContext<'ast>, >; fn format(&self) -> Self::Format<'_> { FormatRefWithRule::new( self, - crate::other::formatted_value::FormatFormattedValue::default(), + crate::other::formatted_value::FormatFStringExpressionElement::default(), ) } } -impl<'ast> IntoFormat> for ast::FormattedValue { +impl<'ast> IntoFormat> for ast::FStringExpressionElement { type Format = FormatOwnedWithRule< - ast::FormattedValue, - crate::other::formatted_value::FormatFormattedValue, + ast::FStringExpressionElement, + crate::other::formatted_value::FormatFStringExpressionElement, PyFormatContext<'ast>, >; fn into_format(self) -> Self::Format { FormatOwnedWithRule::new( self, - crate::other::formatted_value::FormatFormattedValue::default(), + crate::other::formatted_value::FormatFStringExpressionElement::default(), ) } } -impl FormatRule> - for crate::other::partial_string::FormatPartialString +impl FormatRule> + for crate::other::partial_string::FormatFStringLiteralElement { #[inline] - fn fmt(&self, node: &ast::PartialString, f: &mut PyFormatter) -> FormatResult<()> { - FormatNodeRule::::fmt(self, node, f) + fn fmt(&self, node: &ast::FStringLiteralElement, f: &mut PyFormatter) -> FormatResult<()> { + FormatNodeRule::::fmt(self, node, f) } } -impl<'ast> AsFormat> for ast::PartialString { +impl<'ast> AsFormat> for ast::FStringLiteralElement { type Format<'a> = FormatRefWithRule< 'a, - ast::PartialString, - crate::other::partial_string::FormatPartialString, + ast::FStringLiteralElement, + crate::other::partial_string::FormatFStringLiteralElement, PyFormatContext<'ast>, >; fn format(&self) -> Self::Format<'_> { FormatRefWithRule::new( self, - crate::other::partial_string::FormatPartialString::default(), + crate::other::partial_string::FormatFStringLiteralElement::default(), ) } } -impl<'ast> IntoFormat> for ast::PartialString { +impl<'ast> IntoFormat> for ast::FStringLiteralElement { type Format = FormatOwnedWithRule< - ast::PartialString, - crate::other::partial_string::FormatPartialString, + ast::FStringLiteralElement, + crate::other::partial_string::FormatFStringLiteralElement, PyFormatContext<'ast>, >; fn into_format(self) -> Self::Format { FormatOwnedWithRule::new( self, - crate::other::partial_string::FormatPartialString::default(), + crate::other::partial_string::FormatFStringLiteralElement::default(), ) } } diff --git a/crates/ruff_python_formatter/src/other/formatted_value.rs b/crates/ruff_python_formatter/src/other/formatted_value.rs index 3f56c8b38e5e4..decab89d407c8 100644 --- a/crates/ruff_python_formatter/src/other/formatted_value.rs +++ b/crates/ruff_python_formatter/src/other/formatted_value.rs @@ -1,12 +1,16 @@ use crate::{FormatNodeRule, PyFormatter}; use ruff_formatter::FormatResult; -use ruff_python_ast::FormattedValue; +use ruff_python_ast::FStringExpressionElement; #[derive(Default)] -pub struct FormatFormattedValue; +pub struct FormatFStringExpressionElement; -impl FormatNodeRule for FormatFormattedValue { - fn fmt_fields(&self, _item: &FormattedValue, _f: &mut PyFormatter) -> FormatResult<()> { +impl FormatNodeRule for FormatFStringExpressionElement { + fn fmt_fields( + &self, + _item: &FStringExpressionElement, + _f: &mut PyFormatter, + ) -> FormatResult<()> { unreachable!("Handled inside of `FormatExprFString"); } } diff --git a/crates/ruff_python_formatter/src/other/partial_string.rs b/crates/ruff_python_formatter/src/other/partial_string.rs index 9605d93d0d5e0..2ad90a56ca719 100644 --- a/crates/ruff_python_formatter/src/other/partial_string.rs +++ b/crates/ruff_python_formatter/src/other/partial_string.rs @@ -1,12 +1,12 @@ use crate::{FormatNodeRule, PyFormatter}; use ruff_formatter::FormatResult; -use ruff_python_ast::PartialString; +use ruff_python_ast::FStringLiteralElement; #[derive(Default)] -pub struct FormatPartialString; +pub struct FormatFStringLiteralElement; -impl FormatNodeRule for FormatPartialString { - fn fmt_fields(&self, _item: &PartialString, _f: &mut PyFormatter) -> FormatResult<()> { +impl FormatNodeRule for FormatFStringLiteralElement { + fn fmt_fields(&self, _item: &FStringLiteralElement, _f: &mut PyFormatter) -> FormatResult<()> { unreachable!("Handled inside of `FormatExprFString"); } } diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_f_string.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_f_string.snap index f80a93face317..1502bc4a79f20 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_f_string.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__parse_f_string.snap @@ -10,9 +10,9 @@ expression: parse_ast ExprFString { range: 0..14, implicit_concatenated: false, - parts: [ + elements: [ Literal( - PartialString { + FStringLiteralElement { range: 2..13, value: "Hello world", }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try.snap index 918f4b9f30395..942b917820c6d 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try.snap @@ -82,15 +82,15 @@ expression: parse_ast ExprFString { range: 62..81, implicit_concatenated: false, - parts: [ + elements: [ Literal( - PartialString { + FStringLiteralElement { range: 64..71, value: "caught ", }, ), - FormattedValue( - FormattedValue { + Expression( + FStringExpressionElement { range: 71..80, expression: Call( ExprCall { @@ -174,15 +174,15 @@ expression: parse_ast ExprFString { range: 114..133, implicit_concatenated: false, - parts: [ + elements: [ Literal( - PartialString { + FStringLiteralElement { range: 116..123, value: "caught ", }, ), - FormattedValue( - FormattedValue { + Expression( + FStringExpressionElement { range: 123..132, expression: Call( ExprCall { diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try_star.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try_star.snap index ecacb9205f3b5..625bea4f2914b 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try_star.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__parser__tests__try_star.snap @@ -198,15 +198,15 @@ expression: parse_ast ExprFString { range: 133..179, implicit_concatenated: false, - parts: [ + elements: [ Literal( - PartialString { + FStringLiteralElement { range: 135..142, value: "caught ", }, ), - FormattedValue( - FormattedValue { + Expression( + FStringExpressionElement { range: 142..151, expression: Call( ExprCall { @@ -239,13 +239,13 @@ expression: parse_ast }, ), Literal( - PartialString { + FStringLiteralElement { range: 151..164, value: " with nested ", }, ), - FormattedValue( - FormattedValue { + Expression( + FStringExpressionElement { range: 164..178, expression: Attribute( ExprAttribute { @@ -321,15 +321,15 @@ expression: parse_ast ExprFString { range: 213..259, implicit_concatenated: false, - parts: [ + elements: [ Literal( - PartialString { + FStringLiteralElement { range: 215..222, value: "caught ", }, ), - FormattedValue( - FormattedValue { + Expression( + FStringExpressionElement { range: 222..231, expression: Call( ExprCall { @@ -362,13 +362,13 @@ expression: parse_ast }, ), Literal( - PartialString { + FStringLiteralElement { range: 231..244, value: " with nested ", }, ), - FormattedValue( - FormattedValue { + Expression( + FStringExpressionElement { range: 244..258, expression: Attribute( ExprAttribute { diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_constant_range.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_constant_range.snap index 2b55b4e275eee..723939bef6e90 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_constant_range.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_constant_range.snap @@ -10,15 +10,15 @@ expression: parse_ast ExprFString { range: 0..22, implicit_concatenated: false, - parts: [ + elements: [ Literal( - PartialString { + FStringLiteralElement { range: 2..5, value: "aaa", }, ), - FormattedValue( - FormattedValue { + Expression( + FStringExpressionElement { range: 5..10, expression: Name( ExprName { @@ -33,13 +33,13 @@ expression: parse_ast }, ), Literal( - PartialString { + FStringLiteralElement { range: 10..13, value: "ccc", }, ), - FormattedValue( - FormattedValue { + Expression( + FStringExpressionElement { range: 13..18, expression: Name( ExprName { @@ -54,7 +54,7 @@ expression: parse_ast }, ), Literal( - PartialString { + FStringLiteralElement { range: 18..21, value: "eee", }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_character.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_character.snap index 9adcbf6008b5f..06c9c808cd6c9 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_character.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_character.snap @@ -10,15 +10,15 @@ expression: parse_ast ExprFString { range: 0..8, implicit_concatenated: false, - parts: [ + elements: [ Literal( - PartialString { + FStringLiteralElement { range: 2..4, value: "\\", }, ), - FormattedValue( - FormattedValue { + Expression( + FStringExpressionElement { range: 4..7, expression: Name( ExprName { diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_newline.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_newline.snap index 9800251950494..cd85d85fa6a8e 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_newline.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_escaped_newline.snap @@ -10,15 +10,15 @@ expression: parse_ast ExprFString { range: 0..8, implicit_concatenated: false, - parts: [ + elements: [ Literal( - PartialString { + FStringLiteralElement { range: 2..4, value: "\n", }, ), - FormattedValue( - FormattedValue { + Expression( + FStringExpressionElement { range: 4..7, expression: Name( ExprName { diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_line_continuation.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_line_continuation.snap index a8b64fb64af0c..67f7fba48efa4 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_line_continuation.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_line_continuation.snap @@ -10,15 +10,15 @@ expression: parse_ast ExprFString { range: 0..9, implicit_concatenated: false, - parts: [ + elements: [ Literal( - PartialString { + FStringLiteralElement { range: 3..5, value: "\\\n", }, ), - FormattedValue( - FormattedValue { + Expression( + FStringExpressionElement { range: 5..8, expression: Name( ExprName { diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base.snap index bb257fdc4349b..dcfd014a76dd0 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base.snap @@ -6,9 +6,9 @@ FString( ExprFString { range: 2..9, implicit_concatenated: false, - parts: [ - FormattedValue( - FormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 2..9, expression: Name( ExprName { diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base_more.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base_more.snap index 5d2f649895b45..49f217a3fc57c 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base_more.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_base_more.snap @@ -6,15 +6,15 @@ FString( ExprFString { range: 2..37, implicit_concatenated: false, - parts: [ + elements: [ Literal( - PartialString { + FStringLiteralElement { range: 2..6, value: "mix ", }, ), - FormattedValue( - FormattedValue { + Expression( + FStringExpressionElement { range: 6..13, expression: Name( ExprName { @@ -34,13 +34,13 @@ FString( }, ), Literal( - PartialString { + FStringLiteralElement { range: 13..28, value: " with text and ", }, ), - FormattedValue( - FormattedValue { + Expression( + FStringExpressionElement { range: 28..37, expression: Name( ExprName { diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_format.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_format.snap index 0a6dad037ecd8..662b43216670a 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_format.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_parse_self_documenting_format.snap @@ -6,9 +6,9 @@ FString( ExprFString { range: 2..13, implicit_concatenated: false, - parts: [ - FormattedValue( - FormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 2..13, expression: Name( ExprName { @@ -26,7 +26,7 @@ FString( conversion: None, format_spec: [ Literal( - PartialString { + FStringLiteralElement { range: 9..12, value: ">10", }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_unescaped_newline.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_unescaped_newline.snap index f4dfd26711c8a..dd1cbd25b988d 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_unescaped_newline.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__fstring_unescaped_newline.snap @@ -10,15 +10,15 @@ expression: parse_ast ExprFString { range: 0..11, implicit_concatenated: false, - parts: [ + elements: [ Literal( - PartialString { + FStringLiteralElement { range: 4..5, value: "\n", }, ), - FormattedValue( - FormattedValue { + Expression( + FStringExpressionElement { range: 5..8, expression: Name( ExprName { diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_empty_fstring.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_empty_fstring.snap index c704373b44aed..a99a6dd3c3f10 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_empty_fstring.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_empty_fstring.snap @@ -6,6 +6,6 @@ FString( ExprFString { range: 2..2, implicit_concatenated: false, - parts: [], + elements: [], }, ) diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_1.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_1.snap index 3d4fb7e40b1b3..b5ac5a83a595a 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_1.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_1.snap @@ -10,9 +10,9 @@ expression: parse_ast ExprFString { range: 0..17, implicit_concatenated: true, - parts: [ + elements: [ Literal( - PartialString { + FStringLiteralElement { range: 1..16, value: "Hello world", }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_2.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_2.snap index 3d4fb7e40b1b3..b5ac5a83a595a 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_2.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_2.snap @@ -10,9 +10,9 @@ expression: parse_ast ExprFString { range: 0..17, implicit_concatenated: true, - parts: [ + elements: [ Literal( - PartialString { + FStringLiteralElement { range: 1..16, value: "Hello world", }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_3.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_3.snap index de8c04740e639..754f3c9d73ef0 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_3.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_3.snap @@ -10,15 +10,15 @@ expression: parse_ast ExprFString { range: 0..22, implicit_concatenated: true, - parts: [ + elements: [ Literal( - PartialString { + FStringLiteralElement { range: 1..16, value: "Hello world", }, ), - FormattedValue( - FormattedValue { + Expression( + FStringExpressionElement { range: 16..21, expression: Constant( ExprConstant { diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_4.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_4.snap index 30ff989893e69..48d820bce9399 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_4.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_f_string_concat_4.snap @@ -10,15 +10,15 @@ expression: parse_ast ExprFString { range: 0..31, implicit_concatenated: true, - parts: [ + elements: [ Literal( - PartialString { + FStringLiteralElement { range: 1..16, value: "Hello world", }, ), - FormattedValue( - FormattedValue { + Expression( + FStringExpressionElement { range: 16..21, expression: Constant( ExprConstant { @@ -38,7 +38,7 @@ expression: parse_ast }, ), Literal( - PartialString { + FStringLiteralElement { range: 24..30, value: "again!", }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring.snap index 9e387b6f4f4fc..2652e6016ccd6 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring.snap @@ -6,9 +6,9 @@ FString( ExprFString { range: 2..17, implicit_concatenated: false, - parts: [ - FormattedValue( - FormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 2..5, expression: Name( ExprName { @@ -22,8 +22,8 @@ FString( format_spec: [], }, ), - FormattedValue( - FormattedValue { + Expression( + FStringExpressionElement { range: 5..10, expression: Name( ExprName { @@ -38,7 +38,7 @@ FString( }, ), Literal( - PartialString { + FStringLiteralElement { range: 10..17, value: "{foo}", }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_equals.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_equals.snap index ef20767fb833b..8470a55c8c0bc 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_equals.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_equals.snap @@ -6,9 +6,9 @@ FString( ExprFString { range: 2..12, implicit_concatenated: false, - parts: [ - FormattedValue( - FormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 2..12, expression: Compare( ExprCompare { diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_concatenation_string_spec.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_concatenation_string_spec.snap index ca0f544e27a09..748af65bed33c 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_concatenation_string_spec.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_concatenation_string_spec.snap @@ -6,9 +6,9 @@ FString( ExprFString { range: 2..15, implicit_concatenated: false, - parts: [ - FormattedValue( - FormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 2..15, expression: Name( ExprName { @@ -20,8 +20,8 @@ FString( debug_text: None, conversion: None, format_spec: [ - FormattedValue( - FormattedValue { + Expression( + FStringExpressionElement { range: 7..14, expression: Constant( ExprConstant { diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_spec.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_spec.snap index 9fd8c07f5abce..62b0b753538a2 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_spec.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_spec.snap @@ -6,9 +6,9 @@ FString( ExprFString { range: 2..14, implicit_concatenated: false, - parts: [ - FormattedValue( - FormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 2..14, expression: Name( ExprName { @@ -20,8 +20,8 @@ FString( debug_text: None, conversion: None, format_spec: [ - FormattedValue( - FormattedValue { + Expression( + FStringExpressionElement { range: 7..13, expression: Name( ExprName { diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_string_spec.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_string_spec.snap index 267bfb58a5565..f36df6e5e2897 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_string_spec.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_nested_string_spec.snap @@ -6,9 +6,9 @@ FString( ExprFString { range: 2..12, implicit_concatenated: false, - parts: [ - FormattedValue( - FormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 2..12, expression: Name( ExprName { @@ -20,8 +20,8 @@ FString( debug_text: None, conversion: None, format_spec: [ - FormattedValue( - FormattedValue { + Expression( + FStringExpressionElement { range: 7..11, expression: Constant( ExprConstant { diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_equals.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_equals.snap index 06ae95d28278e..16b2704d2d2b9 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_equals.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_equals.snap @@ -6,9 +6,9 @@ FString( ExprFString { range: 2..10, implicit_concatenated: false, - parts: [ - FormattedValue( - FormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 2..10, expression: Compare( ExprCompare { diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_nested_spec.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_nested_spec.snap index 572ca3349f858..dc6042d755c23 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_nested_spec.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_not_nested_spec.snap @@ -6,9 +6,9 @@ FString( ExprFString { range: 2..12, implicit_concatenated: false, - parts: [ - FormattedValue( - FormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 2..12, expression: Name( ExprName { @@ -21,7 +21,7 @@ FString( conversion: None, format_spec: [ Literal( - PartialString { + FStringLiteralElement { range: 7..11, value: "spec", }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_self_doc_prec_space.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_self_doc_prec_space.snap index d74d5dc69b35d..67715ae61abc5 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_self_doc_prec_space.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_self_doc_prec_space.snap @@ -6,9 +6,9 @@ FString( ExprFString { range: 2..9, implicit_concatenated: false, - parts: [ - FormattedValue( - FormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 2..9, expression: Name( ExprName { diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_self_doc_trailing_space.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_self_doc_trailing_space.snap index 721aea1ca9ff2..3cfbb69b9bc90 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_self_doc_trailing_space.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_self_doc_trailing_space.snap @@ -6,9 +6,9 @@ FString( ExprFString { range: 2..9, implicit_concatenated: false, - parts: [ - FormattedValue( - FormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 2..9, expression: Name( ExprName { diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_yield_expr.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_yield_expr.snap index a9f2af8c6e21c..2cb51164552c5 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_yield_expr.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_fstring_yield_expr.snap @@ -6,9 +6,9 @@ FString( ExprFString { range: 2..9, implicit_concatenated: false, - parts: [ - FormattedValue( - FormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 2..9, expression: Yield( ExprYield { diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_f_string_concat_1.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_f_string_concat_1.snap index 564dfb67bd0b2..16ba36a282fc0 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_f_string_concat_1.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_f_string_concat_1.snap @@ -10,9 +10,9 @@ expression: parse_ast ExprFString { range: 0..18, implicit_concatenated: true, - parts: [ + elements: [ Literal( - PartialString { + FStringLiteralElement { range: 2..17, value: "Hello world", }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_f_string_concat_2.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_f_string_concat_2.snap index c9b8a9b34007d..fe5df99f6dd70 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_f_string_concat_2.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__parse_u_f_string_concat_2.snap @@ -10,9 +10,9 @@ expression: parse_ast ExprFString { range: 0..22, implicit_concatenated: true, - parts: [ + elements: [ Literal( - PartialString { + FStringLiteralElement { range: 2..21, value: "Hello world!", }, diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__raw_fstring.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__raw_fstring.snap index e8b37db3235b0..a9596dcea8854 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__raw_fstring.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__raw_fstring.snap @@ -10,9 +10,9 @@ expression: parse_ast ExprFString { range: 0..7, implicit_concatenated: false, - parts: [ - FormattedValue( - FormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 3..6, expression: Name( ExprName { diff --git a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__triple_quoted_raw_fstring.snap b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__triple_quoted_raw_fstring.snap index f81548a8a85d8..806bd791fa572 100644 --- a/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__triple_quoted_raw_fstring.snap +++ b/crates/ruff_python_parser/src/snapshots/ruff_python_parser__string__tests__triple_quoted_raw_fstring.snap @@ -10,9 +10,9 @@ expression: parse_ast ExprFString { range: 0..11, implicit_concatenated: false, - parts: [ - FormattedValue( - FormattedValue { + elements: [ + Expression( + FStringExpressionElement { range: 5..8, expression: Name( ExprName { diff --git a/crates/ruff_python_parser/src/string.rs b/crates/ruff_python_parser/src/string.rs index c0bde09ba9eba..61727395b74ef 100644 --- a/crates/ruff_python_parser/src/string.rs +++ b/crates/ruff_python_parser/src/string.rs @@ -173,7 +173,10 @@ impl<'a> StringParser<'a> { } } - fn parse_formatted_value(&mut self, nested: u8) -> Result, LexicalError> { + fn parse_formatted_value( + &mut self, + nested: u8, + ) -> Result, LexicalError> { use FStringErrorType::{ EmptyExpression, ExpressionNestedTooDeeply, InvalidConversionFlag, InvalidExpression, MismatchedDelimiter, UnclosedLbrace, Unmatched, UnterminatedString, @@ -317,31 +320,37 @@ impl<'a> StringParser<'a> { let leading = &expression[..usize::from(value.start() - start_location) - 1]; let trailing = &expression[usize::from(value.end() - start_location) - 1..]; - vec![ast::FStringPart::FormattedValue(ast::FormattedValue { - expression: Box::new(value), - debug_text: Some(ast::DebugText { - leading: leading.to_string(), - trailing: trailing.to_string(), - }), - conversion, - format_spec: spec, - range: self.range(start_location), - })] + vec![ast::FStringElement::Expression( + ast::FStringExpressionElement { + expression: Box::new(value), + debug_text: Some(ast::DebugText { + leading: leading.to_string(), + trailing: trailing.to_string(), + }), + conversion, + format_spec: spec, + range: self.range(start_location), + }, + )] } else { - vec![ast::FStringPart::FormattedValue(ast::FormattedValue { - expression: Box::new( - parse_fstring_expr(&expression, start_location).map_err(|e| { - FStringError::new( - InvalidExpression(Box::new(e.error)), - start_location, - ) - })?, - ), - debug_text: None, - conversion, - format_spec: spec, - range: self.range(start_location), - })] + vec![ast::FStringElement::Expression( + ast::FStringExpressionElement { + expression: Box::new( + parse_fstring_expr(&expression, start_location).map_err( + |e| { + FStringError::new( + InvalidExpression(Box::new(e.error)), + start_location, + ) + }, + )?, + ), + debug_text: None, + conversion, + format_spec: spec, + range: self.range(start_location), + }, + )] }; return Ok(ret); } @@ -373,7 +382,7 @@ impl<'a> StringParser<'a> { Err(FStringError::new(UnclosedLbrace, self.get_pos()).into()) } - fn parse_spec(&mut self, nested: u8) -> Result, LexicalError> { + fn parse_spec(&mut self, nested: u8) -> Result, LexicalError> { let mut spec_constructor = Vec::new(); let mut constant_piece = String::new(); let mut start_location = self.get_pos(); @@ -381,10 +390,12 @@ impl<'a> StringParser<'a> { match next { '{' => { if !constant_piece.is_empty() { - spec_constructor.push(ast::FStringPart::Literal(ast::PartialString { - value: std::mem::take(&mut constant_piece), - range: self.range(start_location), - })); + spec_constructor.push(ast::FStringElement::Literal( + ast::FStringLiteralElement { + value: std::mem::take(&mut constant_piece), + range: self.range(start_location), + }, + )); } let parsed_expr = self.parse_formatted_value(nested + 1)?; spec_constructor.extend(parsed_expr); @@ -401,7 +412,7 @@ impl<'a> StringParser<'a> { self.next_char(); } if !constant_piece.is_empty() { - spec_constructor.push(ast::FStringPart::Literal(ast::PartialString { + spec_constructor.push(ast::FStringElement::Literal(ast::FStringLiteralElement { value: std::mem::take(&mut constant_piece), range: self.range(start_location), })); @@ -414,8 +425,8 @@ impl<'a> StringParser<'a> { let mut content = String::new(); let start_location = self.get_pos(); - let mut part_start_location = self.get_pos(); - let mut parts = vec![]; + let mut element_start_location = self.get_pos(); + let mut elements = vec![]; while let Some(ch) = self.peek() { match ch { @@ -435,15 +446,15 @@ impl<'a> StringParser<'a> { } } if !content.is_empty() { - parts.push(ast::FStringPart::Literal(ast::PartialString { + elements.push(ast::FStringElement::Literal(ast::FStringLiteralElement { value: std::mem::take(&mut content), - range: self.range(part_start_location), + range: self.range(element_start_location), })); } - let parsed_parts = self.parse_formatted_value(nested)?; - parts.extend(parsed_parts); - part_start_location = self.get_pos(); + let parsed_elements = self.parse_formatted_value(nested)?; + elements.extend(parsed_elements); + element_start_location = self.get_pos(); } '}' => { if nested > 0 { @@ -469,14 +480,14 @@ impl<'a> StringParser<'a> { } if !content.is_empty() { - parts.push(ast::FStringPart::Literal(ast::PartialString { + elements.push(ast::FStringElement::Literal(ast::FStringLiteralElement { value: content, - range: self.range(part_start_location), + range: self.range(element_start_location), })); } Ok(Expr::from(ast::ExprFString { - parts, + elements, implicit_concatenated: false, range: self.range(start_location), })) @@ -628,13 +639,13 @@ pub(crate) fn parse_strings( } // De-duplicate adjacent constants. - let mut deduped: Vec = vec![]; + let mut deduped: Vec = vec![]; let mut current: Vec = vec![]; let mut current_start = initial_start; let mut current_end = last_end; - let take_current = |current: &mut Vec, start, end| -> ast::FStringPart { - ast::FStringPart::Literal(ast::PartialString { + let take_current = |current: &mut Vec, start, end| -> ast::FStringElement { + ast::FStringElement::Literal(ast::FStringLiteralElement { value: current.drain(..).collect::(), range: TextRange::new(start, end), }) @@ -643,10 +654,10 @@ pub(crate) fn parse_strings( for (start, (source, kind, triple_quoted), _) in values { let value = parse_string(&source, kind, triple_quoted, start)?; match value { - Expr::FString(ast::ExprFString { parts, .. }) => { - for part in parts { - match part { - ast::FStringPart::Literal(ast::PartialString { + Expr::FString(ast::ExprFString { elements, .. }) => { + for element in elements { + match element { + ast::FStringElement::Literal(ast::FStringLiteralElement { value: inner, range, }) => { @@ -656,7 +667,9 @@ pub(crate) fn parse_strings( current_end = range.end(); current.push(inner); } - ast::FStringPart::FormattedValue(ast::FormattedValue { .. }) => { + ast::FStringElement::Expression(ast::FStringExpressionElement { + .. + }) => { if !current.is_empty() { deduped.push(take_current( &mut current, @@ -664,7 +677,7 @@ pub(crate) fn parse_strings( current_end, )); } - deduped.push(part); + deduped.push(element); } } } @@ -687,7 +700,7 @@ pub(crate) fn parse_strings( } Ok(Expr::FString(ast::ExprFString { - parts: deduped, + elements: deduped, implicit_concatenated, range: TextRange::new(initial_start, last_end), })) From 42786db10adafbed87a43a8d11c19d7dad13be17 Mon Sep 17 00:00:00 2001 From: David Szotten Date: Mon, 28 Aug 2023 13:32:45 +0100 Subject: [PATCH 14/17] leftover todo --- crates/ruff_python_ast/src/node.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/ruff_python_ast/src/node.rs b/crates/ruff_python_ast/src/node.rs index 14b84a5f54d21..6cf569f07dea4 100644 --- a/crates/ruff_python_ast/src/node.rs +++ b/crates/ruff_python_ast/src/node.rs @@ -2648,7 +2648,6 @@ impl AstNode for ast::FStringLiteralElement { where V: PreorderVisitor<'a> + ?Sized, { - // TODO: is this correct? } } impl AstNode for ast::ExprFString { From 0e86813a3cff4e002b3b784b6d7463ff8349a632 Mon Sep 17 00:00:00 2001 From: David Szotten Date: Sat, 23 Sep 2023 09:34:26 +0100 Subject: [PATCH 15/17] lint rules for f-string literal parts --- .../test/fixtures/flake8_bandit/S104.py | 1 + .../test/fixtures/flake8_bandit/S108.py | 3 ++ .../src/checkers/ast/analyze/expression.rs | 18 +++++++++++- .../rules/hardcoded_tmp_directory.rs | 6 ++-- ...s__flake8_bandit__tests__S104_S104.py.snap | 24 ++++++++++----- ...s__flake8_bandit__tests__S108_S108.py.snap | 21 ++++++++++---- ...es__flake8_bandit__tests__S108_extend.snap | 29 ++++++++++++------- 7 files changed, 75 insertions(+), 27 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S104.py b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S104.py index 3bbab01871247..7e50db007619c 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S104.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S104.py @@ -8,6 +8,7 @@ def func(address): # Error "0.0.0.0" '0.0.0.0' +f"0.0.0.0" # Error diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S108.py b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S108.py index 1689af66e63c5..c7cc7dd4809f5 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S108.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S108.py @@ -5,6 +5,9 @@ with open("/tmp/abc", "w") as f: f.write("def") +with open(f"/tmp/abc", "w") as f: + f.write("def") + with open("/var/tmp/123", "w") as f: f.write("def") diff --git a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs index 3f10860a1b51d..4994dfda95b8a 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs @@ -967,6 +967,22 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { if checker.enabled(Rule::ExplicitFStringTypeConversion) { ruff::rules::explicit_f_string_type_conversion(checker, expr, elements); } + for element in elements { + if let ast::FStringElement::Literal(ast::FStringLiteralElement { value, range }) = + element + { + if checker.enabled(Rule::HardcodedBindAllInterfaces) { + if let Some(diagnostic) = + flake8_bandit::rules::hardcoded_bind_all_interfaces(value, *range) + { + checker.diagnostics.push(diagnostic); + } + } + if checker.enabled(Rule::HardcodedTempFile) { + flake8_bandit::rules::hardcoded_tmp_directory(checker, *range, value); + } + } + } } Expr::BinOp(ast::ExprBinOp { left, @@ -1246,7 +1262,7 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { } } if checker.enabled(Rule::HardcodedTempFile) { - flake8_bandit::rules::hardcoded_tmp_directory(checker, expr, value); + flake8_bandit::rules::hardcoded_tmp_directory(checker, expr.range(), value); } if checker.enabled(Rule::UnicodeKindPrefix) { pyupgrade::rules::unicode_kind_prefix(checker, expr, value.unicode); diff --git a/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_tmp_directory.rs b/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_tmp_directory.rs index 58e9180806ac5..295aeaac6a29d 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_tmp_directory.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/rules/hardcoded_tmp_directory.rs @@ -1,8 +1,8 @@ use ruff_python_ast::{self as ast, Expr}; +use ruff_text_size::TextRange; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; -use ruff_text_size::Ranged; use crate::checkers::ast::Checker; @@ -52,7 +52,7 @@ impl Violation for HardcodedTempFile { } /// S108 -pub(crate) fn hardcoded_tmp_directory(checker: &mut Checker, expr: &Expr, value: &str) { +pub(crate) fn hardcoded_tmp_directory(checker: &mut Checker, range: TextRange, value: &str) { if !checker .settings .flake8_bandit @@ -79,6 +79,6 @@ pub(crate) fn hardcoded_tmp_directory(checker: &mut Checker, expr: &Expr, value: HardcodedTempFile { string: value.to_string(), }, - expr.range(), + range, )); } diff --git a/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S104_S104.py.snap b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S104_S104.py.snap index 192731979437a..b3b9ad07d38d4 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S104_S104.py.snap +++ b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S104_S104.py.snap @@ -7,6 +7,7 @@ S104.py:9:1: S104 Possible binding to all interfaces 9 | "0.0.0.0" | ^^^^^^^^^ S104 10 | '0.0.0.0' +11 | f"0.0.0.0" | S104.py:10:1: S104 Possible binding to all interfaces @@ -15,21 +16,30 @@ S104.py:10:1: S104 Possible binding to all interfaces 9 | "0.0.0.0" 10 | '0.0.0.0' | ^^^^^^^^^ S104 +11 | f"0.0.0.0" | -S104.py:14:6: S104 Possible binding to all interfaces +S104.py:11:3: S104 Possible binding to all interfaces | -13 | # Error -14 | func("0.0.0.0") + 9 | "0.0.0.0" +10 | '0.0.0.0' +11 | f"0.0.0.0" + | ^^^^^^^ S104 + | + +S104.py:15:6: S104 Possible binding to all interfaces + | +14 | # Error +15 | func("0.0.0.0") | ^^^^^^^^^ S104 | -S104.py:18:9: S104 Possible binding to all interfaces +S104.py:19:9: S104 Possible binding to all interfaces | -17 | def my_func(): -18 | x = "0.0.0.0" +18 | def my_func(): +19 | x = "0.0.0.0" | ^^^^^^^^^ S104 -19 | print(x) +20 | print(x) | diff --git a/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S108_S108.py.snap b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S108_S108.py.snap index 9ecf1141d98a2..7336a5015aa28 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S108_S108.py.snap +++ b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S108_S108.py.snap @@ -10,22 +10,31 @@ S108.py:5:11: S108 Probable insecure usage of temporary file or directory: "/tmp 6 | f.write("def") | -S108.py:8:11: S108 Probable insecure usage of temporary file or directory: "/var/tmp/123" +S108.py:8:13: S108 Probable insecure usage of temporary file or directory: "/tmp/abc" | 6 | f.write("def") 7 | -8 | with open("/var/tmp/123", "w") as f: - | ^^^^^^^^^^^^^^ S108 +8 | with open(f"/tmp/abc", "w") as f: + | ^^^^^^^^ S108 9 | f.write("def") | -S108.py:11:11: S108 Probable insecure usage of temporary file or directory: "/dev/shm/unit/test" +S108.py:11:11: S108 Probable insecure usage of temporary file or directory: "/var/tmp/123" | 9 | f.write("def") 10 | -11 | with open("/dev/shm/unit/test", "w") as f: - | ^^^^^^^^^^^^^^^^^^^^ S108 +11 | with open("/var/tmp/123", "w") as f: + | ^^^^^^^^^^^^^^ S108 +12 | f.write("def") + | + +S108.py:14:11: S108 Probable insecure usage of temporary file or directory: "/dev/shm/unit/test" + | 12 | f.write("def") +13 | +14 | with open("/dev/shm/unit/test", "w") as f: + | ^^^^^^^^^^^^^^^^^^^^ S108 +15 | f.write("def") | diff --git a/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S108_extend.snap b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S108_extend.snap index 998bc900593bf..b562794a05d7c 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S108_extend.snap +++ b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__S108_extend.snap @@ -10,30 +10,39 @@ S108.py:5:11: S108 Probable insecure usage of temporary file or directory: "/tmp 6 | f.write("def") | -S108.py:8:11: S108 Probable insecure usage of temporary file or directory: "/var/tmp/123" +S108.py:8:13: S108 Probable insecure usage of temporary file or directory: "/tmp/abc" | 6 | f.write("def") 7 | -8 | with open("/var/tmp/123", "w") as f: - | ^^^^^^^^^^^^^^ S108 +8 | with open(f"/tmp/abc", "w") as f: + | ^^^^^^^^ S108 9 | f.write("def") | -S108.py:11:11: S108 Probable insecure usage of temporary file or directory: "/dev/shm/unit/test" +S108.py:11:11: S108 Probable insecure usage of temporary file or directory: "/var/tmp/123" | 9 | f.write("def") 10 | -11 | with open("/dev/shm/unit/test", "w") as f: - | ^^^^^^^^^^^^^^^^^^^^ S108 +11 | with open("/var/tmp/123", "w") as f: + | ^^^^^^^^^^^^^^ S108 +12 | f.write("def") + | + +S108.py:14:11: S108 Probable insecure usage of temporary file or directory: "/dev/shm/unit/test" + | 12 | f.write("def") +13 | +14 | with open("/dev/shm/unit/test", "w") as f: + | ^^^^^^^^^^^^^^^^^^^^ S108 +15 | f.write("def") | -S108.py:15:11: S108 Probable insecure usage of temporary file or directory: "/foo/bar" +S108.py:18:11: S108 Probable insecure usage of temporary file or directory: "/foo/bar" | -14 | # not ok by config -15 | with open("/foo/bar", "w") as f: +17 | # not ok by config +18 | with open("/foo/bar", "w") as f: | ^^^^^^^^^^ S108 -16 | f.write("def") +19 | f.write("def") | From d9fdd3d7452149371d9954b6ff870e093ccc9f6d Mon Sep 17 00:00:00 2001 From: David Szotten Date: Sun, 24 Sep 2023 08:13:31 +0100 Subject: [PATCH 16/17] string_or_bytes_too_long for f-string parts --- .../test/fixtures/flake8_pyi/PYI053.py | 1 + .../test/fixtures/flake8_pyi/PYI053.pyi | 4 ++ .../src/checkers/ast/analyze/expression.rs | 42 +++++++++++++------ .../rules/string_or_bytes_too_long.rs | 18 ++++---- ..._flake8_pyi__tests__PYI053_PYI053.pyi.snap | 27 ++++++++++-- 5 files changed, 70 insertions(+), 22 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI053.py b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI053.py index 8b2811eb63467..640d1fb42b87c 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI053.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI053.py @@ -32,6 +32,7 @@ def f8(x: bytes = b"50 character byte stringgggggggggggggggggggggggggg\xff") -> foo: str = "50 character stringggggggggggggggggggggggggggggggg" bar: str = "51 character stringgggggggggggggggggggggggggggggggg" +baz: str = f"51 character stringgggggggggggggggggggggggggggggggg" baz: bytes = b"50 character byte stringgggggggggggggggggggggggggg" diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI053.pyi b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI053.pyi index 71064d9bdbd02..e87388ec9acbb 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI053.pyi +++ b/crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI053.pyi @@ -29,6 +29,10 @@ baz: bytes = b"50 character byte stringgggggggggggggggggggggggggg" # OK qux: bytes = b"51 character byte stringggggggggggggggggggggggggggg\xff" # Error: PYI053 +ffoo: str = f"50 character stringggggggggggggggggggggggggggggggg" # OK + +fbar: str = f"51 character stringgggggggggggggggggggggggggggggggg" # Error: PYI053 + class Demo: """Docstrings are excluded from this rule. Some padding.""" # OK diff --git a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs index 4994dfda95b8a..8072062b3ba35 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs @@ -3,6 +3,7 @@ use ruff_python_literal::cformat::{CFormatError, CFormatErrorType}; use ruff_diagnostics::Diagnostic; +use ruff_python_ast::node::AstNode; use ruff_python_ast::types::Node; use ruff_python_semantic::analyze::typing; use ruff_python_semantic::ScopeKind; @@ -968,8 +969,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { ruff::rules::explicit_f_string_type_conversion(checker, expr, elements); } for element in elements { - if let ast::FStringElement::Literal(ast::FStringLiteralElement { value, range }) = - element + if let ast::FStringElement::Literal( + literal_element @ ast::FStringLiteralElement { value, range }, + ) = element { if checker.enabled(Rule::HardcodedBindAllInterfaces) { if let Some(diagnostic) = @@ -981,6 +983,15 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { if checker.enabled(Rule::HardcodedTempFile) { flake8_bandit::rules::hardcoded_tmp_directory(checker, *range, value); } + + if checker.source_type.is_stub() { + if checker.enabled(Rule::StringOrBytesTooLong) { + flake8_pyi::rules::string_or_bytes_too_long( + checker, + literal_element.as_any_node_ref(), + ); + } + } } } } @@ -1242,18 +1253,22 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { flake8_pyi::rules::numeric_literal_too_long(checker, expr); } } - Expr::Constant(ast::ExprConstant { - value: Constant::Bytes(_), - range: _, - }) => { + Expr::Constant( + constant @ ast::ExprConstant { + value: Constant::Bytes(_), + range: _, + }, + ) => { if checker.source_type.is_stub() && checker.enabled(Rule::StringOrBytesTooLong) { - flake8_pyi::rules::string_or_bytes_too_long(checker, expr); + flake8_pyi::rules::string_or_bytes_too_long(checker, constant.as_any_node_ref()); } } - Expr::Constant(ast::ExprConstant { - value: Constant::Str(value), - range: _, - }) => { + Expr::Constant( + constant @ ast::ExprConstant { + value: Constant::Str(value), + range: _, + }, + ) => { if checker.enabled(Rule::HardcodedBindAllInterfaces) { if let Some(diagnostic) = flake8_bandit::rules::hardcoded_bind_all_interfaces(value, expr.range()) @@ -1269,7 +1284,10 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { } if checker.source_type.is_stub() { if checker.enabled(Rule::StringOrBytesTooLong) { - flake8_pyi::rules::string_or_bytes_too_long(checker, expr); + flake8_pyi::rules::string_or_bytes_too_long( + checker, + constant.as_any_node_ref(), + ); } } } diff --git a/crates/ruff_linter/src/rules/flake8_pyi/rules/string_or_bytes_too_long.rs b/crates/ruff_linter/src/rules/flake8_pyi/rules/string_or_bytes_too_long.rs index bbf20bda6273c..697e1aa2361ce 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/rules/string_or_bytes_too_long.rs +++ b/crates/ruff_linter/src/rules/flake8_pyi/rules/string_or_bytes_too_long.rs @@ -1,8 +1,9 @@ -use ruff_python_ast::{self as ast, Constant, Expr}; +use ruff_python_ast::{self as ast, Constant}; use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::helpers::is_docstring_stmt; +use ruff_python_ast::node::AnyNodeRef; use ruff_text_size::Ranged; use crate::checkers::ast::Checker; @@ -42,32 +43,35 @@ impl AlwaysAutofixableViolation for StringOrBytesTooLong { } /// PYI053 -pub(crate) fn string_or_bytes_too_long(checker: &mut Checker, expr: &Expr) { +pub(crate) fn string_or_bytes_too_long(checker: &mut Checker, node: AnyNodeRef) { // Ignore docstrings. if is_docstring_stmt(checker.semantic().current_statement()) { return; } - let length = match expr { - Expr::Constant(ast::ExprConstant { + let length = match node { + AnyNodeRef::ExprConstant(ast::ExprConstant { value: Constant::Str(s), .. }) => s.chars().count(), - Expr::Constant(ast::ExprConstant { + AnyNodeRef::ExprConstant(ast::ExprConstant { value: Constant::Bytes(bytes), .. }) => bytes.len(), + AnyNodeRef::FStringLiteralElement(ast::FStringLiteralElement { value, .. }) => { + value.chars().count() + } _ => return, }; if length <= 50 { return; } - let mut diagnostic = Diagnostic::new(StringOrBytesTooLong, expr.range()); + let mut diagnostic = Diagnostic::new(StringOrBytesTooLong, node.range()); if checker.patch(diagnostic.kind.rule()) { diagnostic.set_fix(Fix::suggested(Edit::range_replacement( "...".to_string(), - expr.range(), + node.range(), ))); } checker.diagnostics.push(diagnostic); diff --git a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI053_PYI053.pyi.snap b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI053_PYI053.pyi.snap index 5b9f3aa1a1332..aa4b57d184df4 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI053_PYI053.pyi.snap +++ b/crates/ruff_linter/src/rules/flake8_pyi/snapshots/ruff_linter__rules__flake8_pyi__tests__PYI053_PYI053.pyi.snap @@ -90,7 +90,7 @@ PYI053.pyi:30:14: PYI053 [*] String and bytes literals longer than 50 characters 30 | qux: bytes = b"51 character byte stringggggggggggggggggggggggggggg\xff" # Error: PYI053 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI053 31 | -32 | class Demo: +32 | ffoo: str = f"50 character stringggggggggggggggggggggggggggggggg" # OK | = help: Replace with `...` @@ -101,7 +101,28 @@ PYI053.pyi:30:14: PYI053 [*] String and bytes literals longer than 50 characters 30 |-qux: bytes = b"51 character byte stringggggggggggggggggggggggggggg\xff" # Error: PYI053 30 |+qux: bytes = ... # Error: PYI053 31 31 | -32 32 | class Demo: -33 33 | """Docstrings are excluded from this rule. Some padding.""" # OK +32 32 | ffoo: str = f"50 character stringggggggggggggggggggggggggggggggg" # OK +33 33 | + +PYI053.pyi:34:15: PYI053 [*] String and bytes literals longer than 50 characters are not permitted + | +32 | ffoo: str = f"50 character stringggggggggggggggggggggggggggggggg" # OK +33 | +34 | fbar: str = f"51 character stringgggggggggggggggggggggggggggggggg" # Error: PYI053 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI053 +35 | +36 | class Demo: + | + = help: Replace with `...` + +ℹ Suggested fix +31 31 | +32 32 | ffoo: str = f"50 character stringggggggggggggggggggggggggggggggg" # OK +33 33 | +34 |-fbar: str = f"51 character stringgggggggggggggggggggggggggggggggg" # Error: PYI053 + 34 |+fbar: str = f"..." # Error: PYI053 +35 35 | +36 36 | class Demo: +37 37 | """Docstrings are excluded from this rule. Some padding.""" # OK From 1c3558875669d6692102f5dc5812d875bfc7bbca Mon Sep 17 00:00:00 2001 From: David Szotten Date: Wed, 27 Sep 2023 09:36:41 +0100 Subject: [PATCH 17/17] rename helper to clarify its use --- crates/ruff_linter/src/rules/flynt/helpers.rs | 4 ++-- .../src/rules/flynt/rules/static_join_to_fstring.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/ruff_linter/src/rules/flynt/helpers.rs b/crates/ruff_linter/src/rules/flynt/helpers.rs index 56b1cbac653cb..8bdcfffda0359 100644 --- a/crates/ruff_linter/src/rules/flynt/helpers.rs +++ b/crates/ruff_linter/src/rules/flynt/helpers.rs @@ -12,8 +12,8 @@ fn to_formatted_value_expr(inner: &Expr) -> ast::FStringElement { }) } -/// Convert a string to a constant string expression. -pub(super) fn to_constant_string(s: &str) -> ast::FStringElement { +/// Convert a string to a literal fstring element +pub(super) fn to_fstring_literal(s: &str) -> ast::FStringElement { ast::FStringElement::Literal(ast::FStringLiteralElement { value: s.to_owned(), range: TextRange::default(), diff --git a/crates/ruff_linter/src/rules/flynt/rules/static_join_to_fstring.rs b/crates/ruff_linter/src/rules/flynt/rules/static_join_to_fstring.rs index 8d557fd57edc9..3ebeca32e18f0 100644 --- a/crates/ruff_linter/src/rules/flynt/rules/static_join_to_fstring.rs +++ b/crates/ruff_linter/src/rules/flynt/rules/static_join_to_fstring.rs @@ -101,7 +101,7 @@ fn build_fstring(joiner: &str, joinees: &[Expr]) -> Option { return None; } if !std::mem::take(&mut first) { - fstring_elements.push(helpers::to_constant_string(joiner)); + fstring_elements.push(helpers::to_fstring_literal(joiner)); } fstring_elements.push(helpers::to_fstring_element(expr)?); }