mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-30 22:01:47 +00:00
Remove per-diagnostic check for fixability (#7919)
## Summary Throughout the codebase, we have this pattern: ```rust let mut diagnostic = ... if checker.patch(Rule::UnusedVariable) { // Do the fix. } diagnostics.push(diagnostic) ``` This was helpful when we computed fixes lazily; however, we now compute fixes eagerly, and this is _only_ used to ensure that we don't generate fixes for rules marked as unfixable. We often forget to add this, and it leads to bugs in enforcing `--unfixable`. This PR instead removes all of these checks, moving the responsibility of enforcing `--unfixable` up to `check_path`. This is similar to how @zanieb handled the `--extend-unsafe` logic: we post-process the diagnostics to remove any fixes that should be ignored.
This commit is contained in:
parent
1835d7bb45
commit
c38617fa27
189 changed files with 2433 additions and 3210 deletions
|
@ -32,15 +32,10 @@ pub(crate) fn bindings(checker: &mut Checker) {
|
||||||
},
|
},
|
||||||
binding.range(),
|
binding.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(Rule::UnusedVariable) {
|
diagnostic.try_set_fix(|| {
|
||||||
diagnostic.try_set_fix(|| {
|
pyflakes::fixes::remove_exception_handler_assignment(binding, checker.locator)
|
||||||
pyflakes::fixes::remove_exception_handler_assignment(
|
|
||||||
binding,
|
|
||||||
checker.locator,
|
|
||||||
)
|
|
||||||
.map(Fix::safe_edit)
|
.map(Fix::safe_edit)
|
||||||
});
|
});
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -143,11 +143,6 @@ impl<'a> Checker<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Checker<'a> {
|
impl<'a> Checker<'a> {
|
||||||
/// Return `true` if a patch should be generated for a given [`Rule`].
|
|
||||||
pub(crate) fn patch(&self, code: Rule) -> bool {
|
|
||||||
self.settings.rules.should_fix(code)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return `true` if a [`Rule`] is disabled by a `noqa` directive.
|
/// Return `true` if a [`Rule`] is disabled by a `noqa` directive.
|
||||||
pub(crate) fn rule_is_ignored(&self, code: Rule, offset: TextSize) -> bool {
|
pub(crate) fn rule_is_ignored(&self, code: Rule, offset: TextSize) -> bool {
|
||||||
// TODO(charlie): `noqa` directives are mostly enforced in `check_lines.rs`.
|
// TODO(charlie): `noqa` directives are mostly enforced in `check_lines.rs`.
|
||||||
|
|
|
@ -5,7 +5,7 @@ use ruff_python_parser::TokenKind;
|
||||||
use ruff_source_file::Locator;
|
use ruff_source_file::Locator;
|
||||||
use ruff_text_size::{Ranged, TextRange};
|
use ruff_text_size::{Ranged, TextRange};
|
||||||
|
|
||||||
use crate::registry::{AsRule, Rule};
|
use crate::registry::AsRule;
|
||||||
use crate::rules::pycodestyle::rules::logical_lines::{
|
use crate::rules::pycodestyle::rules::logical_lines::{
|
||||||
extraneous_whitespace, indentation, missing_whitespace, missing_whitespace_after_keyword,
|
extraneous_whitespace, indentation, missing_whitespace, missing_whitespace_after_keyword,
|
||||||
missing_whitespace_around_operator, space_after_comma, space_around_operator,
|
missing_whitespace_around_operator, space_after_comma, space_around_operator,
|
||||||
|
@ -38,17 +38,6 @@ pub(crate) fn check_logical_lines(
|
||||||
) -> Vec<Diagnostic> {
|
) -> Vec<Diagnostic> {
|
||||||
let mut context = LogicalLinesContext::new(settings);
|
let mut context = LogicalLinesContext::new(settings);
|
||||||
|
|
||||||
let should_fix_missing_whitespace = settings.rules.should_fix(Rule::MissingWhitespace);
|
|
||||||
let should_fix_whitespace_before_parameters =
|
|
||||||
settings.rules.should_fix(Rule::WhitespaceBeforeParameters);
|
|
||||||
let should_fix_whitespace_after_open_bracket =
|
|
||||||
settings.rules.should_fix(Rule::WhitespaceAfterOpenBracket);
|
|
||||||
let should_fix_whitespace_before_close_bracket = settings
|
|
||||||
.rules
|
|
||||||
.should_fix(Rule::WhitespaceBeforeCloseBracket);
|
|
||||||
let should_fix_whitespace_before_punctuation =
|
|
||||||
settings.rules.should_fix(Rule::WhitespaceBeforePunctuation);
|
|
||||||
|
|
||||||
let mut prev_line = None;
|
let mut prev_line = None;
|
||||||
let mut prev_indent_level = None;
|
let mut prev_indent_level = None;
|
||||||
let indent_char = stylist.indentation().as_char();
|
let indent_char = stylist.indentation().as_char();
|
||||||
|
@ -58,7 +47,7 @@ pub(crate) fn check_logical_lines(
|
||||||
space_around_operator(&line, &mut context);
|
space_around_operator(&line, &mut context);
|
||||||
whitespace_around_named_parameter_equals(&line, &mut context);
|
whitespace_around_named_parameter_equals(&line, &mut context);
|
||||||
missing_whitespace_around_operator(&line, &mut context);
|
missing_whitespace_around_operator(&line, &mut context);
|
||||||
missing_whitespace(&line, should_fix_missing_whitespace, &mut context);
|
missing_whitespace(&line, &mut context);
|
||||||
}
|
}
|
||||||
if line.flags().contains(TokenFlags::PUNCTUATION) {
|
if line.flags().contains(TokenFlags::PUNCTUATION) {
|
||||||
space_after_comma(&line, &mut context);
|
space_after_comma(&line, &mut context);
|
||||||
|
@ -68,13 +57,7 @@ pub(crate) fn check_logical_lines(
|
||||||
.flags()
|
.flags()
|
||||||
.intersects(TokenFlags::OPERATOR | TokenFlags::BRACKET | TokenFlags::PUNCTUATION)
|
.intersects(TokenFlags::OPERATOR | TokenFlags::BRACKET | TokenFlags::PUNCTUATION)
|
||||||
{
|
{
|
||||||
extraneous_whitespace(
|
extraneous_whitespace(&line, &mut context);
|
||||||
&line,
|
|
||||||
&mut context,
|
|
||||||
should_fix_whitespace_after_open_bracket,
|
|
||||||
should_fix_whitespace_before_close_bracket,
|
|
||||||
should_fix_whitespace_before_punctuation,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if line.flags().contains(TokenFlags::KEYWORD) {
|
if line.flags().contains(TokenFlags::KEYWORD) {
|
||||||
|
@ -87,11 +70,7 @@ pub(crate) fn check_logical_lines(
|
||||||
}
|
}
|
||||||
|
|
||||||
if line.flags().contains(TokenFlags::BRACKET) {
|
if line.flags().contains(TokenFlags::BRACKET) {
|
||||||
whitespace_before_parameters(
|
whitespace_before_parameters(&line, &mut context);
|
||||||
&line,
|
|
||||||
should_fix_whitespace_before_parameters,
|
|
||||||
&mut context,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract the indentation level.
|
// Extract the indentation level.
|
||||||
|
|
|
@ -109,10 +109,8 @@ pub(crate) fn check_noqa(
|
||||||
if line.matches.is_empty() {
|
if line.matches.is_empty() {
|
||||||
let mut diagnostic =
|
let mut diagnostic =
|
||||||
Diagnostic::new(UnusedNOQA { codes: None }, directive.range());
|
Diagnostic::new(UnusedNOQA { codes: None }, directive.range());
|
||||||
if settings.rules.should_fix(diagnostic.kind.rule()) {
|
diagnostic.set_fix(Fix::safe_edit(delete_noqa(directive.range(), locator)));
|
||||||
diagnostic
|
|
||||||
.set_fix(Fix::safe_edit(delete_noqa(directive.range(), locator)));
|
|
||||||
}
|
|
||||||
diagnostics.push(diagnostic);
|
diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -173,18 +171,14 @@ pub(crate) fn check_noqa(
|
||||||
},
|
},
|
||||||
directive.range(),
|
directive.range(),
|
||||||
);
|
);
|
||||||
if settings.rules.should_fix(diagnostic.kind.rule()) {
|
if valid_codes.is_empty() {
|
||||||
if valid_codes.is_empty() {
|
diagnostic
|
||||||
diagnostic.set_fix(Fix::safe_edit(delete_noqa(
|
.set_fix(Fix::safe_edit(delete_noqa(directive.range(), locator)));
|
||||||
directive.range(),
|
} else {
|
||||||
locator,
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
)));
|
format!("# noqa: {}", valid_codes.join(", ")),
|
||||||
} else {
|
directive.range(),
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
)));
|
||||||
format!("# noqa: {}", valid_codes.join(", ")),
|
|
||||||
directive.range(),
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
diagnostics.push(diagnostic);
|
diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,11 +71,7 @@ pub(crate) fn check_physical_lines(
|
||||||
}
|
}
|
||||||
|
|
||||||
if enforce_no_newline_at_end_of_file {
|
if enforce_no_newline_at_end_of_file {
|
||||||
if let Some(diagnostic) = no_newline_at_end_of_file(
|
if let Some(diagnostic) = no_newline_at_end_of_file(locator, stylist) {
|
||||||
locator,
|
|
||||||
stylist,
|
|
||||||
settings.rules.should_fix(Rule::MissingNewlineAtEndOfFile),
|
|
||||||
) {
|
|
||||||
diagnostics.push(diagnostic);
|
diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,7 @@ pub(crate) fn check_tokens(
|
||||||
}
|
}
|
||||||
|
|
||||||
if settings.rules.enabled(Rule::UTF8EncodingDeclaration) {
|
if settings.rules.enabled(Rule::UTF8EncodingDeclaration) {
|
||||||
pyupgrade::rules::unnecessary_coding_comment(&mut diagnostics, locator, indexer, settings);
|
pyupgrade::rules::unnecessary_coding_comment(&mut diagnostics, locator, indexer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if settings.rules.enabled(Rule::InvalidEscapeSequence) {
|
if settings.rules.enabled(Rule::InvalidEscapeSequence) {
|
||||||
|
@ -83,7 +83,6 @@ pub(crate) fn check_tokens(
|
||||||
indexer,
|
indexer,
|
||||||
tok,
|
tok,
|
||||||
*range,
|
*range,
|
||||||
settings.rules.should_fix(Rule::InvalidEscapeSequence),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,13 +108,7 @@ pub(crate) fn check_tokens(
|
||||||
Rule::MultipleStatementsOnOneLineSemicolon,
|
Rule::MultipleStatementsOnOneLineSemicolon,
|
||||||
Rule::UselessSemicolon,
|
Rule::UselessSemicolon,
|
||||||
]) {
|
]) {
|
||||||
pycodestyle::rules::compound_statements(
|
pycodestyle::rules::compound_statements(&mut diagnostics, tokens, locator, indexer);
|
||||||
&mut diagnostics,
|
|
||||||
tokens,
|
|
||||||
locator,
|
|
||||||
indexer,
|
|
||||||
settings,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if settings.rules.enabled(Rule::AvoidableEscapedQuote) && settings.flake8_quotes.avoid_escape {
|
if settings.rules.enabled(Rule::AvoidableEscapedQuote) && settings.flake8_quotes.avoid_escape {
|
||||||
|
@ -148,11 +141,11 @@ pub(crate) fn check_tokens(
|
||||||
Rule::TrailingCommaOnBareTuple,
|
Rule::TrailingCommaOnBareTuple,
|
||||||
Rule::ProhibitedTrailingComma,
|
Rule::ProhibitedTrailingComma,
|
||||||
]) {
|
]) {
|
||||||
flake8_commas::rules::trailing_commas(&mut diagnostics, tokens, locator, settings);
|
flake8_commas::rules::trailing_commas(&mut diagnostics, tokens, locator);
|
||||||
}
|
}
|
||||||
|
|
||||||
if settings.rules.enabled(Rule::ExtraneousParentheses) {
|
if settings.rules.enabled(Rule::ExtraneousParentheses) {
|
||||||
pyupgrade::rules::extraneous_parentheses(&mut diagnostics, tokens, locator, settings);
|
pyupgrade::rules::extraneous_parentheses(&mut diagnostics, tokens, locator);
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_stub && settings.rules.enabled(Rule::TypeCommentInStub) {
|
if is_stub && settings.rules.enabled(Rule::TypeCommentInStub) {
|
||||||
|
@ -166,7 +159,7 @@ pub(crate) fn check_tokens(
|
||||||
Rule::ShebangNotFirstLine,
|
Rule::ShebangNotFirstLine,
|
||||||
Rule::ShebangMissingPython,
|
Rule::ShebangMissingPython,
|
||||||
]) {
|
]) {
|
||||||
flake8_executable::rules::from_tokens(tokens, path, locator, settings, &mut diagnostics);
|
flake8_executable::rules::from_tokens(tokens, path, locator, &mut diagnostics);
|
||||||
}
|
}
|
||||||
|
|
||||||
if settings.rules.any_enabled(&[
|
if settings.rules.any_enabled(&[
|
||||||
|
@ -191,7 +184,7 @@ pub(crate) fn check_tokens(
|
||||||
TodoComment::from_comment(comment, *comment_range, i)
|
TodoComment::from_comment(comment, *comment_range, i)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
flake8_todos::rules::todos(&mut diagnostics, &todo_comments, locator, indexer, settings);
|
flake8_todos::rules::todos(&mut diagnostics, &todo_comments, locator, indexer);
|
||||||
flake8_fixme::rules::todos(&mut diagnostics, &todo_comments);
|
flake8_fixme::rules::todos(&mut diagnostics, &todo_comments);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -260,6 +260,13 @@ pub fn check_path(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove fixes for any rules marked as unfixable.
|
||||||
|
for diagnostic in &mut diagnostics {
|
||||||
|
if !settings.rules.should_fix(diagnostic.kind.rule()) {
|
||||||
|
diagnostic.fix = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Update fix applicability to account for overrides
|
// Update fix applicability to account for overrides
|
||||||
if !settings.extend_safe_fixes.is_empty() || !settings.extend_unsafe_fixes.is_empty() {
|
if !settings.extend_safe_fixes.is_empty() || !settings.extend_unsafe_fixes.is_empty() {
|
||||||
for diagnostic in &mut diagnostics {
|
for diagnostic in &mut diagnostics {
|
||||||
|
|
|
@ -3,7 +3,6 @@ use ruff_macros::{derive_message_formats, violation};
|
||||||
use ruff_python_index::Indexer;
|
use ruff_python_index::Indexer;
|
||||||
use ruff_source_file::Locator;
|
use ruff_source_file::Locator;
|
||||||
|
|
||||||
use crate::registry::Rule;
|
|
||||||
use crate::settings::LinterSettings;
|
use crate::settings::LinterSettings;
|
||||||
|
|
||||||
use super::super::detection::comment_contains_code;
|
use super::super::detection::comment_contains_code;
|
||||||
|
@ -67,11 +66,9 @@ pub(crate) fn commented_out_code(
|
||||||
if is_standalone_comment(line) && comment_contains_code(line, &settings.task_tags[..]) {
|
if is_standalone_comment(line) && comment_contains_code(line, &settings.task_tags[..]) {
|
||||||
let mut diagnostic = Diagnostic::new(CommentedOutCode, *range);
|
let mut diagnostic = Diagnostic::new(CommentedOutCode, *range);
|
||||||
|
|
||||||
if settings.rules.should_fix(Rule::CommentedOutCode) {
|
diagnostic.set_fix(Fix::display_edit(Edit::range_deletion(
|
||||||
diagnostic.set_fix(Fix::display_edit(Edit::range_deletion(
|
locator.full_lines_range(*range),
|
||||||
locator.full_lines_range(*range),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
diagnostics.push(diagnostic);
|
diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ use ruff_python_stdlib::typing::simple_magic_return_type;
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::{AsRule, Rule};
|
use crate::registry::Rule;
|
||||||
use crate::rules::ruff::typing::type_hint_resolves_to_any;
|
use crate::rules::ruff::typing::type_hint_resolves_to_any;
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
|
@ -702,12 +702,10 @@ pub(crate) fn definition(
|
||||||
},
|
},
|
||||||
function.identifier(),
|
function.identifier(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.set_fix(Fix::unsafe_edit(Edit::insertion(
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::insertion(
|
" -> None".to_string(),
|
||||||
" -> None".to_string(),
|
function.parameters.range().end(),
|
||||||
function.parameters.range().end(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
diagnostics.push(diagnostic);
|
diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -719,13 +717,11 @@ pub(crate) fn definition(
|
||||||
},
|
},
|
||||||
function.identifier(),
|
function.identifier(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
if let Some(return_type) = simple_magic_return_type(name) {
|
||||||
if let Some(return_type) = simple_magic_return_type(name) {
|
diagnostic.set_fix(Fix::unsafe_edit(Edit::insertion(
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::insertion(
|
format!(" -> {return_type}"),
|
||||||
format!(" -> {return_type}"),
|
function.parameters.range().end(),
|
||||||
function.parameters.range().end(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
diagnostics.push(diagnostic);
|
diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ use ruff_macros::{derive_message_formats, violation};
|
||||||
use ruff_python_ast::helpers::is_const_false;
|
use ruff_python_ast::helpers::is_const_false;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for uses of `assert False`.
|
/// Checks for uses of `assert False`.
|
||||||
|
@ -75,11 +74,9 @@ pub(crate) fn assert_false(checker: &mut Checker, stmt: &Stmt, test: &Expr, msg:
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut diagnostic = Diagnostic::new(AssertFalse, test.range());
|
let mut diagnostic = Diagnostic::new(AssertFalse, test.range());
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
checker.generator().stmt(&assertion_error(msg)),
|
||||||
checker.generator().stmt(&assertion_error(msg)),
|
stmt.range(),
|
||||||
stmt.range(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ use ruff_python_ast::call_path::CallPath;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::fix::edits::pad;
|
use crate::fix::edits::pad;
|
||||||
use crate::registry::{AsRule, Rule};
|
use crate::registry::Rule;
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for `try-except` blocks with duplicate exception handlers.
|
/// Checks for `try-except` blocks with duplicate exception handlers.
|
||||||
|
@ -146,24 +146,22 @@ fn duplicate_handler_exceptions<'a>(
|
||||||
},
|
},
|
||||||
expr.range(),
|
expr.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
// Single exceptions don't require parentheses, but since we're _removing_
|
||||||
// Single exceptions don't require parentheses, but since we're _removing_
|
// parentheses, insert whitespace as needed.
|
||||||
// parentheses, insert whitespace as needed.
|
if let [elt] = unique_elts.as_slice() {
|
||||||
if let [elt] = unique_elts.as_slice() {
|
pad(
|
||||||
pad(
|
checker.generator().expr(elt),
|
||||||
checker.generator().expr(elt),
|
expr.range(),
|
||||||
expr.range(),
|
checker.locator(),
|
||||||
checker.locator(),
|
)
|
||||||
)
|
} else {
|
||||||
} else {
|
// Multiple exceptions must always be parenthesized. This is done
|
||||||
// Multiple exceptions must always be parenthesized. This is done
|
// manually as the generator never parenthesizes lone tuples.
|
||||||
// manually as the generator never parenthesizes lone tuples.
|
format!("({})", checker.generator().expr(&type_pattern(unique_elts)))
|
||||||
format!("({})", checker.generator().expr(&type_pattern(unique_elts)))
|
},
|
||||||
},
|
expr.range(),
|
||||||
expr.range(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ use ruff_python_stdlib::identifiers::{is_identifier, is_mangled_private};
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for uses of `getattr` that take a constant attribute value as an
|
/// Checks for uses of `getattr` that take a constant attribute value as an
|
||||||
|
@ -85,26 +84,24 @@ pub(crate) fn getattr_with_constant(
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut diagnostic = Diagnostic::new(GetAttrWithConstant, expr.range());
|
let mut diagnostic = Diagnostic::new(GetAttrWithConstant, expr.range());
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
pad(
|
||||||
pad(
|
if matches!(
|
||||||
if matches!(
|
obj,
|
||||||
obj,
|
Expr::Name(_) | Expr::Attribute(_) | Expr::Subscript(_) | Expr::Call(_)
|
||||||
Expr::Name(_) | Expr::Attribute(_) | Expr::Subscript(_) | Expr::Call(_)
|
) && !checker.locator().contains_line_break(obj.range())
|
||||||
) && !checker.locator().contains_line_break(obj.range())
|
{
|
||||||
{
|
format!("{}.{}", checker.locator().slice(obj), value)
|
||||||
format!("{}.{}", checker.locator().slice(obj), value)
|
} else {
|
||||||
} else {
|
// Defensively parenthesize any other expressions. For example, attribute accesses
|
||||||
// Defensively parenthesize any other expressions. For example, attribute accesses
|
// on `int` literals must be parenthesized, e.g., `getattr(1, "real")` becomes
|
||||||
// on `int` literals must be parenthesized, e.g., `getattr(1, "real")` becomes
|
// `(1).real`. The same is true for named expressions and others.
|
||||||
// `(1).real`. The same is true for named expressions and others.
|
format!("({}).{}", checker.locator().slice(obj), value)
|
||||||
format!("({}).{}", checker.locator().slice(obj), value)
|
},
|
||||||
},
|
|
||||||
expr.range(),
|
|
||||||
checker.locator(),
|
|
||||||
),
|
|
||||||
expr.range(),
|
expr.range(),
|
||||||
)));
|
checker.locator(),
|
||||||
}
|
),
|
||||||
|
expr.range(),
|
||||||
|
)));
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@ use ruff_source_file::Locator;
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for uses of mutable objects as function argument defaults.
|
/// Checks for uses of mutable objects as function argument defaults.
|
||||||
|
@ -110,18 +109,16 @@ pub(crate) fn mutable_argument_default(checker: &mut Checker, function_def: &ast
|
||||||
let mut diagnostic = Diagnostic::new(MutableArgumentDefault, default.range());
|
let mut diagnostic = Diagnostic::new(MutableArgumentDefault, default.range());
|
||||||
|
|
||||||
// If the function body is on the same line as the function def, do not fix
|
// If the function body is on the same line as the function def, do not fix
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
if let Some(fix) = move_initialization(
|
||||||
if let Some(fix) = move_initialization(
|
function_def,
|
||||||
function_def,
|
parameter,
|
||||||
parameter,
|
default,
|
||||||
default,
|
checker.locator(),
|
||||||
checker.locator(),
|
checker.stylist(),
|
||||||
checker.stylist(),
|
checker.indexer(),
|
||||||
checker.indexer(),
|
checker.generator(),
|
||||||
checker.generator(),
|
) {
|
||||||
) {
|
diagnostic.set_fix(fix);
|
||||||
diagnostic.set_fix(fix);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::fix::edits::pad;
|
use crate::fix::edits::pad;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for single-element tuples in exception handlers (e.g.,
|
/// Checks for single-element tuples in exception handlers (e.g.,
|
||||||
|
@ -77,23 +76,21 @@ pub(crate) fn redundant_tuple_in_exception_handler(
|
||||||
},
|
},
|
||||||
type_.range(),
|
type_.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
// If there's no space between the `except` and the tuple, we need to insert a space,
|
||||||
// If there's no space between the `except` and the tuple, we need to insert a space,
|
// as in:
|
||||||
// as in:
|
// ```python
|
||||||
// ```python
|
// except(ValueError,):
|
||||||
// except(ValueError,):
|
// ```
|
||||||
// ```
|
// Otherwise, the output will be invalid syntax, since we're removing a set of
|
||||||
// Otherwise, the output will be invalid syntax, since we're removing a set of
|
// parentheses.
|
||||||
// parentheses.
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
pad(
|
||||||
pad(
|
checker.generator().expr(elt),
|
||||||
checker.generator().expr(elt),
|
|
||||||
type_.range(),
|
|
||||||
checker.locator(),
|
|
||||||
),
|
|
||||||
type_.range(),
|
type_.range(),
|
||||||
)));
|
checker.locator(),
|
||||||
}
|
),
|
||||||
|
type_.range(),
|
||||||
|
)));
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ use ruff_python_codegen::Generator;
|
||||||
use ruff_python_stdlib::identifiers::{is_identifier, is_mangled_private};
|
use ruff_python_stdlib::identifiers::{is_identifier, is_mangled_private};
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for uses of `setattr` that take a constant attribute value as an
|
/// Checks for uses of `setattr` that take a constant attribute value as an
|
||||||
|
@ -108,12 +107,10 @@ pub(crate) fn setattr_with_constant(
|
||||||
{
|
{
|
||||||
if expr == child.as_ref() {
|
if expr == child.as_ref() {
|
||||||
let mut diagnostic = Diagnostic::new(SetAttrWithConstant, expr.range());
|
let mut diagnostic = Diagnostic::new(SetAttrWithConstant, expr.range());
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
assignment(obj, name, value, checker.generator()),
|
||||||
assignment(obj, name, value, checker.generator()),
|
expr.range(),
|
||||||
expr.range(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ use ruff_macros::{derive_message_formats, violation};
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for uses of `hasattr` to test if an object is callable (e.g.,
|
/// Checks for uses of `hasattr` to test if an object is callable (e.g.,
|
||||||
|
@ -80,14 +79,12 @@ pub(crate) fn unreliable_callable_check(
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut diagnostic = Diagnostic::new(UnreliableCallableCheck, expr.range());
|
let mut diagnostic = Diagnostic::new(UnreliableCallableCheck, expr.range());
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
if id == "hasattr" {
|
||||||
if id == "hasattr" {
|
if checker.semantic().is_builtin("callable") {
|
||||||
if checker.semantic().is_builtin("callable") {
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
format!("callable({})", checker.locator().slice(obj)),
|
||||||
format!("callable({})", checker.locator().slice(obj)),
|
expr.range(),
|
||||||
expr.range(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
|
|
|
@ -8,7 +8,6 @@ use ruff_python_ast::{helpers, visitor};
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, result_like::BoolLike)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, result_like::BoolLike)]
|
||||||
enum Certainty {
|
enum Certainty {
|
||||||
|
@ -156,23 +155,21 @@ pub(crate) fn unused_loop_control_variable(checker: &mut Checker, stmt_for: &ast
|
||||||
},
|
},
|
||||||
expr.range(),
|
expr.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
if let Some(rename) = rename {
|
||||||
if let Some(rename) = rename {
|
if certainty.into() {
|
||||||
if certainty.into() {
|
// Avoid fixing if the variable, or any future bindings to the variable, are
|
||||||
// Avoid fixing if the variable, or any future bindings to the variable, are
|
// used _after_ the loop.
|
||||||
// used _after_ the loop.
|
let scope = checker.semantic().current_scope();
|
||||||
let scope = checker.semantic().current_scope();
|
if scope
|
||||||
if scope
|
.get_all(name)
|
||||||
.get_all(name)
|
.map(|binding_id| checker.semantic().binding(binding_id))
|
||||||
.map(|binding_id| checker.semantic().binding(binding_id))
|
.filter(|binding| binding.start() >= expr.start())
|
||||||
.filter(|binding| binding.start() >= expr.start())
|
.all(|binding| !binding.is_used())
|
||||||
.all(|binding| !binding.is_used())
|
{
|
||||||
{
|
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
rename,
|
||||||
rename,
|
expr.range(),
|
||||||
expr.range(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,6 @@ use ruff_python_parser::Tok;
|
||||||
use ruff_source_file::Locator;
|
use ruff_source_file::Locator;
|
||||||
use ruff_text_size::{Ranged, TextRange};
|
use ruff_text_size::{Ranged, TextRange};
|
||||||
|
|
||||||
use crate::registry::Rule;
|
|
||||||
use crate::settings::LinterSettings;
|
|
||||||
|
|
||||||
/// Simplified token type.
|
/// Simplified token type.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
enum TokenType {
|
enum TokenType {
|
||||||
|
@ -225,7 +222,6 @@ pub(crate) fn trailing_commas(
|
||||||
diagnostics: &mut Vec<Diagnostic>,
|
diagnostics: &mut Vec<Diagnostic>,
|
||||||
tokens: &[LexResult],
|
tokens: &[LexResult],
|
||||||
locator: &Locator,
|
locator: &Locator,
|
||||||
settings: &LinterSettings,
|
|
||||||
) {
|
) {
|
||||||
let tokens = tokens
|
let tokens = tokens
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -324,9 +320,7 @@ pub(crate) fn trailing_commas(
|
||||||
if comma_prohibited {
|
if comma_prohibited {
|
||||||
let comma = prev.spanned.unwrap();
|
let comma = prev.spanned.unwrap();
|
||||||
let mut diagnostic = Diagnostic::new(ProhibitedTrailingComma, comma.1);
|
let mut diagnostic = Diagnostic::new(ProhibitedTrailingComma, comma.1);
|
||||||
if settings.rules.should_fix(Rule::ProhibitedTrailingComma) {
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_deletion(diagnostic.range())));
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_deletion(diagnostic.range())));
|
|
||||||
}
|
|
||||||
diagnostics.push(diagnostic);
|
diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -359,17 +353,15 @@ pub(crate) fn trailing_commas(
|
||||||
MissingTrailingComma,
|
MissingTrailingComma,
|
||||||
TextRange::empty(missing_comma.1.end()),
|
TextRange::empty(missing_comma.1.end()),
|
||||||
);
|
);
|
||||||
if settings.rules.should_fix(Rule::MissingTrailingComma) {
|
// Create a replacement that includes the final bracket (or other token),
|
||||||
// Create a replacement that includes the final bracket (or other token),
|
// rather than just inserting a comma at the end. This prevents the UP034 fix
|
||||||
// rather than just inserting a comma at the end. This prevents the UP034 fix
|
// removing any brackets in the same linter pass - doing both at the same time could
|
||||||
// removing any brackets in the same linter pass - doing both at the same time could
|
// lead to a syntax error.
|
||||||
// lead to a syntax error.
|
let contents = locator.slice(missing_comma.1);
|
||||||
let contents = locator.slice(missing_comma.1);
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
format!("{contents},"),
|
||||||
format!("{contents},"),
|
missing_comma.1,
|
||||||
missing_comma.1,
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
diagnostics.push(diagnostic);
|
diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ use ruff_python_ast::{self as ast, Expr};
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
use crate::rules::flake8_comprehensions::fixes;
|
use crate::rules::flake8_comprehensions::fixes;
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
|
@ -82,19 +82,14 @@ pub(crate) fn unnecessary_call_around_sorted(
|
||||||
},
|
},
|
||||||
expr.range(),
|
expr.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.try_set_fix(|| {
|
||||||
diagnostic.try_set_fix(|| {
|
let edit =
|
||||||
let edit = fixes::fix_unnecessary_call_around_sorted(
|
fixes::fix_unnecessary_call_around_sorted(expr, checker.locator(), checker.stylist())?;
|
||||||
expr,
|
if outer.id == "reversed" {
|
||||||
checker.locator(),
|
Ok(Fix::unsafe_edit(edit))
|
||||||
checker.stylist(),
|
} else {
|
||||||
)?;
|
Ok(Fix::safe_edit(edit))
|
||||||
if outer.id == "reversed" {
|
}
|
||||||
Ok(Fix::unsafe_edit(edit))
|
});
|
||||||
} else {
|
|
||||||
Ok(Fix::safe_edit(edit))
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use ruff_python_ast::{Expr, Keyword};
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
use crate::rules::flake8_comprehensions::fixes;
|
use crate::rules::flake8_comprehensions::fixes;
|
||||||
use crate::rules::flake8_comprehensions::settings::Settings;
|
use crate::rules::flake8_comprehensions::settings::Settings;
|
||||||
|
|
||||||
|
@ -86,10 +86,8 @@ pub(crate) fn unnecessary_collection_call(
|
||||||
},
|
},
|
||||||
expr.range(),
|
expr.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.try_set_fix(|| {
|
||||||
diagnostic.try_set_fix(|| {
|
fixes::fix_unnecessary_collection_call(expr, checker).map(Fix::unsafe_edit)
|
||||||
fixes::fix_unnecessary_collection_call(expr, checker).map(Fix::unsafe_edit)
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ use ruff_python_ast::{self as ast, Comprehension, Expr};
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
use crate::rules::flake8_comprehensions::fixes;
|
use crate::rules::flake8_comprehensions::fixes;
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
|
@ -64,12 +64,10 @@ fn add_diagnostic(checker: &mut Checker, expr: &Expr) {
|
||||||
},
|
},
|
||||||
expr.range(),
|
expr.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.try_set_fix(|| {
|
||||||
diagnostic.try_set_fix(|| {
|
fixes::fix_unnecessary_comprehension(expr, checker.locator(), checker.stylist())
|
||||||
fixes::fix_unnecessary_comprehension(expr, checker.locator(), checker.stylist())
|
.map(Fix::unsafe_edit)
|
||||||
.map(Fix::unsafe_edit)
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ use ruff_python_ast::helpers::any_over_expr;
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
use crate::rules::flake8_comprehensions::fixes;
|
use crate::rules::flake8_comprehensions::fixes;
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
|
@ -89,11 +89,9 @@ pub(crate) fn unnecessary_comprehension_any_all(
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut diagnostic = Diagnostic::new(UnnecessaryComprehensionAnyAll, arg.range());
|
let mut diagnostic = Diagnostic::new(UnnecessaryComprehensionAnyAll, arg.range());
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.try_set_fix(|| {
|
||||||
diagnostic.try_set_fix(|| {
|
fixes::fix_unnecessary_comprehension_any_all(expr, checker.locator(), checker.stylist())
|
||||||
fixes::fix_unnecessary_comprehension_any_all(expr, checker.locator(), checker.stylist())
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ use ruff_python_ast::{self as ast, Arguments, Expr, Keyword};
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
use crate::rules::flake8_comprehensions::fixes;
|
use crate::rules::flake8_comprehensions::fixes;
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
|
@ -130,16 +130,14 @@ pub(crate) fn unnecessary_double_cast_or_process(
|
||||||
},
|
},
|
||||||
expr.range(),
|
expr.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.try_set_fix(|| {
|
||||||
diagnostic.try_set_fix(|| {
|
fixes::fix_unnecessary_double_cast_or_process(
|
||||||
fixes::fix_unnecessary_double_cast_or_process(
|
expr,
|
||||||
expr,
|
checker.locator(),
|
||||||
checker.locator(),
|
checker.stylist(),
|
||||||
checker.stylist(),
|
)
|
||||||
)
|
.map(Fix::unsafe_edit)
|
||||||
.map(Fix::unsafe_edit)
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use ruff_python_ast::{self as ast, Expr, Keyword};
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
use crate::rules::flake8_comprehensions::fixes;
|
use crate::rules::flake8_comprehensions::fixes;
|
||||||
|
|
||||||
use super::helpers;
|
use super::helpers;
|
||||||
|
@ -67,10 +67,7 @@ pub(crate) fn unnecessary_generator_dict(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let mut diagnostic = Diagnostic::new(UnnecessaryGeneratorDict, expr.range());
|
let mut diagnostic = Diagnostic::new(UnnecessaryGeneratorDict, expr.range());
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic
|
||||||
diagnostic.try_set_fix(|| {
|
.try_set_fix(|| fixes::fix_unnecessary_generator_dict(expr, checker).map(Fix::unsafe_edit));
|
||||||
fixes::fix_unnecessary_generator_dict(expr, checker).map(Fix::unsafe_edit)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ use ruff_macros::{derive_message_formats, violation};
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
use crate::rules::flake8_comprehensions::fixes;
|
use crate::rules::flake8_comprehensions::fixes;
|
||||||
|
|
||||||
use super::helpers;
|
use super::helpers;
|
||||||
|
@ -60,12 +60,10 @@ pub(crate) fn unnecessary_generator_list(
|
||||||
}
|
}
|
||||||
if let Expr::GeneratorExp(_) = argument {
|
if let Expr::GeneratorExp(_) = argument {
|
||||||
let mut diagnostic = Diagnostic::new(UnnecessaryGeneratorList, expr.range());
|
let mut diagnostic = Diagnostic::new(UnnecessaryGeneratorList, expr.range());
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.try_set_fix(|| {
|
||||||
diagnostic.try_set_fix(|| {
|
fixes::fix_unnecessary_generator_list(expr, checker.locator(), checker.stylist())
|
||||||
fixes::fix_unnecessary_generator_list(expr, checker.locator(), checker.stylist())
|
.map(Fix::unsafe_edit)
|
||||||
.map(Fix::unsafe_edit)
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ use ruff_macros::{derive_message_formats, violation};
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
use crate::rules::flake8_comprehensions::fixes;
|
use crate::rules::flake8_comprehensions::fixes;
|
||||||
|
|
||||||
use super::helpers;
|
use super::helpers;
|
||||||
|
@ -60,11 +60,9 @@ pub(crate) fn unnecessary_generator_set(
|
||||||
}
|
}
|
||||||
if let Expr::GeneratorExp(_) = argument {
|
if let Expr::GeneratorExp(_) = argument {
|
||||||
let mut diagnostic = Diagnostic::new(UnnecessaryGeneratorSet, expr.range());
|
let mut diagnostic = Diagnostic::new(UnnecessaryGeneratorSet, expr.range());
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.try_set_fix(|| {
|
||||||
diagnostic.try_set_fix(|| {
|
fixes::fix_unnecessary_generator_set(expr, checker).map(Fix::unsafe_edit)
|
||||||
fixes::fix_unnecessary_generator_set(expr, checker).map(Fix::unsafe_edit)
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ use ruff_macros::{derive_message_formats, violation};
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
use crate::rules::flake8_comprehensions::fixes;
|
use crate::rules::flake8_comprehensions::fixes;
|
||||||
|
|
||||||
use super::helpers;
|
use super::helpers;
|
||||||
|
@ -56,11 +56,9 @@ pub(crate) fn unnecessary_list_call(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let mut diagnostic = Diagnostic::new(UnnecessaryListCall, expr.range());
|
let mut diagnostic = Diagnostic::new(UnnecessaryListCall, expr.range());
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.try_set_fix(|| {
|
||||||
diagnostic.try_set_fix(|| {
|
fixes::fix_unnecessary_list_call(expr, checker.locator(), checker.stylist())
|
||||||
fixes::fix_unnecessary_list_call(expr, checker.locator(), checker.stylist())
|
.map(Fix::unsafe_edit)
|
||||||
.map(Fix::unsafe_edit)
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use ruff_python_ast::{self as ast, Expr, Keyword};
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
use crate::rules::flake8_comprehensions::fixes;
|
use crate::rules::flake8_comprehensions::fixes;
|
||||||
|
|
||||||
use super::helpers;
|
use super::helpers;
|
||||||
|
@ -65,10 +65,8 @@ pub(crate) fn unnecessary_list_comprehension_dict(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let mut diagnostic = Diagnostic::new(UnnecessaryListComprehensionDict, expr.range());
|
let mut diagnostic = Diagnostic::new(UnnecessaryListComprehensionDict, expr.range());
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.try_set_fix(|| {
|
||||||
diagnostic.try_set_fix(|| {
|
fixes::fix_unnecessary_list_comprehension_dict(expr, checker).map(Fix::unsafe_edit)
|
||||||
fixes::fix_unnecessary_list_comprehension_dict(expr, checker).map(Fix::unsafe_edit)
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ use ruff_macros::{derive_message_formats, violation};
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
use crate::rules::flake8_comprehensions::fixes;
|
use crate::rules::flake8_comprehensions::fixes;
|
||||||
|
|
||||||
use super::helpers;
|
use super::helpers;
|
||||||
|
@ -58,11 +58,9 @@ pub(crate) fn unnecessary_list_comprehension_set(
|
||||||
}
|
}
|
||||||
if argument.is_list_comp_expr() {
|
if argument.is_list_comp_expr() {
|
||||||
let mut diagnostic = Diagnostic::new(UnnecessaryListComprehensionSet, expr.range());
|
let mut diagnostic = Diagnostic::new(UnnecessaryListComprehensionSet, expr.range());
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.try_set_fix(|| {
|
||||||
diagnostic.try_set_fix(|| {
|
fixes::fix_unnecessary_list_comprehension_set(expr, checker).map(Fix::unsafe_edit)
|
||||||
fixes::fix_unnecessary_list_comprehension_set(expr, checker).map(Fix::unsafe_edit)
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use ruff_python_ast::{self as ast, Expr, Keyword};
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
use crate::rules::flake8_comprehensions::fixes;
|
use crate::rules::flake8_comprehensions::fixes;
|
||||||
|
|
||||||
use super::helpers;
|
use super::helpers;
|
||||||
|
@ -80,10 +80,7 @@ pub(crate) fn unnecessary_literal_dict(
|
||||||
},
|
},
|
||||||
expr.range(),
|
expr.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic
|
||||||
diagnostic.try_set_fix(|| {
|
.try_set_fix(|| fixes::fix_unnecessary_literal_dict(expr, checker).map(Fix::unsafe_edit));
|
||||||
fixes::fix_unnecessary_literal_dict(expr, checker).map(Fix::unsafe_edit)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ use ruff_macros::{derive_message_formats, violation};
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
use crate::rules::flake8_comprehensions::fixes;
|
use crate::rules::flake8_comprehensions::fixes;
|
||||||
|
|
||||||
use super::helpers;
|
use super::helpers;
|
||||||
|
@ -75,10 +75,7 @@ pub(crate) fn unnecessary_literal_set(
|
||||||
},
|
},
|
||||||
expr.range(),
|
expr.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic
|
||||||
diagnostic.try_set_fix(|| {
|
.try_set_fix(|| fixes::fix_unnecessary_literal_set(expr, checker).map(Fix::unsafe_edit));
|
||||||
fixes::fix_unnecessary_literal_set(expr, checker).map(Fix::unsafe_edit)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ use ruff_macros::{derive_message_formats, violation};
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
use crate::rules::flake8_comprehensions::fixes;
|
use crate::rules::flake8_comprehensions::fixes;
|
||||||
|
|
||||||
use super::helpers;
|
use super::helpers;
|
||||||
|
@ -91,15 +91,9 @@ pub(crate) fn unnecessary_literal_within_dict_call(
|
||||||
},
|
},
|
||||||
expr.range(),
|
expr.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.try_set_fix(|| {
|
||||||
diagnostic.try_set_fix(|| {
|
fixes::fix_unnecessary_literal_within_dict_call(expr, checker.locator(), checker.stylist())
|
||||||
fixes::fix_unnecessary_literal_within_dict_call(
|
|
||||||
expr,
|
|
||||||
checker.locator(),
|
|
||||||
checker.stylist(),
|
|
||||||
)
|
|
||||||
.map(Fix::unsafe_edit)
|
.map(Fix::unsafe_edit)
|
||||||
});
|
});
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use ruff_python_ast::{Expr, Keyword};
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
use crate::rules::flake8_comprehensions::fixes;
|
use crate::rules::flake8_comprehensions::fixes;
|
||||||
|
|
||||||
use super::helpers;
|
use super::helpers;
|
||||||
|
@ -93,15 +93,9 @@ pub(crate) fn unnecessary_literal_within_list_call(
|
||||||
},
|
},
|
||||||
expr.range(),
|
expr.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.try_set_fix(|| {
|
||||||
diagnostic.try_set_fix(|| {
|
fixes::fix_unnecessary_literal_within_list_call(expr, checker.locator(), checker.stylist())
|
||||||
fixes::fix_unnecessary_literal_within_list_call(
|
|
||||||
expr,
|
|
||||||
checker.locator(),
|
|
||||||
checker.stylist(),
|
|
||||||
)
|
|
||||||
.map(Fix::unsafe_edit)
|
.map(Fix::unsafe_edit)
|
||||||
});
|
});
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ use ruff_macros::{derive_message_formats, violation};
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
use crate::rules::flake8_comprehensions::fixes;
|
use crate::rules::flake8_comprehensions::fixes;
|
||||||
|
|
||||||
use super::helpers;
|
use super::helpers;
|
||||||
|
@ -95,15 +95,9 @@ pub(crate) fn unnecessary_literal_within_tuple_call(
|
||||||
},
|
},
|
||||||
expr.range(),
|
expr.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.try_set_fix(|| {
|
||||||
diagnostic.try_set_fix(|| {
|
fixes::fix_unnecessary_literal_within_tuple_call(expr, checker.locator(), checker.stylist())
|
||||||
fixes::fix_unnecessary_literal_within_tuple_call(
|
|
||||||
expr,
|
|
||||||
checker.locator(),
|
|
||||||
checker.stylist(),
|
|
||||||
)
|
|
||||||
.map(Fix::unsafe_edit)
|
.map(Fix::unsafe_edit)
|
||||||
});
|
});
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ use ruff_python_ast::{self as ast, Arguments, Expr, ExprContext, Parameters, Stm
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
use crate::rules::flake8_comprehensions::fixes;
|
use crate::rules::flake8_comprehensions::fixes;
|
||||||
|
|
||||||
use super::helpers;
|
use super::helpers;
|
||||||
|
@ -221,18 +221,16 @@ pub(crate) fn unnecessary_map(
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut diagnostic = Diagnostic::new(UnnecessaryMap { object_type }, expr.range());
|
let mut diagnostic = Diagnostic::new(UnnecessaryMap { object_type }, expr.range());
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.try_set_fix(|| {
|
||||||
diagnostic.try_set_fix(|| {
|
fixes::fix_unnecessary_map(
|
||||||
fixes::fix_unnecessary_map(
|
expr,
|
||||||
expr,
|
parent,
|
||||||
parent,
|
object_type,
|
||||||
object_type,
|
checker.locator(),
|
||||||
checker.locator(),
|
checker.stylist(),
|
||||||
checker.stylist(),
|
)
|
||||||
)
|
.map(Fix::unsafe_edit)
|
||||||
.map(Fix::unsafe_edit)
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ use ruff_python_ast::whitespace;
|
||||||
use ruff_python_codegen::{Generator, Stylist};
|
use ruff_python_codegen::{Generator, Stylist};
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::{AsRule, Rule};
|
use crate::registry::Rule;
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for the use of string literals in exception constructors.
|
/// Checks for the use of string literals in exception constructors.
|
||||||
|
@ -190,30 +190,6 @@ pub(crate) fn string_in_exception(checker: &mut Checker, stmt: &Stmt, exc: &Expr
|
||||||
if string.len() >= checker.settings.flake8_errmsg.max_string_length {
|
if string.len() >= checker.settings.flake8_errmsg.max_string_length {
|
||||||
let mut diagnostic =
|
let mut diagnostic =
|
||||||
Diagnostic::new(RawStringInException, first.range());
|
Diagnostic::new(RawStringInException, first.range());
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
|
||||||
if let Some(indentation) =
|
|
||||||
whitespace::indentation(checker.locator(), stmt)
|
|
||||||
{
|
|
||||||
if checker.semantic().is_available("msg") {
|
|
||||||
diagnostic.set_fix(generate_fix(
|
|
||||||
stmt,
|
|
||||||
first,
|
|
||||||
indentation,
|
|
||||||
checker.stylist(),
|
|
||||||
checker.generator(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Check for f-strings.
|
|
||||||
Expr::FString(_) => {
|
|
||||||
if checker.enabled(Rule::FStringInException) {
|
|
||||||
let mut diagnostic = Diagnostic::new(FStringInException, first.range());
|
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
|
||||||
if let Some(indentation) =
|
if let Some(indentation) =
|
||||||
whitespace::indentation(checker.locator(), stmt)
|
whitespace::indentation(checker.locator(), stmt)
|
||||||
{
|
{
|
||||||
|
@ -227,6 +203,25 @@ pub(crate) fn string_in_exception(checker: &mut Checker, stmt: &Stmt, exc: &Expr
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
checker.diagnostics.push(diagnostic);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Check for f-strings.
|
||||||
|
Expr::FString(_) => {
|
||||||
|
if checker.enabled(Rule::FStringInException) {
|
||||||
|
let mut diagnostic = Diagnostic::new(FStringInException, first.range());
|
||||||
|
if let Some(indentation) = whitespace::indentation(checker.locator(), stmt)
|
||||||
|
{
|
||||||
|
if checker.semantic().is_available("msg") {
|
||||||
|
diagnostic.set_fix(generate_fix(
|
||||||
|
stmt,
|
||||||
|
first,
|
||||||
|
indentation,
|
||||||
|
checker.stylist(),
|
||||||
|
checker.generator(),
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
@ -240,19 +235,17 @@ pub(crate) fn string_in_exception(checker: &mut Checker, stmt: &Stmt, exc: &Expr
|
||||||
if attr == "format" && value.is_constant_expr() {
|
if attr == "format" && value.is_constant_expr() {
|
||||||
let mut diagnostic =
|
let mut diagnostic =
|
||||||
Diagnostic::new(DotFormatInException, first.range());
|
Diagnostic::new(DotFormatInException, first.range());
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
if let Some(indentation) =
|
||||||
if let Some(indentation) =
|
whitespace::indentation(checker.locator(), stmt)
|
||||||
whitespace::indentation(checker.locator(), stmt)
|
{
|
||||||
{
|
if checker.semantic().is_available("msg") {
|
||||||
if checker.semantic().is_available("msg") {
|
diagnostic.set_fix(generate_fix(
|
||||||
diagnostic.set_fix(generate_fix(
|
stmt,
|
||||||
stmt,
|
first,
|
||||||
first,
|
indentation,
|
||||||
indentation,
|
checker.stylist(),
|
||||||
checker.stylist(),
|
checker.generator(),
|
||||||
checker.generator(),
|
));
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
|
|
|
@ -12,7 +12,6 @@ pub(crate) use shebang_not_executable::*;
|
||||||
pub(crate) use shebang_not_first_line::*;
|
pub(crate) use shebang_not_first_line::*;
|
||||||
|
|
||||||
use crate::comments::shebang::ShebangDirective;
|
use crate::comments::shebang::ShebangDirective;
|
||||||
use crate::settings::LinterSettings;
|
|
||||||
|
|
||||||
mod shebang_leading_whitespace;
|
mod shebang_leading_whitespace;
|
||||||
mod shebang_missing_executable_file;
|
mod shebang_missing_executable_file;
|
||||||
|
@ -24,7 +23,6 @@ pub(crate) fn from_tokens(
|
||||||
tokens: &[LexResult],
|
tokens: &[LexResult],
|
||||||
path: &Path,
|
path: &Path,
|
||||||
locator: &Locator,
|
locator: &Locator,
|
||||||
settings: &LinterSettings,
|
|
||||||
diagnostics: &mut Vec<Diagnostic>,
|
diagnostics: &mut Vec<Diagnostic>,
|
||||||
) {
|
) {
|
||||||
let mut has_any_shebang = false;
|
let mut has_any_shebang = false;
|
||||||
|
@ -41,7 +39,7 @@ pub(crate) fn from_tokens(
|
||||||
diagnostics.push(diagnostic);
|
diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(diagnostic) = shebang_leading_whitespace(*range, locator, settings) {
|
if let Some(diagnostic) = shebang_leading_whitespace(*range, locator) {
|
||||||
diagnostics.push(diagnostic);
|
diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,6 @@ use ruff_macros::{derive_message_formats, violation};
|
||||||
use ruff_python_trivia::is_python_whitespace;
|
use ruff_python_trivia::is_python_whitespace;
|
||||||
use ruff_source_file::Locator;
|
use ruff_source_file::Locator;
|
||||||
|
|
||||||
use crate::registry::AsRule;
|
|
||||||
use crate::settings::LinterSettings;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for whitespace before a shebang directive.
|
/// Checks for whitespace before a shebang directive.
|
||||||
///
|
///
|
||||||
|
@ -50,7 +47,6 @@ impl AlwaysFixableViolation for ShebangLeadingWhitespace {
|
||||||
pub(crate) fn shebang_leading_whitespace(
|
pub(crate) fn shebang_leading_whitespace(
|
||||||
range: TextRange,
|
range: TextRange,
|
||||||
locator: &Locator,
|
locator: &Locator,
|
||||||
settings: &LinterSettings,
|
|
||||||
) -> Option<Diagnostic> {
|
) -> Option<Diagnostic> {
|
||||||
// If the shebang is at the beginning of the file, abort.
|
// If the shebang is at the beginning of the file, abort.
|
||||||
if range.start() == TextSize::from(0) {
|
if range.start() == TextSize::from(0) {
|
||||||
|
@ -68,8 +64,6 @@ pub(crate) fn shebang_leading_whitespace(
|
||||||
|
|
||||||
let prefix = TextRange::up_to(range.start());
|
let prefix = TextRange::up_to(range.start());
|
||||||
let mut diagnostic = Diagnostic::new(ShebangLeadingWhitespace, prefix);
|
let mut diagnostic = Diagnostic::new(ShebangLeadingWhitespace, prefix);
|
||||||
if settings.rules.should_fix(diagnostic.kind.rule()) {
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_deletion(prefix)));
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_deletion(prefix)));
|
|
||||||
}
|
|
||||||
Some(diagnostic)
|
Some(diagnostic)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ use ruff_python_parser::Tok;
|
||||||
use ruff_source_file::Locator;
|
use ruff_source_file::Locator;
|
||||||
use ruff_text_size::{Ranged, TextRange};
|
use ruff_text_size::{Ranged, TextRange};
|
||||||
|
|
||||||
use crate::registry::AsRule;
|
|
||||||
use crate::settings::LinterSettings;
|
use crate::settings::LinterSettings;
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
|
@ -137,10 +136,8 @@ pub(crate) fn implicit(
|
||||||
TextRange::new(a_range.start(), b_range.end()),
|
TextRange::new(a_range.start(), b_range.end()),
|
||||||
);
|
);
|
||||||
|
|
||||||
if settings.rules.should_fix(diagnostic.kind.rule()) {
|
if let Some(fix) = concatenate_strings(a_range, b_range, locator) {
|
||||||
if let Some(fix) = concatenate_strings(a_range, b_range, locator) {
|
diagnostic.set_fix(fix);
|
||||||
diagnostic.set_fix(fix);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
diagnostics.push(diagnostic);
|
diagnostics.push(diagnostic);
|
||||||
|
|
|
@ -6,7 +6,7 @@ use ruff_python_semantic::{Binding, Imported};
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
use crate::renamer::Renamer;
|
use crate::renamer::Renamer;
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
|
@ -79,16 +79,14 @@ pub(crate) fn unconventional_import_alias(
|
||||||
},
|
},
|
||||||
binding.range(),
|
binding.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
if !import.is_submodule_import() {
|
||||||
if !import.is_submodule_import() {
|
if checker.semantic().is_available(expected_alias) {
|
||||||
if checker.semantic().is_available(expected_alias) {
|
diagnostic.try_set_fix(|| {
|
||||||
diagnostic.try_set_fix(|| {
|
let scope = &checker.semantic().scopes[binding.scope];
|
||||||
let scope = &checker.semantic().scopes[binding.scope];
|
let (edit, rest) =
|
||||||
let (edit, rest) =
|
Renamer::rename(name, expected_alias, scope, checker.semantic())?;
|
||||||
Renamer::rename(name, expected_alias, scope, checker.semantic())?;
|
Ok(Fix::unsafe_edits(edit, rest))
|
||||||
Ok(Fix::unsafe_edits(edit, rest))
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(diagnostic)
|
Some(diagnostic)
|
||||||
|
|
|
@ -5,7 +5,6 @@ use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::importer::ImportRequest;
|
use crate::importer::ImportRequest;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for direct instantiation of `logging.Logger`, as opposed to using
|
/// Checks for direct instantiation of `logging.Logger`, as opposed to using
|
||||||
|
@ -61,17 +60,15 @@ pub(crate) fn direct_logger_instantiation(checker: &mut Checker, call: &ast::Exp
|
||||||
.is_some_and(|call_path| matches!(call_path.as_slice(), ["logging", "Logger"]))
|
.is_some_and(|call_path| matches!(call_path.as_slice(), ["logging", "Logger"]))
|
||||||
{
|
{
|
||||||
let mut diagnostic = Diagnostic::new(DirectLoggerInstantiation, call.func.range());
|
let mut diagnostic = Diagnostic::new(DirectLoggerInstantiation, call.func.range());
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.try_set_fix(|| {
|
||||||
diagnostic.try_set_fix(|| {
|
let (import_edit, binding) = checker.importer().get_or_import_symbol(
|
||||||
let (import_edit, binding) = checker.importer().get_or_import_symbol(
|
&ImportRequest::import("logging", "getLogger"),
|
||||||
&ImportRequest::import("logging", "getLogger"),
|
call.func.start(),
|
||||||
call.func.start(),
|
checker.semantic(),
|
||||||
checker.semantic(),
|
)?;
|
||||||
)?;
|
let reference_edit = Edit::range_replacement(binding, call.func.range());
|
||||||
let reference_edit = Edit::range_replacement(binding, call.func.range());
|
Ok(Fix::unsafe_edits(import_edit, [reference_edit]))
|
||||||
Ok(Fix::unsafe_edits(import_edit, [reference_edit]))
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@ use ruff_python_ast::{self as ast, Expr};
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for any usage of `__cached__` and `__file__` as an argument to
|
/// Checks for any usage of `__cached__` and `__file__` as an argument to
|
||||||
|
@ -80,13 +79,11 @@ pub(crate) fn invalid_get_logger_argument(checker: &mut Checker, call: &ast::Exp
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut diagnostic = Diagnostic::new(InvalidGetLoggerArgument, expr.range());
|
let mut diagnostic = Diagnostic::new(InvalidGetLoggerArgument, expr.range());
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
if checker.semantic().is_builtin("__name__") {
|
||||||
if checker.semantic().is_builtin("__name__") {
|
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
"__name__".to_string(),
|
||||||
"__name__".to_string(),
|
expr.range(),
|
||||||
expr.range(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::importer::ImportRequest;
|
use crate::importer::ImportRequest;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for uses of `logging.WARN`.
|
/// Checks for uses of `logging.WARN`.
|
||||||
|
@ -55,17 +54,15 @@ pub(crate) fn undocumented_warn(checker: &mut Checker, expr: &Expr) {
|
||||||
.is_some_and(|call_path| matches!(call_path.as_slice(), ["logging", "WARN"]))
|
.is_some_and(|call_path| matches!(call_path.as_slice(), ["logging", "WARN"]))
|
||||||
{
|
{
|
||||||
let mut diagnostic = Diagnostic::new(UndocumentedWarn, expr.range());
|
let mut diagnostic = Diagnostic::new(UndocumentedWarn, expr.range());
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.try_set_fix(|| {
|
||||||
diagnostic.try_set_fix(|| {
|
let (import_edit, binding) = checker.importer().get_or_import_symbol(
|
||||||
let (import_edit, binding) = checker.importer().get_or_import_symbol(
|
&ImportRequest::import("logging", "WARNING"),
|
||||||
&ImportRequest::import("logging", "WARNING"),
|
expr.start(),
|
||||||
expr.start(),
|
checker.semantic(),
|
||||||
checker.semantic(),
|
)?;
|
||||||
)?;
|
let reference_edit = Edit::range_replacement(binding, expr.range());
|
||||||
let reference_edit = Edit::range_replacement(binding, expr.range());
|
Ok(Fix::safe_edits(import_edit, [reference_edit]))
|
||||||
Ok(Fix::safe_edits(import_edit, [reference_edit]))
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ use ruff_python_stdlib::logging::LoggingLevel;
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::{AsRule, Rule};
|
use crate::registry::Rule;
|
||||||
use crate::rules::flake8_logging_format::violations::{
|
use crate::rules::flake8_logging_format::violations::{
|
||||||
LoggingExcInfo, LoggingExtraAttrClash, LoggingFString, LoggingPercentFormat,
|
LoggingExcInfo, LoggingExtraAttrClash, LoggingFString, LoggingPercentFormat,
|
||||||
LoggingRedundantExcInfo, LoggingStringConcat, LoggingStringFormat, LoggingWarn,
|
LoggingRedundantExcInfo, LoggingStringConcat, LoggingStringFormat, LoggingWarn,
|
||||||
|
@ -196,12 +196,10 @@ pub(crate) fn logging_call(checker: &mut Checker, call: &ast::ExprCall) {
|
||||||
LoggingCallType::LevelCall(LoggingLevel::Warn)
|
LoggingCallType::LevelCall(LoggingLevel::Warn)
|
||||||
) {
|
) {
|
||||||
let mut diagnostic = Diagnostic::new(LoggingWarn, range);
|
let mut diagnostic = Diagnostic::new(LoggingWarn, range);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
"warning".to_string(),
|
||||||
"warning".to_string(),
|
range,
|
||||||
range,
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::fix;
|
use crate::fix;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for duplicate field definitions in classes.
|
/// Checks for duplicate field definitions in classes.
|
||||||
|
@ -79,13 +78,11 @@ pub(crate) fn duplicate_class_field_definition(checker: &mut Checker, body: &[St
|
||||||
},
|
},
|
||||||
stmt.range(),
|
stmt.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
let edit =
|
||||||
let edit =
|
fix::edits::delete_stmt(stmt, Some(stmt), checker.locator(), checker.indexer());
|
||||||
fix::edits::delete_stmt(stmt, Some(stmt), checker.locator(), checker.indexer());
|
diagnostic.set_fix(Fix::unsafe_edit(edit).isolate(Checker::isolation(
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(edit).isolate(Checker::isolation(
|
checker.semantic().current_statement_id(),
|
||||||
checker.semantic().current_statement_id(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@ use ruff_diagnostics::{Diagnostic, Edit, Fix};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for `startswith` or `endswith` calls on the same value with
|
/// Checks for `startswith` or `endswith` calls on the same value with
|
||||||
|
@ -115,92 +114,90 @@ pub(crate) fn multiple_starts_ends_with(checker: &mut Checker, expr: &Expr) {
|
||||||
},
|
},
|
||||||
expr.range(),
|
expr.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
let words: Vec<&Expr> = indices
|
||||||
let words: Vec<&Expr> = indices
|
.iter()
|
||||||
|
.map(|index| &values[*index])
|
||||||
|
.map(|expr| {
|
||||||
|
let Expr::Call(ast::ExprCall {
|
||||||
|
func: _,
|
||||||
|
arguments:
|
||||||
|
Arguments {
|
||||||
|
args,
|
||||||
|
keywords: _,
|
||||||
|
range: _,
|
||||||
|
},
|
||||||
|
range: _,
|
||||||
|
}) = expr
|
||||||
|
else {
|
||||||
|
unreachable!(
|
||||||
|
"{}",
|
||||||
|
format!("Indices should only contain `{attr_name}` calls")
|
||||||
|
)
|
||||||
|
};
|
||||||
|
args.get(0)
|
||||||
|
.unwrap_or_else(|| panic!("`{attr_name}` should have one argument"))
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let node = Expr::Tuple(ast::ExprTuple {
|
||||||
|
elts: words
|
||||||
.iter()
|
.iter()
|
||||||
.map(|index| &values[*index])
|
.flat_map(|value| {
|
||||||
.map(|expr| {
|
if let Expr::Tuple(ast::ExprTuple { elts, .. }) = value {
|
||||||
let Expr::Call(ast::ExprCall {
|
Left(elts.iter())
|
||||||
func: _,
|
} else {
|
||||||
arguments:
|
Right(iter::once(*value))
|
||||||
Arguments {
|
}
|
||||||
args,
|
|
||||||
keywords: _,
|
|
||||||
range: _,
|
|
||||||
},
|
|
||||||
range: _,
|
|
||||||
}) = expr
|
|
||||||
else {
|
|
||||||
unreachable!(
|
|
||||||
"{}",
|
|
||||||
format!("Indices should only contain `{attr_name}` calls")
|
|
||||||
)
|
|
||||||
};
|
|
||||||
args.get(0)
|
|
||||||
.unwrap_or_else(|| panic!("`{attr_name}` should have one argument"))
|
|
||||||
})
|
})
|
||||||
.collect();
|
.map(Clone::clone)
|
||||||
|
.collect(),
|
||||||
|
ctx: ExprContext::Load,
|
||||||
|
range: TextRange::default(),
|
||||||
|
});
|
||||||
|
let node1 = Expr::Name(ast::ExprName {
|
||||||
|
id: arg_name.into(),
|
||||||
|
ctx: ExprContext::Load,
|
||||||
|
range: TextRange::default(),
|
||||||
|
});
|
||||||
|
let node2 = Expr::Attribute(ast::ExprAttribute {
|
||||||
|
value: Box::new(node1),
|
||||||
|
attr: Identifier::new(attr_name.to_string(), TextRange::default()),
|
||||||
|
ctx: ExprContext::Load,
|
||||||
|
range: TextRange::default(),
|
||||||
|
});
|
||||||
|
let node3 = Expr::Call(ast::ExprCall {
|
||||||
|
func: Box::new(node2),
|
||||||
|
arguments: Arguments {
|
||||||
|
args: vec![node],
|
||||||
|
keywords: vec![],
|
||||||
|
range: TextRange::default(),
|
||||||
|
},
|
||||||
|
range: TextRange::default(),
|
||||||
|
});
|
||||||
|
let call = node3;
|
||||||
|
|
||||||
let node = Expr::Tuple(ast::ExprTuple {
|
// Generate the combined `BoolOp`.
|
||||||
elts: words
|
let mut call = Some(call);
|
||||||
.iter()
|
let node = Expr::BoolOp(ast::ExprBoolOp {
|
||||||
.flat_map(|value| {
|
op: BoolOp::Or,
|
||||||
if let Expr::Tuple(ast::ExprTuple { elts, .. }) = value {
|
values: values
|
||||||
Left(elts.iter())
|
.iter()
|
||||||
} else {
|
.enumerate()
|
||||||
Right(iter::once(*value))
|
.filter_map(|(index, elt)| {
|
||||||
}
|
if indices.contains(&index) {
|
||||||
})
|
std::mem::take(&mut call)
|
||||||
.map(Clone::clone)
|
} else {
|
||||||
.collect(),
|
Some(elt.clone())
|
||||||
ctx: ExprContext::Load,
|
}
|
||||||
range: TextRange::default(),
|
})
|
||||||
});
|
.collect(),
|
||||||
let node1 = Expr::Name(ast::ExprName {
|
range: TextRange::default(),
|
||||||
id: arg_name.into(),
|
});
|
||||||
ctx: ExprContext::Load,
|
let bool_op = node;
|
||||||
range: TextRange::default(),
|
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
||||||
});
|
checker.generator().expr(&bool_op),
|
||||||
let node2 = Expr::Attribute(ast::ExprAttribute {
|
expr.range(),
|
||||||
value: Box::new(node1),
|
)));
|
||||||
attr: Identifier::new(attr_name.to_string(), TextRange::default()),
|
|
||||||
ctx: ExprContext::Load,
|
|
||||||
range: TextRange::default(),
|
|
||||||
});
|
|
||||||
let node3 = Expr::Call(ast::ExprCall {
|
|
||||||
func: Box::new(node2),
|
|
||||||
arguments: Arguments {
|
|
||||||
args: vec![node],
|
|
||||||
keywords: vec![],
|
|
||||||
range: TextRange::default(),
|
|
||||||
},
|
|
||||||
range: TextRange::default(),
|
|
||||||
});
|
|
||||||
let call = node3;
|
|
||||||
|
|
||||||
// Generate the combined `BoolOp`.
|
|
||||||
let mut call = Some(call);
|
|
||||||
let node = Expr::BoolOp(ast::ExprBoolOp {
|
|
||||||
op: BoolOp::Or,
|
|
||||||
values: values
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.filter_map(|(index, elt)| {
|
|
||||||
if indices.contains(&index) {
|
|
||||||
std::mem::take(&mut call)
|
|
||||||
} else {
|
|
||||||
Some(elt.clone())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
range: TextRange::default(),
|
|
||||||
});
|
|
||||||
let bool_op = node;
|
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
|
||||||
checker.generator().expr(&bool_op),
|
|
||||||
expr.range(),
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ use ruff_macros::{derive_message_formats, violation};
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for lambdas that can be replaced with the `list` builtin.
|
/// Checks for lambdas that can be replaced with the `list` builtin.
|
||||||
|
@ -64,13 +63,11 @@ pub(crate) fn reimplemented_list_builtin(checker: &mut Checker, expr: &ExprLambd
|
||||||
if let Expr::List(ast::ExprList { elts, .. }) = body.as_ref() {
|
if let Expr::List(ast::ExprList { elts, .. }) = body.as_ref() {
|
||||||
if elts.is_empty() {
|
if elts.is_empty() {
|
||||||
let mut diagnostic = Diagnostic::new(ReimplementedListBuiltin, expr.range());
|
let mut diagnostic = Diagnostic::new(ReimplementedListBuiltin, expr.range());
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
if checker.semantic().is_builtin("list") {
|
||||||
if checker.semantic().is_builtin("list") {
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
"list".to_string(),
|
||||||
"list".to_string(),
|
expr.range(),
|
||||||
expr.range(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ use ruff_text_size::Ranged;
|
||||||
use ruff_python_stdlib::identifiers::is_identifier;
|
use ruff_python_stdlib::identifiers::is_identifier;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for unnecessary `dict` kwargs.
|
/// Checks for unnecessary `dict` kwargs.
|
||||||
|
@ -68,12 +67,10 @@ pub(crate) fn unnecessary_dict_kwargs(checker: &mut Checker, expr: &Expr, kwargs
|
||||||
if matches!(keys.as_slice(), [None]) {
|
if matches!(keys.as_slice(), [None]) {
|
||||||
let mut diagnostic = Diagnostic::new(UnnecessaryDictKwargs, expr.range());
|
let mut diagnostic = Diagnostic::new(UnnecessaryDictKwargs, expr.range());
|
||||||
|
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
format!("**{}", checker.locator().slice(values[0].range())),
|
||||||
format!("**{}", checker.locator().slice(values[0].range())),
|
kw.range(),
|
||||||
kw.range(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
continue;
|
continue;
|
||||||
|
@ -91,18 +88,16 @@ pub(crate) fn unnecessary_dict_kwargs(checker: &mut Checker, expr: &Expr, kwargs
|
||||||
|
|
||||||
let mut diagnostic = Diagnostic::new(UnnecessaryDictKwargs, expr.range());
|
let mut diagnostic = Diagnostic::new(UnnecessaryDictKwargs, expr.range());
|
||||||
|
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
kwargs
|
||||||
kwargs
|
.iter()
|
||||||
.iter()
|
.zip(values.iter())
|
||||||
.zip(values.iter())
|
.map(|(kwarg, value)| {
|
||||||
.map(|(kwarg, value)| {
|
format!("{}={}", kwarg.value, checker.locator().slice(value.range()))
|
||||||
format!("{}={}", kwarg.value, checker.locator().slice(value.range()))
|
})
|
||||||
})
|
.join(", "),
|
||||||
.join(", "),
|
kw.range(),
|
||||||
kw.range(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::fix;
|
use crate::fix;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for unnecessary `pass` statements in functions, classes, and other
|
/// Checks for unnecessary `pass` statements in functions, classes, and other
|
||||||
|
@ -63,17 +62,14 @@ pub(crate) fn no_unnecessary_pass(checker: &mut Checker, body: &[Stmt]) {
|
||||||
.filter(|stmt| stmt.is_pass_stmt())
|
.filter(|stmt| stmt.is_pass_stmt())
|
||||||
.for_each(|stmt| {
|
.for_each(|stmt| {
|
||||||
let mut diagnostic = Diagnostic::new(UnnecessaryPass, stmt.range());
|
let mut diagnostic = Diagnostic::new(UnnecessaryPass, stmt.range());
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
let edit = if let Some(index) = trailing_comment_start_offset(stmt, checker.locator()) {
|
||||||
let edit =
|
Edit::range_deletion(stmt.range().add_end(index))
|
||||||
if let Some(index) = trailing_comment_start_offset(stmt, checker.locator()) {
|
} else {
|
||||||
Edit::range_deletion(stmt.range().add_end(index))
|
fix::edits::delete_stmt(stmt, None, checker.locator(), checker.indexer())
|
||||||
} else {
|
};
|
||||||
fix::edits::delete_stmt(stmt, None, checker.locator(), checker.indexer())
|
diagnostic.set_fix(Fix::safe_edit(edit).isolate(Checker::isolation(
|
||||||
};
|
checker.semantic().current_statement_id(),
|
||||||
diagnostic.set_fix(Fix::safe_edit(edit).isolate(Checker::isolation(
|
)));
|
||||||
checker.semantic().current_statement_id(),
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::fix::edits::{remove_argument, Parentheses};
|
use crate::fix::edits::{remove_argument, Parentheses};
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for `range` calls with an unnecessary `start` argument.
|
/// Checks for `range` calls with an unnecessary `start` argument.
|
||||||
|
@ -78,16 +77,14 @@ pub(crate) fn unnecessary_range_start(checker: &mut Checker, call: &ast::ExprCal
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut diagnostic = Diagnostic::new(UnnecessaryRangeStart, start.range());
|
let mut diagnostic = Diagnostic::new(UnnecessaryRangeStart, start.range());
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.try_set_fix(|| {
|
||||||
diagnostic.try_set_fix(|| {
|
remove_argument(
|
||||||
remove_argument(
|
&start,
|
||||||
&start,
|
&call.arguments,
|
||||||
&call.arguments,
|
Parentheses::Preserve,
|
||||||
Parentheses::Preserve,
|
checker.locator().contents(),
|
||||||
checker.locator().contents(),
|
)
|
||||||
)
|
.map(Fix::safe_edit)
|
||||||
.map(Fix::safe_edit)
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ use ruff_macros::{derive_message_formats, violation};
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for `__eq__` and `__ne__` implementations that use `typing.Any` as
|
/// Checks for `__eq__` and `__ne__` implementations that use `typing.Any` as
|
||||||
|
@ -78,14 +77,12 @@ pub(crate) fn any_eq_ne_annotation(checker: &mut Checker, name: &str, parameters
|
||||||
},
|
},
|
||||||
annotation.range(),
|
annotation.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
// Ex) `def __eq__(self, obj: Any): ...`
|
||||||
// Ex) `def __eq__(self, obj: Any): ...`
|
if checker.semantic().is_builtin("object") {
|
||||||
if checker.semantic().is_builtin("object") {
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
"object".to_string(),
|
||||||
"object".to_string(),
|
annotation.range(),
|
||||||
annotation.range(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ use rustc_hash::FxHashSet;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
use crate::rules::flake8_pyi::helpers::traverse_union;
|
use crate::rules::flake8_pyi::helpers::traverse_union;
|
||||||
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
|
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
@ -64,19 +64,17 @@ pub(crate) fn duplicate_union_member<'a>(checker: &mut Checker, expr: &'a Expr)
|
||||||
},
|
},
|
||||||
expr.range(),
|
expr.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
// Delete the "|" character as well as the duplicate value by reconstructing the
|
||||||
// Delete the "|" character as well as the duplicate value by reconstructing the
|
// parent without the duplicate.
|
||||||
// parent without the duplicate.
|
|
||||||
|
|
||||||
// If the parent node is not a `BinOp` we will not perform a fix
|
// If the parent node is not a `BinOp` we will not perform a fix
|
||||||
if let Some(parent @ Expr::BinOp(ast::ExprBinOp { left, right, .. })) = parent {
|
if let Some(parent @ Expr::BinOp(ast::ExprBinOp { left, right, .. })) = parent {
|
||||||
// Replace the parent with its non-duplicate child.
|
// Replace the parent with its non-duplicate child.
|
||||||
let child = if expr == left.as_ref() { right } else { left };
|
let child = if expr == left.as_ref() { right } else { left };
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
checker.locator().slice(child.as_ref()).to_string(),
|
checker.locator().slice(child.as_ref()).to_string(),
|
||||||
parent.range(),
|
parent.range(),
|
||||||
)));
|
)));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
diagnostics.push(diagnostic);
|
diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::fix;
|
use crate::fix;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Removes ellipses (`...`) in otherwise non-empty class bodies.
|
/// Removes ellipses (`...`) in otherwise non-empty class bodies.
|
||||||
|
@ -63,13 +62,11 @@ pub(crate) fn ellipsis_in_non_empty_class_body(checker: &mut Checker, body: &[St
|
||||||
})
|
})
|
||||||
) {
|
) {
|
||||||
let mut diagnostic = Diagnostic::new(EllipsisInNonEmptyClassBody, stmt.range());
|
let mut diagnostic = Diagnostic::new(EllipsisInNonEmptyClassBody, stmt.range());
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
let edit =
|
||||||
let edit =
|
fix::edits::delete_stmt(stmt, Some(stmt), checker.locator(), checker.indexer());
|
||||||
fix::edits::delete_stmt(stmt, Some(stmt), checker.locator(), checker.indexer());
|
diagnostic.set_fix(Fix::safe_edit(edit).isolate(Checker::isolation(
|
||||||
diagnostic.set_fix(Fix::safe_edit(edit).isolate(Checker::isolation(
|
checker.semantic().current_statement_id(),
|
||||||
checker.semantic().current_statement_id(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,6 @@ use ruff_python_semantic::SemanticModel;
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for incorrect function signatures on `__exit__` and `__aexit__`
|
/// Checks for incorrect function signatures on `__exit__` and `__aexit__`
|
||||||
|
@ -175,13 +174,11 @@ fn check_short_args_list(checker: &mut Checker, parameters: &Parameters, func_ki
|
||||||
annotation.range(),
|
annotation.range(),
|
||||||
);
|
);
|
||||||
|
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
if checker.semantic().is_builtin("object") {
|
||||||
if checker.semantic().is_builtin("object") {
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
"object".to_string(),
|
||||||
"object".to_string(),
|
annotation.range(),
|
||||||
annotation.range(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
|
|
|
@ -5,7 +5,6 @@ use ruff_python_ast::{self as ast, Expr, Stmt};
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::Rule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for non-empty function stub bodies.
|
/// Checks for non-empty function stub bodies.
|
||||||
|
@ -69,11 +68,9 @@ pub(crate) fn non_empty_stub_body(checker: &mut Checker, body: &[Stmt]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut diagnostic = Diagnostic::new(NonEmptyStubBody, stmt.range());
|
let mut diagnostic = Diagnostic::new(NonEmptyStubBody, stmt.range());
|
||||||
if checker.patch(Rule::NonEmptyStubBody) {
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
format!("..."),
|
||||||
format!("..."),
|
stmt.range(),
|
||||||
stmt.range(),
|
)));
|
||||||
)));
|
|
||||||
};
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for numeric literals with a string representation longer than ten
|
/// Checks for numeric literals with a string representation longer than ten
|
||||||
|
@ -50,11 +49,9 @@ pub(crate) fn numeric_literal_too_long(checker: &mut Checker, expr: &Expr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut diagnostic = Diagnostic::new(NumericLiteralTooLong, expr.range());
|
let mut diagnostic = Diagnostic::new(NumericLiteralTooLong, expr.range());
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
"...".to_string(),
|
||||||
"...".to_string(),
|
expr.range(),
|
||||||
expr.range(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::fix;
|
use crate::fix;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for the presence of the `pass` statement within a class body
|
/// Checks for the presence of the `pass` statement within a class body
|
||||||
|
@ -60,13 +59,10 @@ pub(crate) fn pass_in_class_body(checker: &mut Checker, class_def: &ast::StmtCla
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut diagnostic = Diagnostic::new(PassInClassBody, stmt.range());
|
let mut diagnostic = Diagnostic::new(PassInClassBody, stmt.range());
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
let edit = fix::edits::delete_stmt(stmt, Some(stmt), checker.locator(), checker.indexer());
|
||||||
let edit =
|
diagnostic.set_fix(Fix::safe_edit(edit).isolate(Checker::isolation(
|
||||||
fix::edits::delete_stmt(stmt, Some(stmt), checker.locator(), checker.indexer());
|
checker.semantic().current_statement_id(),
|
||||||
diagnostic.set_fix(Fix::safe_edit(edit).isolate(Checker::isolation(
|
)));
|
||||||
checker.semantic().current_statement_id(),
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@ use ruff_python_ast::Stmt;
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::Rule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for `pass` statements in empty stub bodies.
|
/// Checks for `pass` statements in empty stub bodies.
|
||||||
|
@ -47,11 +46,9 @@ pub(crate) fn pass_statement_stub_body(checker: &mut Checker, body: &[Stmt]) {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut diagnostic = Diagnostic::new(PassStatementStubBody, pass.range());
|
let mut diagnostic = Diagnostic::new(PassStatementStubBody, pass.range());
|
||||||
if checker.patch(Rule::PassStatementStubBody) {
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
format!("..."),
|
||||||
format!("..."),
|
pass.range(),
|
||||||
pass.range(),
|
)));
|
||||||
)));
|
|
||||||
};
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@ use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::Rule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for quoted type annotations in stub (`.pyi`) files, which should be avoided.
|
/// Checks for quoted type annotations in stub (`.pyi`) files, which should be avoided.
|
||||||
|
@ -43,11 +42,9 @@ impl AlwaysFixableViolation for QuotedAnnotationInStub {
|
||||||
/// PYI020
|
/// PYI020
|
||||||
pub(crate) fn quoted_annotation_in_stub(checker: &mut Checker, annotation: &str, range: TextRange) {
|
pub(crate) fn quoted_annotation_in_stub(checker: &mut Checker, annotation: &str, range: TextRange) {
|
||||||
let mut diagnostic = Diagnostic::new(QuotedAnnotationInStub, range);
|
let mut diagnostic = Diagnostic::new(QuotedAnnotationInStub, range);
|
||||||
if checker.patch(Rule::QuotedAnnotationInStub) {
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
annotation.to_string(),
|
||||||
annotation.to_string(),
|
range,
|
||||||
range,
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::importer::ImportRequest;
|
use crate::importer::ImportRequest;
|
||||||
use crate::registry::AsRule;
|
|
||||||
use crate::rules::flake8_pyi::rules::TypingModule;
|
use crate::rules::flake8_pyi::rules::TypingModule;
|
||||||
use crate::settings::types::PythonVersion;
|
use crate::settings::types::PythonVersion;
|
||||||
|
|
||||||
|
@ -534,12 +534,10 @@ pub(crate) fn typed_argument_simple_defaults(checker: &mut Checker, parameters:
|
||||||
) {
|
) {
|
||||||
let mut diagnostic = Diagnostic::new(TypedArgumentDefaultInStub, default.range());
|
let mut diagnostic = Diagnostic::new(TypedArgumentDefaultInStub, default.range());
|
||||||
|
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
"...".to_string(),
|
||||||
"...".to_string(),
|
default.range(),
|
||||||
default.range(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
@ -571,12 +569,10 @@ pub(crate) fn argument_simple_defaults(checker: &mut Checker, parameters: &Param
|
||||||
) {
|
) {
|
||||||
let mut diagnostic = Diagnostic::new(ArgumentDefaultInStub, default.range());
|
let mut diagnostic = Diagnostic::new(ArgumentDefaultInStub, default.range());
|
||||||
|
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
"...".to_string(),
|
||||||
"...".to_string(),
|
default.range(),
|
||||||
default.range(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
@ -606,12 +602,10 @@ pub(crate) fn assignment_default_in_stub(checker: &mut Checker, targets: &[Expr]
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut diagnostic = Diagnostic::new(AssignmentDefaultInStub, value.range());
|
let mut diagnostic = Diagnostic::new(AssignmentDefaultInStub, value.range());
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
"...".to_string(),
|
||||||
"...".to_string(),
|
value.range(),
|
||||||
value.range(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -642,12 +636,10 @@ pub(crate) fn annotated_assignment_default_in_stub(
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut diagnostic = Diagnostic::new(AssignmentDefaultInStub, value.range());
|
let mut diagnostic = Diagnostic::new(AssignmentDefaultInStub, value.range());
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
"...".to_string(),
|
||||||
"...".to_string(),
|
value.range(),
|
||||||
value.range(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -741,18 +733,16 @@ pub(crate) fn type_alias_without_annotation(checker: &mut Checker, value: &Expr,
|
||||||
},
|
},
|
||||||
target.range(),
|
target.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.try_set_fix(|| {
|
||||||
diagnostic.try_set_fix(|| {
|
let (import_edit, binding) = checker.importer().get_or_import_symbol(
|
||||||
let (import_edit, binding) = checker.importer().get_or_import_symbol(
|
&ImportRequest::import(module.as_str(), "TypeAlias"),
|
||||||
&ImportRequest::import(module.as_str(), "TypeAlias"),
|
target.start(),
|
||||||
target.start(),
|
checker.semantic(),
|
||||||
checker.semantic(),
|
)?;
|
||||||
)?;
|
Ok(Fix::safe_edits(
|
||||||
Ok(Fix::safe_edits(
|
Edit::range_replacement(format!("{id}: {binding}"), target.range()),
|
||||||
Edit::range_replacement(format!("{id}: {binding}"), target.range()),
|
[import_edit],
|
||||||
[import_edit],
|
))
|
||||||
))
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ use ruff_python_semantic::analyze::visibility::is_abstract;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::fix::edits::delete_stmt;
|
use crate::fix::edits::delete_stmt;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for redundant definitions of `__str__` or `__repr__` in stubs.
|
/// Checks for redundant definitions of `__str__` or `__repr__` in stubs.
|
||||||
|
@ -95,13 +94,11 @@ pub(crate) fn str_or_repr_defined_in_stub(checker: &mut Checker, stmt: &Stmt) {
|
||||||
},
|
},
|
||||||
stmt.identifier(),
|
stmt.identifier(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
let stmt = checker.semantic().current_statement();
|
||||||
let stmt = checker.semantic().current_statement();
|
let parent = checker.semantic().current_statement_parent();
|
||||||
let parent = checker.semantic().current_statement_parent();
|
let edit = delete_stmt(stmt, parent, checker.locator(), checker.indexer());
|
||||||
let edit = delete_stmt(stmt, parent, checker.locator(), checker.indexer());
|
diagnostic.set_fix(Fix::safe_edit(edit).isolate(Checker::isolation(
|
||||||
diagnostic.set_fix(Fix::safe_edit(edit).isolate(Checker::isolation(
|
checker.semantic().current_statement_parent_id(),
|
||||||
checker.semantic().current_statement_parent_id(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ use ruff_python_ast::helpers::is_docstring_stmt;
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for the use of string and bytes literals longer than 50 characters
|
/// Checks for the use of string and bytes literals longer than 50 characters
|
||||||
|
@ -67,11 +66,9 @@ pub(crate) fn string_or_bytes_too_long(checker: &mut Checker, expr: &Expr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut diagnostic = Diagnostic::new(StringOrBytesTooLong, expr.range());
|
let mut diagnostic = Diagnostic::new(StringOrBytesTooLong, expr.range());
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
"...".to_string(),
|
||||||
"...".to_string(),
|
expr.range(),
|
||||||
expr.range(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ use ruff_python_semantic::{Binding, BindingKind};
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
use crate::renamer::Renamer;
|
use crate::renamer::Renamer;
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
|
@ -65,14 +65,12 @@ pub(crate) fn unaliased_collections_abc_set_import(
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut diagnostic = Diagnostic::new(UnaliasedCollectionsAbcSetImport, binding.range());
|
let mut diagnostic = Diagnostic::new(UnaliasedCollectionsAbcSetImport, binding.range());
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
if checker.semantic().is_available("AbstractSet") {
|
||||||
if checker.semantic().is_available("AbstractSet") {
|
diagnostic.try_set_fix(|| {
|
||||||
diagnostic.try_set_fix(|| {
|
let scope = &checker.semantic().scopes[binding.scope];
|
||||||
let scope = &checker.semantic().scopes[binding.scope];
|
let (edit, rest) = Renamer::rename(name, "AbstractSet", scope, checker.semantic())?;
|
||||||
let (edit, rest) = Renamer::rename(name, "AbstractSet", scope, checker.semantic())?;
|
Ok(Fix::unsafe_edits(edit, rest))
|
||||||
Ok(Fix::unsafe_edits(edit, rest))
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Some(diagnostic)
|
Some(diagnostic)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use ruff_python_ast::{self as ast, Expr};
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
use crate::rules::flake8_pyi::helpers::traverse_union;
|
use crate::rules::flake8_pyi::helpers::traverse_union;
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
|
@ -76,12 +76,10 @@ pub(crate) fn unnecessary_literal_union<'a>(checker: &mut Checker, expr: &'a Exp
|
||||||
expr.range(),
|
expr.range(),
|
||||||
);
|
);
|
||||||
|
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
format!("Literal[{}]", literal_members.join(", ")),
|
||||||
format!("Literal[{}]", literal_members.join(", ")),
|
expr.range(),
|
||||||
expr.range(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,6 @@ use crate::cst::matchers::match_indented_block;
|
||||||
use crate::cst::matchers::match_module;
|
use crate::cst::matchers::match_module;
|
||||||
use crate::fix::codemods::CodegenStylist;
|
use crate::fix::codemods::CodegenStylist;
|
||||||
use crate::importer::ImportRequest;
|
use crate::importer::ImportRequest;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
use super::unittest_assert::UnittestAssert;
|
use super::unittest_assert::UnittestAssert;
|
||||||
|
|
||||||
|
@ -284,25 +283,23 @@ pub(crate) fn unittest_assertion(
|
||||||
},
|
},
|
||||||
func.range(),
|
func.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
// We're converting an expression to a statement, so avoid applying the fix if
|
||||||
// We're converting an expression to a statement, so avoid applying the fix if
|
// the assertion is part of a larger expression.
|
||||||
// the assertion is part of a larger expression.
|
if checker.semantic().current_statement().is_expr_stmt()
|
||||||
if checker.semantic().current_statement().is_expr_stmt()
|
&& checker.semantic().current_expression_parent().is_none()
|
||||||
&& checker.semantic().current_expression_parent().is_none()
|
&& !checker.indexer().comment_ranges().intersects(expr.range())
|
||||||
&& !checker.indexer().comment_ranges().intersects(expr.range())
|
{
|
||||||
{
|
if let Ok(stmt) = unittest_assert.generate_assert(args, keywords) {
|
||||||
if let Ok(stmt) = unittest_assert.generate_assert(args, keywords) {
|
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
checker.generator().stmt(&stmt),
|
||||||
checker.generator().stmt(&stmt),
|
parenthesized_range(
|
||||||
parenthesized_range(
|
expr.into(),
|
||||||
expr.into(),
|
checker.semantic().current_statement().into(),
|
||||||
checker.semantic().current_statement().into(),
|
checker.indexer().comment_ranges(),
|
||||||
checker.indexer().comment_ranges(),
|
checker.locator().contents(),
|
||||||
checker.locator().contents(),
|
)
|
||||||
)
|
.unwrap_or(expr.range()),
|
||||||
.unwrap_or(expr.range()),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(diagnostic)
|
Some(diagnostic)
|
||||||
|
@ -390,9 +387,7 @@ pub(crate) fn unittest_raises_assertion(
|
||||||
},
|
},
|
||||||
call.func.range(),
|
call.func.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule())
|
if !checker.indexer().has_comments(call, checker.locator()) {
|
||||||
&& !checker.indexer().has_comments(call, checker.locator())
|
|
||||||
{
|
|
||||||
if let Some(args) = to_pytest_raises_args(checker, attr.as_str(), &call.arguments) {
|
if let Some(args) = to_pytest_raises_args(checker, attr.as_str(), &call.arguments) {
|
||||||
diagnostic.try_set_fix(|| {
|
diagnostic.try_set_fix(|| {
|
||||||
let (import_edit, binding) = checker.importer().get_or_import_symbol(
|
let (import_edit, binding) = checker.importer().get_or_import_symbol(
|
||||||
|
@ -746,19 +741,17 @@ pub(crate) fn composite_condition(
|
||||||
let composite = is_composite_condition(test);
|
let composite = is_composite_condition(test);
|
||||||
if matches!(composite, CompositionKind::Simple | CompositionKind::Mixed) {
|
if matches!(composite, CompositionKind::Simple | CompositionKind::Mixed) {
|
||||||
let mut diagnostic = Diagnostic::new(PytestCompositeAssertion, stmt.range());
|
let mut diagnostic = Diagnostic::new(PytestCompositeAssertion, stmt.range());
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
if matches!(composite, CompositionKind::Simple)
|
||||||
if matches!(composite, CompositionKind::Simple)
|
&& msg.is_none()
|
||||||
&& msg.is_none()
|
&& !checker.indexer().comment_ranges().intersects(stmt.range())
|
||||||
&& !checker.indexer().comment_ranges().intersects(stmt.range())
|
&& !checker
|
||||||
&& !checker
|
.indexer()
|
||||||
.indexer()
|
.in_multi_statement_line(stmt, checker.locator())
|
||||||
.in_multi_statement_line(stmt, checker.locator())
|
{
|
||||||
{
|
diagnostic.try_set_fix(|| {
|
||||||
diagnostic.try_set_fix(|| {
|
fix_composite_condition(stmt, checker.locator(), checker.stylist())
|
||||||
fix_composite_condition(stmt, checker.locator(), checker.stylist())
|
.map(Fix::unsafe_edit)
|
||||||
.map(Fix::unsafe_edit)
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ use ruff_text_size::{TextLen, TextRange};
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::fix::edits;
|
use crate::fix::edits;
|
||||||
use crate::registry::{AsRule, Rule};
|
use crate::registry::Rule;
|
||||||
|
|
||||||
use super::helpers::{
|
use super::helpers::{
|
||||||
get_mark_decorators, is_pytest_fixture, is_pytest_yield_fixture, keyword_is_literal,
|
get_mark_decorators, is_pytest_fixture, is_pytest_yield_fixture, keyword_is_literal,
|
||||||
|
@ -681,9 +681,7 @@ fn pytest_fixture_parentheses(
|
||||||
PytestFixtureIncorrectParenthesesStyle { expected, actual },
|
PytestFixtureIncorrectParenthesesStyle { expected, actual },
|
||||||
decorator.range(),
|
decorator.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.set_fix(fix);
|
||||||
diagnostic.set_fix(fix);
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -727,17 +725,15 @@ fn check_fixture_decorator(checker: &mut Checker, func_name: &str, decorator: &D
|
||||||
if keyword_is_literal(keyword, "function") {
|
if keyword_is_literal(keyword, "function") {
|
||||||
let mut diagnostic =
|
let mut diagnostic =
|
||||||
Diagnostic::new(PytestExtraneousScopeFunction, keyword.range());
|
Diagnostic::new(PytestExtraneousScopeFunction, keyword.range());
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.try_set_fix(|| {
|
||||||
diagnostic.try_set_fix(|| {
|
edits::remove_argument(
|
||||||
edits::remove_argument(
|
keyword,
|
||||||
keyword,
|
arguments,
|
||||||
arguments,
|
edits::Parentheses::Preserve,
|
||||||
edits::Parentheses::Preserve,
|
checker.locator().contents(),
|
||||||
checker.locator().contents(),
|
)
|
||||||
)
|
.map(Fix::unsafe_edit)
|
||||||
.map(Fix::unsafe_edit)
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -819,30 +815,28 @@ fn check_fixture_returns(
|
||||||
},
|
},
|
||||||
stmt.range(),
|
stmt.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
let yield_edit = Edit::range_replacement(
|
||||||
let yield_edit = Edit::range_replacement(
|
"return".to_string(),
|
||||||
"return".to_string(),
|
TextRange::at(stmt.start(), "yield".text_len()),
|
||||||
TextRange::at(stmt.start(), "yield".text_len()),
|
);
|
||||||
);
|
let return_type_edit = returns.and_then(|returns| {
|
||||||
let return_type_edit = returns.and_then(|returns| {
|
let ast::ExprSubscript { value, slice, .. } = returns.as_subscript_expr()?;
|
||||||
let ast::ExprSubscript { value, slice, .. } = returns.as_subscript_expr()?;
|
let ast::ExprTuple { elts, .. } = slice.as_tuple_expr()?;
|
||||||
let ast::ExprTuple { elts, .. } = slice.as_tuple_expr()?;
|
let [first, ..] = elts.as_slice() else {
|
||||||
let [first, ..] = elts.as_slice() else {
|
return None;
|
||||||
return None;
|
};
|
||||||
};
|
if !checker.semantic().match_typing_expr(value, "Generator") {
|
||||||
if !checker.semantic().match_typing_expr(value, "Generator") {
|
return None;
|
||||||
return None;
|
|
||||||
}
|
|
||||||
Some(Edit::range_replacement(
|
|
||||||
checker.generator().expr(first),
|
|
||||||
returns.range(),
|
|
||||||
))
|
|
||||||
});
|
|
||||||
if let Some(return_type_edit) = return_type_edit {
|
|
||||||
diagnostic.set_fix(Fix::safe_edits(yield_edit, [return_type_edit]));
|
|
||||||
} else {
|
|
||||||
diagnostic.set_fix(Fix::safe_edit(yield_edit));
|
|
||||||
}
|
}
|
||||||
|
Some(Edit::range_replacement(
|
||||||
|
checker.generator().expr(first),
|
||||||
|
returns.range(),
|
||||||
|
))
|
||||||
|
});
|
||||||
|
if let Some(return_type_edit) = return_type_edit {
|
||||||
|
diagnostic.set_fix(Fix::safe_edits(yield_edit, [return_type_edit]));
|
||||||
|
} else {
|
||||||
|
diagnostic.set_fix(Fix::safe_edit(yield_edit));
|
||||||
}
|
}
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
@ -912,10 +906,8 @@ fn check_fixture_marks(checker: &mut Checker, decorators: &[Decorator]) {
|
||||||
if *name == "asyncio" {
|
if *name == "asyncio" {
|
||||||
let mut diagnostic =
|
let mut diagnostic =
|
||||||
Diagnostic::new(PytestUnnecessaryAsyncioMarkOnFixture, expr.range());
|
Diagnostic::new(PytestUnnecessaryAsyncioMarkOnFixture, expr.range());
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
let range = checker.locator().full_lines_range(expr.range());
|
||||||
let range = checker.locator().full_lines_range(expr.range());
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_deletion(range)));
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_deletion(range)));
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -924,10 +916,8 @@ fn check_fixture_marks(checker: &mut Checker, decorators: &[Decorator]) {
|
||||||
if *name == "usefixtures" {
|
if *name == "usefixtures" {
|
||||||
let mut diagnostic =
|
let mut diagnostic =
|
||||||
Diagnostic::new(PytestErroneousUseFixturesOnFixture, expr.range());
|
Diagnostic::new(PytestErroneousUseFixturesOnFixture, expr.range());
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
let line_range = checker.locator().full_lines_range(expr.range());
|
||||||
let line_range = checker.locator().full_lines_range(expr.range());
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_deletion(line_range)));
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_deletion(line_range)));
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ use ruff_python_ast::call_path::CallPath;
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::{AsRule, Rule};
|
use crate::registry::Rule;
|
||||||
|
|
||||||
use super::helpers::get_mark_decorators;
|
use super::helpers::get_mark_decorators;
|
||||||
|
|
||||||
|
@ -130,9 +130,7 @@ fn pytest_mark_parentheses(
|
||||||
},
|
},
|
||||||
decorator.range(),
|
decorator.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.set_fix(fix);
|
||||||
diagnostic.set_fix(fix);
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,9 +182,7 @@ fn check_useless_usefixtures(checker: &mut Checker, decorator: &Decorator, call_
|
||||||
|
|
||||||
if !has_parameters {
|
if !has_parameters {
|
||||||
let mut diagnostic = Diagnostic::new(PytestUseFixturesWithoutParameters, decorator.range());
|
let mut diagnostic = Diagnostic::new(PytestUseFixturesWithoutParameters, decorator.range());
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_deletion(decorator.range())));
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_deletion(decorator.range())));
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ use ruff_python_trivia::{SimpleTokenKind, SimpleTokenizer};
|
||||||
use ruff_text_size::{Ranged, TextRange, TextSize};
|
use ruff_text_size::{Ranged, TextRange, TextSize};
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::{AsRule, Rule};
|
use crate::registry::Rule;
|
||||||
|
|
||||||
use super::super::types;
|
use super::super::types;
|
||||||
use super::helpers::{is_pytest_parametrize, split_names};
|
use super::helpers::{is_pytest_parametrize, split_names};
|
||||||
|
@ -338,25 +338,23 @@ fn check_names(checker: &mut Checker, decorator: &Decorator, expr: &Expr) {
|
||||||
},
|
},
|
||||||
name_range,
|
name_range,
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
let node = Expr::Tuple(ast::ExprTuple {
|
||||||
let node = Expr::Tuple(ast::ExprTuple {
|
elts: names
|
||||||
elts: names
|
.iter()
|
||||||
.iter()
|
.map(|name| {
|
||||||
.map(|name| {
|
Expr::Constant(ast::ExprConstant {
|
||||||
Expr::Constant(ast::ExprConstant {
|
value: (*name).to_string().into(),
|
||||||
value: (*name).to_string().into(),
|
range: TextRange::default(),
|
||||||
range: TextRange::default(),
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
.collect(),
|
})
|
||||||
ctx: ExprContext::Load,
|
.collect(),
|
||||||
range: TextRange::default(),
|
ctx: ExprContext::Load,
|
||||||
});
|
range: TextRange::default(),
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
});
|
||||||
format!("({})", checker.generator().expr(&node)),
|
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
||||||
name_range,
|
format!("({})", checker.generator().expr(&node)),
|
||||||
)));
|
name_range,
|
||||||
}
|
)));
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
types::ParametrizeNameType::List => {
|
types::ParametrizeNameType::List => {
|
||||||
|
@ -373,25 +371,23 @@ fn check_names(checker: &mut Checker, decorator: &Decorator, expr: &Expr) {
|
||||||
},
|
},
|
||||||
name_range,
|
name_range,
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
let node = Expr::List(ast::ExprList {
|
||||||
let node = Expr::List(ast::ExprList {
|
elts: names
|
||||||
elts: names
|
.iter()
|
||||||
.iter()
|
.map(|name| {
|
||||||
.map(|name| {
|
Expr::Constant(ast::ExprConstant {
|
||||||
Expr::Constant(ast::ExprConstant {
|
value: (*name).to_string().into(),
|
||||||
value: (*name).to_string().into(),
|
range: TextRange::default(),
|
||||||
range: TextRange::default(),
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
.collect(),
|
})
|
||||||
ctx: ExprContext::Load,
|
.collect(),
|
||||||
range: TextRange::default(),
|
ctx: ExprContext::Load,
|
||||||
});
|
range: TextRange::default(),
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
});
|
||||||
checker.generator().expr(&node),
|
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
||||||
name_range,
|
checker.generator().expr(&node),
|
||||||
)));
|
name_range,
|
||||||
}
|
)));
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
types::ParametrizeNameType::Csv => {}
|
types::ParametrizeNameType::Csv => {}
|
||||||
|
@ -413,17 +409,15 @@ fn check_names(checker: &mut Checker, decorator: &Decorator, expr: &Expr) {
|
||||||
},
|
},
|
||||||
expr.range(),
|
expr.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
let node = Expr::List(ast::ExprList {
|
||||||
let node = Expr::List(ast::ExprList {
|
elts: elts.clone(),
|
||||||
elts: elts.clone(),
|
ctx: ExprContext::Load,
|
||||||
ctx: ExprContext::Load,
|
range: TextRange::default(),
|
||||||
range: TextRange::default(),
|
});
|
||||||
});
|
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
checker.generator().expr(&node),
|
||||||
checker.generator().expr(&node),
|
expr.range(),
|
||||||
expr.range(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
types::ParametrizeNameType::Csv => {
|
types::ParametrizeNameType::Csv => {
|
||||||
|
@ -433,13 +427,11 @@ fn check_names(checker: &mut Checker, decorator: &Decorator, expr: &Expr) {
|
||||||
},
|
},
|
||||||
expr.range(),
|
expr.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
if let Some(content) = elts_to_csv(elts, checker.generator()) {
|
||||||
if let Some(content) = elts_to_csv(elts, checker.generator()) {
|
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
content,
|
||||||
content,
|
expr.range(),
|
||||||
expr.range(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
@ -461,17 +453,15 @@ fn check_names(checker: &mut Checker, decorator: &Decorator, expr: &Expr) {
|
||||||
},
|
},
|
||||||
expr.range(),
|
expr.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
let node = Expr::Tuple(ast::ExprTuple {
|
||||||
let node = Expr::Tuple(ast::ExprTuple {
|
elts: elts.clone(),
|
||||||
elts: elts.clone(),
|
ctx: ExprContext::Load,
|
||||||
ctx: ExprContext::Load,
|
range: TextRange::default(),
|
||||||
range: TextRange::default(),
|
});
|
||||||
});
|
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
format!("({})", checker.generator().expr(&node)),
|
||||||
format!("({})", checker.generator().expr(&node)),
|
expr.range(),
|
||||||
expr.range(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
types::ParametrizeNameType::Csv => {
|
types::ParametrizeNameType::Csv => {
|
||||||
|
@ -481,13 +471,11 @@ fn check_names(checker: &mut Checker, decorator: &Decorator, expr: &Expr) {
|
||||||
},
|
},
|
||||||
expr.range(),
|
expr.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
if let Some(content) = elts_to_csv(elts, checker.generator()) {
|
||||||
if let Some(content) = elts_to_csv(elts, checker.generator()) {
|
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
content,
|
||||||
content,
|
expr.range(),
|
||||||
expr.range(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
@ -585,22 +573,19 @@ fn check_duplicates(checker: &mut Checker, values: &Expr) {
|
||||||
PytestDuplicateParametrizeTestCases { index: *index },
|
PytestDuplicateParametrizeTestCases { index: *index },
|
||||||
element.range(),
|
element.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
if let Some(prev) = prev {
|
||||||
if let Some(prev) = prev {
|
let values_end = values.range().end() - TextSize::new(1);
|
||||||
let values_end = values.range().end() - TextSize::new(1);
|
let previous_end =
|
||||||
let previous_end = trailing_comma(prev, checker.locator().contents())
|
trailing_comma(prev, checker.locator().contents()).unwrap_or(values_end);
|
||||||
.unwrap_or(values_end);
|
let element_end =
|
||||||
let element_end = trailing_comma(element, checker.locator().contents())
|
trailing_comma(element, checker.locator().contents()).unwrap_or(values_end);
|
||||||
.unwrap_or(values_end);
|
let deletion_range = TextRange::new(previous_end, element_end);
|
||||||
let deletion_range = TextRange::new(previous_end, element_end);
|
if !checker
|
||||||
if !checker
|
.indexer()
|
||||||
.indexer()
|
.comment_ranges()
|
||||||
.comment_ranges()
|
.intersects(deletion_range)
|
||||||
.intersects(deletion_range)
|
{
|
||||||
{
|
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_deletion(deletion_range)));
|
||||||
diagnostic
|
|
||||||
.set_fix(Fix::unsafe_edit(Edit::range_deletion(deletion_range)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
|
@ -618,13 +603,11 @@ fn handle_single_name(checker: &mut Checker, expr: &Expr, value: &Expr) {
|
||||||
expr.range(),
|
expr.range(),
|
||||||
);
|
);
|
||||||
|
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
let node = value.clone();
|
||||||
let node = value.clone();
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
checker.generator().expr(&node),
|
||||||
checker.generator().expr(&node),
|
expr.range(),
|
||||||
expr.range(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ use ruff_source_file::Locator;
|
||||||
use ruff_text_size::TextRange;
|
use ruff_text_size::TextRange;
|
||||||
|
|
||||||
use crate::lex::docstring_detection::StateMachine;
|
use crate::lex::docstring_detection::StateMachine;
|
||||||
use crate::registry::AsRule;
|
|
||||||
use crate::settings::LinterSettings;
|
use crate::settings::LinterSettings;
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
|
@ -135,18 +135,16 @@ pub(crate) fn avoidable_escaped_quote(
|
||||||
&& !string_contents.contains(quotes_settings.inline_quotes.opposite().as_char())
|
&& !string_contents.contains(quotes_settings.inline_quotes.opposite().as_char())
|
||||||
{
|
{
|
||||||
let mut diagnostic = Diagnostic::new(AvoidableEscapedQuote, tok_range);
|
let mut diagnostic = Diagnostic::new(AvoidableEscapedQuote, tok_range);
|
||||||
if settings.rules.should_fix(diagnostic.kind.rule()) {
|
let fixed_contents = format!(
|
||||||
let fixed_contents = format!(
|
"{prefix}{quote}{value}{quote}",
|
||||||
"{prefix}{quote}{value}{quote}",
|
prefix = kind.as_str(),
|
||||||
prefix = kind.as_str(),
|
quote = quotes_settings.inline_quotes.opposite().as_char(),
|
||||||
quote = quotes_settings.inline_quotes.opposite().as_char(),
|
value = unescape_string(string_contents)
|
||||||
value = unescape_string(string_contents)
|
);
|
||||||
);
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
fixed_contents,
|
||||||
fixed_contents,
|
tok_range,
|
||||||
tok_range,
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
diagnostics.push(diagnostic);
|
diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -192,35 +190,33 @@ pub(crate) fn avoidable_escaped_quote(
|
||||||
AvoidableEscapedQuote,
|
AvoidableEscapedQuote,
|
||||||
TextRange::new(context.start_range.start(), tok_range.end()),
|
TextRange::new(context.start_range.start(), tok_range.end()),
|
||||||
);
|
);
|
||||||
if settings.rules.should_fix(diagnostic.kind.rule()) {
|
let fstring_start_edit = Edit::range_replacement(
|
||||||
let fstring_start_edit = Edit::range_replacement(
|
// No need for `r`/`R` as we don't perform the checks
|
||||||
// No need for `r`/`R` as we don't perform the checks
|
// for raw strings.
|
||||||
// for raw strings.
|
format!("f{}", quotes_settings.inline_quotes.opposite().as_char()),
|
||||||
format!("f{}", quotes_settings.inline_quotes.opposite().as_char()),
|
context.start_range,
|
||||||
context.start_range,
|
);
|
||||||
);
|
let fstring_middle_and_end_edits = context
|
||||||
let fstring_middle_and_end_edits = context
|
.middle_ranges_with_escapes
|
||||||
.middle_ranges_with_escapes
|
.iter()
|
||||||
.iter()
|
.map(|&range| {
|
||||||
.map(|&range| {
|
Edit::range_replacement(unescape_string(locator.slice(range)), range)
|
||||||
Edit::range_replacement(unescape_string(locator.slice(range)), range)
|
})
|
||||||
})
|
.chain(std::iter::once(
|
||||||
.chain(std::iter::once(
|
// `FStringEnd` edit
|
||||||
// `FStringEnd` edit
|
Edit::range_replacement(
|
||||||
Edit::range_replacement(
|
quotes_settings
|
||||||
quotes_settings
|
.inline_quotes
|
||||||
.inline_quotes
|
.opposite()
|
||||||
.opposite()
|
.as_char()
|
||||||
.as_char()
|
.to_string(),
|
||||||
.to_string(),
|
tok_range,
|
||||||
tok_range,
|
),
|
||||||
),
|
|
||||||
));
|
|
||||||
diagnostic.set_fix(Fix::safe_edits(
|
|
||||||
fstring_start_edit,
|
|
||||||
fstring_middle_and_end_edits,
|
|
||||||
));
|
));
|
||||||
}
|
diagnostic.set_fix(Fix::safe_edits(
|
||||||
|
fstring_start_edit,
|
||||||
|
fstring_middle_and_end_edits,
|
||||||
|
));
|
||||||
diagnostics.push(diagnostic);
|
diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
|
@ -7,7 +7,7 @@ use ruff_macros::{derive_message_formats, violation};
|
||||||
use ruff_source_file::Locator;
|
use ruff_source_file::Locator;
|
||||||
|
|
||||||
use crate::lex::docstring_detection::StateMachine;
|
use crate::lex::docstring_detection::StateMachine;
|
||||||
use crate::registry::Rule;
|
|
||||||
use crate::settings::LinterSettings;
|
use crate::settings::LinterSettings;
|
||||||
|
|
||||||
use super::super::settings::Quote;
|
use super::super::settings::Quote;
|
||||||
|
@ -230,21 +230,19 @@ fn docstring(locator: &Locator, range: TextRange, settings: &LinterSettings) ->
|
||||||
},
|
},
|
||||||
range,
|
range,
|
||||||
);
|
);
|
||||||
if settings.rules.should_fix(Rule::BadQuotesDocstring) {
|
let quote_count = if trivia.is_multiline { 3 } else { 1 };
|
||||||
let quote_count = if trivia.is_multiline { 3 } else { 1 };
|
let string_contents = &trivia.raw_text[quote_count..trivia.raw_text.len() - quote_count];
|
||||||
let string_contents = &trivia.raw_text[quote_count..trivia.raw_text.len() - quote_count];
|
let quote = good_docstring(quotes_settings.docstring_quotes).repeat(quote_count);
|
||||||
let quote = good_docstring(quotes_settings.docstring_quotes).repeat(quote_count);
|
let mut fixed_contents =
|
||||||
let mut fixed_contents =
|
String::with_capacity(trivia.prefix.len() + string_contents.len() + quote.len() * 2);
|
||||||
String::with_capacity(trivia.prefix.len() + string_contents.len() + quote.len() * 2);
|
fixed_contents.push_str(trivia.prefix);
|
||||||
fixed_contents.push_str(trivia.prefix);
|
fixed_contents.push_str("e);
|
||||||
fixed_contents.push_str("e);
|
fixed_contents.push_str(string_contents);
|
||||||
fixed_contents.push_str(string_contents);
|
fixed_contents.push_str("e);
|
||||||
fixed_contents.push_str("e);
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
fixed_contents,
|
||||||
fixed_contents,
|
range,
|
||||||
range,
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
Some(diagnostic)
|
Some(diagnostic)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -307,21 +305,19 @@ fn strings(
|
||||||
*range,
|
*range,
|
||||||
);
|
);
|
||||||
|
|
||||||
if settings.rules.should_fix(Rule::BadQuotesMultilineString) {
|
let string_contents = &trivia.raw_text[3..trivia.raw_text.len() - 3];
|
||||||
let string_contents = &trivia.raw_text[3..trivia.raw_text.len() - 3];
|
let quote = good_multiline(quotes_settings.multiline_quotes);
|
||||||
let quote = good_multiline(quotes_settings.multiline_quotes);
|
let mut fixed_contents = String::with_capacity(
|
||||||
let mut fixed_contents = String::with_capacity(
|
trivia.prefix.len() + string_contents.len() + quote.len() * 2,
|
||||||
trivia.prefix.len() + string_contents.len() + quote.len() * 2,
|
);
|
||||||
);
|
fixed_contents.push_str(trivia.prefix);
|
||||||
fixed_contents.push_str(trivia.prefix);
|
fixed_contents.push_str(quote);
|
||||||
fixed_contents.push_str(quote);
|
fixed_contents.push_str(string_contents);
|
||||||
fixed_contents.push_str(string_contents);
|
fixed_contents.push_str(quote);
|
||||||
fixed_contents.push_str(quote);
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
fixed_contents,
|
||||||
fixed_contents,
|
*range,
|
||||||
*range,
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
diagnostics.push(diagnostic);
|
diagnostics.push(diagnostic);
|
||||||
} else if trivia.last_quote_char != quotes_settings.inline_quotes.as_char()
|
} else if trivia.last_quote_char != quotes_settings.inline_quotes.as_char()
|
||||||
// If we're not using the preferred type, only allow use to avoid escapes.
|
// If we're not using the preferred type, only allow use to avoid escapes.
|
||||||
|
@ -333,20 +329,18 @@ fn strings(
|
||||||
},
|
},
|
||||||
*range,
|
*range,
|
||||||
);
|
);
|
||||||
if settings.rules.should_fix(Rule::BadQuotesInlineString) {
|
let quote = quotes_settings.inline_quotes.as_char();
|
||||||
let quote = quotes_settings.inline_quotes.as_char();
|
let string_contents = &trivia.raw_text[1..trivia.raw_text.len() - 1];
|
||||||
let string_contents = &trivia.raw_text[1..trivia.raw_text.len() - 1];
|
let mut fixed_contents =
|
||||||
let mut fixed_contents =
|
String::with_capacity(trivia.prefix.len() + string_contents.len() + 2);
|
||||||
String::with_capacity(trivia.prefix.len() + string_contents.len() + 2);
|
fixed_contents.push_str(trivia.prefix);
|
||||||
fixed_contents.push_str(trivia.prefix);
|
fixed_contents.push(quote);
|
||||||
fixed_contents.push(quote);
|
fixed_contents.push_str(string_contents);
|
||||||
fixed_contents.push_str(string_contents);
|
fixed_contents.push(quote);
|
||||||
fixed_contents.push(quote);
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
fixed_contents,
|
||||||
fixed_contents,
|
*range,
|
||||||
*range,
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
diagnostics.push(diagnostic);
|
diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@ use ruff_python_ast::{self as ast, Expr};
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for unnecessary parentheses on raised exceptions.
|
/// Checks for unnecessary parentheses on raised exceptions.
|
||||||
|
@ -74,26 +73,24 @@ pub(crate) fn unnecessary_paren_on_raise_exception(checker: &mut Checker, expr:
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut diagnostic = Diagnostic::new(UnnecessaryParenOnRaiseException, arguments.range());
|
let mut diagnostic = Diagnostic::new(UnnecessaryParenOnRaiseException, arguments.range());
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
// If the arguments are immediately followed by a `from`, insert whitespace to avoid
|
||||||
// If the arguments are immediately followed by a `from`, insert whitespace to avoid
|
// a syntax error, as in:
|
||||||
// a syntax error, as in:
|
// ```python
|
||||||
// ```python
|
// raise IndexError()from ZeroDivisionError
|
||||||
// raise IndexError()from ZeroDivisionError
|
// ```
|
||||||
// ```
|
if checker
|
||||||
if checker
|
.locator()
|
||||||
.locator()
|
.after(arguments.end())
|
||||||
.after(arguments.end())
|
.chars()
|
||||||
.chars()
|
.next()
|
||||||
.next()
|
.is_some_and(char::is_alphanumeric)
|
||||||
.is_some_and(char::is_alphanumeric)
|
{
|
||||||
{
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
" ".to_string(),
|
||||||
" ".to_string(),
|
arguments.range(),
|
||||||
arguments.range(),
|
)));
|
||||||
)));
|
} else {
|
||||||
} else {
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_deletion(arguments.range())));
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_deletion(arguments.range())));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -345,12 +345,10 @@ fn unnecessary_return_none(checker: &mut Checker, stack: &Stack) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let mut diagnostic = Diagnostic::new(UnnecessaryReturnNone, stmt.range);
|
let mut diagnostic = Diagnostic::new(UnnecessaryReturnNone, stmt.range);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
"return".to_string(),
|
||||||
"return".to_string(),
|
stmt.range(),
|
||||||
stmt.range(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -362,12 +360,10 @@ fn implicit_return_value(checker: &mut Checker, stack: &Stack) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let mut diagnostic = Diagnostic::new(ImplicitReturnValue, stmt.range);
|
let mut diagnostic = Diagnostic::new(ImplicitReturnValue, stmt.range);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
"return None".to_string(),
|
||||||
"return None".to_string(),
|
stmt.range,
|
||||||
stmt.range,
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -409,17 +405,15 @@ fn implicit_return(checker: &mut Checker, stmt: &Stmt) {
|
||||||
None | Some(ast::ElifElseClause { test: Some(_), .. })
|
None | Some(ast::ElifElseClause { test: Some(_), .. })
|
||||||
) {
|
) {
|
||||||
let mut diagnostic = Diagnostic::new(ImplicitReturn, stmt.range());
|
let mut diagnostic = Diagnostic::new(ImplicitReturn, stmt.range());
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
if let Some(indent) = indentation(checker.locator(), stmt) {
|
||||||
if let Some(indent) = indentation(checker.locator(), stmt) {
|
let mut content = String::new();
|
||||||
let mut content = String::new();
|
content.push_str(checker.stylist().line_ending().as_str());
|
||||||
content.push_str(checker.stylist().line_ending().as_str());
|
content.push_str(indent);
|
||||||
content.push_str(indent);
|
content.push_str("return None");
|
||||||
content.push_str("return None");
|
diagnostic.set_fix(Fix::unsafe_edit(Edit::insertion(
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::insertion(
|
content,
|
||||||
content,
|
end_of_last_statement(stmt, checker.locator()),
|
||||||
end_of_last_statement(stmt, checker.locator()),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
@ -431,17 +425,15 @@ fn implicit_return(checker: &mut Checker, stmt: &Stmt) {
|
||||||
implicit_return(checker, last_stmt);
|
implicit_return(checker, last_stmt);
|
||||||
} else {
|
} else {
|
||||||
let mut diagnostic = Diagnostic::new(ImplicitReturn, stmt.range());
|
let mut diagnostic = Diagnostic::new(ImplicitReturn, stmt.range());
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
if let Some(indent) = indentation(checker.locator(), stmt) {
|
||||||
if let Some(indent) = indentation(checker.locator(), stmt) {
|
let mut content = String::new();
|
||||||
let mut content = String::new();
|
content.push_str(checker.stylist().line_ending().as_str());
|
||||||
content.push_str(checker.stylist().line_ending().as_str());
|
content.push_str(indent);
|
||||||
content.push_str(indent);
|
content.push_str("return None");
|
||||||
content.push_str("return None");
|
diagnostic.set_fix(Fix::unsafe_edit(Edit::insertion(
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::insertion(
|
content,
|
||||||
content,
|
end_of_last_statement(stmt, checker.locator()),
|
||||||
end_of_last_statement(stmt, checker.locator()),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
@ -467,17 +459,15 @@ fn implicit_return(checker: &mut Checker, stmt: &Stmt) {
|
||||||
) => {}
|
) => {}
|
||||||
_ => {
|
_ => {
|
||||||
let mut diagnostic = Diagnostic::new(ImplicitReturn, stmt.range());
|
let mut diagnostic = Diagnostic::new(ImplicitReturn, stmt.range());
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
if let Some(indent) = indentation(checker.locator(), stmt) {
|
||||||
if let Some(indent) = indentation(checker.locator(), stmt) {
|
let mut content = String::new();
|
||||||
let mut content = String::new();
|
content.push_str(checker.stylist().line_ending().as_str());
|
||||||
content.push_str(checker.stylist().line_ending().as_str());
|
content.push_str(indent);
|
||||||
content.push_str(indent);
|
content.push_str("return None");
|
||||||
content.push_str("return None");
|
diagnostic.set_fix(Fix::unsafe_edit(Edit::insertion(
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::insertion(
|
content,
|
||||||
content,
|
end_of_last_statement(stmt, checker.locator()),
|
||||||
end_of_last_statement(stmt, checker.locator()),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
@ -529,47 +519,45 @@ fn unnecessary_assign(checker: &mut Checker, stack: &Stack) {
|
||||||
},
|
},
|
||||||
value.range(),
|
value.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.try_set_fix(|| {
|
||||||
diagnostic.try_set_fix(|| {
|
// Delete the `return` statement. There's no need to treat this as an isolated
|
||||||
// Delete the `return` statement. There's no need to treat this as an isolated
|
// edit, since we're editing the preceding statement, so no conflicting edit would
|
||||||
// edit, since we're editing the preceding statement, so no conflicting edit would
|
// be allowed to remove that preceding statement.
|
||||||
// be allowed to remove that preceding statement.
|
let delete_return =
|
||||||
let delete_return =
|
edits::delete_stmt(stmt, None, checker.locator(), checker.indexer());
|
||||||
edits::delete_stmt(stmt, None, checker.locator(), checker.indexer());
|
|
||||||
|
|
||||||
// Replace the `x = 1` statement with `return 1`.
|
// Replace the `x = 1` statement with `return 1`.
|
||||||
let content = checker.locator().slice(assign);
|
let content = checker.locator().slice(assign);
|
||||||
let equals_index = content
|
let equals_index = content
|
||||||
.find('=')
|
.find('=')
|
||||||
.ok_or(anyhow::anyhow!("expected '=' in assignment statement"))?;
|
.ok_or(anyhow::anyhow!("expected '=' in assignment statement"))?;
|
||||||
let after_equals = equals_index + 1;
|
let after_equals = equals_index + 1;
|
||||||
|
|
||||||
let replace_assign = Edit::range_replacement(
|
let replace_assign = Edit::range_replacement(
|
||||||
// If necessary, add whitespace after the `return` keyword.
|
// If necessary, add whitespace after the `return` keyword.
|
||||||
// Ex) Convert `x=y` to `return y` (instead of `returny`).
|
// Ex) Convert `x=y` to `return y` (instead of `returny`).
|
||||||
if content[after_equals..]
|
if content[after_equals..]
|
||||||
.chars()
|
.chars()
|
||||||
.next()
|
.next()
|
||||||
.is_some_and(is_python_whitespace)
|
.is_some_and(is_python_whitespace)
|
||||||
{
|
{
|
||||||
"return".to_string()
|
"return".to_string()
|
||||||
} else {
|
} else {
|
||||||
"return ".to_string()
|
"return ".to_string()
|
||||||
},
|
},
|
||||||
// Replace from the start of the assignment statement to the end of the equals
|
// Replace from the start of the assignment statement to the end of the equals
|
||||||
// sign.
|
// sign.
|
||||||
TextRange::new(
|
TextRange::new(
|
||||||
assign.start(),
|
assign.start(),
|
||||||
assign
|
assign
|
||||||
.range()
|
.range()
|
||||||
.start()
|
.start()
|
||||||
.add(TextSize::try_from(after_equals)?),
|
.add(TextSize::try_from(after_equals)?),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(Fix::unsafe_edits(replace_assign, [delete_return]))
|
Ok(Fix::unsafe_edits(replace_assign, [delete_return]))
|
||||||
});
|
});
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,6 @@ use ruff_python_codegen::Generator;
|
||||||
use ruff_python_semantic::SemanticModel;
|
use ruff_python_semantic::SemanticModel;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for multiple `isinstance` calls on the same target.
|
/// Checks for multiple `isinstance` calls on the same target.
|
||||||
|
@ -394,78 +393,76 @@ pub(crate) fn duplicate_isinstance_call(checker: &mut Checker, expr: &Expr) {
|
||||||
},
|
},
|
||||||
expr.range(),
|
expr.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
if !contains_effect(target, |id| checker.semantic().is_builtin(id)) {
|
||||||
if !contains_effect(target, |id| checker.semantic().is_builtin(id)) {
|
// Grab the types used in each duplicate `isinstance` call (e.g., `int` and `str`
|
||||||
// Grab the types used in each duplicate `isinstance` call (e.g., `int` and `str`
|
// in `isinstance(obj, int) or isinstance(obj, str)`).
|
||||||
// in `isinstance(obj, int) or isinstance(obj, str)`).
|
let types: Vec<&Expr> = indices
|
||||||
let types: Vec<&Expr> = indices
|
.iter()
|
||||||
|
.map(|index| &values[*index])
|
||||||
|
.map(|expr| {
|
||||||
|
let Expr::Call(ast::ExprCall {
|
||||||
|
arguments: Arguments { args, .. },
|
||||||
|
..
|
||||||
|
}) = expr
|
||||||
|
else {
|
||||||
|
unreachable!("Indices should only contain `isinstance` calls")
|
||||||
|
};
|
||||||
|
args.get(1).expect("`isinstance` should have two arguments")
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// Generate a single `isinstance` call.
|
||||||
|
let node = ast::ExprTuple {
|
||||||
|
// Flatten all the types used across the `isinstance` calls.
|
||||||
|
elts: types
|
||||||
.iter()
|
.iter()
|
||||||
.map(|index| &values[*index])
|
.flat_map(|value| {
|
||||||
.map(|expr| {
|
if let Expr::Tuple(ast::ExprTuple { elts, .. }) = value {
|
||||||
let Expr::Call(ast::ExprCall {
|
Left(elts.iter())
|
||||||
arguments: Arguments { args, .. },
|
} else {
|
||||||
..
|
Right(iter::once(*value))
|
||||||
}) = expr
|
}
|
||||||
else {
|
|
||||||
unreachable!("Indices should only contain `isinstance` calls")
|
|
||||||
};
|
|
||||||
args.get(1).expect("`isinstance` should have two arguments")
|
|
||||||
})
|
})
|
||||||
.collect();
|
.map(Clone::clone)
|
||||||
|
.collect(),
|
||||||
|
ctx: ExprContext::Load,
|
||||||
|
range: TextRange::default(),
|
||||||
|
};
|
||||||
|
let node1 = ast::ExprName {
|
||||||
|
id: "isinstance".into(),
|
||||||
|
ctx: ExprContext::Load,
|
||||||
|
range: TextRange::default(),
|
||||||
|
};
|
||||||
|
let node2 = ast::ExprCall {
|
||||||
|
func: Box::new(node1.into()),
|
||||||
|
arguments: Arguments {
|
||||||
|
args: vec![target.clone(), node.into()],
|
||||||
|
keywords: vec![],
|
||||||
|
range: TextRange::default(),
|
||||||
|
},
|
||||||
|
range: TextRange::default(),
|
||||||
|
};
|
||||||
|
let call = node2.into();
|
||||||
|
|
||||||
// Generate a single `isinstance` call.
|
// Generate the combined `BoolOp`.
|
||||||
let node = ast::ExprTuple {
|
let [first, .., last] = indices.as_slice() else {
|
||||||
// Flatten all the types used across the `isinstance` calls.
|
unreachable!("Indices should have at least two elements")
|
||||||
elts: types
|
};
|
||||||
.iter()
|
let before = values.iter().take(*first).cloned();
|
||||||
.flat_map(|value| {
|
let after = values.iter().skip(last + 1).cloned();
|
||||||
if let Expr::Tuple(ast::ExprTuple { elts, .. }) = value {
|
let node = ast::ExprBoolOp {
|
||||||
Left(elts.iter())
|
op: BoolOp::Or,
|
||||||
} else {
|
values: before.chain(iter::once(call)).chain(after).collect(),
|
||||||
Right(iter::once(*value))
|
range: TextRange::default(),
|
||||||
}
|
};
|
||||||
})
|
let bool_op = node.into();
|
||||||
.map(Clone::clone)
|
|
||||||
.collect(),
|
|
||||||
ctx: ExprContext::Load,
|
|
||||||
range: TextRange::default(),
|
|
||||||
};
|
|
||||||
let node1 = ast::ExprName {
|
|
||||||
id: "isinstance".into(),
|
|
||||||
ctx: ExprContext::Load,
|
|
||||||
range: TextRange::default(),
|
|
||||||
};
|
|
||||||
let node2 = ast::ExprCall {
|
|
||||||
func: Box::new(node1.into()),
|
|
||||||
arguments: Arguments {
|
|
||||||
args: vec![target.clone(), node.into()],
|
|
||||||
keywords: vec![],
|
|
||||||
range: TextRange::default(),
|
|
||||||
},
|
|
||||||
range: TextRange::default(),
|
|
||||||
};
|
|
||||||
let call = node2.into();
|
|
||||||
|
|
||||||
// Generate the combined `BoolOp`.
|
// Populate the `Fix`. Replace the _entire_ `BoolOp`. Note that if we have
|
||||||
let [first, .., last] = indices.as_slice() else {
|
// multiple duplicates, the fixes will conflict.
|
||||||
unreachable!("Indices should have at least two elements")
|
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
||||||
};
|
checker.generator().expr(&bool_op),
|
||||||
let before = values.iter().take(*first).cloned();
|
expr.range(),
|
||||||
let after = values.iter().skip(last + 1).cloned();
|
)));
|
||||||
let node = ast::ExprBoolOp {
|
|
||||||
op: BoolOp::Or,
|
|
||||||
values: before.chain(iter::once(call)).chain(after).collect(),
|
|
||||||
range: TextRange::default(),
|
|
||||||
};
|
|
||||||
let bool_op = node.into();
|
|
||||||
|
|
||||||
// Populate the `Fix`. Replace the _entire_ `BoolOp`. Note that if we have
|
|
||||||
// multiple duplicates, the fixes will conflict.
|
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
|
||||||
checker.generator().expr(&bool_op),
|
|
||||||
expr.range(),
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
@ -564,29 +561,27 @@ pub(crate) fn compare_with_tuple(checker: &mut Checker, expr: &Expr) {
|
||||||
},
|
},
|
||||||
expr.range(),
|
expr.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
let unmatched: Vec<Expr> = values
|
||||||
let unmatched: Vec<Expr> = values
|
.iter()
|
||||||
.iter()
|
.enumerate()
|
||||||
.enumerate()
|
.filter(|(index, _)| !indices.contains(index))
|
||||||
.filter(|(index, _)| !indices.contains(index))
|
.map(|(_, elt)| elt.clone())
|
||||||
.map(|(_, elt)| elt.clone())
|
.collect();
|
||||||
.collect();
|
let in_expr = if unmatched.is_empty() {
|
||||||
let in_expr = if unmatched.is_empty() {
|
in_expr
|
||||||
in_expr
|
} else {
|
||||||
} else {
|
// Wrap in a `x in (a, b) or ...` boolean operation.
|
||||||
// Wrap in a `x in (a, b) or ...` boolean operation.
|
let node = ast::ExprBoolOp {
|
||||||
let node = ast::ExprBoolOp {
|
op: BoolOp::Or,
|
||||||
op: BoolOp::Or,
|
values: iter::once(in_expr).chain(unmatched).collect(),
|
||||||
values: iter::once(in_expr).chain(unmatched).collect(),
|
range: TextRange::default(),
|
||||||
range: TextRange::default(),
|
|
||||||
};
|
|
||||||
node.into()
|
|
||||||
};
|
};
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
node.into()
|
||||||
checker.generator().expr(&in_expr),
|
};
|
||||||
expr.range(),
|
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
||||||
)));
|
checker.generator().expr(&in_expr),
|
||||||
}
|
expr.range(),
|
||||||
|
)));
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -638,12 +633,10 @@ pub(crate) fn expr_and_not_expr(checker: &mut Checker, expr: &Expr) {
|
||||||
},
|
},
|
||||||
expr.range(),
|
expr.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
"False".to_string(),
|
||||||
"False".to_string(),
|
expr.range(),
|
||||||
expr.range(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -697,12 +690,10 @@ pub(crate) fn expr_or_not_expr(checker: &mut Checker, expr: &Expr) {
|
||||||
},
|
},
|
||||||
expr.range(),
|
expr.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
"True".to_string(),
|
||||||
"True".to_string(),
|
expr.range(),
|
||||||
expr.range(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -850,9 +841,7 @@ pub(crate) fn expr_or_true(checker: &mut Checker, expr: &Expr) {
|
||||||
},
|
},
|
||||||
edit.range(),
|
edit.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.set_fix(Fix::unsafe_edit(edit));
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(edit));
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -867,9 +856,7 @@ pub(crate) fn expr_and_false(checker: &mut Checker, expr: &Expr) {
|
||||||
},
|
},
|
||||||
edit.range(),
|
edit.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.set_fix(Fix::unsafe_edit(edit));
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(edit));
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ use ruff_macros::{derive_message_formats, violation};
|
||||||
use ruff_python_ast::helpers::is_const_none;
|
use ruff_python_ast::helpers::is_const_none;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Check for environment variables that are not capitalized.
|
/// Check for environment variables that are not capitalized.
|
||||||
|
@ -207,21 +206,19 @@ fn check_os_environ_subscript(checker: &mut Checker, expr: &Expr) {
|
||||||
},
|
},
|
||||||
slice.range(),
|
slice.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
let node = ast::ExprConstant {
|
||||||
let node = ast::ExprConstant {
|
value: ast::Constant::Str(ast::StringConstant {
|
||||||
value: ast::Constant::Str(ast::StringConstant {
|
value: capital_env_var,
|
||||||
value: capital_env_var,
|
unicode: *unicode,
|
||||||
unicode: *unicode,
|
implicit_concatenated: false,
|
||||||
implicit_concatenated: false,
|
}),
|
||||||
}),
|
range: TextRange::default(),
|
||||||
range: TextRange::default(),
|
};
|
||||||
};
|
let new_env_var = node.into();
|
||||||
let new_env_var = node.into();
|
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
checker.generator().expr(&new_env_var),
|
||||||
checker.generator().expr(&new_env_var),
|
slice.range(),
|
||||||
slice.range(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,11 +272,9 @@ pub(crate) fn dict_get_with_none_default(checker: &mut Checker, expr: &Expr) {
|
||||||
expr.range(),
|
expr.range(),
|
||||||
);
|
);
|
||||||
|
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
expected,
|
||||||
expected,
|
expr.range(),
|
||||||
expr.range(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ use ruff_python_ast::helpers::{is_const_false, is_const_true};
|
||||||
use ruff_python_ast::parenthesize::parenthesized_range;
|
use ruff_python_ast::parenthesize::parenthesized_range;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for `if` expressions that can be replaced with `bool()` calls.
|
/// Checks for `if` expressions that can be replaced with `bool()` calls.
|
||||||
|
@ -157,48 +156,46 @@ pub(crate) fn if_expr_with_true_false(
|
||||||
},
|
},
|
||||||
expr.range(),
|
expr.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
if test.is_compare_expr() {
|
||||||
if test.is_compare_expr() {
|
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
checker
|
||||||
checker
|
.locator()
|
||||||
.locator()
|
.slice(
|
||||||
.slice(
|
parenthesized_range(
|
||||||
parenthesized_range(
|
test.into(),
|
||||||
test.into(),
|
expr.into(),
|
||||||
expr.into(),
|
checker.indexer().comment_ranges(),
|
||||||
checker.indexer().comment_ranges(),
|
checker.locator().contents(),
|
||||||
checker.locator().contents(),
|
|
||||||
)
|
|
||||||
.unwrap_or(test.range()),
|
|
||||||
)
|
)
|
||||||
.to_string(),
|
.unwrap_or(test.range()),
|
||||||
expr.range(),
|
)
|
||||||
)));
|
.to_string(),
|
||||||
} else if checker.semantic().is_builtin("bool") {
|
expr.range(),
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
)));
|
||||||
checker.generator().expr(
|
} else if checker.semantic().is_builtin("bool") {
|
||||||
&ast::ExprCall {
|
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
||||||
func: Box::new(
|
checker.generator().expr(
|
||||||
ast::ExprName {
|
&ast::ExprCall {
|
||||||
id: "bool".into(),
|
func: Box::new(
|
||||||
ctx: ExprContext::Load,
|
ast::ExprName {
|
||||||
range: TextRange::default(),
|
id: "bool".into(),
|
||||||
}
|
ctx: ExprContext::Load,
|
||||||
.into(),
|
|
||||||
),
|
|
||||||
arguments: Arguments {
|
|
||||||
args: vec![test.clone()],
|
|
||||||
keywords: vec![],
|
|
||||||
range: TextRange::default(),
|
range: TextRange::default(),
|
||||||
},
|
}
|
||||||
|
.into(),
|
||||||
|
),
|
||||||
|
arguments: Arguments {
|
||||||
|
args: vec![test.clone()],
|
||||||
|
keywords: vec![],
|
||||||
range: TextRange::default(),
|
range: TextRange::default(),
|
||||||
}
|
},
|
||||||
.into(),
|
range: TextRange::default(),
|
||||||
),
|
}
|
||||||
expr.range(),
|
.into(),
|
||||||
)));
|
),
|
||||||
};
|
expr.range(),
|
||||||
}
|
)));
|
||||||
|
};
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,19 +212,17 @@ pub(crate) fn if_expr_with_false_true(
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut diagnostic = Diagnostic::new(IfExprWithFalseTrue, expr.range());
|
let mut diagnostic = Diagnostic::new(IfExprWithFalseTrue, expr.range());
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
checker.generator().expr(
|
||||||
checker.generator().expr(
|
&ast::ExprUnaryOp {
|
||||||
&ast::ExprUnaryOp {
|
op: UnaryOp::Not,
|
||||||
op: UnaryOp::Not,
|
operand: Box::new(test.clone()),
|
||||||
operand: Box::new(test.clone()),
|
range: TextRange::default(),
|
||||||
range: TextRange::default(),
|
}
|
||||||
}
|
.into(),
|
||||||
.into(),
|
),
|
||||||
),
|
expr.range(),
|
||||||
expr.range(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -269,20 +264,18 @@ pub(crate) fn twisted_arms_in_ifexpr(
|
||||||
},
|
},
|
||||||
expr.range(),
|
expr.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
let node = body.clone();
|
||||||
let node = body.clone();
|
let node1 = orelse.clone();
|
||||||
let node1 = orelse.clone();
|
let node2 = orelse.clone();
|
||||||
let node2 = orelse.clone();
|
let node3 = ast::ExprIfExp {
|
||||||
let node3 = ast::ExprIfExp {
|
test: Box::new(node2),
|
||||||
test: Box::new(node2),
|
body: Box::new(node1),
|
||||||
body: Box::new(node1),
|
orelse: Box::new(node),
|
||||||
orelse: Box::new(node),
|
range: TextRange::default(),
|
||||||
range: TextRange::default(),
|
};
|
||||||
};
|
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
checker.generator().expr(&node3.into()),
|
||||||
checker.generator().expr(&node3.into()),
|
expr.range(),
|
||||||
expr.range(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ use ruff_macros::{derive_message_formats, violation};
|
||||||
use ruff_python_semantic::ScopeKind;
|
use ruff_python_semantic::ScopeKind;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for negated `==` operators.
|
/// Checks for negated `==` operators.
|
||||||
|
@ -175,18 +174,16 @@ pub(crate) fn negation_with_equal_op(
|
||||||
},
|
},
|
||||||
expr.range(),
|
expr.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
let node = ast::ExprCompare {
|
||||||
let node = ast::ExprCompare {
|
left: left.clone(),
|
||||||
left: left.clone(),
|
ops: vec![CmpOp::NotEq],
|
||||||
ops: vec![CmpOp::NotEq],
|
comparators: comparators.clone(),
|
||||||
comparators: comparators.clone(),
|
range: TextRange::default(),
|
||||||
range: TextRange::default(),
|
};
|
||||||
};
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
checker.generator().expr(&node.into()),
|
||||||
checker.generator().expr(&node.into()),
|
expr.range(),
|
||||||
expr.range(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,18 +229,16 @@ pub(crate) fn negation_with_not_equal_op(
|
||||||
},
|
},
|
||||||
expr.range(),
|
expr.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
let node = ast::ExprCompare {
|
||||||
let node = ast::ExprCompare {
|
left: left.clone(),
|
||||||
left: left.clone(),
|
ops: vec![CmpOp::Eq],
|
||||||
ops: vec![CmpOp::Eq],
|
comparators: comparators.clone(),
|
||||||
comparators: comparators.clone(),
|
range: TextRange::default(),
|
||||||
range: TextRange::default(),
|
};
|
||||||
};
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
checker.generator().expr(&node.into()),
|
||||||
checker.generator().expr(&node.into()),
|
expr.range(),
|
||||||
expr.range(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,32 +265,30 @@ pub(crate) fn double_negation(checker: &mut Checker, expr: &Expr, op: UnaryOp, o
|
||||||
},
|
},
|
||||||
expr.range(),
|
expr.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
if checker.semantic().in_boolean_test() {
|
||||||
if checker.semantic().in_boolean_test() {
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
checker.locator().slice(operand.as_ref()).to_string(),
|
||||||
checker.locator().slice(operand.as_ref()).to_string(),
|
expr.range(),
|
||||||
expr.range(),
|
)));
|
||||||
)));
|
} else if checker.semantic().is_builtin("bool") {
|
||||||
} else if checker.semantic().is_builtin("bool") {
|
let node = ast::ExprName {
|
||||||
let node = ast::ExprName {
|
id: "bool".into(),
|
||||||
id: "bool".into(),
|
ctx: ExprContext::Load,
|
||||||
ctx: ExprContext::Load,
|
range: TextRange::default(),
|
||||||
range: TextRange::default(),
|
|
||||||
};
|
|
||||||
let node1 = ast::ExprCall {
|
|
||||||
func: Box::new(node.into()),
|
|
||||||
arguments: Arguments {
|
|
||||||
args: vec![*operand.clone()],
|
|
||||||
keywords: vec![],
|
|
||||||
range: TextRange::default(),
|
|
||||||
},
|
|
||||||
range: TextRange::default(),
|
|
||||||
};
|
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
|
||||||
checker.generator().expr(&node1.into()),
|
|
||||||
expr.range(),
|
|
||||||
)));
|
|
||||||
};
|
};
|
||||||
}
|
let node1 = ast::ExprCall {
|
||||||
|
func: Box::new(node.into()),
|
||||||
|
arguments: Arguments {
|
||||||
|
args: vec![*operand.clone()],
|
||||||
|
keywords: vec![],
|
||||||
|
range: TextRange::default(),
|
||||||
|
},
|
||||||
|
range: TextRange::default(),
|
||||||
|
};
|
||||||
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
|
checker.generator().expr(&node1.into()),
|
||||||
|
expr.range(),
|
||||||
|
)));
|
||||||
|
};
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ use ruff_text_size::{Ranged, TextRange};
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::fix::edits::fits;
|
use crate::fix::edits::fits;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
use super::fix_with;
|
use super::fix_with;
|
||||||
|
|
||||||
|
@ -124,32 +123,30 @@ pub(crate) fn multiple_with_statements(
|
||||||
MultipleWithStatements,
|
MultipleWithStatements,
|
||||||
TextRange::new(with_stmt.start(), colon.end()),
|
TextRange::new(with_stmt.start(), colon.end()),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
if !checker
|
||||||
if !checker
|
.indexer()
|
||||||
.indexer()
|
.comment_ranges()
|
||||||
.comment_ranges()
|
.intersects(TextRange::new(with_stmt.start(), with_stmt.body[0].start()))
|
||||||
.intersects(TextRange::new(with_stmt.start(), with_stmt.body[0].start()))
|
{
|
||||||
{
|
match fix_with::fix_multiple_with_statements(
|
||||||
match fix_with::fix_multiple_with_statements(
|
checker.locator(),
|
||||||
checker.locator(),
|
checker.stylist(),
|
||||||
checker.stylist(),
|
with_stmt,
|
||||||
with_stmt,
|
) {
|
||||||
) {
|
Ok(edit) => {
|
||||||
Ok(edit) => {
|
if edit.content().map_or(true, |content| {
|
||||||
if edit.content().map_or(true, |content| {
|
fits(
|
||||||
fits(
|
content,
|
||||||
content,
|
with_stmt.into(),
|
||||||
with_stmt.into(),
|
checker.locator(),
|
||||||
checker.locator(),
|
checker.settings.line_length,
|
||||||
checker.settings.line_length,
|
checker.settings.tab_size,
|
||||||
checker.settings.tab_size,
|
)
|
||||||
)
|
}) {
|
||||||
}) {
|
diagnostic.set_fix(Fix::unsafe_edit(edit));
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(edit));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Err(err) => error!("Failed to fix nested with: {err}"),
|
|
||||||
}
|
}
|
||||||
|
Err(err) => error!("Failed to fix nested with: {err}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
|
|
|
@ -18,7 +18,6 @@ use crate::cst::helpers::space;
|
||||||
use crate::cst::matchers::{match_function_def, match_if, match_indented_block, match_statement};
|
use crate::cst::matchers::{match_function_def, match_if, match_indented_block, match_statement};
|
||||||
use crate::fix::codemods::CodegenStylist;
|
use crate::fix::codemods::CodegenStylist;
|
||||||
use crate::fix::edits::fits;
|
use crate::fix::edits::fits;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for nested `if` statements that can be collapsed into a single `if`
|
/// Checks for nested `if` statements that can be collapsed into a single `if`
|
||||||
|
@ -101,33 +100,31 @@ pub(crate) fn nested_if_statements(
|
||||||
CollapsibleIf,
|
CollapsibleIf,
|
||||||
TextRange::new(nested_if.start(), colon.end()),
|
TextRange::new(nested_if.start(), colon.end()),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
// The fixer preserves comments in the nested body, but removes comments between
|
||||||
// The fixer preserves comments in the nested body, but removes comments between
|
// the outer and inner if statements.
|
||||||
// the outer and inner if statements.
|
if !checker
|
||||||
if !checker
|
.indexer()
|
||||||
.indexer()
|
.comment_ranges()
|
||||||
.comment_ranges()
|
.intersects(TextRange::new(
|
||||||
.intersects(TextRange::new(
|
nested_if.start(),
|
||||||
nested_if.start(),
|
nested_if.body()[0].start(),
|
||||||
nested_if.body()[0].start(),
|
))
|
||||||
))
|
{
|
||||||
{
|
match collapse_nested_if(checker.locator(), checker.stylist(), nested_if) {
|
||||||
match collapse_nested_if(checker.locator(), checker.stylist(), nested_if) {
|
Ok(edit) => {
|
||||||
Ok(edit) => {
|
if edit.content().map_or(true, |content| {
|
||||||
if edit.content().map_or(true, |content| {
|
fits(
|
||||||
fits(
|
content,
|
||||||
content,
|
(&nested_if).into(),
|
||||||
(&nested_if).into(),
|
checker.locator(),
|
||||||
checker.locator(),
|
checker.settings.line_length,
|
||||||
checker.settings.line_length,
|
checker.settings.tab_size,
|
||||||
checker.settings.tab_size,
|
)
|
||||||
)
|
}) {
|
||||||
}) {
|
diagnostic.set_fix(Fix::unsafe_edit(edit));
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(edit));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Err(err) => error!("Failed to fix nested if: {err}"),
|
|
||||||
}
|
}
|
||||||
|
Err(err) => error!("Failed to fix nested if: {err}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
|
|
|
@ -9,7 +9,6 @@ use ruff_text_size::{Ranged, TextRange};
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::fix::edits::fits;
|
use crate::fix::edits::fits;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for `if` statements that can be replaced with `dict.get` calls.
|
/// Checks for `if` statements that can be replaced with `dict.get` calls.
|
||||||
|
@ -184,13 +183,11 @@ pub(crate) fn use_dict_get_with_default(checker: &mut Checker, stmt_if: &ast::St
|
||||||
},
|
},
|
||||||
stmt_if.range(),
|
stmt_if.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
if !checker.indexer().has_comments(stmt_if, checker.locator()) {
|
||||||
if !checker.indexer().has_comments(stmt_if, checker.locator()) {
|
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
contents,
|
||||||
contents,
|
stmt_if.range(),
|
||||||
stmt_if.range(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ use ruff_text_size::{Ranged, TextRange};
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::fix::edits::fits;
|
use crate::fix::edits::fits;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Check for `if`-`else`-blocks that can be replaced with a ternary operator.
|
/// Check for `if`-`else`-blocks that can be replaced with a ternary operator.
|
||||||
|
@ -143,13 +142,11 @@ pub(crate) fn use_ternary_operator(checker: &mut Checker, stmt: &Stmt) {
|
||||||
},
|
},
|
||||||
stmt.range(),
|
stmt.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
if !checker.indexer().has_comments(stmt, checker.locator()) {
|
||||||
if !checker.indexer().has_comments(stmt, checker.locator()) {
|
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
contents,
|
||||||
contents,
|
stmt.range(),
|
||||||
stmt.range(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ use ruff_python_trivia::{SimpleTokenKind, SimpleTokenizer};
|
||||||
use ruff_text_size::{Ranged, TextRange};
|
use ruff_text_size::{Ranged, TextRange};
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for key-existence checks against `dict.keys()` calls.
|
/// Checks for key-existence checks against `dict.keys()` calls.
|
||||||
|
@ -109,32 +108,30 @@ fn key_in_dict(
|
||||||
},
|
},
|
||||||
TextRange::new(left_range.start(), right_range.end()),
|
TextRange::new(left_range.start(), right_range.end()),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
// Delete from the start of the dot to the end of the expression.
|
||||||
// Delete from the start of the dot to the end of the expression.
|
if let Some(dot) = SimpleTokenizer::starts_at(value.end(), checker.locator().contents())
|
||||||
if let Some(dot) = SimpleTokenizer::starts_at(value.end(), checker.locator().contents())
|
.skip_trivia()
|
||||||
.skip_trivia()
|
.find(|token| token.kind == SimpleTokenKind::Dot)
|
||||||
.find(|token| token.kind == SimpleTokenKind::Dot)
|
{
|
||||||
|
// If the `.keys()` is followed by (e.g.) a keyword, we need to insert a space,
|
||||||
|
// since we're removing parentheses, which could lead to invalid syntax, as in:
|
||||||
|
// ```python
|
||||||
|
// if key in foo.keys()and bar:
|
||||||
|
// ```
|
||||||
|
let range = TextRange::new(dot.start(), right.end());
|
||||||
|
if checker
|
||||||
|
.locator()
|
||||||
|
.after(range.end())
|
||||||
|
.chars()
|
||||||
|
.next()
|
||||||
|
.is_some_and(|char| char.is_ascii_alphabetic())
|
||||||
{
|
{
|
||||||
// If the `.keys()` is followed by (e.g.) a keyword, we need to insert a space,
|
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
||||||
// since we're removing parentheses, which could lead to invalid syntax, as in:
|
" ".to_string(),
|
||||||
// ```python
|
range,
|
||||||
// if key in foo.keys()and bar:
|
)));
|
||||||
// ```
|
} else {
|
||||||
let range = TextRange::new(dot.start(), right.end());
|
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_deletion(range)));
|
||||||
if checker
|
|
||||||
.locator()
|
|
||||||
.after(range.end())
|
|
||||||
.chars()
|
|
||||||
.next()
|
|
||||||
.is_some_and(|char| char.is_ascii_alphabetic())
|
|
||||||
{
|
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
|
||||||
" ".to_string(),
|
|
||||||
range,
|
|
||||||
)));
|
|
||||||
} else {
|
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_deletion(range)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
|
|
|
@ -4,7 +4,6 @@ use ruff_python_ast::{self as ast, Arguments, Constant, ElifElseClause, Expr, Ex
|
||||||
use ruff_text_size::{Ranged, TextRange};
|
use ruff_text_size::{Ranged, TextRange};
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for `if` statements that can be replaced with `bool`.
|
/// Checks for `if` statements that can be replaced with `bool`.
|
||||||
|
@ -100,49 +99,47 @@ pub(crate) fn needless_bool(checker: &mut Checker, stmt: &Stmt) {
|
||||||
|
|
||||||
let condition = checker.generator().expr(if_test);
|
let condition = checker.generator().expr(if_test);
|
||||||
let mut diagnostic = Diagnostic::new(NeedlessBool { condition }, range);
|
let mut diagnostic = Diagnostic::new(NeedlessBool { condition }, range);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
if matches!(if_return, Bool::True)
|
||||||
if matches!(if_return, Bool::True)
|
&& matches!(else_return, Bool::False)
|
||||||
&& matches!(else_return, Bool::False)
|
&& !checker.indexer().has_comments(&range, checker.locator())
|
||||||
&& !checker.indexer().has_comments(&range, checker.locator())
|
&& (if_test.is_compare_expr() || checker.semantic().is_builtin("bool"))
|
||||||
&& (if_test.is_compare_expr() || checker.semantic().is_builtin("bool"))
|
{
|
||||||
{
|
if if_test.is_compare_expr() {
|
||||||
if if_test.is_compare_expr() {
|
// If the condition is a comparison, we can replace it with the condition.
|
||||||
// If the condition is a comparison, we can replace it with the condition.
|
let node = ast::StmtReturn {
|
||||||
let node = ast::StmtReturn {
|
value: Some(Box::new(if_test.clone())),
|
||||||
value: Some(Box::new(if_test.clone())),
|
range: TextRange::default(),
|
||||||
range: TextRange::default(),
|
|
||||||
};
|
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
|
||||||
checker.generator().stmt(&node.into()),
|
|
||||||
range,
|
|
||||||
)));
|
|
||||||
} else {
|
|
||||||
// Otherwise, we need to wrap the condition in a call to `bool`. (We've already
|
|
||||||
// verified, above, that `bool` is a builtin.)
|
|
||||||
let node = ast::ExprName {
|
|
||||||
id: "bool".into(),
|
|
||||||
ctx: ExprContext::Load,
|
|
||||||
range: TextRange::default(),
|
|
||||||
};
|
|
||||||
let node1 = ast::ExprCall {
|
|
||||||
func: Box::new(node.into()),
|
|
||||||
arguments: Arguments {
|
|
||||||
args: vec![if_test.clone()],
|
|
||||||
keywords: vec![],
|
|
||||||
range: TextRange::default(),
|
|
||||||
},
|
|
||||||
range: TextRange::default(),
|
|
||||||
};
|
|
||||||
let node2 = ast::StmtReturn {
|
|
||||||
value: Some(Box::new(node1.into())),
|
|
||||||
range: TextRange::default(),
|
|
||||||
};
|
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
|
||||||
checker.generator().stmt(&node2.into()),
|
|
||||||
range,
|
|
||||||
)));
|
|
||||||
};
|
};
|
||||||
}
|
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
||||||
|
checker.generator().stmt(&node.into()),
|
||||||
|
range,
|
||||||
|
)));
|
||||||
|
} else {
|
||||||
|
// Otherwise, we need to wrap the condition in a call to `bool`. (We've already
|
||||||
|
// verified, above, that `bool` is a builtin.)
|
||||||
|
let node = ast::ExprName {
|
||||||
|
id: "bool".into(),
|
||||||
|
ctx: ExprContext::Load,
|
||||||
|
range: TextRange::default(),
|
||||||
|
};
|
||||||
|
let node1 = ast::ExprCall {
|
||||||
|
func: Box::new(node.into()),
|
||||||
|
arguments: Arguments {
|
||||||
|
args: vec![if_test.clone()],
|
||||||
|
keywords: vec![],
|
||||||
|
range: TextRange::default(),
|
||||||
|
},
|
||||||
|
range: TextRange::default(),
|
||||||
|
};
|
||||||
|
let node2 = ast::StmtReturn {
|
||||||
|
value: Some(Box::new(node1.into())),
|
||||||
|
range: TextRange::default(),
|
||||||
|
};
|
||||||
|
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
||||||
|
checker.generator().stmt(&node2.into()),
|
||||||
|
range,
|
||||||
|
)));
|
||||||
|
};
|
||||||
}
|
}
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@ use ruff_text_size::{Ranged, TextRange};
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::fix::edits::fits;
|
use crate::fix::edits::fits;
|
||||||
use crate::line_width::LineWidthBuilder;
|
use crate::line_width::LineWidthBuilder;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for `for` loops that can be replaced with a builtin function, like
|
/// Checks for `for` loops that can be replaced with a builtin function, like
|
||||||
|
@ -114,7 +113,7 @@ pub(crate) fn convert_for_loop_to_any_all(checker: &mut Checker, stmt: &Stmt) {
|
||||||
},
|
},
|
||||||
TextRange::new(stmt.start(), terminal.stmt.end()),
|
TextRange::new(stmt.start(), terminal.stmt.end()),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) && checker.semantic().is_builtin("any") {
|
if checker.semantic().is_builtin("any") {
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::replacement(
|
diagnostic.set_fix(Fix::unsafe_edit(Edit::replacement(
|
||||||
contents,
|
contents,
|
||||||
stmt.start(),
|
stmt.start(),
|
||||||
|
@ -200,7 +199,7 @@ pub(crate) fn convert_for_loop_to_any_all(checker: &mut Checker, stmt: &Stmt) {
|
||||||
},
|
},
|
||||||
TextRange::new(stmt.start(), terminal.stmt.end()),
|
TextRange::new(stmt.start(), terminal.stmt.end()),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) && checker.semantic().is_builtin("all") {
|
if checker.semantic().is_builtin("all") {
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::replacement(
|
diagnostic.set_fix(Fix::unsafe_edit(Edit::replacement(
|
||||||
contents,
|
contents,
|
||||||
stmt.start(),
|
stmt.start(),
|
||||||
|
|
|
@ -8,7 +8,6 @@ use ruff_text_size::{TextLen, TextRange};
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::importer::ImportRequest;
|
use crate::importer::ImportRequest;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for `try`-`except`-`pass` blocks that can be replaced with the
|
/// Checks for `try`-`except`-`pass` blocks that can be replaced with the
|
||||||
|
@ -132,28 +131,25 @@ pub(crate) fn suppressible_exception(
|
||||||
},
|
},
|
||||||
stmt.range(),
|
stmt.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
if !checker.indexer().has_comments(stmt, checker.locator()) {
|
||||||
if !checker.indexer().has_comments(stmt, checker.locator()) {
|
diagnostic.try_set_fix(|| {
|
||||||
diagnostic.try_set_fix(|| {
|
// let range = statement_range(stmt, checker.locator(), checker.indexer());
|
||||||
// let range = statement_range(stmt, checker.locator(), checker.indexer());
|
|
||||||
|
|
||||||
let (import_edit, binding) = checker.importer().get_or_import_symbol(
|
let (import_edit, binding) = checker.importer().get_or_import_symbol(
|
||||||
&ImportRequest::import("contextlib", "suppress"),
|
&ImportRequest::import("contextlib", "suppress"),
|
||||||
stmt.start(),
|
stmt.start(),
|
||||||
checker.semantic(),
|
checker.semantic(),
|
||||||
)?;
|
)?;
|
||||||
let replace_try = Edit::range_replacement(
|
let replace_try = Edit::range_replacement(
|
||||||
format!("with {binding}({exception})"),
|
format!("with {binding}({exception})"),
|
||||||
TextRange::at(stmt.start(), "try".text_len()),
|
TextRange::at(stmt.start(), "try".text_len()),
|
||||||
);
|
);
|
||||||
let remove_handler =
|
let remove_handler = Edit::range_deletion(checker.locator().full_lines_range(*range));
|
||||||
Edit::range_deletion(checker.locator().full_lines_range(*range));
|
Ok(Fix::unsafe_edits(
|
||||||
Ok(Fix::unsafe_edits(
|
import_edit,
|
||||||
import_edit,
|
[replace_try, remove_handler],
|
||||||
[replace_try, remove_handler],
|
))
|
||||||
))
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,6 @@ use crate::cst::helpers::or_space;
|
||||||
use crate::cst::matchers::{match_comparison, transform_expression};
|
use crate::cst::matchers::{match_comparison, transform_expression};
|
||||||
use crate::fix::edits::pad;
|
use crate::fix::edits::pad;
|
||||||
use crate::fix::snippet::SourceCodeSnippet;
|
use crate::fix::snippet::SourceCodeSnippet;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for conditions that position a constant on the left-hand side of the
|
/// Checks for conditions that position a constant on the left-hand side of the
|
||||||
|
@ -193,12 +192,10 @@ pub(crate) fn yoda_conditions(
|
||||||
},
|
},
|
||||||
expr.range(),
|
expr.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
pad(suggestion, expr.range(), checker.locator()),
|
||||||
pad(suggestion, expr.range(), checker.locator()),
|
expr.range(),
|
||||||
expr.range(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
} else {
|
} else {
|
||||||
checker.diagnostics.push(Diagnostic::new(
|
checker.diagnostics.push(Diagnostic::new(
|
||||||
|
|
|
@ -8,7 +8,7 @@ use ruff_python_codegen::Generator;
|
||||||
use ruff_python_stdlib::identifiers::is_identifier;
|
use ruff_python_stdlib::identifiers::is_identifier;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
use crate::rules::flake8_tidy_imports::settings::Strictness;
|
use crate::rules::flake8_tidy_imports::settings::Strictness;
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
|
@ -124,13 +124,11 @@ pub(crate) fn banned_relative_import(
|
||||||
};
|
};
|
||||||
if level? > strictness_level {
|
if level? > strictness_level {
|
||||||
let mut diagnostic = Diagnostic::new(RelativeImports { strictness }, stmt.range());
|
let mut diagnostic = Diagnostic::new(RelativeImports { strictness }, stmt.range());
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
if let Some(fix) =
|
||||||
if let Some(fix) =
|
fix_banned_relative_import(stmt, level, module, module_path, checker.generator())
|
||||||
fix_banned_relative_import(stmt, level, module, module_path, checker.generator())
|
{
|
||||||
{
|
diagnostic.set_fix(fix);
|
||||||
diagnostic.set_fix(fix);
|
};
|
||||||
};
|
|
||||||
}
|
|
||||||
Some(diagnostic)
|
Some(diagnostic)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
|
@ -7,11 +7,7 @@ use ruff_text_size::{TextLen, TextRange, TextSize};
|
||||||
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix, Violation};
|
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix, Violation};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
|
||||||
use crate::settings::LinterSettings;
|
use crate::directives::{TodoComment, TodoDirective, TodoDirectiveKind};
|
||||||
use crate::{
|
|
||||||
directives::{TodoComment, TodoDirective, TodoDirectiveKind},
|
|
||||||
registry::Rule,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks that a TODO comment is labelled with "TODO".
|
/// Checks that a TODO comment is labelled with "TODO".
|
||||||
|
@ -240,7 +236,6 @@ pub(crate) fn todos(
|
||||||
todo_comments: &[TodoComment],
|
todo_comments: &[TodoComment],
|
||||||
locator: &Locator,
|
locator: &Locator,
|
||||||
indexer: &Indexer,
|
indexer: &Indexer,
|
||||||
settings: &LinterSettings,
|
|
||||||
) {
|
) {
|
||||||
for todo_comment in todo_comments {
|
for todo_comment in todo_comments {
|
||||||
let TodoComment {
|
let TodoComment {
|
||||||
|
@ -256,7 +251,7 @@ pub(crate) fn todos(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
directive_errors(diagnostics, directive, settings);
|
directive_errors(diagnostics, directive);
|
||||||
static_errors(diagnostics, content, range, directive);
|
static_errors(diagnostics, content, range, directive);
|
||||||
|
|
||||||
let mut has_issue_link = false;
|
let mut has_issue_link = false;
|
||||||
|
@ -300,11 +295,7 @@ pub(crate) fn todos(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check that the directive itself is valid. This function modifies `diagnostics` in-place.
|
/// Check that the directive itself is valid. This function modifies `diagnostics` in-place.
|
||||||
fn directive_errors(
|
fn directive_errors(diagnostics: &mut Vec<Diagnostic>, directive: &TodoDirective) {
|
||||||
diagnostics: &mut Vec<Diagnostic>,
|
|
||||||
directive: &TodoDirective,
|
|
||||||
settings: &LinterSettings,
|
|
||||||
) {
|
|
||||||
if directive.content == "TODO" {
|
if directive.content == "TODO" {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -318,12 +309,10 @@ fn directive_errors(
|
||||||
directive.range,
|
directive.range,
|
||||||
);
|
);
|
||||||
|
|
||||||
if settings.rules.should_fix(Rule::InvalidTodoCapitalization) {
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
"TODO".to_string(),
|
||||||
"TODO".to_string(),
|
directive.range,
|
||||||
directive.range,
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
diagnostics.push(diagnostic);
|
diagnostics.push(diagnostic);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -6,7 +6,6 @@ use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::fix;
|
use crate::fix;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for an empty type-checking block.
|
/// Checks for an empty type-checking block.
|
||||||
|
@ -56,14 +55,12 @@ pub(crate) fn empty_type_checking_block(checker: &mut Checker, stmt: &ast::StmtI
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut diagnostic = Diagnostic::new(EmptyTypeCheckingBlock, stmt.range());
|
let mut diagnostic = Diagnostic::new(EmptyTypeCheckingBlock, stmt.range());
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
// Delete the entire type-checking block.
|
||||||
// Delete the entire type-checking block.
|
let stmt = checker.semantic().current_statement();
|
||||||
let stmt = checker.semantic().current_statement();
|
let parent = checker.semantic().current_statement_parent();
|
||||||
let parent = checker.semantic().current_statement_parent();
|
let edit = fix::edits::delete_stmt(stmt, parent, checker.locator(), checker.indexer());
|
||||||
let edit = fix::edits::delete_stmt(stmt, parent, checker.locator(), checker.indexer());
|
diagnostic.set_fix(Fix::safe_edit(edit).isolate(Checker::isolation(
|
||||||
diagnostic.set_fix(Fix::safe_edit(edit).isolate(Checker::isolation(
|
checker.semantic().current_statement_parent_id(),
|
||||||
checker.semantic().current_statement_parent_id(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,11 +126,7 @@ pub(crate) fn runtime_import_in_type_checking_block(
|
||||||
// Generate a diagnostic for every import, but share a fix across all imports within the same
|
// Generate a diagnostic for every import, but share a fix across all imports within the same
|
||||||
// statement (excluding those that are ignored).
|
// statement (excluding those that are ignored).
|
||||||
for (node_id, imports) in errors_by_statement {
|
for (node_id, imports) in errors_by_statement {
|
||||||
let fix = if checker.patch(Rule::RuntimeImportInTypeCheckingBlock) {
|
let fix = fix_imports(checker, node_id, &imports).ok();
|
||||||
fix_imports(checker, node_id, &imports).ok()
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
for ImportBinding {
|
for ImportBinding {
|
||||||
import,
|
import,
|
||||||
|
|
|
@ -334,11 +334,7 @@ pub(crate) fn typing_only_runtime_import(
|
||||||
// Generate a diagnostic for every import, but share a fix across all imports within the same
|
// Generate a diagnostic for every import, but share a fix across all imports within the same
|
||||||
// statement (excluding those that are ignored).
|
// statement (excluding those that are ignored).
|
||||||
for ((node_id, import_type), imports) in errors_by_statement {
|
for ((node_id, import_type), imports) in errors_by_statement {
|
||||||
let fix = if checker.patch(rule_for(import_type)) {
|
let fix = fix_imports(checker, node_id, &imports).ok();
|
||||||
fix_imports(checker, node_id, &imports).ok()
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
for ImportBinding {
|
for ImportBinding {
|
||||||
import,
|
import,
|
||||||
|
|
|
@ -4,7 +4,6 @@ use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for `pathlib.Path` objects that are initialized with the current
|
/// Checks for `pathlib.Path` objects that are initialized with the current
|
||||||
|
@ -76,9 +75,7 @@ pub(crate) fn path_constructor_current_directory(checker: &mut Checker, expr: &E
|
||||||
|
|
||||||
if matches!(value.as_str(), "" | ".") {
|
if matches!(value.as_str(), "" | ".") {
|
||||||
let mut diagnostic = Diagnostic::new(PathConstructorCurrentDirectory, *range);
|
let mut diagnostic = Diagnostic::new(PathConstructorCurrentDirectory, *range);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_deletion(*range)));
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_deletion(*range)));
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ use ruff_text_size::{Ranged, TextRange};
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::fix::snippet::SourceCodeSnippet;
|
use crate::fix::snippet::SourceCodeSnippet;
|
||||||
use crate::registry::AsRule;
|
|
||||||
use crate::rules::flynt::helpers;
|
use crate::rules::flynt::helpers;
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
|
@ -154,11 +154,9 @@ pub(crate) fn static_join_to_fstring(checker: &mut Checker, expr: &Expr, joiner:
|
||||||
},
|
},
|
||||||
expr.range(),
|
expr.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement(
|
pad(contents, expr.range(), checker.locator()),
|
||||||
pad(contents, expr.range(), checker.locator()),
|
expr.range(),
|
||||||
expr.range(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ use ruff_source_file::Locator;
|
||||||
use ruff_text_size::{TextRange, TextSize};
|
use ruff_text_size::{TextRange, TextSize};
|
||||||
|
|
||||||
use crate::importer::Importer;
|
use crate::importer::Importer;
|
||||||
use crate::registry::Rule;
|
|
||||||
use crate::settings::LinterSettings;
|
use crate::settings::LinterSettings;
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
|
@ -90,7 +90,6 @@ fn add_required_import(
|
||||||
python_ast: &Suite,
|
python_ast: &Suite,
|
||||||
locator: &Locator,
|
locator: &Locator,
|
||||||
stylist: &Stylist,
|
stylist: &Stylist,
|
||||||
settings: &LinterSettings,
|
|
||||||
source_type: PySourceType,
|
source_type: PySourceType,
|
||||||
) -> Option<Diagnostic> {
|
) -> Option<Diagnostic> {
|
||||||
// Don't add imports to semantically-empty files.
|
// Don't add imports to semantically-empty files.
|
||||||
|
@ -116,12 +115,10 @@ fn add_required_import(
|
||||||
MissingRequiredImport(required_import.to_string()),
|
MissingRequiredImport(required_import.to_string()),
|
||||||
TextRange::default(),
|
TextRange::default(),
|
||||||
);
|
);
|
||||||
if settings.rules.should_fix(Rule::MissingRequiredImport) {
|
diagnostic.set_fix(Fix::safe_edit(
|
||||||
diagnostic.set_fix(Fix::safe_edit(
|
Importer::new(python_ast, locator, stylist)
|
||||||
Importer::new(python_ast, locator, stylist)
|
.add_import(required_import, TextSize::default()),
|
||||||
.add_import(required_import, TextSize::default()),
|
));
|
||||||
));
|
|
||||||
}
|
|
||||||
Some(diagnostic)
|
Some(diagnostic)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,7 +168,6 @@ pub(crate) fn add_required_imports(
|
||||||
python_ast,
|
python_ast,
|
||||||
locator,
|
locator,
|
||||||
stylist,
|
stylist,
|
||||||
settings,
|
|
||||||
source_type,
|
source_type,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -189,7 +185,6 @@ pub(crate) fn add_required_imports(
|
||||||
python_ast,
|
python_ast,
|
||||||
locator,
|
locator,
|
||||||
stylist,
|
stylist,
|
||||||
settings,
|
|
||||||
source_type,
|
source_type,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
@ -13,7 +13,7 @@ use ruff_source_file::{Locator, UniversalNewlines};
|
||||||
use ruff_text_size::{Ranged, TextRange};
|
use ruff_text_size::{Ranged, TextRange};
|
||||||
|
|
||||||
use crate::line_width::LineWidthBuilder;
|
use crate::line_width::LineWidthBuilder;
|
||||||
use crate::registry::AsRule;
|
|
||||||
use crate::settings::LinterSettings;
|
use crate::settings::LinterSettings;
|
||||||
|
|
||||||
use super::super::block::Block;
|
use super::super::block::Block;
|
||||||
|
@ -138,11 +138,9 @@ pub(crate) fn organize_imports(
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut diagnostic = Diagnostic::new(UnsortedImports, range);
|
let mut diagnostic = Diagnostic::new(UnsortedImports, range);
|
||||||
if settings.rules.should_fix(diagnostic.kind.rule()) {
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
indent(&expected, indentation).to_string(),
|
||||||
indent(&expected, indentation).to_string(),
|
range,
|
||||||
range,
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
Some(diagnostic)
|
Some(diagnostic)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::importer::ImportRequest;
|
use crate::importer::ImportRequest;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for uses of deprecated NumPy functions.
|
/// Checks for uses of deprecated NumPy functions.
|
||||||
|
@ -76,17 +75,15 @@ pub(crate) fn deprecated_function(checker: &mut Checker, expr: &Expr) {
|
||||||
},
|
},
|
||||||
expr.range(),
|
expr.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.try_set_fix(|| {
|
||||||
diagnostic.try_set_fix(|| {
|
let (import_edit, binding) = checker.importer().get_or_import_symbol(
|
||||||
let (import_edit, binding) = checker.importer().get_or_import_symbol(
|
&ImportRequest::import_from("numpy", replacement),
|
||||||
&ImportRequest::import_from("numpy", replacement),
|
expr.start(),
|
||||||
expr.start(),
|
checker.semantic(),
|
||||||
checker.semantic(),
|
)?;
|
||||||
)?;
|
let replacement_edit = Edit::range_replacement(binding, expr.range());
|
||||||
let replacement_edit = Edit::range_replacement(binding, expr.range());
|
Ok(Fix::safe_edits(import_edit, [replacement_edit]))
|
||||||
Ok(Fix::safe_edits(import_edit, [replacement_edit]))
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@ use ruff_python_ast::Expr;
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for deprecated NumPy type aliases.
|
/// Checks for deprecated NumPy type aliases.
|
||||||
|
@ -73,18 +72,16 @@ pub(crate) fn deprecated_type_alias(checker: &mut Checker, expr: &Expr) {
|
||||||
},
|
},
|
||||||
expr.range(),
|
expr.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
let type_name = match type_name {
|
||||||
let type_name = match type_name {
|
"unicode" => "str",
|
||||||
"unicode" => "str",
|
"long" => "int",
|
||||||
"long" => "int",
|
_ => type_name,
|
||||||
_ => type_name,
|
};
|
||||||
};
|
if checker.semantic().is_builtin(type_name) {
|
||||||
if checker.semantic().is_builtin(type_name) {
|
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
|
type_name.to_string(),
|
||||||
type_name.to_string(),
|
expr.range(),
|
||||||
expr.range(),
|
)));
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::fix::edits::{remove_argument, Parentheses};
|
use crate::fix::edits::{remove_argument, Parentheses};
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for `inplace=True` usages in `pandas` function and method
|
/// Checks for `inplace=True` usages in `pandas` function and method
|
||||||
|
@ -71,26 +70,24 @@ pub(crate) fn inplace_argument(checker: &mut Checker, call: &ast::ExprCall) {
|
||||||
if arg == "inplace" {
|
if arg == "inplace" {
|
||||||
if is_const_true(&keyword.value) {
|
if is_const_true(&keyword.value) {
|
||||||
let mut diagnostic = Diagnostic::new(PandasUseOfInplaceArgument, keyword.range());
|
let mut diagnostic = Diagnostic::new(PandasUseOfInplaceArgument, keyword.range());
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
// Avoid applying the fix if:
|
||||||
// Avoid applying the fix if:
|
// 1. The keyword argument is followed by a star argument (we can't be certain that
|
||||||
// 1. The keyword argument is followed by a star argument (we can't be certain that
|
// the star argument _doesn't_ contain an override).
|
||||||
// the star argument _doesn't_ contain an override).
|
// 2. The call is part of a larger expression (we're converting an expression to a
|
||||||
// 2. The call is part of a larger expression (we're converting an expression to a
|
// statement, and expressions can't contain statements).
|
||||||
// statement, and expressions can't contain statements).
|
let statement = checker.semantic().current_statement();
|
||||||
let statement = checker.semantic().current_statement();
|
if !seen_star
|
||||||
if !seen_star
|
&& checker.semantic().current_expression_parent().is_none()
|
||||||
&& checker.semantic().current_expression_parent().is_none()
|
&& statement.is_expr_stmt()
|
||||||
&& statement.is_expr_stmt()
|
{
|
||||||
{
|
if let Some(fix) = convert_inplace_argument_to_assignment(
|
||||||
if let Some(fix) = convert_inplace_argument_to_assignment(
|
call,
|
||||||
call,
|
keyword,
|
||||||
keyword,
|
statement,
|
||||||
statement,
|
checker.indexer().comment_ranges(),
|
||||||
checker.indexer().comment_ranges(),
|
checker.locator(),
|
||||||
checker.locator(),
|
) {
|
||||||
) {
|
diagnostic.set_fix(fix);
|
||||||
diagnostic.set_fix(fix);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@ use ruff_python_ast::{Arguments, Expr};
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for uses of `dict.items()` that discard either the key or the value
|
/// Checks for uses of `dict.items()` that discard either the key or the value
|
||||||
|
@ -100,18 +99,16 @@ pub(crate) fn incorrect_dict_iterator(checker: &mut Checker, stmt_for: &ast::Stm
|
||||||
},
|
},
|
||||||
func.range(),
|
func.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
let replace_attribute = Edit::range_replacement("values".to_string(), attr.range());
|
||||||
let replace_attribute = Edit::range_replacement("values".to_string(), attr.range());
|
let replace_target = Edit::range_replacement(
|
||||||
let replace_target = Edit::range_replacement(
|
pad(
|
||||||
pad(
|
checker.locator().slice(value).to_string(),
|
||||||
checker.locator().slice(value).to_string(),
|
|
||||||
stmt_for.target.range(),
|
|
||||||
checker.locator(),
|
|
||||||
),
|
|
||||||
stmt_for.target.range(),
|
stmt_for.target.range(),
|
||||||
);
|
checker.locator(),
|
||||||
diagnostic.set_fix(Fix::unsafe_edits(replace_attribute, [replace_target]));
|
),
|
||||||
}
|
stmt_for.target.range(),
|
||||||
|
);
|
||||||
|
diagnostic.set_fix(Fix::unsafe_edits(replace_attribute, [replace_target]));
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
(false, true) => {
|
(false, true) => {
|
||||||
|
@ -122,18 +119,16 @@ pub(crate) fn incorrect_dict_iterator(checker: &mut Checker, stmt_for: &ast::Stm
|
||||||
},
|
},
|
||||||
func.range(),
|
func.range(),
|
||||||
);
|
);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
let replace_attribute = Edit::range_replacement("keys".to_string(), attr.range());
|
||||||
let replace_attribute = Edit::range_replacement("keys".to_string(), attr.range());
|
let replace_target = Edit::range_replacement(
|
||||||
let replace_target = Edit::range_replacement(
|
pad(
|
||||||
pad(
|
checker.locator().slice(key).to_string(),
|
||||||
checker.locator().slice(key).to_string(),
|
|
||||||
stmt_for.target.range(),
|
|
||||||
checker.locator(),
|
|
||||||
),
|
|
||||||
stmt_for.target.range(),
|
stmt_for.target.range(),
|
||||||
);
|
checker.locator(),
|
||||||
diagnostic.set_fix(Fix::unsafe_edits(replace_attribute, [replace_target]));
|
),
|
||||||
}
|
stmt_for.target.range(),
|
||||||
|
);
|
||||||
|
diagnostic.set_fix(Fix::unsafe_edits(replace_attribute, [replace_target]));
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ use ruff_python_ast::{self as ast, Arguments, Expr};
|
||||||
use ruff_text_size::TextRange;
|
use ruff_text_size::TextRange;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
use crate::registry::AsRule;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for explicit casts to `list` on for-loop iterables.
|
/// Checks for explicit casts to `list` on for-loop iterables.
|
||||||
|
@ -91,9 +90,7 @@ pub(crate) fn unnecessary_list_cast(checker: &mut Checker, iter: &Expr) {
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
let mut diagnostic = Diagnostic::new(UnnecessaryListCast, *list_range);
|
let mut diagnostic = Diagnostic::new(UnnecessaryListCast, *list_range);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.set_fix(remove_cast(*list_range, *iterable_range));
|
||||||
diagnostic.set_fix(remove_cast(*list_range, *iterable_range));
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
Expr::Name(ast::ExprName {
|
Expr::Name(ast::ExprName {
|
||||||
|
@ -119,9 +116,7 @@ pub(crate) fn unnecessary_list_cast(checker: &mut Checker, iter: &Expr) {
|
||||||
) {
|
) {
|
||||||
let mut diagnostic =
|
let mut diagnostic =
|
||||||
Diagnostic::new(UnnecessaryListCast, *list_range);
|
Diagnostic::new(UnnecessaryListCast, *list_range);
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
diagnostic.set_fix(remove_cast(*list_range, *iterable_range));
|
||||||
diagnostic.set_fix(remove_cast(*list_range, *iterable_range));
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,6 @@ use ruff_macros::{derive_message_formats, violation};
|
||||||
use ruff_python_index::Indexer;
|
use ruff_python_index::Indexer;
|
||||||
use ruff_source_file::Locator;
|
use ruff_source_file::Locator;
|
||||||
|
|
||||||
use crate::registry::Rule;
|
|
||||||
use crate::settings::LinterSettings;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for compound statements (multiple statements on the same line).
|
/// Checks for compound statements (multiple statements on the same line).
|
||||||
///
|
///
|
||||||
|
@ -104,7 +101,6 @@ pub(crate) fn compound_statements(
|
||||||
lxr: &[LexResult],
|
lxr: &[LexResult],
|
||||||
locator: &Locator,
|
locator: &Locator,
|
||||||
indexer: &Indexer,
|
indexer: &Indexer,
|
||||||
settings: &LinterSettings,
|
|
||||||
) {
|
) {
|
||||||
// Track the last seen instance of a variety of tokens.
|
// Track the last seen instance of a variety of tokens.
|
||||||
let mut colon = None;
|
let mut colon = None;
|
||||||
|
@ -169,14 +165,12 @@ pub(crate) fn compound_statements(
|
||||||
if let Some((start, end)) = semi {
|
if let Some((start, end)) = semi {
|
||||||
let mut diagnostic =
|
let mut diagnostic =
|
||||||
Diagnostic::new(UselessSemicolon, TextRange::new(start, end));
|
Diagnostic::new(UselessSemicolon, TextRange::new(start, end));
|
||||||
if settings.rules.should_fix(Rule::UselessSemicolon) {
|
diagnostic.set_fix(Fix::safe_edit(Edit::deletion(
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::deletion(
|
indexer
|
||||||
indexer
|
.preceded_by_continuations(start, locator)
|
||||||
.preceded_by_continuations(start, locator)
|
.unwrap_or(start),
|
||||||
.unwrap_or(start),
|
end,
|
||||||
end,
|
)));
|
||||||
)));
|
|
||||||
};
|
|
||||||
diagnostics.push(diagnostic);
|
diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue