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);
}
}
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);

View file

@ -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()))];

View file

@ -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<String>], 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()));
}
}