Skip to content

Commit

Permalink
Create a newtype wrapper around Vec<FStringElement>
Browse files Browse the repository at this point in the history
  • Loading branch information
dhruvmanila committed May 13, 2024
1 parent 128414c commit 6a26b08
Show file tree
Hide file tree
Showing 15 changed files with 71 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ pub(crate) fn hardcoded_bind_all_interfaces(checker: &mut Checker, string: Strin
}
}
ast::FStringPart::FString(f_string) => {
for literal in f_string.literals() {
for literal in f_string.elements.literals() {
if &**literal == "0.0.0.0" {
checker.diagnostics.push(Diagnostic::new(
HardcodedBindAllInterfaces,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ pub(crate) fn hardcoded_tmp_directory(checker: &mut Checker, string: StringLike)
check(checker, literal, literal.range());
}
ast::FStringPart::FString(f_string) => {
for literal in f_string.literals() {
for literal in f_string.elements.literals() {
check(checker, literal, literal.range());
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,11 @@ pub(crate) fn call_datetime_strptime_without_zone(checker: &mut Checker, call: &
}
}
ast::FStringPart::FString(f_string) => {
if f_string.literals().any(|literal| literal.contains("%z")) {
if f_string
.elements
.literals()
.any(|literal| literal.contains("%z"))
{
return;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ impl Visitor<'_> for AvoidableEscapedQuoteChecker<'_> {
// f"'normal' {f'\'nested\' {x} "double quotes"'} normal"
// ```
if !f_string
.elements
.literals()
.any(|literal| contains_quote(literal, opposite_quote_char))
{
Expand Down Expand Up @@ -269,7 +270,7 @@ fn check_f_string(
let opposite_quote_char = quotes_settings.inline_quotes.opposite().as_char();

let mut edits = vec![];
for literal in f_string.literals() {
for literal in f_string.elements.literals() {
let content = locator.slice(literal);
if !contains_escaped_quote(content, quote_char) {
continue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ fn check_f_string(locator: &Locator, f_string: &ast::FString) -> Option<Diagnost
let opposite_quote_char = flags.quote_style().opposite().as_char();

let mut edits = vec![];
for literal in f_string.literals() {
for literal in f_string.elements.literals() {
let content = locator.slice(literal);
if !contains_escaped_quote(content, opposite_quote_char) {
continue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ fn build_fstring(joiner: &str, joinees: &[Expr]) -> Option<Expr> {
}

let node = ast::FString {
elements: f_string_elements,
elements: f_string_elements.into(),
range: TextRange::default(),
flags: FStringFlags::default(),
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ pub(crate) fn ambiguous_unicode_character_string(checker: &mut Checker, string_l
}
ast::StringLikePart::Bytes(_) => {}
ast::StringLikePart::FString(f_string) => {
for literal in f_string.literals() {
for literal in f_string.elements.literals() {
let text = checker.locator().slice(literal);
ambiguous_unicode_character(
&mut checker.diagnostics,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ fn should_be_fstring(

for f_string in value.f_strings() {
let mut has_name = false;
for element in f_string.expressions() {
for element in f_string.elements.expressions() {
if let ast::Expr::Name(ast::ExprName { id, .. }) = element.expression.as_ref() {
if arg_names.contains(id.as_str()) {
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ fn contains_message(expr: &Expr) -> bool {
}
}
ast::FStringPart::FString(f_string) => {
for literal in f_string.literals() {
for literal in f_string.elements.literals() {
if literal.chars().any(char::is_whitespace) {
return true;
}
Expand Down
6 changes: 3 additions & 3 deletions crates/ruff_python_ast/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2814,7 +2814,7 @@ impl AstNode for ast::FStringFormatSpec {
where
V: PreorderVisitor<'a> + ?Sized,
{
for element in &self.elements {
for element in self.elements.iter() {
visitor.visit_f_string_element(element);
}
}
Expand Down Expand Up @@ -2864,7 +2864,7 @@ impl AstNode for ast::FStringExpressionElement {
visitor.visit_expr(expression);

if let Some(format_spec) = format_spec {
for spec_part in &format_spec.elements {
for spec_part in format_spec.elements.iter() {
visitor.visit_f_string_element(spec_part);
}
}
Expand Down Expand Up @@ -4800,7 +4800,7 @@ impl AstNode for ast::FString {
flags: _,
} = self;

for fstring_element in elements {
for fstring_element in elements.iter() {
visitor.visit_f_string_element(fstring_element);
}
}
Expand Down
64 changes: 45 additions & 19 deletions crates/ruff_python_ast/src/nodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use std::fmt;
use std::fmt::Debug;
use std::iter::FusedIterator;
use std::ops::Deref;
use std::ops::{Deref, DerefMut};
use std::slice::{Iter, IterMut};
use std::sync::OnceLock;

Expand Down Expand Up @@ -1084,7 +1084,7 @@ impl From<ExprCall> for Expr {
#[derive(Clone, Debug, PartialEq)]
pub struct FStringFormatSpec {
pub range: TextRange,
pub elements: Vec<FStringElement>,
pub elements: FStringElements,
}

impl Ranged for FStringFormatSpec {
Expand Down Expand Up @@ -1484,26 +1484,10 @@ impl fmt::Debug for FStringFlags {
#[derive(Clone, Debug, PartialEq)]
pub struct FString {
pub range: TextRange,
pub elements: Vec<FStringElement>,
pub elements: FStringElements,
pub flags: FStringFlags,
}

impl FString {
/// Returns an iterator over all the [`FStringLiteralElement`] nodes contained in this f-string.
pub fn literals(&self) -> impl Iterator<Item = &FStringLiteralElement> {
self.elements
.iter()
.filter_map(|element| element.as_literal())
}

/// Returns an iterator over all the [`FStringExpressionElement`] nodes contained in this f-string.
pub fn expressions(&self) -> impl Iterator<Item = &FStringExpressionElement> {
self.elements
.iter()
.filter_map(|element| element.as_expression())
}
}

impl Ranged for FString {
fn range(&self) -> TextRange {
self.range
Expand All @@ -1520,6 +1504,48 @@ impl From<FString> for Expr {
}
}

/// A newtype wrapper around a list of [`FStringElement`].
#[derive(Clone, Default, PartialEq)]
pub struct FStringElements(Vec<FStringElement>);

impl FStringElements {
/// Returns an iterator over all the [`FStringLiteralElement`] nodes contained in this f-string.
pub fn literals(&self) -> impl Iterator<Item = &FStringLiteralElement> {
self.iter().filter_map(|element| element.as_literal())
}

/// Returns an iterator over all the [`FStringExpressionElement`] nodes contained in this f-string.
pub fn expressions(&self) -> impl Iterator<Item = &FStringExpressionElement> {
self.iter().filter_map(|element| element.as_expression())
}
}

impl From<Vec<FStringElement>> for FStringElements {
fn from(elements: Vec<FStringElement>) -> Self {
FStringElements(elements)
}
}

impl Deref for FStringElements {
type Target = Vec<FStringElement>;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl DerefMut for FStringElements {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}

impl fmt::Debug for FStringElements {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.0, f)
}
}

#[derive(Clone, Debug, PartialEq, is_macro::Is)]
pub enum FStringElement {
Literal(FStringLiteralElement),
Expand Down
4 changes: 2 additions & 2 deletions crates/ruff_python_ast/src/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -739,7 +739,7 @@ pub fn walk_pattern_keyword<'a, V: Visitor<'a> + ?Sized>(
}

pub fn walk_f_string<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, f_string: &'a FString) {
for f_string_element in &f_string.elements {
for f_string_element in f_string.elements.iter() {
visitor.visit_f_string_element(f_string_element);
}
}
Expand All @@ -756,7 +756,7 @@ pub fn walk_f_string_element<'a, V: Visitor<'a> + ?Sized>(
{
visitor.visit_expr(expression);
if let Some(format_spec) = format_spec {
for spec_element in &format_spec.elements {
for spec_element in format_spec.elements.iter() {
visitor.visit_f_string_element(spec_element);
}
}
Expand Down
4 changes: 2 additions & 2 deletions crates/ruff_python_ast/src/visitor/transformer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -746,7 +746,7 @@ pub fn walk_pattern_keyword<V: Transformer + ?Sized>(
}

pub fn walk_f_string<V: Transformer + ?Sized>(visitor: &V, f_string: &mut FString) {
for element in &mut f_string.elements {
for element in f_string.elements.iter_mut() {
visitor.visit_f_string_element(element);
}
}
Expand All @@ -763,7 +763,7 @@ pub fn walk_f_string_element<V: Transformer + ?Sized>(
{
visitor.visit_expr(expression);
if let Some(format_spec) = format_spec {
for spec_element in &mut format_spec.elements {
for spec_element in format_spec.elements.iter_mut() {
visitor.visit_f_string_element(spec_element);
}
}
Expand Down
1 change: 1 addition & 0 deletions crates/ruff_python_formatter/src/other/f_string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ impl FStringLayout {
//
// Reference: https://prettier.io/docs/en/next/rationale.html#template-literals
if f_string
.elements
.expressions()
.any(|expr| memchr::memchr2(b'\n', b'\r', locator.slice(expr).as_bytes()).is_some())
{
Expand Down
8 changes: 4 additions & 4 deletions crates/ruff_python_parser/src/parser/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ use bitflags::bitflags;
use rustc_hash::FxHashSet;

use ruff_python_ast::{
self as ast, BoolOp, CmpOp, ConversionFlag, Expr, ExprContext, FStringElement, IpyEscapeKind,
Number, Operator, UnaryOp,
self as ast, BoolOp, CmpOp, ConversionFlag, Expr, ExprContext, FStringElement, FStringElements,
IpyEscapeKind, Number, Operator, UnaryOp,
};
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};

Expand Down Expand Up @@ -1297,8 +1297,8 @@ impl<'src> Parser<'src> {
/// # Panics
///
/// If the parser isn't positioned at a `{` or `FStringMiddle` token.
fn parse_fstring_elements(&mut self) -> Vec<FStringElement> {
let mut elements = vec![];
fn parse_fstring_elements(&mut self) -> FStringElements {
let mut elements = FStringElements::default();

self.parse_list(RecoveryContextKind::FStringElements, |parser| {
let element = match parser.current_token_kind() {
Expand Down

0 comments on commit 6a26b08

Please sign in to comment.