Avoid lexer usage in PLE1300 and PLE1307 (#11406)

## Summary

This PR updates `PLE1300` and `PLE1307` to avoid using the lexer.

This is part of #11401 

## Test Plan

`cargo test`
This commit is contained in:
Dhruv Manilawala 2024-05-13 20:18:44 +05:30 committed by GitHub
parent af60d539ab
commit 10b85a0f07
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 34 additions and 59 deletions

View file

@ -1065,13 +1065,17 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
pyflakes::rules::invalid_print_syntax(checker, left); pyflakes::rules::invalid_print_syntax(checker, left);
} }
} }
Expr::BinOp(ast::ExprBinOp { Expr::BinOp(
bin_op @ ast::ExprBinOp {
left, left,
op: Operator::Mod, op: Operator::Mod,
right, right,
range: _, range: _,
}) => { },
if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = left.as_ref() { ) => {
if let Expr::StringLiteral(format_string @ ast::ExprStringLiteral { value, .. }) =
left.as_ref()
{
if checker.any_enabled(&[ if checker.any_enabled(&[
Rule::PercentFormatInvalidFormat, Rule::PercentFormatInvalidFormat,
Rule::PercentFormatExpectedMapping, Rule::PercentFormatExpectedMapping,
@ -1151,10 +1155,14 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
pyupgrade::rules::printf_string_formatting(checker, expr, right); pyupgrade::rules::printf_string_formatting(checker, expr, right);
} }
if checker.enabled(Rule::BadStringFormatCharacter) { 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) { 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) { if checker.enabled(Rule::HardcodedSQLExpression) {
flake8_bandit::rules::hardcoded_sql_expression(checker, expr); flake8_bandit::rules::hardcoded_sql_expression(checker, expr);

View file

@ -2,14 +2,13 @@ use std::str::FromStr;
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, 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::{ use ruff_python_literal::{
cformat::{CFormatErrorType, CFormatString}, cformat::{CFormatErrorType, CFormatString},
format::FormatPart, format::FormatPart,
format::FromTemplate, format::FromTemplate,
format::{FormatSpec, FormatSpecError, FormatString}, format::{FormatSpec, FormatSpecError, FormatString},
}; };
use ruff_python_parser::{lexer, Mode, Tok};
use ruff_text_size::{Ranged, TextRange}; use ruff_text_size::{Ranged, TextRange};
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
@ -90,27 +89,10 @@ pub(crate) fn call(checker: &mut Checker, string: &str, range: TextRange) {
/// PLE1300 /// PLE1300
/// Ex) `"%z" % "1"` /// Ex) `"%z" % "1"`
pub(crate) fn percent(checker: &mut Checker, expr: &Expr) { pub(crate) fn percent(checker: &mut Checker, expr: &Expr, format_string: &ExprStringLiteral) {
// Grab each string segment (in case there's an implicit concatenation). for string_literal in &format_string.value {
let mut strings: Vec<(TextRange, AnyStringFlags)> = vec![]; let string = checker.locator().slice(string_literal);
for (tok, range) in let flags = AnyStringFlags::from(string_literal.flags);
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);
let string = &string let string = &string
[usize::from(flags.opener_len())..(string.len() - usize::from(flags.closer_len()))]; [usize::from(flags.opener_len())..(string.len() - usize::from(flags.closer_len()))];

View file

@ -2,8 +2,7 @@ use std::str::FromStr;
use ruff_python_ast::{self as ast, AnyStringFlags, Expr}; use ruff_python_ast::{self as ast, AnyStringFlags, Expr};
use ruff_python_literal::cformat::{CFormatPart, CFormatSpec, CFormatStrOrBytes, CFormatString}; use ruff_python_literal::cformat::{CFormatPart, CFormatSpec, CFormatStrOrBytes, CFormatString};
use ruff_python_parser::{lexer, AsMode, Tok}; use ruff_text_size::Ranged;
use ruff_text_size::{Ranged, TextRange};
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
@ -211,30 +210,16 @@ fn is_valid_dict(formats: &[CFormatStrOrBytes<String>], items: &[ast::DictItem])
} }
/// PLE1307 /// PLE1307
pub(crate) fn bad_string_format_type(checker: &mut Checker, expr: &Expr, right: &Expr) { pub(crate) fn bad_string_format_type(
// Grab each string segment (in case there's an implicit concatenation). checker: &mut Checker,
let content = checker.locator().slice(expr); bin_op: &ast::ExprBinOp,
let mut strings: Vec<(TextRange, AnyStringFlags)> = vec![]; format_string: &ast::ExprStringLiteral,
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;
}
// Parse each string segment. // Parse each string segment.
let mut format_strings = vec![]; let mut format_strings = vec![];
for (range, flags) in &strings { for string_literal in &format_string.value {
let string = checker.locator().slice(*range); let string = checker.locator().slice(string_literal);
let flags = AnyStringFlags::from(string_literal.flags);
let quote_len = usize::from(flags.quote_len()); let quote_len = usize::from(flags.quote_len());
let string = let string =
&string[(usize::from(flags.prefix_len()) + quote_len)..(string.len() - quote_len)]; &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. // 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::Tuple(ast::ExprTuple { elts, .. }) => is_valid_tuple(&format_strings, elts),
Expr::Dict(ast::ExprDict { items, range: _ }) => is_valid_dict(&format_strings, items), 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 { if !is_valid {
checker checker
.diagnostics .diagnostics
.push(Diagnostic::new(BadStringFormatType, expr.range())); .push(Diagnostic::new(BadStringFormatType, bin_op.range()));
} }
} }