The changes in this commit were generated by running: for f in $(find src -name '*.rs'); do sed -Ei 's/use crate::registry::.*;/\0use crate::violations;/g' $f; done for f in $(find src -name '*.rs'); do sed -Ei 's/CheckKind::([A-Z])/violations::\1/g' $f; done git checkout src/registry.rs src/lib.rs src/lib_wasm.rs src/violations.rs cargo +nightly fmt
117 lines
3.7 KiB
Rust
117 lines
3.7 KiB
Rust
use log::error;
|
|
use rustc_hash::FxHashSet;
|
|
use rustpython_ast::{Constant, Expr, ExprKind, Stmt, StmtKind};
|
|
|
|
use crate::ast::types::Range;
|
|
use crate::autofix::helpers::delete_stmt;
|
|
use crate::autofix::Fix;
|
|
use crate::checkers::ast::Checker;
|
|
use crate::registry::{Check, CheckCode, CheckKind};
|
|
use crate::violations;
|
|
|
|
/// PIE790
|
|
pub fn no_unnecessary_pass(checker: &mut Checker, body: &[Stmt]) {
|
|
if body.len() > 1 {
|
|
// This only catches the case in which a docstring makes a `pass` statement
|
|
// redundant. Consider removing all `pass` statements instead.
|
|
let docstring_stmt = &body[0];
|
|
let pass_stmt = &body[1];
|
|
let StmtKind::Expr { value } = &docstring_stmt.node else {
|
|
return;
|
|
};
|
|
if matches!(
|
|
value.node,
|
|
ExprKind::Constant {
|
|
value: Constant::Str(..),
|
|
..
|
|
}
|
|
) {
|
|
if matches!(pass_stmt.node, StmtKind::Pass) {
|
|
let mut check = Check::new(
|
|
violations::NoUnnecessaryPass,
|
|
Range::from_located(pass_stmt),
|
|
);
|
|
if checker.patch(&CheckCode::PIE790) {
|
|
match delete_stmt(pass_stmt, None, &[], checker.locator) {
|
|
Ok(fix) => {
|
|
check.amend(fix);
|
|
}
|
|
Err(e) => {
|
|
error!("Failed to delete `pass` statement: {}", e);
|
|
}
|
|
}
|
|
}
|
|
checker.checks.push(check);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// PIE794
|
|
pub fn dupe_class_field_definitions(checker: &mut Checker, bases: &[Expr], body: &[Stmt]) {
|
|
if bases.is_empty() {
|
|
return;
|
|
}
|
|
|
|
let mut seen_targets = FxHashSet::default();
|
|
for stmt in body {
|
|
// Extract the property name from the assignment statement.
|
|
let target = match &stmt.node {
|
|
StmtKind::Assign { targets, .. } => {
|
|
if targets.len() != 1 {
|
|
continue;
|
|
}
|
|
if let ExprKind::Name { id, .. } = &targets[0].node {
|
|
id
|
|
} else {
|
|
continue;
|
|
}
|
|
}
|
|
StmtKind::AnnAssign { target, .. } => {
|
|
if let ExprKind::Name { id, .. } = &target.node {
|
|
id
|
|
} else {
|
|
continue;
|
|
}
|
|
}
|
|
_ => continue,
|
|
};
|
|
|
|
if seen_targets.contains(target) {
|
|
let mut check = Check::new(
|
|
violations::DupeClassFieldDefinitions(target.to_string()),
|
|
Range::from_located(stmt),
|
|
);
|
|
if checker.patch(&CheckCode::PIE794) {
|
|
check.amend(Fix::deletion(stmt.location, stmt.end_location.unwrap()));
|
|
}
|
|
checker.checks.push(check);
|
|
} else {
|
|
seen_targets.insert(target);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// PIE807
|
|
pub fn prefer_list_builtin(checker: &mut Checker, expr: &Expr) {
|
|
let ExprKind::Lambda { args, body } = &expr.node else {
|
|
unreachable!("Expected ExprKind::Lambda");
|
|
};
|
|
if args.args.is_empty() {
|
|
if let ExprKind::List { elts, .. } = &body.node {
|
|
if elts.is_empty() {
|
|
let mut check =
|
|
Check::new(violations::PreferListBuiltin, Range::from_located(expr));
|
|
if checker.patch(&CheckCode::PIE807) {
|
|
check.amend(Fix::replacement(
|
|
"list".to_string(),
|
|
expr.location,
|
|
expr.end_location.unwrap(),
|
|
));
|
|
}
|
|
checker.checks.push(check);
|
|
}
|
|
}
|
|
}
|
|
}
|