Refactor tokens-based rules to take an &mut Vec<Diagnostic> (#5525)
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
use anyhow::{bail, Result};
|
||||
use ruff_text_size::{TextLen, TextRange, TextSize};
|
||||
use rustpython_parser::ast::{self, ExceptHandler, Expr, Keyword, Ranged, Stmt};
|
||||
use rustpython_parser::{lexer, Mode, Tok};
|
||||
use rustpython_parser::{lexer, Mode};
|
||||
|
||||
use ruff_diagnostics::Edit;
|
||||
use ruff_python_ast::helpers;
|
||||
@@ -98,7 +98,7 @@ pub(crate) fn remove_argument(
|
||||
// Case 1: there is only one argument.
|
||||
let mut count = 0u32;
|
||||
for (tok, range) in lexer::lex_starts_at(contents, Mode::Module, call_at).flatten() {
|
||||
if matches!(tok, Tok::Lpar) {
|
||||
if tok.is_lpar() {
|
||||
if count == 0 {
|
||||
fix_start = Some(if remove_parentheses {
|
||||
range.start()
|
||||
@@ -109,7 +109,7 @@ pub(crate) fn remove_argument(
|
||||
count = count.saturating_add(1);
|
||||
}
|
||||
|
||||
if matches!(tok, Tok::Rpar) {
|
||||
if tok.is_rpar() {
|
||||
count = count.saturating_sub(1);
|
||||
if count == 0 {
|
||||
fix_end = Some(if remove_parentheses {
|
||||
@@ -131,11 +131,11 @@ pub(crate) fn remove_argument(
|
||||
let mut seen_comma = false;
|
||||
for (tok, range) in lexer::lex_starts_at(contents, Mode::Module, call_at).flatten() {
|
||||
if seen_comma {
|
||||
if matches!(tok, Tok::NonLogicalNewline) {
|
||||
if tok.is_non_logical_newline() {
|
||||
// Also delete any non-logical newlines after the comma.
|
||||
continue;
|
||||
}
|
||||
fix_end = Some(if matches!(tok, Tok::Newline) {
|
||||
fix_end = Some(if tok.is_newline() {
|
||||
range.end()
|
||||
} else {
|
||||
range.start()
|
||||
@@ -145,7 +145,7 @@ pub(crate) fn remove_argument(
|
||||
if range.start() == expr_range.start() {
|
||||
fix_start = Some(range.start());
|
||||
}
|
||||
if fix_start.is_some() && matches!(tok, Tok::Comma) {
|
||||
if fix_start.is_some() && tok.is_comma() {
|
||||
seen_comma = true;
|
||||
}
|
||||
}
|
||||
@@ -157,7 +157,7 @@ pub(crate) fn remove_argument(
|
||||
fix_end = Some(expr_range.end());
|
||||
break;
|
||||
}
|
||||
if matches!(tok, Tok::Comma) {
|
||||
if tok.is_comma() {
|
||||
fix_start = Some(range.start());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
use rustpython_parser::lexer::LexResult;
|
||||
use rustpython_parser::Tok;
|
||||
|
||||
use ruff_diagnostics::Diagnostic;
|
||||
use ruff_python_ast::source_code::{Indexer, Locator};
|
||||
|
||||
use crate::directives::TodoComment;
|
||||
use crate::lex::docstring_detection::StateMachine;
|
||||
use crate::registry::{AsRule, Rule};
|
||||
@@ -12,8 +15,6 @@ use crate::rules::{
|
||||
flake8_todos, pycodestyle, pylint, pyupgrade, ruff,
|
||||
};
|
||||
use crate::settings::Settings;
|
||||
use ruff_diagnostics::Diagnostic;
|
||||
use ruff_python_ast::source_code::{Indexer, Locator};
|
||||
|
||||
pub(crate) fn check_tokens(
|
||||
locator: &Locator,
|
||||
@@ -88,10 +89,11 @@ pub(crate) fn check_tokens(
|
||||
};
|
||||
|
||||
if matches!(tok, Tok::String { .. } | Tok::Comment(_)) {
|
||||
diagnostics.extend(ruff::rules::ambiguous_unicode_character(
|
||||
ruff::rules::ambiguous_unicode_character(
|
||||
&mut diagnostics,
|
||||
locator,
|
||||
range,
|
||||
if matches!(tok, Tok::String { .. }) {
|
||||
if tok.is_string() {
|
||||
if is_docstring {
|
||||
Context::Docstring
|
||||
} else {
|
||||
@@ -101,93 +103,77 @@ pub(crate) fn check_tokens(
|
||||
Context::Comment
|
||||
},
|
||||
settings,
|
||||
));
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ERA001
|
||||
if enforce_commented_out_code {
|
||||
diagnostics.extend(eradicate::rules::commented_out_code(
|
||||
locator, indexer, settings,
|
||||
));
|
||||
eradicate::rules::commented_out_code(&mut diagnostics, locator, indexer, settings);
|
||||
}
|
||||
|
||||
// W605
|
||||
if enforce_invalid_escape_sequence {
|
||||
for (tok, range) in tokens.iter().flatten() {
|
||||
if matches!(tok, Tok::String { .. }) {
|
||||
diagnostics.extend(pycodestyle::rules::invalid_escape_sequence(
|
||||
if tok.is_string() {
|
||||
pycodestyle::rules::invalid_escape_sequence(
|
||||
&mut diagnostics,
|
||||
locator,
|
||||
*range,
|
||||
settings.rules.should_fix(Rule::InvalidEscapeSequence),
|
||||
));
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
// PLE2510, PLE2512, PLE2513
|
||||
if enforce_invalid_string_character {
|
||||
for (tok, range) in tokens.iter().flatten() {
|
||||
if matches!(tok, Tok::String { .. }) {
|
||||
diagnostics.extend(
|
||||
pylint::rules::invalid_string_characters(locator, *range)
|
||||
.into_iter()
|
||||
.filter(|diagnostic| settings.rules.enabled(diagnostic.kind.rule())),
|
||||
);
|
||||
if tok.is_string() {
|
||||
pylint::rules::invalid_string_characters(&mut diagnostics, *range, locator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// E701, E702, E703
|
||||
if enforce_compound_statements {
|
||||
diagnostics.extend(
|
||||
pycodestyle::rules::compound_statements(tokens, locator, indexer, settings)
|
||||
.into_iter()
|
||||
.filter(|diagnostic| settings.rules.enabled(diagnostic.kind.rule())),
|
||||
pycodestyle::rules::compound_statements(
|
||||
&mut diagnostics,
|
||||
tokens,
|
||||
locator,
|
||||
indexer,
|
||||
settings,
|
||||
);
|
||||
}
|
||||
|
||||
// Q001, Q002, Q003
|
||||
if enforce_quotes {
|
||||
diagnostics.extend(
|
||||
flake8_quotes::rules::from_tokens(tokens, locator, settings)
|
||||
.into_iter()
|
||||
.filter(|diagnostic| settings.rules.enabled(diagnostic.kind.rule())),
|
||||
);
|
||||
flake8_quotes::rules::from_tokens(&mut diagnostics, tokens, locator, settings);
|
||||
}
|
||||
|
||||
// ISC001, ISC002
|
||||
if enforce_implicit_string_concatenation {
|
||||
diagnostics.extend(
|
||||
flake8_implicit_str_concat::rules::implicit(
|
||||
tokens,
|
||||
&settings.flake8_implicit_str_concat,
|
||||
locator,
|
||||
)
|
||||
.into_iter()
|
||||
.filter(|diagnostic| settings.rules.enabled(diagnostic.kind.rule())),
|
||||
flake8_implicit_str_concat::rules::implicit(
|
||||
&mut diagnostics,
|
||||
tokens,
|
||||
&settings.flake8_implicit_str_concat,
|
||||
locator,
|
||||
);
|
||||
}
|
||||
|
||||
// COM812, COM818, COM819
|
||||
if enforce_trailing_comma {
|
||||
diagnostics.extend(
|
||||
flake8_commas::rules::trailing_commas(tokens, locator, settings)
|
||||
.into_iter()
|
||||
.filter(|diagnostic| settings.rules.enabled(diagnostic.kind.rule())),
|
||||
);
|
||||
flake8_commas::rules::trailing_commas(&mut diagnostics, tokens, locator, settings);
|
||||
}
|
||||
|
||||
// UP034
|
||||
if enforce_extraneous_parenthesis {
|
||||
diagnostics.extend(
|
||||
pyupgrade::rules::extraneous_parentheses(tokens, locator, settings).into_iter(),
|
||||
);
|
||||
pyupgrade::rules::extraneous_parentheses(&mut diagnostics, tokens, locator, settings);
|
||||
}
|
||||
|
||||
// PYI033
|
||||
if enforce_type_comment_in_stub && is_stub {
|
||||
diagnostics.extend(flake8_pyi::rules::type_comment_in_stub(locator, indexer));
|
||||
flake8_pyi::rules::type_comment_in_stub(&mut diagnostics, locator, indexer);
|
||||
}
|
||||
|
||||
// TD001, TD002, TD003, TD004, TD005, TD006, TD007
|
||||
@@ -203,18 +189,12 @@ pub(crate) fn check_tokens(
|
||||
})
|
||||
.collect();
|
||||
|
||||
diagnostics.extend(
|
||||
flake8_todos::rules::todos(&todo_comments, locator, indexer, settings)
|
||||
.into_iter()
|
||||
.filter(|diagnostic| settings.rules.enabled(diagnostic.kind.rule())),
|
||||
);
|
||||
flake8_todos::rules::todos(&mut diagnostics, &todo_comments, locator, indexer, settings);
|
||||
|
||||
diagnostics.extend(
|
||||
flake8_fixme::rules::todos(&todo_comments)
|
||||
.into_iter()
|
||||
.filter(|diagnostic| settings.rules.enabled(diagnostic.kind.rule())),
|
||||
);
|
||||
flake8_fixme::rules::todos(&mut diagnostics, &todo_comments);
|
||||
}
|
||||
|
||||
diagnostics.retain(|diagnostic| settings.rules.enabled(diagnostic.kind.rule()));
|
||||
|
||||
diagnostics
|
||||
}
|
||||
|
||||
@@ -48,12 +48,11 @@ fn is_standalone_comment(line: &str) -> bool {
|
||||
|
||||
/// ERA001
|
||||
pub(crate) fn commented_out_code(
|
||||
diagnostics: &mut Vec<Diagnostic>,
|
||||
locator: &Locator,
|
||||
indexer: &Indexer,
|
||||
settings: &Settings,
|
||||
) -> Vec<Diagnostic> {
|
||||
let mut diagnostics = vec![];
|
||||
|
||||
) {
|
||||
for range in indexer.comment_ranges() {
|
||||
let line = locator.full_lines(*range);
|
||||
|
||||
@@ -69,6 +68,4 @@ pub(crate) fn commented_out_code(
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
|
||||
diagnostics
|
||||
}
|
||||
|
||||
@@ -222,12 +222,11 @@ impl AlwaysAutofixableViolation for ProhibitedTrailingComma {
|
||||
|
||||
/// COM812, COM818, COM819
|
||||
pub(crate) fn trailing_commas(
|
||||
diagnostics: &mut Vec<Diagnostic>,
|
||||
tokens: &[LexResult],
|
||||
locator: &Locator,
|
||||
settings: &Settings,
|
||||
) -> Vec<Diagnostic> {
|
||||
let mut diagnostics = vec![];
|
||||
|
||||
) {
|
||||
let tokens = tokens
|
||||
.iter()
|
||||
.flatten()
|
||||
@@ -387,6 +386,4 @@ pub(crate) fn trailing_commas(
|
||||
stack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
diagnostics
|
||||
}
|
||||
|
||||
@@ -39,18 +39,19 @@ impl Violation for LineContainsHack {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn todos(directive_ranges: &[TodoComment]) -> Vec<Diagnostic> {
|
||||
directive_ranges
|
||||
.iter()
|
||||
.map(|TodoComment { directive, .. }| match directive.kind {
|
||||
// FIX001
|
||||
TodoDirectiveKind::Fixme => Diagnostic::new(LineContainsFixme, directive.range),
|
||||
// FIX002
|
||||
TodoDirectiveKind::Hack => Diagnostic::new(LineContainsHack, directive.range),
|
||||
// FIX003
|
||||
TodoDirectiveKind::Todo => Diagnostic::new(LineContainsTodo, directive.range),
|
||||
// FIX004
|
||||
TodoDirectiveKind::Xxx => Diagnostic::new(LineContainsXxx, directive.range),
|
||||
})
|
||||
.collect::<Vec<Diagnostic>>()
|
||||
pub(crate) fn todos(diagnostics: &mut Vec<Diagnostic>, directive_ranges: &[TodoComment]) {
|
||||
diagnostics.extend(
|
||||
directive_ranges
|
||||
.iter()
|
||||
.map(|TodoComment { directive, .. }| match directive.kind {
|
||||
// FIX001
|
||||
TodoDirectiveKind::Fixme => Diagnostic::new(LineContainsFixme, directive.range),
|
||||
// FIX002
|
||||
TodoDirectiveKind::Hack => Diagnostic::new(LineContainsHack, directive.range),
|
||||
// FIX003
|
||||
TodoDirectiveKind::Todo => Diagnostic::new(LineContainsTodo, directive.range),
|
||||
// FIX004
|
||||
TodoDirectiveKind::Xxx => Diagnostic::new(LineContainsXxx, directive.range),
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use itertools::Itertools;
|
||||
use ruff_text_size::TextRange;
|
||||
use rustpython_parser::lexer::LexResult;
|
||||
use rustpython_parser::Tok;
|
||||
|
||||
use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
@@ -91,21 +90,20 @@ impl Violation for MultiLineImplicitStringConcatenation {
|
||||
|
||||
/// ISC001, ISC002
|
||||
pub(crate) fn implicit(
|
||||
diagnostics: &mut Vec<Diagnostic>,
|
||||
tokens: &[LexResult],
|
||||
settings: &Settings,
|
||||
locator: &Locator,
|
||||
) -> Vec<Diagnostic> {
|
||||
let mut diagnostics = vec![];
|
||||
) {
|
||||
for ((a_tok, a_range), (b_tok, b_range)) in tokens
|
||||
.iter()
|
||||
.flatten()
|
||||
.filter(|(tok, _)| {
|
||||
!matches!(tok, Tok::Comment(..))
|
||||
&& (settings.allow_multiline || !matches!(tok, Tok::NonLogicalNewline))
|
||||
!tok.is_comment() && (settings.allow_multiline || !tok.is_non_logical_newline())
|
||||
})
|
||||
.tuple_windows()
|
||||
{
|
||||
if matches!(a_tok, Tok::String { .. }) && matches!(b_tok, Tok::String { .. }) {
|
||||
if a_tok.is_string() && b_tok.is_string() {
|
||||
if locator.contains_line_break(TextRange::new(a_range.end(), b_range.start())) {
|
||||
diagnostics.push(Diagnostic::new(
|
||||
MultiLineImplicitStringConcatenation,
|
||||
@@ -125,7 +123,6 @@ pub(crate) fn implicit(
|
||||
};
|
||||
};
|
||||
}
|
||||
diagnostics
|
||||
}
|
||||
|
||||
fn concatenate_strings(a_range: TextRange, b_range: TextRange, locator: &Locator) -> Option<Fix> {
|
||||
|
||||
@@ -34,9 +34,11 @@ impl Violation for TypeCommentInStub {
|
||||
}
|
||||
|
||||
/// PYI033
|
||||
pub(crate) fn type_comment_in_stub(locator: &Locator, indexer: &Indexer) -> Vec<Diagnostic> {
|
||||
let mut diagnostics = vec![];
|
||||
|
||||
pub(crate) fn type_comment_in_stub(
|
||||
diagnostics: &mut Vec<Diagnostic>,
|
||||
locator: &Locator,
|
||||
indexer: &Indexer,
|
||||
) {
|
||||
for range in indexer.comment_ranges() {
|
||||
let comment = locator.slice(*range);
|
||||
|
||||
@@ -44,8 +46,6 @@ pub(crate) fn type_comment_in_stub(locator: &Locator, indexer: &Indexer) -> Vec<
|
||||
diagnostics.push(Diagnostic::new(TypeCommentInStub, *range));
|
||||
}
|
||||
}
|
||||
|
||||
diagnostics
|
||||
}
|
||||
|
||||
static TYPE_COMMENT_REGEX: Lazy<Regex> =
|
||||
|
||||
@@ -464,12 +464,11 @@ fn strings(locator: &Locator, sequence: &[TextRange], settings: &Settings) -> Ve
|
||||
|
||||
/// Generate `flake8-quote` diagnostics from a token stream.
|
||||
pub(crate) fn from_tokens(
|
||||
diagnostics: &mut Vec<Diagnostic>,
|
||||
lxr: &[LexResult],
|
||||
locator: &Locator,
|
||||
settings: &Settings,
|
||||
) -> Vec<Diagnostic> {
|
||||
let mut diagnostics = vec![];
|
||||
|
||||
) {
|
||||
// Keep track of sequences of strings, which represent implicit string
|
||||
// concatenation, and should thus be handled as a single unit.
|
||||
let mut sequence = vec![];
|
||||
@@ -488,7 +487,7 @@ pub(crate) fn from_tokens(
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
} else {
|
||||
if matches!(tok, Tok::String { .. }) {
|
||||
if tok.is_string() {
|
||||
// If this is a string, add it to the sequence.
|
||||
sequence.push(range);
|
||||
} else if !matches!(tok, Tok::Comment(..) | Tok::NonLogicalNewline) {
|
||||
@@ -506,6 +505,4 @@ pub(crate) fn from_tokens(
|
||||
diagnostics.extend(strings(locator, &sequence, settings));
|
||||
sequence.clear();
|
||||
}
|
||||
|
||||
diagnostics
|
||||
}
|
||||
|
||||
@@ -235,13 +235,12 @@ static ISSUE_LINK_REGEX_SET: Lazy<RegexSet> = Lazy::new(|| {
|
||||
});
|
||||
|
||||
pub(crate) fn todos(
|
||||
diagnostics: &mut Vec<Diagnostic>,
|
||||
todo_comments: &[TodoComment],
|
||||
locator: &Locator,
|
||||
indexer: &Indexer,
|
||||
settings: &Settings,
|
||||
) -> Vec<Diagnostic> {
|
||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
||||
|
||||
) {
|
||||
for todo_comment in todo_comments {
|
||||
let TodoComment {
|
||||
directive,
|
||||
@@ -256,8 +255,8 @@ pub(crate) fn todos(
|
||||
continue;
|
||||
}
|
||||
|
||||
directive_errors(directive, &mut diagnostics, settings);
|
||||
static_errors(&mut diagnostics, content, range, directive);
|
||||
directive_errors(diagnostics, directive, settings);
|
||||
static_errors(diagnostics, content, range, directive);
|
||||
|
||||
let mut has_issue_link = false;
|
||||
let mut curr_range = range;
|
||||
@@ -297,14 +296,12 @@ pub(crate) fn todos(
|
||||
diagnostics.push(Diagnostic::new(MissingTodoLink, directive.range));
|
||||
}
|
||||
}
|
||||
|
||||
diagnostics
|
||||
}
|
||||
|
||||
/// Check that the directive itself is valid. This function modifies `diagnostics` in-place.
|
||||
fn directive_errors(
|
||||
directive: &TodoDirective,
|
||||
diagnostics: &mut Vec<Diagnostic>,
|
||||
directive: &TodoDirective,
|
||||
settings: &Settings,
|
||||
) {
|
||||
if directive.content == "TODO" {
|
||||
|
||||
@@ -100,13 +100,12 @@ impl AlwaysAutofixableViolation for UselessSemicolon {
|
||||
|
||||
/// E701, E702, E703
|
||||
pub(crate) fn compound_statements(
|
||||
diagnostics: &mut Vec<Diagnostic>,
|
||||
lxr: &[LexResult],
|
||||
locator: &Locator,
|
||||
indexer: &Indexer,
|
||||
settings: &Settings,
|
||||
) -> Vec<Diagnostic> {
|
||||
let mut diagnostics = vec![];
|
||||
|
||||
) {
|
||||
// Track the last seen instance of a variety of tokens.
|
||||
let mut colon = None;
|
||||
let mut semi = None;
|
||||
@@ -311,6 +310,4 @@ pub(crate) fn compound_statements(
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
|
||||
diagnostics
|
||||
}
|
||||
|
||||
@@ -40,25 +40,24 @@ impl AlwaysAutofixableViolation for InvalidEscapeSequence {
|
||||
|
||||
/// W605
|
||||
pub(crate) fn invalid_escape_sequence(
|
||||
diagnostics: &mut Vec<Diagnostic>,
|
||||
locator: &Locator,
|
||||
range: TextRange,
|
||||
autofix: bool,
|
||||
) -> Vec<Diagnostic> {
|
||||
let mut diagnostics = vec![];
|
||||
|
||||
) {
|
||||
let text = locator.slice(range);
|
||||
|
||||
// Determine whether the string is single- or triple-quoted.
|
||||
let Some(leading_quote) = leading_quote(text) else {
|
||||
return diagnostics;
|
||||
return;
|
||||
};
|
||||
let Some(trailing_quote) = trailing_quote(text) else {
|
||||
return diagnostics;
|
||||
return;
|
||||
};
|
||||
let body = &text[leading_quote.len()..text.len() - trailing_quote.len()];
|
||||
|
||||
if leading_quote.contains(['r', 'R']) {
|
||||
return diagnostics;
|
||||
return;
|
||||
}
|
||||
|
||||
let start_offset = range.start() + TextSize::try_from(leading_quote.len()).unwrap();
|
||||
@@ -67,6 +66,7 @@ pub(crate) fn invalid_escape_sequence(
|
||||
|
||||
let mut contains_valid_escape_sequence = false;
|
||||
|
||||
let mut invalid_escape_sequence = Vec::new();
|
||||
while let Some((i, c)) = chars_iter.next() {
|
||||
if c != '\\' {
|
||||
continue;
|
||||
@@ -122,14 +122,13 @@ pub(crate) fn invalid_escape_sequence(
|
||||
|
||||
let location = start_offset + TextSize::try_from(i).unwrap();
|
||||
let range = TextRange::at(location, next_char.text_len() + TextSize::from(1));
|
||||
let diagnostic = Diagnostic::new(InvalidEscapeSequence(*next_char), range);
|
||||
diagnostics.push(diagnostic);
|
||||
invalid_escape_sequence.push(Diagnostic::new(InvalidEscapeSequence(*next_char), range));
|
||||
}
|
||||
|
||||
if autofix {
|
||||
if contains_valid_escape_sequence {
|
||||
// Escape with backslash.
|
||||
for diagnostic in &mut diagnostics {
|
||||
for diagnostic in &mut invalid_escape_sequence {
|
||||
diagnostic.set_fix(Fix::automatic(Edit::insertion(
|
||||
r"\".to_string(),
|
||||
diagnostic.range().start() + TextSize::from(1),
|
||||
@@ -137,7 +136,7 @@ pub(crate) fn invalid_escape_sequence(
|
||||
}
|
||||
} else {
|
||||
// Turn into raw string.
|
||||
for diagnostic in &mut diagnostics {
|
||||
for diagnostic in &mut invalid_escape_sequence {
|
||||
// If necessary, add a space between any leading keyword (`return`, `yield`,
|
||||
// `assert`, etc.) and the string. For example, `return"foo"` is valid, but
|
||||
// `returnr"foo"` is not.
|
||||
@@ -159,5 +158,5 @@ pub(crate) fn invalid_escape_sequence(
|
||||
}
|
||||
}
|
||||
|
||||
diagnostics
|
||||
diagnostics.extend(invalid_escape_sequence);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use anyhow::{bail, Ok, Result};
|
||||
use ruff_text_size::TextRange;
|
||||
use rustpython_parser::ast::{ExceptHandler, Expr, Ranged};
|
||||
use rustpython_parser::{lexer, Mode, Tok};
|
||||
use rustpython_parser::{lexer, Mode};
|
||||
|
||||
use ruff_diagnostics::Edit;
|
||||
use ruff_python_ast::source_code::{Locator, Stylist};
|
||||
@@ -10,7 +10,7 @@ use crate::autofix::codemods::CodegenStylist;
|
||||
use crate::cst::matchers::{match_call_mut, match_dict, match_expression};
|
||||
|
||||
/// Generate a [`Edit`] to remove unused keys from format dict.
|
||||
pub(crate) fn remove_unused_format_arguments_from_dict(
|
||||
pub(super) fn remove_unused_format_arguments_from_dict(
|
||||
unused_arguments: &[usize],
|
||||
stmt: &Expr,
|
||||
locator: &Locator,
|
||||
@@ -35,7 +35,7 @@ pub(crate) fn remove_unused_format_arguments_from_dict(
|
||||
}
|
||||
|
||||
/// Generate a [`Edit`] to remove unused keyword arguments from a `format` call.
|
||||
pub(crate) fn remove_unused_keyword_arguments_from_format_call(
|
||||
pub(super) fn remove_unused_keyword_arguments_from_format_call(
|
||||
unused_arguments: &[usize],
|
||||
location: TextRange,
|
||||
locator: &Locator,
|
||||
@@ -102,10 +102,10 @@ pub(crate) fn remove_exception_handler_assignment(
|
||||
for (tok, range) in
|
||||
lexer::lex_starts_at(contents, Mode::Module, except_handler.start()).flatten()
|
||||
{
|
||||
if matches!(tok, Tok::As) {
|
||||
if tok.is_as() {
|
||||
fix_start = prev;
|
||||
}
|
||||
if matches!(tok, Tok::Colon) {
|
||||
if tok.is_colon() {
|
||||
fix_end = Some(range.start());
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ use ruff_text_size::TextRange;
|
||||
use rustc_hash::FxHashMap;
|
||||
use rustpython_format::cformat::{CFormatPart, CFormatSpec, CFormatStrOrBytes, CFormatString};
|
||||
use rustpython_parser::ast::{self, Constant, Expr, Ranged};
|
||||
use rustpython_parser::{lexer, Mode, Tok};
|
||||
use rustpython_parser::{lexer, Mode};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
@@ -205,9 +205,9 @@ pub(crate) fn bad_string_format_type(checker: &mut Checker, expr: &Expr, right:
|
||||
let content = checker.locator.slice(expr.range());
|
||||
let mut strings: Vec<TextRange> = vec![];
|
||||
for (tok, range) in lexer::lex_starts_at(content, Mode::Module, expr.start()).flatten() {
|
||||
if matches!(tok, Tok::String { .. }) {
|
||||
if tok.is_string() {
|
||||
strings.push(range);
|
||||
} else if matches!(tok, Tok::Percent) {
|
||||
} else if tok.is_percent() {
|
||||
// Break as soon as we find the modulo symbol.
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -171,8 +171,11 @@ impl AlwaysAutofixableViolation for InvalidCharacterZeroWidthSpace {
|
||||
}
|
||||
|
||||
/// PLE2510, PLE2512, PLE2513, PLE2514, PLE2515
|
||||
pub(crate) fn invalid_string_characters(locator: &Locator, range: TextRange) -> Vec<Diagnostic> {
|
||||
let mut diagnostics = Vec::new();
|
||||
pub(crate) fn invalid_string_characters(
|
||||
diagnostics: &mut Vec<Diagnostic>,
|
||||
range: TextRange,
|
||||
locator: &Locator,
|
||||
) {
|
||||
let text = locator.slice(range);
|
||||
|
||||
for (column, match_) in text.match_indices(&['\x08', '\x1A', '\x1B', '\0', '\u{200b}']) {
|
||||
@@ -195,6 +198,4 @@ pub(crate) fn invalid_string_characters(locator: &Locator, range: TextRange) ->
|
||||
Edit::range_replacement(replacement.to_string(), range),
|
||||
)));
|
||||
}
|
||||
|
||||
diagnostics
|
||||
}
|
||||
|
||||
@@ -134,21 +134,21 @@ fn match_extraneous_parentheses(tokens: &[LexResult], mut i: usize) -> Option<(u
|
||||
|
||||
/// UP034
|
||||
pub(crate) fn extraneous_parentheses(
|
||||
diagnostics: &mut Vec<Diagnostic>,
|
||||
tokens: &[LexResult],
|
||||
locator: &Locator,
|
||||
settings: &Settings,
|
||||
) -> Vec<Diagnostic> {
|
||||
let mut diagnostics = vec![];
|
||||
) {
|
||||
let mut i = 0;
|
||||
while i < tokens.len() {
|
||||
if matches!(tokens[i], Ok((Tok::Lpar, _))) {
|
||||
if let Some((start, end)) = match_extraneous_parentheses(tokens, i) {
|
||||
i = end + 1;
|
||||
let Ok((_, start_range)) = &tokens[start] else {
|
||||
return diagnostics;
|
||||
return;
|
||||
};
|
||||
let Ok((.., end_range)) = &tokens[end] else {
|
||||
return diagnostics;
|
||||
return;
|
||||
};
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
ExtraneousParentheses,
|
||||
@@ -171,5 +171,4 @@ pub(crate) fn extraneous_parentheses(
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
diagnostics
|
||||
}
|
||||
|
||||
@@ -344,7 +344,7 @@ pub(crate) fn printf_string_formatting(
|
||||
)
|
||||
.flatten()
|
||||
{
|
||||
if matches!(tok, Tok::String { .. }) {
|
||||
if tok.is_string() {
|
||||
strings.push(range);
|
||||
} else if matches!(tok, Tok::Rpar) {
|
||||
// If we hit a right paren, we have to preserve it.
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::str::FromStr;
|
||||
use anyhow::{anyhow, Result};
|
||||
use ruff_text_size::TextSize;
|
||||
use rustpython_parser::ast::{self, Constant, Expr, Keyword, Ranged};
|
||||
use rustpython_parser::{lexer, Mode, Tok};
|
||||
use rustpython_parser::{lexer, Mode};
|
||||
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
@@ -168,15 +168,15 @@ fn create_remove_param_fix(locator: &Locator, expr: &Expr, mode_param: &Expr) ->
|
||||
fix_end = Some(range.end());
|
||||
break;
|
||||
}
|
||||
if delete_first_arg && matches!(tok, Tok::Name { .. }) {
|
||||
if delete_first_arg && tok.is_name() {
|
||||
fix_end = Some(range.start());
|
||||
break;
|
||||
}
|
||||
if matches!(tok, Tok::Lpar) {
|
||||
if tok.is_lpar() {
|
||||
is_first_arg = true;
|
||||
fix_start = Some(range.end());
|
||||
}
|
||||
if matches!(tok, Tok::Comma) {
|
||||
if tok.is_comma() {
|
||||
is_first_arg = false;
|
||||
if !delete_first_arg {
|
||||
fix_start = Some(range.start());
|
||||
|
||||
@@ -159,18 +159,17 @@ impl AlwaysAutofixableViolation for AmbiguousUnicodeCharacterComment {
|
||||
}
|
||||
|
||||
pub(crate) fn ambiguous_unicode_character(
|
||||
diagnostics: &mut Vec<Diagnostic>,
|
||||
locator: &Locator,
|
||||
range: TextRange,
|
||||
context: Context,
|
||||
settings: &Settings,
|
||||
) -> Vec<Diagnostic> {
|
||||
let mut diagnostics = vec![];
|
||||
|
||||
) {
|
||||
let text = locator.slice(range);
|
||||
|
||||
// Most of the time, we don't need to check for ambiguous unicode characters at all.
|
||||
if text.is_ascii() {
|
||||
return diagnostics;
|
||||
return;
|
||||
}
|
||||
|
||||
// Iterate over the "words" in the text.
|
||||
@@ -232,8 +231,6 @@ pub(crate) fn ambiguous_unicode_character(
|
||||
}
|
||||
word_candidates.clear();
|
||||
}
|
||||
|
||||
diagnostics
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
|
||||
Reference in New Issue
Block a user