mirror of https://github.com/astral-sh/ruff
Enable autofix for B014
This commit is contained in:
parent
765db12b84
commit
ee42413e10
|
|
@ -220,7 +220,7 @@ pub enum CheckKind {
|
||||||
BuiltinAttributeShadowing(String),
|
BuiltinAttributeShadowing(String),
|
||||||
// flake8-bugbear
|
// flake8-bugbear
|
||||||
DoNotAssertFalse,
|
DoNotAssertFalse,
|
||||||
DuplicateHandlerException(String),
|
DuplicateHandlerException(Vec<String>),
|
||||||
DuplicateTryBlockException(String),
|
DuplicateTryBlockException(String),
|
||||||
// flake8-comprehensions
|
// flake8-comprehensions
|
||||||
UnnecessaryGeneratorList,
|
UnnecessaryGeneratorList,
|
||||||
|
|
@ -317,7 +317,7 @@ impl CheckCode {
|
||||||
CheckCode::A003 => CheckKind::BuiltinAttributeShadowing("...".to_string()),
|
CheckCode::A003 => CheckKind::BuiltinAttributeShadowing("...".to_string()),
|
||||||
// flake8-bugbear
|
// flake8-bugbear
|
||||||
CheckCode::B011 => CheckKind::DoNotAssertFalse,
|
CheckCode::B011 => CheckKind::DoNotAssertFalse,
|
||||||
CheckCode::B014 => CheckKind::DuplicateHandlerException("Exception".to_string()),
|
CheckCode::B014 => CheckKind::DuplicateHandlerException(vec!["ValueError".to_string()]),
|
||||||
CheckCode::B025 => CheckKind::DuplicateTryBlockException("Exception".to_string()),
|
CheckCode::B025 => CheckKind::DuplicateTryBlockException("Exception".to_string()),
|
||||||
// flake8-comprehensions
|
// flake8-comprehensions
|
||||||
CheckCode::C400 => CheckKind::UnnecessaryGeneratorList,
|
CheckCode::C400 => CheckKind::UnnecessaryGeneratorList,
|
||||||
|
|
@ -594,8 +594,14 @@ impl CheckKind {
|
||||||
"Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`"
|
"Do not `assert False` (`python -O` removes these calls), raise `AssertionError()`"
|
||||||
.to_string()
|
.to_string()
|
||||||
}
|
}
|
||||||
CheckKind::DuplicateHandlerException(name) => {
|
CheckKind::DuplicateHandlerException(names) => {
|
||||||
format!("Exception handler with duplicate exception `{name}`")
|
if names.len() == 1 {
|
||||||
|
let name = &names[0];
|
||||||
|
format!("Exception handler with duplicate exception: `{name}")
|
||||||
|
} else {
|
||||||
|
let names = names.iter().map(|name| format!("`{name}`")).join(", ");
|
||||||
|
format!("Exception handler with duplicate exceptions: {names}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
CheckKind::DuplicateTryBlockException(name) => {
|
CheckKind::DuplicateTryBlockException(name) => {
|
||||||
format!("try-except block with duplicate exception `{name}`")
|
format!("try-except block with duplicate exception `{name}`")
|
||||||
|
|
@ -704,6 +710,7 @@ impl CheckKind {
|
||||||
self,
|
self,
|
||||||
CheckKind::DeprecatedUnittestAlias(_, _)
|
CheckKind::DeprecatedUnittestAlias(_, _)
|
||||||
| CheckKind::DoNotAssertFalse
|
| CheckKind::DoNotAssertFalse
|
||||||
|
| CheckKind::DuplicateHandlerException(_)
|
||||||
| CheckKind::PPrintFound
|
| CheckKind::PPrintFound
|
||||||
| CheckKind::PrintFound
|
| CheckKind::PrintFound
|
||||||
| CheckKind::SuperCallWithParameters
|
| CheckKind::SuperCallWithParameters
|
||||||
|
|
|
||||||
|
|
@ -1,37 +1,69 @@
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use rustpython_ast::{Excepthandler, ExcepthandlerKind, Expr, ExprKind, Stmt};
|
use rustpython_ast::{Excepthandler, ExcepthandlerKind, Expr, ExprContext, ExprKind, Stmt};
|
||||||
|
|
||||||
use crate::ast::helpers;
|
use crate::ast::helpers;
|
||||||
use crate::ast::types::{CheckLocator, Range};
|
use crate::ast::types::{CheckLocator, Range};
|
||||||
|
use crate::autofix::fixer;
|
||||||
use crate::check_ast::Checker;
|
use crate::check_ast::Checker;
|
||||||
use crate::checks::{Check, CheckCode, CheckKind};
|
use crate::checks::{Check, CheckCode, CheckKind, Fix};
|
||||||
|
use crate::code_gen::SourceGenerator;
|
||||||
|
|
||||||
|
fn type_pattern(elts: Vec<&Expr>) -> Expr {
|
||||||
|
Expr::new(
|
||||||
|
Default::default(),
|
||||||
|
Default::default(),
|
||||||
|
ExprKind::Tuple {
|
||||||
|
elts: elts.into_iter().cloned().collect(),
|
||||||
|
ctx: ExprContext::Load,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn duplicate_handler_exceptions(
|
pub fn duplicate_handler_exceptions(
|
||||||
checker: &mut Checker,
|
checker: &mut Checker,
|
||||||
stmt: &Stmt,
|
expr: &Expr,
|
||||||
elts: &Vec<Expr>,
|
elts: &Vec<Expr>,
|
||||||
) -> BTreeSet<String> {
|
) -> BTreeSet<String> {
|
||||||
let mut seen: BTreeSet<String> = Default::default();
|
let mut seen: BTreeSet<String> = Default::default();
|
||||||
let mut duplicates: BTreeSet<String> = Default::default();
|
let mut duplicates: BTreeSet<String> = Default::default();
|
||||||
|
let mut unique_elts: Vec<&Expr> = Default::default();
|
||||||
for type_ in elts {
|
for type_ in elts {
|
||||||
if let Some(name) = helpers::compose_call_path(type_) {
|
if let Some(name) = helpers::compose_call_path(type_) {
|
||||||
if seen.contains(&name) {
|
if seen.contains(&name) {
|
||||||
duplicates.insert(name);
|
duplicates.insert(name);
|
||||||
} else {
|
} else {
|
||||||
seen.insert(name);
|
seen.insert(name);
|
||||||
|
unique_elts.push(type_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if checker.settings.enabled.contains(&CheckCode::B014) {
|
if checker.settings.enabled.contains(&CheckCode::B014) {
|
||||||
// TODO(charlie): Handle "BaseException" and redundant exception aliases.
|
// TODO(charlie): Handle "BaseException" and redundant exception aliases.
|
||||||
for duplicate in duplicates.into_iter().sorted() {
|
if !duplicates.is_empty() {
|
||||||
checker.add_check(Check::new(
|
let mut check = Check::new(
|
||||||
CheckKind::DuplicateHandlerException(duplicate),
|
CheckKind::DuplicateHandlerException(
|
||||||
checker.locate_check(Range::from_located(stmt)),
|
duplicates.into_iter().sorted().collect::<Vec<String>>(),
|
||||||
));
|
),
|
||||||
|
checker.locate_check(Range::from_located(expr)),
|
||||||
|
);
|
||||||
|
if matches!(checker.autofix, fixer::Mode::Generate | fixer::Mode::Apply) {
|
||||||
|
// TODO(charlie): If we have a single element, remove the tuple.
|
||||||
|
let mut generator = SourceGenerator::new();
|
||||||
|
if let Ok(()) = generator.unparse_expr(&type_pattern(unique_elts), 0) {
|
||||||
|
if let Ok(content) = generator.generate() {
|
||||||
|
check.amend(Fix {
|
||||||
|
content,
|
||||||
|
location: expr.location,
|
||||||
|
end_location: expr.end_location,
|
||||||
|
applied: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
checker.add_check(check);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -56,7 +88,7 @@ pub fn duplicate_exceptions(checker: &mut Checker, stmt: &Stmt, handlers: &[Exce
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExprKind::Tuple { elts, .. } => {
|
ExprKind::Tuple { elts, .. } => {
|
||||||
for name in duplicate_handler_exceptions(checker, stmt, elts) {
|
for name in duplicate_handler_exceptions(checker, type_, elts) {
|
||||||
if seen.contains(&name) {
|
if seen.contains(&name) {
|
||||||
duplicates.insert(name);
|
duplicates.insert(name);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -3,30 +3,57 @@ source: src/linter.rs
|
||||||
expression: checks
|
expression: checks
|
||||||
---
|
---
|
||||||
- kind:
|
- kind:
|
||||||
DuplicateHandlerException: OSError
|
DuplicateHandlerException:
|
||||||
|
- OSError
|
||||||
location:
|
location:
|
||||||
row: 15
|
row: 17
|
||||||
column: 1
|
column: 9
|
||||||
end_location:
|
end_location:
|
||||||
row: 22
|
row: 17
|
||||||
column: 1
|
column: 25
|
||||||
fix: ~
|
fix:
|
||||||
|
content: "OSError,"
|
||||||
|
location:
|
||||||
|
row: 17
|
||||||
|
column: 9
|
||||||
|
end_location:
|
||||||
|
row: 17
|
||||||
|
column: 25
|
||||||
|
applied: false
|
||||||
- kind:
|
- kind:
|
||||||
DuplicateHandlerException: MyError
|
DuplicateHandlerException:
|
||||||
|
- MyError
|
||||||
location:
|
location:
|
||||||
row: 26
|
row: 28
|
||||||
column: 1
|
column: 9
|
||||||
end_location:
|
end_location:
|
||||||
row: 33
|
row: 28
|
||||||
column: 1
|
column: 25
|
||||||
fix: ~
|
fix:
|
||||||
|
content: "MyError,"
|
||||||
|
location:
|
||||||
|
row: 28
|
||||||
|
column: 9
|
||||||
|
end_location:
|
||||||
|
row: 28
|
||||||
|
column: 25
|
||||||
|
applied: false
|
||||||
- kind:
|
- kind:
|
||||||
DuplicateHandlerException: re.error
|
DuplicateHandlerException:
|
||||||
|
- re.error
|
||||||
location:
|
location:
|
||||||
row: 47
|
row: 49
|
||||||
column: 1
|
column: 9
|
||||||
end_location:
|
end_location:
|
||||||
row: 54
|
row: 49
|
||||||
column: 1
|
column: 27
|
||||||
fix: ~
|
fix:
|
||||||
|
content: "re.error,"
|
||||||
|
location:
|
||||||
|
row: 49
|
||||||
|
column: 9
|
||||||
|
end_location:
|
||||||
|
row: 49
|
||||||
|
column: 27
|
||||||
|
applied: false
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue