Remove Fix::from(Edit) and add deprecated replacement methods to Diagnostics (#4275)

This commit is contained in:
Micha Reiser 2023-05-08 12:25:50 +02:00 committed by GitHub
parent 0801f14046
commit 4d5a339d9e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
51 changed files with 205 additions and 144 deletions

View file

@ -10,7 +10,7 @@ use rustpython_parser::ast::{
ExprKind, KeywordData, Located, Operator, Pattern, PatternKind, Stmt, StmtKind, Suite,
};
use ruff_diagnostics::Diagnostic;
use ruff_diagnostics::{Diagnostic, Fix};
use ruff_python_ast::all::{extract_all_names, AllNamesFlags};
use ruff_python_ast::helpers::{extract_handled_exceptions, to_module_path};
use ruff_python_ast::source_code::{Indexer, Locator, Stylist};
@ -4033,7 +4033,8 @@ where
name_range,
);
if self.patch(Rule::UnusedVariable) {
diagnostic.try_set_fix(|| {
#[allow(deprecated)]
diagnostic.try_set_fix_from_edit(|| {
pyflakes::fixes::remove_exception_handler_assignment(
excepthandler,
self.locator,
@ -5323,8 +5324,8 @@ impl<'a> Checker<'a> {
if matches!(child.node, StmtKind::ImportFrom { .. }) {
diagnostic.set_parent(child.start());
}
if let Some(fix) = &fix {
diagnostic.set_fix(fix.clone());
if let Some(edit) = &fix {
diagnostic.set_fix(Fix::unspecified(edit.clone()));
}
diagnostics.push(diagnostic);
}

View file

@ -102,7 +102,8 @@ pub fn check_noqa(
let mut diagnostic =
Diagnostic::new(UnusedNOQA { codes: None }, *noqa_range);
if autofix.into() && settings.rules.should_fix(diagnostic.kind.rule()) {
diagnostic.set_fix(delete_noqa(
#[allow(deprecated)]
diagnostic.set_fix_from_edit(delete_noqa(
*leading_spaces,
*noqa_range,
*trailing_spaces,
@ -171,7 +172,8 @@ pub fn check_noqa(
);
if autofix.into() && settings.rules.should_fix(diagnostic.kind.rule()) {
if valid_codes.is_empty() {
diagnostic.set_fix(delete_noqa(
#[allow(deprecated)]
diagnostic.set_fix_from_edit(delete_noqa(
*leading_spaces,
*range,
*trailing_spaces,

View file

@ -666,7 +666,8 @@ pub fn definition(
helpers::identifier_range(stmt, checker.locator),
);
if checker.patch(diagnostic.kind.rule()) {
diagnostic.try_set_fix(|| {
#[allow(deprecated)]
diagnostic.try_set_fix_from_edit(|| {
fixes::add_return_annotation(checker.locator, stmt, "None")
});
}
@ -688,7 +689,8 @@ pub fn definition(
let return_type = SIMPLE_MAGIC_RETURN_TYPES.get(name);
if let Some(return_type) = return_type {
if checker.patch(diagnostic.kind.rule()) {
diagnostic.try_set_fix(|| {
#[allow(deprecated)]
diagnostic.try_set_fix_from_edit(|| {
fixes::add_return_annotation(checker.locator, stmt, return_type)
});
}

View file

@ -84,7 +84,8 @@ pub fn unnecessary_call_around_sorted(
expr.range(),
);
if checker.patch(diagnostic.kind.rule()) {
diagnostic.try_set_fix(|| {
#[allow(deprecated)]
diagnostic.try_set_fix_from_edit(|| {
fixes::fix_unnecessary_call_around_sorted(checker.locator, checker.stylist, expr)
});
}

View file

@ -89,7 +89,8 @@ pub fn unnecessary_collection_call(
expr.range(),
);
if checker.patch(diagnostic.kind.rule()) {
diagnostic.try_set_fix(|| {
#[allow(deprecated)]
diagnostic.try_set_fix_from_edit(|| {
fixes::fix_unnecessary_collection_call(checker.locator, checker.stylist, expr)
});
}

View file

@ -66,7 +66,8 @@ fn add_diagnostic(checker: &mut Checker, expr: &Expr) {
expr.range(),
);
if checker.patch(diagnostic.kind.rule()) {
diagnostic.try_set_fix(|| {
#[allow(deprecated)]
diagnostic.try_set_fix_from_edit(|| {
fixes::fix_unnecessary_comprehension(checker.locator, checker.stylist, expr)
});
}

View file

@ -79,7 +79,8 @@ pub fn unnecessary_comprehension_any_all(
}
let mut diagnostic = Diagnostic::new(UnnecessaryComprehensionAnyAll, args[0].range());
if checker.patch(diagnostic.kind.rule()) {
diagnostic.try_set_fix(|| {
#[allow(deprecated)]
diagnostic.try_set_fix_from_edit(|| {
fixes::fix_unnecessary_comprehension_any_all(checker.locator, checker.stylist, expr)
});
}

View file

@ -110,7 +110,8 @@ pub fn unnecessary_double_cast_or_process(
expr.range(),
);
if checker.patch(diagnostic.kind.rule()) {
diagnostic.try_set_fix(|| {
#[allow(deprecated)]
diagnostic.try_set_fix_from_edit(|| {
fixes::fix_unnecessary_double_cast_or_process(
checker.locator,
checker.stylist,

View file

@ -58,7 +58,8 @@ pub fn unnecessary_generator_dict(
ExprKind::Tuple { elts, .. } if elts.len() == 2 => {
let mut diagnostic = Diagnostic::new(UnnecessaryGeneratorDict, expr.range());
if checker.patch(diagnostic.kind.rule()) {
diagnostic.try_set_fix(|| {
#[allow(deprecated)]
diagnostic.try_set_fix_from_edit(|| {
fixes::fix_unnecessary_generator_dict(
checker.locator,
checker.stylist,

View file

@ -58,7 +58,8 @@ pub fn unnecessary_generator_list(
if let ExprKind::GeneratorExp { .. } = argument {
let mut diagnostic = Diagnostic::new(UnnecessaryGeneratorList, expr.range());
if checker.patch(diagnostic.kind.rule()) {
diagnostic.try_set_fix(|| {
#[allow(deprecated)]
diagnostic.try_set_fix_from_edit(|| {
fixes::fix_unnecessary_generator_list(checker.locator, checker.stylist, expr)
});
}

View file

@ -59,7 +59,8 @@ pub fn unnecessary_generator_set(
if let ExprKind::GeneratorExp { .. } = argument {
let mut diagnostic = Diagnostic::new(UnnecessaryGeneratorSet, expr.range());
if checker.patch(diagnostic.kind.rule()) {
diagnostic.try_set_fix(|| {
#[allow(deprecated)]
diagnostic.try_set_fix_from_edit(|| {
fixes::fix_unnecessary_generator_set(checker.locator, checker.stylist, expr, parent)
});
}

View file

@ -50,7 +50,8 @@ pub fn unnecessary_list_call(checker: &mut Checker, expr: &Expr, func: &Expr, ar
}
let mut diagnostic = Diagnostic::new(UnnecessaryListCall, expr.range());
if checker.patch(diagnostic.kind.rule()) {
diagnostic.try_set_fix(|| {
#[allow(deprecated)]
diagnostic.try_set_fix_from_edit(|| {
fixes::fix_unnecessary_list_call(checker.locator, checker.stylist, expr)
});
}

View file

@ -63,7 +63,8 @@ pub fn unnecessary_list_comprehension_dict(
}
let mut diagnostic = Diagnostic::new(UnnecessaryListComprehensionDict, expr.range());
if checker.patch(diagnostic.kind.rule()) {
diagnostic.try_set_fix(|| {
#[allow(deprecated)]
diagnostic.try_set_fix_from_edit(|| {
fixes::fix_unnecessary_list_comprehension_dict(checker.locator, checker.stylist, expr)
});
}

View file

@ -56,7 +56,8 @@ pub fn unnecessary_list_comprehension_set(
if let ExprKind::ListComp { .. } = &argument {
let mut diagnostic = Diagnostic::new(UnnecessaryListComprehensionSet, expr.range());
if checker.patch(diagnostic.kind.rule()) {
diagnostic.try_set_fix(|| {
#[allow(deprecated)]
diagnostic.try_set_fix_from_edit(|| {
fixes::fix_unnecessary_list_comprehension_set(
checker.locator,
checker.stylist,

View file

@ -78,7 +78,8 @@ pub fn unnecessary_literal_dict(
expr.range(),
);
if checker.patch(diagnostic.kind.rule()) {
diagnostic.try_set_fix(|| {
#[allow(deprecated)]
diagnostic.try_set_fix_from_edit(|| {
fixes::fix_unnecessary_literal_dict(checker.locator, checker.stylist, expr)
});
}

View file

@ -72,7 +72,8 @@ pub fn unnecessary_literal_set(
expr.range(),
);
if checker.patch(diagnostic.kind.rule()) {
diagnostic.try_set_fix(|| {
#[allow(deprecated)]
diagnostic.try_set_fix_from_edit(|| {
fixes::fix_unnecessary_literal_set(checker.locator, checker.stylist, expr)
});
}

View file

@ -90,7 +90,8 @@ pub fn unnecessary_literal_within_dict_call(
expr.range(),
);
if checker.patch(diagnostic.kind.rule()) {
diagnostic.try_set_fix(|| {
#[allow(deprecated)]
diagnostic.try_set_fix_from_edit(|| {
fixes::fix_unnecessary_literal_within_dict_call(checker.locator, checker.stylist, expr)
});
}

View file

@ -93,7 +93,8 @@ pub fn unnecessary_literal_within_list_call(
expr.range(),
);
if checker.patch(diagnostic.kind.rule()) {
diagnostic.try_set_fix(|| {
#[allow(deprecated)]
diagnostic.try_set_fix_from_edit(|| {
fixes::fix_unnecessary_literal_within_list_call(checker.locator, checker.stylist, expr)
});
}

View file

@ -94,7 +94,8 @@ pub fn unnecessary_literal_within_tuple_call(
expr.range(),
);
if checker.patch(diagnostic.kind.rule()) {
diagnostic.try_set_fix(|| {
#[allow(deprecated)]
diagnostic.try_set_fix_from_edit(|| {
fixes::fix_unnecessary_literal_within_tuple_call(checker.locator, checker.stylist, expr)
});
}

View file

@ -107,7 +107,8 @@ pub fn unnecessary_map(
if args.len() == 2 && matches!(&args[0].node, ExprKind::Lambda { .. }) {
let mut diagnostic = create_diagnostic("generator", expr.range());
if checker.patch(diagnostic.kind.rule()) {
diagnostic.try_set_fix(|| {
#[allow(deprecated)]
diagnostic.try_set_fix_from_edit(|| {
fixes::fix_unnecessary_map(
checker.locator,
checker.stylist,
@ -136,7 +137,8 @@ pub fn unnecessary_map(
if let ExprKind::Lambda { .. } = argument {
let mut diagnostic = create_diagnostic(id, expr.range());
if checker.patch(diagnostic.kind.rule()) {
diagnostic.try_set_fix(|| {
#[allow(deprecated)]
diagnostic.try_set_fix_from_edit(|| {
fixes::fix_unnecessary_map(
checker.locator,
checker.stylist,
@ -166,7 +168,8 @@ pub fn unnecessary_map(
{
let mut diagnostic = create_diagnostic(id, expr.range());
if checker.patch(diagnostic.kind.rule()) {
diagnostic.try_set_fix(|| {
#[allow(deprecated)]
diagnostic.try_set_fix_from_edit(|| {
fixes::fix_unnecessary_map(
checker.locator,
checker.stylist,

View file

@ -140,7 +140,8 @@ pub fn no_unnecessary_pass(checker: &mut Checker, body: &[Stmt]) {
pass_stmt.range().add_end(index),
)));
} else {
diagnostic.try_set_fix(|| {
#[allow(deprecated)]
diagnostic.try_set_fix_from_edit(|| {
delete_stmt(
pass_stmt,
None,
@ -208,7 +209,8 @@ pub fn duplicate_class_field_definition<'a, 'b>(
) {
Ok(fix) => {
checker.deletions.insert(RefEquality(stmt));
diagnostic.set_fix(fix);
#[allow(deprecated)]
diagnostic.set_fix_from_edit(fix);
}
Err(err) => {
error!("Failed to remove duplicate class definition: {}", err);

View file

@ -48,7 +48,8 @@ pub fn pass_in_class_body<'a>(checker: &mut Checker<'a>, parent: &'a Stmt, body:
if fix.is_deletion() || fix.content() == Some("pass") {
checker.deletions.insert(RefEquality(stmt));
}
diagnostic.set_fix(fix);
#[allow(deprecated)]
diagnostic.set_fix_from_edit(fix);
}
Err(e) => {
error!("Failed to delete `pass` statement: {}", e);

View file

@ -1,4 +1,4 @@
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit};
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation};
use ruff_text_size::TextRange;
@ -23,7 +23,10 @@ impl AlwaysAutofixableViolation for QuotedAnnotationInStub {
pub fn quoted_annotation_in_stub(checker: &mut Checker, annotation: &str, range: TextRange) {
let mut diagnostic = Diagnostic::new(QuotedAnnotationInStub, range);
if checker.patch(Rule::QuotedAnnotationInStub) {
diagnostic.set_fix(Edit::range_replacement(annotation.to_string(), range));
diagnostic.set_fix(Fix::unspecified(Edit::range_replacement(
annotation.to_string(),
range,
)));
}
checker.diagnostics.push(diagnostic);
}

View file

@ -426,8 +426,10 @@ pub fn composite_condition(checker: &mut Checker, stmt: &Stmt, test: &Expr, msg:
&& !has_comments_in(stmt.range(), checker.locator);
let mut diagnostic = Diagnostic::new(PytestCompositeAssertion { fixable }, stmt.range());
if fixable && checker.patch(diagnostic.kind.rule()) {
diagnostic
.try_set_fix(|| fix_composite_condition(stmt, checker.locator, checker.stylist));
#[allow(deprecated)]
diagnostic.try_set_fix_from_edit(|| {
fix_composite_condition(stmt, checker.locator, checker.stylist)
});
}
checker.diagnostics.push(diagnostic);
}

View file

@ -239,7 +239,7 @@ fn has_abstractmethod_decorator(decorators: &[Expr], checker: &Checker) -> bool
fn pytest_fixture_parentheses(
checker: &mut Checker,
decorator: &Expr,
fix: Edit,
fix: Fix,
preferred: &str,
actual: &str,
) {
@ -283,7 +283,7 @@ fn check_fixture_decorator(checker: &mut Checker, func_name: &str, decorator: &E
&& args.is_empty()
&& keywords.is_empty()
{
let fix = Edit::deletion(func.end(), decorator.end());
let fix = Fix::unspecified(Edit::deletion(func.end(), decorator.end()));
pytest_fixture_parentheses(checker, decorator, fix, "", "()");
}
@ -316,7 +316,8 @@ fn check_fixture_decorator(checker: &mut Checker, func_name: &str, decorator: &E
Diagnostic::new(PytestExtraneousScopeFunction, scope_keyword.range());
if checker.patch(diagnostic.kind.rule()) {
let expr_range = diagnostic.range();
diagnostic.try_set_fix(|| {
#[allow(deprecated)]
diagnostic.try_set_fix_from_edit(|| {
fix_extraneous_scope_function(
checker.locator,
decorator.start(),
@ -338,7 +339,7 @@ fn check_fixture_decorator(checker: &mut Checker, func_name: &str, decorator: &E
.enabled(Rule::PytestFixtureIncorrectParenthesesStyle)
&& checker.settings.flake8_pytest_style.fixture_parentheses
{
let fix = Edit::insertion("()".to_string(), decorator.end());
let fix = Fix::unspecified(Edit::insertion("()".to_string(), decorator.end()));
pytest_fixture_parentheses(checker, decorator, fix, "()", "");
}
}

View file

@ -54,7 +54,7 @@ fn pytest_mark_parentheses(
checker: &mut Checker,
decorator: &Expr,
call_path: &CallPath,
fix: Edit,
fix: Fix,
preferred: &str,
actual: &str,
) {
@ -84,13 +84,13 @@ fn check_mark_parentheses(checker: &mut Checker, decorator: &Expr, call_path: &C
&& args.is_empty()
&& keywords.is_empty()
{
let fix = Edit::deletion(func.end(), decorator.end());
let fix = Fix::unspecified(Edit::deletion(func.end(), decorator.end()));
pytest_mark_parentheses(checker, decorator, call_path, fix, "", "()");
}
}
_ => {
if checker.settings.flake8_pytest_style.mark_parentheses {
let fix = Edit::insertion("()".to_string(), decorator.end());
let fix = Fix::unspecified(Edit::insertion("()".to_string(), decorator.end()));
pytest_mark_parentheses(checker, decorator, call_path, fix, "()", "");
}
}

View file

@ -695,7 +695,7 @@ pub fn expr_or_true(checker: &mut Checker, expr: &Expr) {
edit.range(),
);
if checker.patch(diagnostic.kind.rule()) {
diagnostic.set_fix(edit);
diagnostic.set_fix(Fix::unspecified(edit));
}
checker.diagnostics.push(diagnostic);
}
@ -714,7 +714,7 @@ pub fn expr_and_false(checker: &mut Checker, expr: &Expr) {
edit.range(),
);
if checker.patch(diagnostic.kind.rule()) {
diagnostic.set_fix(edit);
diagnostic.set_fix(Fix::unspecified(edit));
}
checker.diagnostics.push(diagnostic);
}

View file

@ -297,14 +297,14 @@ pub fn nested_if_statements(
);
if fixable && checker.patch(diagnostic.kind.rule()) {
match fix_if::fix_nested_if_statements(checker.locator, checker.stylist, stmt) {
Ok(fix) => {
if fix
Ok(edit) => {
if edit
.content()
.unwrap_or_default()
.universal_newlines()
.all(|line| line.width() <= checker.settings.line_length)
{
diagnostic.set_fix(fix);
diagnostic.set_fix(Fix::unspecified(edit));
}
}
Err(err) => error!("Failed to fix nested if: {err}"),

View file

@ -3,8 +3,8 @@ use ruff_text_size::TextRange;
use rustpython_parser::ast::{Located, Stmt, StmtKind, Withitem};
use unicode_width::UnicodeWidthStr;
use ruff_diagnostics::Diagnostic;
use ruff_diagnostics::{AutofixKind, Violation};
use ruff_diagnostics::{Diagnostic, Fix};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::{first_colon_range, has_comments_in};
use ruff_python_ast::newlines::StrExt;
@ -111,14 +111,14 @@ pub fn multiple_with_statements(
checker.stylist,
with_stmt,
) {
Ok(fix) => {
if fix
Ok(edit) => {
if edit
.content()
.unwrap_or_default()
.universal_newlines()
.all(|line| line.width() <= checker.settings.line_length)
{
diagnostic.set_fix(fix);
diagnostic.set_fix(Fix::unspecified(edit));
}
}
Err(err) => error!("Failed to fix nested with: {err}"),

View file

@ -2,7 +2,7 @@ use rustpython_parser::ast::{Stmt, StmtKind};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Violation};
use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation};
use ruff_macros::{derive_message_formats, violation, CacheKey};
use ruff_python_ast::helpers::{create_stmt, resolve_imported_module_path, unparse_stmt};
use ruff_python_ast::source_code::Stylist;
@ -91,7 +91,7 @@ fn fix_banned_relative_import(
module: Option<&str>,
module_path: Option<&[String]>,
stylist: &Stylist,
) -> Option<Edit> {
) -> Option<Fix> {
// Only fix is the module path is known.
let Some(module_path) = resolve_imported_module_path(level, module, module_path) else {
return None;
@ -115,7 +115,10 @@ fn fix_banned_relative_import(
stylist,
);
Some(Edit::range_replacement(content, stmt.range()))
Some(Fix::unspecified(Edit::range_replacement(
content,
stmt.range(),
)))
}
/// TID252

View file

@ -1,7 +1,7 @@
use log::error;
use rustpython_parser::ast::{Stmt, StmtKind};
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic};
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Fix};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::types::RefEquality;
@ -70,11 +70,11 @@ pub fn empty_type_checking_block<'a, 'b>(
checker.indexer,
checker.stylist,
) {
Ok(fix) => {
if fix.is_deletion() || fix.content() == Some("pass") {
Ok(edit) => {
if edit.is_deletion() || edit.content() == Some("pass") {
checker.deletions.insert(RefEquality(stmt));
}
diagnostic.set_fix(fix);
diagnostic.set_fix(Fix::unspecified(edit));
}
Err(e) => error!("Failed to remove empty type-checking block: {e}"),
}

View file

@ -3,7 +3,7 @@ use ruff_text_size::{TextRange, TextSize};
use rustpython_parser as parser;
use rustpython_parser::ast::{StmtKind, Suite};
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic};
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Fix};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::is_docstring_stmt;
use ruff_python_ast::imports::{Alias, AnyImport, FutureImport, Import, ImportFrom};
@ -120,10 +120,10 @@ fn add_required_import(
TextRange::default(),
);
if autofix.into() && settings.rules.should_fix(Rule::MissingRequiredImport) {
diagnostic.set_fix(
diagnostic.set_fix(Fix::unspecified(
Importer::new(python_ast, locator, stylist)
.add_import(required_import, TextSize::default()),
);
));
}
Some(diagnostic)
}

View file

@ -138,7 +138,7 @@ pub fn indent(checker: &mut Checker, docstring: &Docstring) {
} else {
Edit::range_replacement(new_indent, over_indented)
};
diagnostic.set_fix(edit);
diagnostic.set_fix(Fix::unspecified(edit));
}
checker.diagnostics.push(diagnostic);
}

View file

@ -2,7 +2,7 @@ use ruff_text_size::{TextRange, TextSize};
use rustpython_parser::ast::{Expr, ExprKind};
use rustpython_parser::{lexer, Mode, StringKind, Tok};
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit};
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::source_code::Locator;
@ -87,13 +87,13 @@ fn fix_f_string_missing_placeholders(
prefix_range: TextRange,
tok_range: TextRange,
checker: &mut Checker,
) -> Edit {
) -> Fix {
let content = &checker.locator.contents()[TextRange::new(prefix_range.end(), tok_range.end())];
Edit::replacement(
Fix::unspecified(Edit::replacement(
unescape_f_string(content),
prefix_range.start(),
tok_range.end(),
)
))
}
/// F541

View file

@ -311,7 +311,8 @@ pub(crate) fn percent_format_extra_named_arguments(
location,
);
if checker.patch(diagnostic.kind.rule()) {
diagnostic.try_set_fix(|| {
#[allow(deprecated)]
diagnostic.try_set_fix_from_edit(|| {
remove_unused_format_arguments_from_dict(
&missing,
right,
@ -474,7 +475,8 @@ pub(crate) fn string_dot_format_extra_named_arguments(
location,
);
if checker.patch(diagnostic.kind.rule()) {
diagnostic.try_set_fix(|| {
#[allow(deprecated)]
diagnostic.try_set_fix_from_edit(|| {
remove_unused_keyword_arguments_from_format_call(
&missing,
location,
@ -518,7 +520,8 @@ pub(crate) fn string_dot_format_extra_positional_arguments(
location,
);
if checker.patch(diagnostic.kind.rule()) {
diagnostic.try_set_fix(|| {
#[allow(deprecated)]
diagnostic.try_set_fix_from_edit(|| {
remove_unused_positional_arguments_from_format_call(
&missing,
location,

View file

@ -4,7 +4,7 @@ use ruff_text_size::TextRange;
use rustpython_parser::ast::{ExprKind, Located, Stmt, StmtKind};
use rustpython_parser::{lexer, Mode, Tok};
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit};
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::contains_effect;
use ruff_python_ast::source_code::Locator;
@ -194,7 +194,7 @@ fn remove_unused_variable(
stmt: &Stmt,
range: TextRange,
checker: &Checker,
) -> Option<(DeletionKind, Edit)> {
) -> Option<(DeletionKind, Fix)> {
// First case: simple assignment (`x = 1`)
if let StmtKind::Assign { targets, value, .. } = &stmt.node {
if let Some(target) = targets.iter().find(|target| range == target.range()) {
@ -206,11 +206,11 @@ fn remove_unused_variable(
// but preserve the right-hand side.
Some((
DeletionKind::Partial,
Edit::deletion(
Fix::unspecified(Edit::deletion(
target.start(),
match_token_after(target, checker.locator, |tok| tok == Tok::Equal)
.start(),
),
)),
))
} else {
// If (e.g.) assigning to a constant (`x = 1`), delete the entire statement.
@ -224,7 +224,7 @@ fn remove_unused_variable(
checker.indexer,
checker.stylist,
) {
Ok(fix) => Some((DeletionKind::Whole, fix)),
Ok(fix) => Some((DeletionKind::Whole, Fix::unspecified(fix))),
Err(err) => {
error!("Failed to delete unused variable: {}", err);
None
@ -248,10 +248,10 @@ fn remove_unused_variable(
// but preserve the right-hand side.
Some((
DeletionKind::Partial,
Edit::deletion(
Fix::unspecified(Edit::deletion(
stmt.start(),
match_token_after(stmt, checker.locator, |tok| tok == Tok::Equal).start(),
),
)),
))
} else {
// If assigning to a constant (`x = 1`), delete the entire statement.
@ -265,7 +265,7 @@ fn remove_unused_variable(
checker.indexer,
checker.stylist,
) {
Ok(fix) => Some((DeletionKind::Whole, fix)),
Ok(edit) => Some((DeletionKind::Whole, Fix::unspecified(edit))),
Err(err) => {
error!("Failed to delete unused variable: {}", err);
None
@ -284,7 +284,7 @@ fn remove_unused_variable(
if optional_vars.range() == range {
return Some((
DeletionKind::Partial,
Edit::deletion(
Fix::unspecified(Edit::deletion(
item.context_expr.end(),
// The end of the `Withitem` is the colon, comma, or closing
// parenthesis following the `optional_vars`.
@ -292,7 +292,7 @@ fn remove_unused_variable(
tok == Tok::Colon || tok == Tok::Comma || tok == Tok::Rpar
})
.start(),
),
)),
));
}
}

View file

@ -1,7 +1,7 @@
use ruff_text_size::TextSize;
use rustpython_parser::ast::{Expr, ExprKind, Keyword};
use ruff_diagnostics::{Diagnostic, Edit, Violation};
use ruff_diagnostics::{Diagnostic, Edit, Fix, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::{has_comments, unparse_expr};
use ruff_python_semantic::context::Context;
@ -121,10 +121,10 @@ pub fn nested_min_max(
keywords: keywords.to_owned(),
},
);
diagnostic.set_fix(Edit::range_replacement(
diagnostic.set_fix(Fix::unspecified(Edit::range_replacement(
unparse_expr(&flattened_expr, checker.stylist),
expr.range(),
));
)));
}
checker.diagnostics.push(diagnostic);
}

View file

@ -1,7 +1,7 @@
use log::error;
use rustpython_parser::ast::{Constant, Expr, ExprKind, Stmt, StmtKind};
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic};
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Fix};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::{is_const_none, ReturnStatementVisitor};
use ruff_python_ast::types::RefEquality;
@ -116,11 +116,11 @@ pub fn useless_return<'a>(
checker.indexer,
checker.stylist,
) {
Ok(fix) => {
if fix.is_deletion() || fix.content() == Some("pass") {
Ok(edit) => {
if edit.is_deletion() || edit.content() == Some("pass") {
checker.deletions.insert(RefEquality(last_stmt));
}
diagnostic.set_fix(fix);
diagnostic.set_fix(Fix::unspecified(edit));
}
Err(e) => {
error!("Failed to delete `return` statement: {}", e);

View file

@ -2,7 +2,7 @@ use anyhow::{bail, Result};
use log::debug;
use rustpython_parser::ast::{Constant, Expr, ExprContext, ExprKind, Keyword, Stmt, StmtKind};
use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Violation};
use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::{create_expr, create_stmt, unparse_stmt};
use ruff_python_ast::source_code::Stylist;
@ -162,11 +162,11 @@ fn convert_to_class(
body: Vec<Stmt>,
base_class: &Expr,
stylist: &Stylist,
) -> Edit {
Edit::range_replacement(
) -> Fix {
Fix::unspecified(Edit::range_replacement(
unparse_stmt(&create_class_def_stmt(typename, body, base_class), stylist),
stmt.range(),
)
))
}
/// UP014

View file

@ -2,7 +2,7 @@ use anyhow::{bail, Result};
use log::debug;
use rustpython_parser::ast::{Constant, Expr, ExprContext, ExprKind, Keyword, Stmt, StmtKind};
use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Violation};
use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::{create_expr, create_stmt, unparse_stmt};
use ruff_python_ast::source_code::Stylist;
@ -209,14 +209,14 @@ fn convert_to_class(
total_keyword: Option<&Keyword>,
base_class: &Expr,
stylist: &Stylist,
) -> Edit {
Edit::range_replacement(
) -> Fix {
Fix::unspecified(Edit::range_replacement(
unparse_stmt(
&create_class_def_stmt(class_name, body, total_keyword, base_class),
stylist,
),
stmt.range(),
)
))
}
/// UP013

View file

@ -331,7 +331,8 @@ pub fn deprecated_mock_import(checker: &mut Checker, stmt: &Stmt) {
);
if checker.patch(diagnostic.kind.rule()) {
if let Some(indent) = indentation(checker.locator, stmt) {
diagnostic.try_set_fix(|| {
#[allow(deprecated)]
diagnostic.try_set_fix_from_edit(|| {
format_import_from(stmt, indent, checker.locator, checker.stylist)
.map(|content| Edit::range_replacement(content, stmt.range()))
});

View file

@ -6,7 +6,7 @@ use ruff_text_size::{TextRange, TextSize};
use rustpython_parser::ast::{Cmpop, Constant, Expr, ExprKind, Located, Stmt};
use rustpython_parser::{lexer, Mode, Tok};
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit};
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::source_code::Locator;
use ruff_python_ast::types::RefEquality;
@ -155,7 +155,7 @@ fn fix_py2_block(
body: &[Stmt],
orelse: &[Stmt],
block: &BlockMetadata,
) -> Option<Edit> {
) -> Option<Fix> {
if orelse.is_empty() {
// Delete the entire statement. If this is an `elif`, know it's the only child
// of its parent, so avoid passing in the parent at all. Otherwise,
@ -175,9 +175,9 @@ fn fix_py2_block(
checker.indexer,
checker.stylist,
) {
Ok(fix) => {
Ok(edit) => {
checker.deletions.insert(RefEquality(defined_by));
Some(fix)
Some(Fix::unspecified(edit))
}
Err(err) => {
error!("Failed to remove block: {}", err);
@ -193,13 +193,13 @@ fn fix_py2_block(
if indentation(checker.locator, start).is_none() {
// Inline `else` block (e.g., `else: x = 1`).
Some(Edit::range_replacement(
Some(Fix::unspecified(Edit::range_replacement(
checker
.locator
.slice(TextRange::new(start.start(), end.end()))
.to_string(),
stmt.range(),
))
)))
} else {
indentation(checker.locator, stmt)
.and_then(|indentation| {
@ -212,11 +212,11 @@ fn fix_py2_block(
.ok()
})
.map(|contents| {
Edit::replacement(
Fix::unspecified(Edit::replacement(
contents,
checker.locator.line_start(stmt.start()),
stmt.end(),
)
))
})
}
} else {
@ -233,7 +233,7 @@ fn fix_py2_block(
end_location = body.last().unwrap().end();
}
}
Some(Edit::deletion(stmt.start(), end_location))
Some(Fix::unspecified(Edit::deletion(stmt.start(), end_location)))
}
}
@ -244,7 +244,7 @@ fn fix_py3_block(
test: &Expr,
body: &[Stmt],
block: &BlockMetadata,
) -> Option<Edit> {
) -> Option<Fix> {
match block.starter {
Tok::If => {
// If the first statement is an if, use the body of this statement, and ignore
@ -254,13 +254,13 @@ fn fix_py3_block(
if indentation(checker.locator, start).is_none() {
// Inline `if` block (e.g., `if ...: x = 1`).
Some(Edit::range_replacement(
Some(Fix::unspecified(Edit::range_replacement(
checker
.locator
.slice(TextRange::new(start.start(), end.end()))
.to_string(),
stmt.range(),
))
)))
} else {
indentation(checker.locator, stmt)
.and_then(|indentation| {
@ -273,11 +273,11 @@ fn fix_py3_block(
.ok()
})
.map(|contents| {
Edit::replacement(
Fix::unspecified(Edit::replacement(
contents,
checker.locator.line_start(stmt.start()),
stmt.end(),
)
))
})
}
}
@ -286,7 +286,10 @@ fn fix_py3_block(
// the rest.
let end = body.last().unwrap();
let text = checker.locator.slice(TextRange::new(test.end(), end.end()));
Some(Edit::range_replacement(format!("else{text}"), stmt.range()))
Some(Fix::unspecified(Edit::range_replacement(
format!("else{text}"),
stmt.range(),
)))
}
_ => None,
}

View file

@ -121,7 +121,8 @@ fn create_check(
mode_param.range(),
)));
} else {
diagnostic.try_set_fix(|| create_remove_param_fix(locator, expr, mode_param));
#[allow(deprecated)]
diagnostic.try_set_fix_from_edit(|| create_remove_param_fix(locator, expr, mode_param));
}
}
diagnostic

View file

@ -1,6 +1,6 @@
use rustpython_parser::ast::{ArgData, Expr, ExprKind, StmtKind};
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic};
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Fix};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_semantic::scope::ScopeKind;
@ -96,8 +96,8 @@ pub fn super_call_with_parameters(checker: &mut Checker, expr: &Expr, func: &Exp
let mut diagnostic = Diagnostic::new(SuperCallWithParameters, expr.range());
if checker.patch(diagnostic.kind.rule()) {
if let Some(fix) = fixes::remove_super_arguments(checker.locator, checker.stylist, expr) {
diagnostic.set_fix(fix);
if let Some(edit) = fixes::remove_super_arguments(checker.locator, checker.stylist, expr) {
diagnostic.set_fix(Fix::unspecified(edit));
}
}
checker.diagnostics.push(diagnostic);

View file

@ -2,7 +2,7 @@ use itertools::Itertools;
use log::error;
use rustpython_parser::ast::{Alias, AliasData, Located, Stmt};
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic};
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Fix};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::types::RefEquality;
@ -121,11 +121,11 @@ pub fn unnecessary_builtin_import(
checker.indexer,
checker.stylist,
) {
Ok(fix) => {
if fix.is_deletion() || fix.content() == Some("pass") {
Ok(edit) => {
if edit.is_deletion() || edit.content() == Some("pass") {
checker.deletions.insert(RefEquality(defined_by));
}
diagnostic.set_fix(fix);
diagnostic.set_fix(Fix::unspecified(edit));
}
Err(e) => error!("Failed to remove builtin import: {e}"),
}

View file

@ -2,7 +2,7 @@ use ruff_text_size::TextRange;
use rustpython_parser::ast::{Constant, Expr, ExprKind, Keyword};
use rustpython_parser::{lexer, Mode, Tok};
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit};
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::source_code::Locator;
@ -106,8 +106,8 @@ fn match_encoding_arg<'a>(args: &'a [Expr], kwargs: &'a [Keyword]) -> Option<Enc
None
}
/// Return an [`Edit`] replacing the call to encode with a byte string.
fn replace_with_bytes_literal(locator: &Locator, expr: &Expr, constant: &Expr) -> Edit {
/// Return a [`Fix`] replacing the call to encode with a byte string.
fn replace_with_bytes_literal(locator: &Locator, expr: &Expr, constant: &Expr) -> Fix {
// Build up a replacement string by prefixing all string tokens with `b`.
let contents = locator.slice(constant.range());
let mut replacement = String::with_capacity(contents.len() + 1);
@ -129,7 +129,7 @@ fn replace_with_bytes_literal(locator: &Locator, expr: &Expr, constant: &Expr) -
}
prev = Some(range.end());
}
Edit::range_replacement(replacement, expr.range())
Fix::unspecified(Edit::range_replacement(replacement, expr.range()))
}
/// UP012
@ -176,7 +176,8 @@ pub fn unnecessary_encode_utf8(
expr.range(),
);
if checker.patch(Rule::UnnecessaryEncodeUTF8) {
diagnostic.try_set_fix(|| {
#[allow(deprecated)]
diagnostic.try_set_fix_from_edit(|| {
remove_argument(
checker.locator,
func.start(),
@ -197,7 +198,8 @@ pub fn unnecessary_encode_utf8(
expr.range(),
);
if checker.patch(Rule::UnnecessaryEncodeUTF8) {
diagnostic.try_set_fix(|| {
#[allow(deprecated)]
diagnostic.try_set_fix_from_edit(|| {
remove_argument(
checker.locator,
func.start(),
@ -225,7 +227,8 @@ pub fn unnecessary_encode_utf8(
expr.range(),
);
if checker.patch(Rule::UnnecessaryEncodeUTF8) {
diagnostic.try_set_fix(|| {
#[allow(deprecated)]
diagnostic.try_set_fix_from_edit(|| {
remove_argument(
checker.locator,
func.start(),
@ -246,7 +249,8 @@ pub fn unnecessary_encode_utf8(
expr.range(),
);
if checker.patch(Rule::UnnecessaryEncodeUTF8) {
diagnostic.try_set_fix(|| {
#[allow(deprecated)]
diagnostic.try_set_fix_from_edit(|| {
remove_argument(
checker.locator,
func.start(),

View file

@ -2,7 +2,7 @@ use itertools::Itertools;
use log::error;
use rustpython_parser::ast::{Alias, AliasData, Located, Stmt};
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic};
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Fix};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::types::RefEquality;
@ -105,7 +105,7 @@ pub fn unnecessary_future_import(checker: &mut Checker, stmt: &Stmt, names: &[Lo
if fix.is_deletion() || fix.content() == Some("pass") {
checker.deletions.insert(RefEquality(defined_by));
}
diagnostic.set_fix(fix);
diagnostic.set_fix(Fix::unspecified(fix));
}
Err(e) => error!("Failed to remove `__future__` import: {e}"),
}

View file

@ -2,7 +2,7 @@ use log::error;
use ruff_text_size::TextRange;
use rustpython_parser::ast::{Expr, ExprKind, Stmt};
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic};
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Fix};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::types::RefEquality;
@ -61,11 +61,11 @@ pub fn useless_metaclass_type(checker: &mut Checker, stmt: &Stmt, value: &Expr,
checker.indexer,
checker.stylist,
) {
Ok(fix) => {
if fix.is_deletion() || fix.content() == Some("pass") {
Ok(edit) => {
if edit.is_deletion() || edit.content() == Some("pass") {
checker.deletions.insert(RefEquality(defined_by));
}
diagnostic.set_fix(fix);
diagnostic.set_fix(Fix::unspecified(edit));
}
Err(e) => error!("Failed to fix remove metaclass type: {e}"),
}

View file

@ -65,7 +65,8 @@ pub fn useless_object_inheritance(
if let Some(mut diagnostic) = rule(name, bases, checker.ctx.scope(), &checker.ctx.bindings) {
if checker.patch(diagnostic.kind.rule()) {
let expr_range = diagnostic.range();
diagnostic.try_set_fix(|| {
#[allow(deprecated)]
diagnostic.try_set_fix_from_edit(|| {
remove_argument(
checker.locator,
stmt.start(),

View file

@ -5,7 +5,7 @@ use ruff_text_size::{TextRange, TextSize};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use crate::Fix;
use crate::{Edit, Fix};
#[derive(Debug, PartialEq, Eq, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
@ -40,14 +40,21 @@ impl Diagnostic {
/// Set the [`Fix`] used to fix the diagnostic.
#[inline]
pub fn set_fix<T: Into<Fix>>(&mut self, fix: T) {
self.fix = Some(fix.into());
pub fn set_fix(&mut self, fix: Fix) {
self.fix = Some(fix);
}
/// Set the [`Fix`] used to fix the diagnostic.
#[inline]
#[deprecated(note = "Use `Diagnostic::set_fix` instead.")]
pub fn set_fix_from_edit(&mut self, edit: Edit) {
self.fix = Some(Fix::unspecified(edit));
}
/// Consumes `self` and returns a new `Diagnostic` with the given `fix`.
#[inline]
#[must_use]
pub fn with_fix<T: Into<Fix>>(mut self, fix: T) -> Self {
pub fn with_fix(mut self, fix: Fix) -> Self {
self.set_fix(fix);
self
}
@ -55,9 +62,20 @@ impl Diagnostic {
/// Set the [`Fix`] used to fix the diagnostic, if the provided function returns `Ok`.
/// Otherwise, log the error.
#[inline]
pub fn try_set_fix<T: Into<Fix>>(&mut self, func: impl FnOnce() -> Result<T>) {
pub fn try_set_fix(&mut self, func: impl FnOnce() -> Result<Fix>) {
match func() {
Ok(fix) => self.fix = Some(fix.into()),
Ok(fix) => self.fix = Some(fix),
Err(err) => error!("Failed to create fix: {}", err),
}
}
/// Sets an [`Edit`] used to fix the diagnostic, if the provided function returns `Ok`.
/// Otherwise, log the error.
#[inline]
#[deprecated(note = "Use Diagnostic::try_set_fix instead")]
pub fn try_set_fix_from_edit(&mut self, func: impl FnOnce() -> Result<Edit>) {
match func() {
Ok(edit) => self.fix = Some(Fix::unspecified(edit)),
Err(err) => error!("Failed to create fix: {}", err),
}
}

View file

@ -38,9 +38,3 @@ impl Fix {
self.edits
}
}
impl From<Edit> for Fix {
fn from(edit: Edit) -> Self {
Self { edits: vec![edit] }
}
}