diff --git a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs index b526dd3777..3a14cbc62b 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs @@ -1065,13 +1065,17 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { pyflakes::rules::invalid_print_syntax(checker, left); } } - Expr::BinOp(ast::ExprBinOp { - left, - op: Operator::Mod, - right, - range: _, - }) => { - if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = left.as_ref() { + Expr::BinOp( + bin_op @ ast::ExprBinOp { + left, + op: Operator::Mod, + right, + range: _, + }, + ) => { + if let Expr::StringLiteral(format_string @ ast::ExprStringLiteral { value, .. }) = + left.as_ref() + { if checker.any_enabled(&[ Rule::PercentFormatInvalidFormat, Rule::PercentFormatExpectedMapping, @@ -1151,10 +1155,14 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { pyupgrade::rules::printf_string_formatting(checker, expr, right); } if checker.enabled(Rule::BadStringFormatCharacter) { - pylint::rules::bad_string_format_character::percent(checker, expr); + pylint::rules::bad_string_format_character::percent( + checker, + expr, + format_string, + ); } if checker.enabled(Rule::BadStringFormatType) { - pylint::rules::bad_string_format_type(checker, expr, right); + pylint::rules::bad_string_format_type(checker, bin_op, format_string); } if checker.enabled(Rule::HardcodedSQLExpression) { flake8_bandit::rules::hardcoded_sql_expression(checker, expr); diff --git a/crates/ruff_linter/src/rules/pylint/rules/bad_string_format_character.rs b/crates/ruff_linter/src/rules/pylint/rules/bad_string_format_character.rs index 50703891f6..16174623dc 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/bad_string_format_character.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/bad_string_format_character.rs @@ -2,14 +2,13 @@ use std::str::FromStr; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::{AnyStringFlags, Expr}; +use ruff_python_ast::{AnyStringFlags, Expr, ExprStringLiteral}; use ruff_python_literal::{ cformat::{CFormatErrorType, CFormatString}, format::FormatPart, format::FromTemplate, format::{FormatSpec, FormatSpecError, FormatString}, }; -use ruff_python_parser::{lexer, Mode, Tok}; use ruff_text_size::{Ranged, TextRange}; use crate::checkers::ast::Checker; @@ -90,27 +89,10 @@ pub(crate) fn call(checker: &mut Checker, string: &str, range: TextRange) { /// PLE1300 /// Ex) `"%z" % "1"` -pub(crate) fn percent(checker: &mut Checker, expr: &Expr) { - // Grab each string segment (in case there's an implicit concatenation). - let mut strings: Vec<(TextRange, AnyStringFlags)> = vec![]; - for (tok, range) in - lexer::lex_starts_at(checker.locator().slice(expr), Mode::Module, expr.start()).flatten() - { - match tok { - Tok::String { flags, .. } => strings.push((range, flags)), - // Break as soon as we find the modulo symbol. - Tok::Percent => break, - _ => {} - } - } - - // If there are no string segments, abort. - if strings.is_empty() { - return; - } - - for (range, flags) in &strings { - let string = checker.locator().slice(*range); +pub(crate) fn percent(checker: &mut Checker, expr: &Expr, format_string: &ExprStringLiteral) { + for string_literal in &format_string.value { + let string = checker.locator().slice(string_literal); + let flags = AnyStringFlags::from(string_literal.flags); let string = &string [usize::from(flags.opener_len())..(string.len() - usize::from(flags.closer_len()))]; diff --git a/crates/ruff_linter/src/rules/pylint/rules/bad_string_format_type.rs b/crates/ruff_linter/src/rules/pylint/rules/bad_string_format_type.rs index 2f8474cec5..0abc95394e 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/bad_string_format_type.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/bad_string_format_type.rs @@ -2,8 +2,7 @@ use std::str::FromStr; use ruff_python_ast::{self as ast, AnyStringFlags, Expr}; use ruff_python_literal::cformat::{CFormatPart, CFormatSpec, CFormatStrOrBytes, CFormatString}; -use ruff_python_parser::{lexer, AsMode, Tok}; -use ruff_text_size::{Ranged, TextRange}; +use ruff_text_size::Ranged; use rustc_hash::FxHashMap; use ruff_diagnostics::{Diagnostic, Violation}; @@ -211,30 +210,16 @@ fn is_valid_dict(formats: &[CFormatStrOrBytes], items: &[ast::DictItem]) } /// PLE1307 -pub(crate) fn bad_string_format_type(checker: &mut Checker, expr: &Expr, right: &Expr) { - // Grab each string segment (in case there's an implicit concatenation). - let content = checker.locator().slice(expr); - let mut strings: Vec<(TextRange, AnyStringFlags)> = vec![]; - for (tok, range) in - lexer::lex_starts_at(content, checker.source_type.as_mode(), expr.start()).flatten() - { - match tok { - Tok::String { flags, .. } => strings.push((range, flags)), - // Break as soon as we find the modulo symbol. - Tok::Percent => break, - _ => {} - } - } - - // If there are no string segments, abort. - if strings.is_empty() { - return; - } - +pub(crate) fn bad_string_format_type( + checker: &mut Checker, + bin_op: &ast::ExprBinOp, + format_string: &ast::ExprStringLiteral, +) { // Parse each string segment. let mut format_strings = vec![]; - for (range, flags) in &strings { - let string = checker.locator().slice(*range); + for string_literal in &format_string.value { + let string = checker.locator().slice(string_literal); + let flags = AnyStringFlags::from(string_literal.flags); let quote_len = usize::from(flags.quote_len()); let string = &string[(usize::from(flags.prefix_len()) + quote_len)..(string.len() - quote_len)]; @@ -246,14 +231,14 @@ pub(crate) fn bad_string_format_type(checker: &mut Checker, expr: &Expr, right: } // Parse the parameters. - let is_valid = match right { + let is_valid = match &*bin_op.right { Expr::Tuple(ast::ExprTuple { elts, .. }) => is_valid_tuple(&format_strings, elts), Expr::Dict(ast::ExprDict { items, range: _ }) => is_valid_dict(&format_strings, items), - _ => is_valid_constant(&format_strings, right), + _ => is_valid_constant(&format_strings, &bin_op.right), }; if !is_valid { checker .diagnostics - .push(Diagnostic::new(BadStringFormatType, expr.range())); + .push(Diagnostic::new(BadStringFormatType, bin_op.range())); } }