mirror of https://github.com/astral-sh/ruff
Move flake8-comprehensions violations to rule files (#2477)
This commit is contained in:
parent
f5fd6f59ea
commit
aa85c81280
|
|
@ -130,22 +130,22 @@ ruff_macros::define_rule_mapping!(
|
|||
// flake8-blind-except
|
||||
BLE001 => violations::BlindExcept,
|
||||
// flake8-comprehensions
|
||||
C400 => violations::UnnecessaryGeneratorList,
|
||||
C401 => violations::UnnecessaryGeneratorSet,
|
||||
C402 => violations::UnnecessaryGeneratorDict,
|
||||
C403 => violations::UnnecessaryListComprehensionSet,
|
||||
C404 => violations::UnnecessaryListComprehensionDict,
|
||||
C405 => violations::UnnecessaryLiteralSet,
|
||||
C406 => violations::UnnecessaryLiteralDict,
|
||||
C408 => violations::UnnecessaryCollectionCall,
|
||||
C409 => violations::UnnecessaryLiteralWithinTupleCall,
|
||||
C410 => violations::UnnecessaryLiteralWithinListCall,
|
||||
C411 => violations::UnnecessaryListCall,
|
||||
C413 => violations::UnnecessaryCallAroundSorted,
|
||||
C414 => violations::UnnecessaryDoubleCastOrProcess,
|
||||
C415 => violations::UnnecessarySubscriptReversal,
|
||||
C416 => violations::UnnecessaryComprehension,
|
||||
C417 => violations::UnnecessaryMap,
|
||||
C400 => rules::flake8_comprehensions::rules::UnnecessaryGeneratorList,
|
||||
C401 => rules::flake8_comprehensions::rules::UnnecessaryGeneratorSet,
|
||||
C402 => rules::flake8_comprehensions::rules::UnnecessaryGeneratorDict,
|
||||
C403 => rules::flake8_comprehensions::rules::UnnecessaryListComprehensionSet,
|
||||
C404 => rules::flake8_comprehensions::rules::UnnecessaryListComprehensionDict,
|
||||
C405 => rules::flake8_comprehensions::rules::UnnecessaryLiteralSet,
|
||||
C406 => rules::flake8_comprehensions::rules::UnnecessaryLiteralDict,
|
||||
C408 => rules::flake8_comprehensions::rules::UnnecessaryCollectionCall,
|
||||
C409 => rules::flake8_comprehensions::rules::UnnecessaryLiteralWithinTupleCall,
|
||||
C410 => rules::flake8_comprehensions::rules::UnnecessaryLiteralWithinListCall,
|
||||
C411 => rules::flake8_comprehensions::rules::UnnecessaryListCall,
|
||||
C413 => rules::flake8_comprehensions::rules::UnnecessaryCallAroundSorted,
|
||||
C414 => rules::flake8_comprehensions::rules::UnnecessaryDoubleCastOrProcess,
|
||||
C415 => rules::flake8_comprehensions::rules::UnnecessarySubscriptReversal,
|
||||
C416 => rules::flake8_comprehensions::rules::UnnecessaryComprehension,
|
||||
C417 => rules::flake8_comprehensions::rules::UnnecessaryMap,
|
||||
// flake8-debugger
|
||||
T100 => violations::Debugger,
|
||||
// mccabe
|
||||
|
|
|
|||
|
|
@ -1,728 +0,0 @@
|
|||
use log::error;
|
||||
use num_bigint::BigInt;
|
||||
use rustpython_ast::{Comprehension, Constant, Expr, ExprKind, Keyword, Unaryop};
|
||||
|
||||
use super::fixes;
|
||||
use crate::ast::types::Range;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::violations;
|
||||
|
||||
fn function_name(func: &Expr) -> Option<&str> {
|
||||
if let ExprKind::Name { id, .. } = &func.node {
|
||||
Some(id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn exactly_one_argument_with_matching_function<'a>(
|
||||
name: &str,
|
||||
func: &Expr,
|
||||
args: &'a [Expr],
|
||||
keywords: &[Keyword],
|
||||
) -> Option<&'a ExprKind> {
|
||||
if !keywords.is_empty() {
|
||||
return None;
|
||||
}
|
||||
if args.len() != 1 {
|
||||
return None;
|
||||
}
|
||||
if function_name(func)? != name {
|
||||
return None;
|
||||
}
|
||||
Some(&args[0].node)
|
||||
}
|
||||
|
||||
fn first_argument_with_matching_function<'a>(
|
||||
name: &str,
|
||||
func: &Expr,
|
||||
args: &'a [Expr],
|
||||
) -> Option<&'a ExprKind> {
|
||||
if function_name(func)? == name {
|
||||
Some(&args.first()?.node)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// C400 (`list(generator)`)
|
||||
pub fn unnecessary_generator_list(
|
||||
checker: &mut Checker,
|
||||
expr: &Expr,
|
||||
func: &Expr,
|
||||
args: &[Expr],
|
||||
keywords: &[Keyword],
|
||||
) {
|
||||
let Some(argument) = exactly_one_argument_with_matching_function("list", func, args, keywords) else {
|
||||
return;
|
||||
};
|
||||
if !checker.is_builtin("list") {
|
||||
return;
|
||||
}
|
||||
if let ExprKind::GeneratorExp { .. } = argument {
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
violations::UnnecessaryGeneratorList,
|
||||
Range::from_located(expr),
|
||||
);
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
match fixes::fix_unnecessary_generator_list(checker.locator, checker.stylist, expr) {
|
||||
Ok(fix) => {
|
||||
diagnostic.amend(fix);
|
||||
}
|
||||
Err(e) => error!("Failed to generate fix: {e}"),
|
||||
}
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
|
||||
/// C401 (`set(generator)`)
|
||||
pub fn unnecessary_generator_set(
|
||||
checker: &mut Checker,
|
||||
expr: &Expr,
|
||||
func: &Expr,
|
||||
args: &[Expr],
|
||||
keywords: &[Keyword],
|
||||
) {
|
||||
let Some(argument) = exactly_one_argument_with_matching_function("set", func, args, keywords) else {
|
||||
return;
|
||||
};
|
||||
if !checker.is_builtin("set") {
|
||||
return;
|
||||
}
|
||||
if let ExprKind::GeneratorExp { .. } = argument {
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
violations::UnnecessaryGeneratorSet,
|
||||
Range::from_located(expr),
|
||||
);
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
match fixes::fix_unnecessary_generator_set(checker.locator, checker.stylist, expr) {
|
||||
Ok(fix) => {
|
||||
diagnostic.amend(fix);
|
||||
}
|
||||
Err(e) => error!("Failed to generate fix: {e}"),
|
||||
}
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
|
||||
/// C402 (`dict((x, y) for x, y in iterable)`)
|
||||
pub fn unnecessary_generator_dict(
|
||||
checker: &mut Checker,
|
||||
expr: &Expr,
|
||||
func: &Expr,
|
||||
args: &[Expr],
|
||||
keywords: &[Keyword],
|
||||
) {
|
||||
let Some(argument) = exactly_one_argument_with_matching_function("dict", func, args, keywords) else {
|
||||
return;
|
||||
};
|
||||
if let ExprKind::GeneratorExp { elt, .. } = argument {
|
||||
match &elt.node {
|
||||
ExprKind::Tuple { elts, .. } if elts.len() == 2 => {
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
violations::UnnecessaryGeneratorDict,
|
||||
Range::from_located(expr),
|
||||
);
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
match fixes::fix_unnecessary_generator_dict(
|
||||
checker.locator,
|
||||
checker.stylist,
|
||||
expr,
|
||||
) {
|
||||
Ok(fix) => {
|
||||
diagnostic.amend(fix);
|
||||
}
|
||||
Err(e) => error!("Failed to generate fix: {e}"),
|
||||
}
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// C403 (`set([...])`)
|
||||
pub fn unnecessary_list_comprehension_set(
|
||||
checker: &mut Checker,
|
||||
expr: &Expr,
|
||||
func: &Expr,
|
||||
args: &[Expr],
|
||||
keywords: &[Keyword],
|
||||
) {
|
||||
let Some(argument) = exactly_one_argument_with_matching_function("set", func, args, keywords) else {
|
||||
return;
|
||||
};
|
||||
if !checker.is_builtin("set") {
|
||||
return;
|
||||
}
|
||||
if let ExprKind::ListComp { .. } = &argument {
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
violations::UnnecessaryListComprehensionSet,
|
||||
Range::from_located(expr),
|
||||
);
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
match fixes::fix_unnecessary_list_comprehension_set(
|
||||
checker.locator,
|
||||
checker.stylist,
|
||||
expr,
|
||||
) {
|
||||
Ok(fix) => {
|
||||
diagnostic.amend(fix);
|
||||
}
|
||||
Err(e) => error!("Failed to generate fix: {e}"),
|
||||
}
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
|
||||
/// C404 (`dict([...])`)
|
||||
pub fn unnecessary_list_comprehension_dict(
|
||||
checker: &mut Checker,
|
||||
expr: &Expr,
|
||||
func: &Expr,
|
||||
args: &[Expr],
|
||||
keywords: &[Keyword],
|
||||
) {
|
||||
let Some(argument) = exactly_one_argument_with_matching_function("dict", func, args, keywords) else {
|
||||
return;
|
||||
};
|
||||
if !checker.is_builtin("dict") {
|
||||
return;
|
||||
}
|
||||
let ExprKind::ListComp { elt, .. } = &argument else {
|
||||
return;
|
||||
};
|
||||
let ExprKind::Tuple { elts, .. } = &elt.node else {
|
||||
return;
|
||||
};
|
||||
if elts.len() != 2 {
|
||||
return;
|
||||
}
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
violations::UnnecessaryListComprehensionDict,
|
||||
Range::from_located(expr),
|
||||
);
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
match fixes::fix_unnecessary_list_comprehension_dict(checker.locator, checker.stylist, expr)
|
||||
{
|
||||
Ok(fix) => {
|
||||
diagnostic.amend(fix);
|
||||
}
|
||||
Err(e) => error!("Failed to generate fix: {e}"),
|
||||
}
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
|
||||
/// C405 (`set([1, 2])`)
|
||||
pub fn unnecessary_literal_set(
|
||||
checker: &mut Checker,
|
||||
expr: &Expr,
|
||||
func: &Expr,
|
||||
args: &[Expr],
|
||||
keywords: &[Keyword],
|
||||
) {
|
||||
let Some(argument) = exactly_one_argument_with_matching_function("set", func, args, keywords) else {
|
||||
return;
|
||||
};
|
||||
if !checker.is_builtin("set") {
|
||||
return;
|
||||
}
|
||||
let kind = match argument {
|
||||
ExprKind::List { .. } => "list",
|
||||
ExprKind::Tuple { .. } => "tuple",
|
||||
_ => return,
|
||||
};
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
violations::UnnecessaryLiteralSet {
|
||||
obj_type: kind.to_string(),
|
||||
},
|
||||
Range::from_located(expr),
|
||||
);
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
match fixes::fix_unnecessary_literal_set(checker.locator, checker.stylist, expr) {
|
||||
Ok(fix) => {
|
||||
diagnostic.amend(fix);
|
||||
}
|
||||
Err(e) => error!("Failed to generate fix: {e}"),
|
||||
}
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
|
||||
/// C406 (`dict([(1, 2)])`)
|
||||
pub fn unnecessary_literal_dict(
|
||||
checker: &mut Checker,
|
||||
expr: &Expr,
|
||||
func: &Expr,
|
||||
args: &[Expr],
|
||||
keywords: &[Keyword],
|
||||
) {
|
||||
let Some(argument) = exactly_one_argument_with_matching_function("dict", func, args, keywords) else {
|
||||
return;
|
||||
};
|
||||
if !checker.is_builtin("dict") {
|
||||
return;
|
||||
}
|
||||
let (kind, elts) = match argument {
|
||||
ExprKind::Tuple { elts, .. } => ("tuple", elts),
|
||||
ExprKind::List { elts, .. } => ("list", elts),
|
||||
_ => return,
|
||||
};
|
||||
// Accept `dict((1, 2), ...))` `dict([(1, 2), ...])`.
|
||||
if !elts
|
||||
.iter()
|
||||
.all(|elt| matches!(&elt.node, ExprKind::Tuple { elts, .. } if elts.len() == 2))
|
||||
{
|
||||
return;
|
||||
}
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
violations::UnnecessaryLiteralDict {
|
||||
obj_type: kind.to_string(),
|
||||
},
|
||||
Range::from_located(expr),
|
||||
);
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
match fixes::fix_unnecessary_literal_dict(checker.locator, checker.stylist, expr) {
|
||||
Ok(fix) => {
|
||||
diagnostic.amend(fix);
|
||||
}
|
||||
Err(e) => error!("Failed to generate fix: {e}"),
|
||||
}
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
|
||||
/// C408
|
||||
pub fn unnecessary_collection_call(
|
||||
checker: &mut Checker,
|
||||
expr: &Expr,
|
||||
func: &Expr,
|
||||
args: &[Expr],
|
||||
keywords: &[Keyword],
|
||||
) {
|
||||
if !args.is_empty() {
|
||||
return;
|
||||
}
|
||||
let Some(id) = function_name(func) else {
|
||||
return;
|
||||
};
|
||||
match id {
|
||||
"dict" if keywords.is_empty() || keywords.iter().all(|kw| kw.node.arg.is_some()) => {
|
||||
// `dict()` or `dict(a=1)` (as opposed to `dict(**a)`)
|
||||
}
|
||||
"list" | "tuple" => {
|
||||
// `list()` or `tuple()`
|
||||
}
|
||||
_ => return,
|
||||
};
|
||||
if !checker.is_builtin(id) {
|
||||
return;
|
||||
}
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
violations::UnnecessaryCollectionCall {
|
||||
obj_type: id.to_string(),
|
||||
},
|
||||
Range::from_located(expr),
|
||||
);
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
match fixes::fix_unnecessary_collection_call(checker.locator, checker.stylist, expr) {
|
||||
Ok(fix) => {
|
||||
diagnostic.amend(fix);
|
||||
}
|
||||
Err(e) => error!("Failed to generate fix: {e}"),
|
||||
}
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
|
||||
/// C409
|
||||
pub fn unnecessary_literal_within_tuple_call(
|
||||
checker: &mut Checker,
|
||||
expr: &Expr,
|
||||
func: &Expr,
|
||||
args: &[Expr],
|
||||
) {
|
||||
let Some(argument) = first_argument_with_matching_function("tuple", func, args) else {
|
||||
return;
|
||||
};
|
||||
if !checker.is_builtin("tuple") {
|
||||
return;
|
||||
}
|
||||
let argument_kind = match argument {
|
||||
ExprKind::Tuple { .. } => "tuple",
|
||||
ExprKind::List { .. } => "list",
|
||||
_ => return,
|
||||
};
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
violations::UnnecessaryLiteralWithinTupleCall {
|
||||
literal: argument_kind.to_string(),
|
||||
},
|
||||
Range::from_located(expr),
|
||||
);
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
match fixes::fix_unnecessary_literal_within_tuple_call(
|
||||
checker.locator,
|
||||
checker.stylist,
|
||||
expr,
|
||||
) {
|
||||
Ok(fix) => {
|
||||
diagnostic.amend(fix);
|
||||
}
|
||||
Err(e) => error!("Failed to generate fix: {e}"),
|
||||
}
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
|
||||
/// C410
|
||||
pub fn unnecessary_literal_within_list_call(
|
||||
checker: &mut Checker,
|
||||
expr: &Expr,
|
||||
func: &Expr,
|
||||
args: &[Expr],
|
||||
) {
|
||||
let Some(argument) = first_argument_with_matching_function("list", func, args) else {
|
||||
return;
|
||||
};
|
||||
if !checker.is_builtin("list") {
|
||||
return;
|
||||
}
|
||||
let argument_kind = match argument {
|
||||
ExprKind::Tuple { .. } => "tuple",
|
||||
ExprKind::List { .. } => "list",
|
||||
_ => return,
|
||||
};
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
violations::UnnecessaryLiteralWithinListCall {
|
||||
literal: argument_kind.to_string(),
|
||||
},
|
||||
Range::from_located(expr),
|
||||
);
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
match fixes::fix_unnecessary_literal_within_list_call(
|
||||
checker.locator,
|
||||
checker.stylist,
|
||||
expr,
|
||||
) {
|
||||
Ok(fix) => {
|
||||
diagnostic.amend(fix);
|
||||
}
|
||||
Err(e) => error!("Failed to generate fix: {e}"),
|
||||
}
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
|
||||
/// C411
|
||||
pub fn unnecessary_list_call(checker: &mut Checker, expr: &Expr, func: &Expr, args: &[Expr]) {
|
||||
let Some(argument) = first_argument_with_matching_function("list", func, args) else {
|
||||
return;
|
||||
};
|
||||
if !checker.is_builtin("list") {
|
||||
return;
|
||||
}
|
||||
if !matches!(argument, ExprKind::ListComp { .. }) {
|
||||
return;
|
||||
}
|
||||
let mut diagnostic =
|
||||
Diagnostic::new(violations::UnnecessaryListCall, Range::from_located(expr));
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
match fixes::fix_unnecessary_list_call(checker.locator, checker.stylist, expr) {
|
||||
Ok(fix) => {
|
||||
diagnostic.amend(fix);
|
||||
}
|
||||
Err(e) => error!("Failed to generate fix: {e}"),
|
||||
}
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
|
||||
/// C413
|
||||
pub fn unnecessary_call_around_sorted(
|
||||
checker: &mut Checker,
|
||||
expr: &Expr,
|
||||
func: &Expr,
|
||||
args: &[Expr],
|
||||
) {
|
||||
let Some(outer) = function_name(func) else {
|
||||
return;
|
||||
};
|
||||
if !(outer == "list" || outer == "reversed") {
|
||||
return;
|
||||
}
|
||||
let Some(arg) = args.first() else {
|
||||
return;
|
||||
};
|
||||
let ExprKind::Call { func, .. } = &arg.node else {
|
||||
return;
|
||||
};
|
||||
let Some(inner) = function_name(func) else {
|
||||
return;
|
||||
};
|
||||
if inner != "sorted" {
|
||||
return;
|
||||
}
|
||||
if !checker.is_builtin(inner) || !checker.is_builtin(outer) {
|
||||
return;
|
||||
}
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
violations::UnnecessaryCallAroundSorted {
|
||||
func: outer.to_string(),
|
||||
},
|
||||
Range::from_located(expr),
|
||||
);
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
match fixes::fix_unnecessary_call_around_sorted(checker.locator, checker.stylist, expr) {
|
||||
Ok(fix) => {
|
||||
diagnostic.amend(fix);
|
||||
}
|
||||
Err(e) => error!("Failed to generate fix: {e}"),
|
||||
}
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
|
||||
/// C414
|
||||
pub fn unnecessary_double_cast_or_process(
|
||||
checker: &mut Checker,
|
||||
expr: &Expr,
|
||||
func: &Expr,
|
||||
args: &[Expr],
|
||||
) {
|
||||
fn diagnostic(inner: &str, outer: &str, location: Range) -> Diagnostic {
|
||||
Diagnostic::new(
|
||||
violations::UnnecessaryDoubleCastOrProcess {
|
||||
inner: inner.to_string(),
|
||||
outer: outer.to_string(),
|
||||
},
|
||||
location,
|
||||
)
|
||||
}
|
||||
|
||||
let Some(outer) = function_name(func) else {
|
||||
return;
|
||||
};
|
||||
if !(outer == "list"
|
||||
|| outer == "tuple"
|
||||
|| outer == "set"
|
||||
|| outer == "reversed"
|
||||
|| outer == "sorted")
|
||||
{
|
||||
return;
|
||||
}
|
||||
let Some(arg) = args.first() else {
|
||||
return;
|
||||
};
|
||||
let ExprKind::Call { func, .. } = &arg.node else {
|
||||
return;
|
||||
};
|
||||
let Some(inner) = function_name(func) else {
|
||||
return;
|
||||
};
|
||||
if !checker.is_builtin(inner) || !checker.is_builtin(outer) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ex) set(tuple(...))
|
||||
if (outer == "set" || outer == "sorted")
|
||||
&& (inner == "list" || inner == "tuple" || inner == "reversed" || inner == "sorted")
|
||||
{
|
||||
checker
|
||||
.diagnostics
|
||||
.push(diagnostic(inner, outer, Range::from_located(expr)));
|
||||
return;
|
||||
}
|
||||
|
||||
// Ex) list(tuple(...))
|
||||
if (outer == "list" || outer == "tuple") && (inner == "list" || inner == "tuple") {
|
||||
checker
|
||||
.diagnostics
|
||||
.push(diagnostic(inner, outer, Range::from_located(expr)));
|
||||
return;
|
||||
}
|
||||
|
||||
// Ex) set(set(...))
|
||||
if outer == "set" && inner == "set" {
|
||||
checker
|
||||
.diagnostics
|
||||
.push(diagnostic(inner, outer, Range::from_located(expr)));
|
||||
}
|
||||
}
|
||||
|
||||
/// C415
|
||||
pub fn unnecessary_subscript_reversal(
|
||||
checker: &mut Checker,
|
||||
expr: &Expr,
|
||||
func: &Expr,
|
||||
args: &[Expr],
|
||||
) {
|
||||
let Some(first_arg) = args.first() else {
|
||||
return;
|
||||
};
|
||||
let Some(id) = function_name(func) else {
|
||||
return;
|
||||
};
|
||||
if !(id == "set" || id == "sorted" || id == "reversed") {
|
||||
return;
|
||||
}
|
||||
if !checker.is_builtin(id) {
|
||||
return;
|
||||
}
|
||||
let ExprKind::Subscript { slice, .. } = &first_arg.node else {
|
||||
return;
|
||||
};
|
||||
let ExprKind::Slice { lower, upper, step } = &slice.node else {
|
||||
return;
|
||||
};
|
||||
if lower.is_some() || upper.is_some() {
|
||||
return;
|
||||
}
|
||||
let Some(step) = step.as_ref() else {
|
||||
return;
|
||||
};
|
||||
let ExprKind::UnaryOp {
|
||||
op: Unaryop::USub,
|
||||
operand,
|
||||
} = &step.node else {
|
||||
return;
|
||||
};
|
||||
let ExprKind::Constant {
|
||||
value: Constant::Int(val),
|
||||
..
|
||||
} = &operand.node else {
|
||||
return;
|
||||
};
|
||||
if *val != BigInt::from(1) {
|
||||
return;
|
||||
};
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
violations::UnnecessarySubscriptReversal {
|
||||
func: id.to_string(),
|
||||
},
|
||||
Range::from_located(expr),
|
||||
));
|
||||
}
|
||||
|
||||
/// C416
|
||||
pub fn unnecessary_comprehension(
|
||||
checker: &mut Checker,
|
||||
expr: &Expr,
|
||||
elt: &Expr,
|
||||
generators: &[Comprehension],
|
||||
) {
|
||||
if generators.len() != 1 {
|
||||
return;
|
||||
}
|
||||
let generator = &generators[0];
|
||||
if !(generator.ifs.is_empty() && generator.is_async == 0) {
|
||||
return;
|
||||
}
|
||||
let Some(elt_id) = function_name(elt) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(target_id) = function_name(&generator.target) else {
|
||||
return;
|
||||
};
|
||||
if elt_id != target_id {
|
||||
return;
|
||||
}
|
||||
let id = match &expr.node {
|
||||
ExprKind::ListComp { .. } => "list",
|
||||
ExprKind::SetComp { .. } => "set",
|
||||
_ => return,
|
||||
};
|
||||
if !checker.is_builtin(id) {
|
||||
return;
|
||||
}
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
violations::UnnecessaryComprehension {
|
||||
obj_type: id.to_string(),
|
||||
},
|
||||
Range::from_located(expr),
|
||||
);
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
match fixes::fix_unnecessary_comprehension(checker.locator, checker.stylist, expr) {
|
||||
Ok(fix) => {
|
||||
diagnostic.amend(fix);
|
||||
}
|
||||
Err(e) => error!("Failed to generate fix: {e}"),
|
||||
}
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
|
||||
/// C417
|
||||
pub fn unnecessary_map(checker: &mut Checker, expr: &Expr, func: &Expr, args: &[Expr]) {
|
||||
fn diagnostic(kind: &str, location: Range) -> Diagnostic {
|
||||
Diagnostic::new(
|
||||
violations::UnnecessaryMap {
|
||||
obj_type: kind.to_string(),
|
||||
},
|
||||
location,
|
||||
)
|
||||
}
|
||||
|
||||
let Some(id) = function_name(func) else {
|
||||
return;
|
||||
};
|
||||
match id {
|
||||
"map" => {
|
||||
if !checker.is_builtin(id) {
|
||||
return;
|
||||
}
|
||||
|
||||
if args.len() == 2 && matches!(&args[0].node, ExprKind::Lambda { .. }) {
|
||||
checker
|
||||
.diagnostics
|
||||
.push(diagnostic("generator", Range::from_located(expr)));
|
||||
}
|
||||
}
|
||||
"list" | "set" => {
|
||||
if !checker.is_builtin(id) {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(arg) = args.first() {
|
||||
if let ExprKind::Call { func, args, .. } = &arg.node {
|
||||
let Some(argument) = first_argument_with_matching_function("map", func, args) else {
|
||||
return;
|
||||
};
|
||||
if let ExprKind::Lambda { .. } = argument {
|
||||
checker
|
||||
.diagnostics
|
||||
.push(diagnostic(id, Range::from_located(expr)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"dict" => {
|
||||
if !checker.is_builtin(id) {
|
||||
return;
|
||||
}
|
||||
|
||||
if args.len() == 1 {
|
||||
if let ExprKind::Call { func, args, .. } = &args[0].node {
|
||||
let Some(argument) = first_argument_with_matching_function("map", func, args) else {
|
||||
return;
|
||||
};
|
||||
if let ExprKind::Lambda { body, .. } = &argument {
|
||||
if matches!(&body.node, ExprKind::Tuple { elts, .. } | ExprKind::List { elts, .. } if elts.len() == 2)
|
||||
{
|
||||
checker
|
||||
.diagnostics
|
||||
.push(diagnostic(id, Range::from_located(expr)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
use rustpython_ast::{Expr, ExprKind, Keyword};
|
||||
|
||||
pub fn function_name(func: &Expr) -> Option<&str> {
|
||||
if let ExprKind::Name { id, .. } = &func.node {
|
||||
Some(id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn exactly_one_argument_with_matching_function<'a>(
|
||||
name: &str,
|
||||
func: &Expr,
|
||||
args: &'a [Expr],
|
||||
keywords: &[Keyword],
|
||||
) -> Option<&'a ExprKind> {
|
||||
if !keywords.is_empty() {
|
||||
return None;
|
||||
}
|
||||
if args.len() != 1 {
|
||||
return None;
|
||||
}
|
||||
if function_name(func)? != name {
|
||||
return None;
|
||||
}
|
||||
Some(&args[0].node)
|
||||
}
|
||||
|
||||
pub fn first_argument_with_matching_function<'a>(
|
||||
name: &str,
|
||||
func: &Expr,
|
||||
args: &'a [Expr],
|
||||
) -> Option<&'a ExprKind> {
|
||||
if function_name(func)? == name {
|
||||
Some(&args.first()?.node)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
mod helpers;
|
||||
mod unnecessary_call_around_sorted;
|
||||
mod unnecessary_collection_call;
|
||||
mod unnecessary_comprehension;
|
||||
mod unnecessary_double_cast_or_process;
|
||||
mod unnecessary_generator_dict;
|
||||
mod unnecessary_generator_list;
|
||||
mod unnecessary_generator_set;
|
||||
mod unnecessary_list_call;
|
||||
mod unnecessary_list_comprehension_dict;
|
||||
mod unnecessary_list_comprehension_set;
|
||||
mod unnecessary_literal_dict;
|
||||
mod unnecessary_literal_set;
|
||||
mod unnecessary_literal_within_list_call;
|
||||
mod unnecessary_literal_within_tuple_call;
|
||||
mod unnecessary_map;
|
||||
mod unnecessary_subscript_reversal;
|
||||
|
||||
pub use unnecessary_call_around_sorted::{
|
||||
unnecessary_call_around_sorted, UnnecessaryCallAroundSorted,
|
||||
};
|
||||
pub use unnecessary_collection_call::{unnecessary_collection_call, UnnecessaryCollectionCall};
|
||||
pub use unnecessary_comprehension::{unnecessary_comprehension, UnnecessaryComprehension};
|
||||
pub use unnecessary_double_cast_or_process::{
|
||||
unnecessary_double_cast_or_process, UnnecessaryDoubleCastOrProcess,
|
||||
};
|
||||
pub use unnecessary_generator_dict::{unnecessary_generator_dict, UnnecessaryGeneratorDict};
|
||||
pub use unnecessary_generator_list::{unnecessary_generator_list, UnnecessaryGeneratorList};
|
||||
pub use unnecessary_generator_set::{unnecessary_generator_set, UnnecessaryGeneratorSet};
|
||||
pub use unnecessary_list_call::{unnecessary_list_call, UnnecessaryListCall};
|
||||
pub use unnecessary_list_comprehension_dict::{
|
||||
unnecessary_list_comprehension_dict, UnnecessaryListComprehensionDict,
|
||||
};
|
||||
pub use unnecessary_list_comprehension_set::{
|
||||
unnecessary_list_comprehension_set, UnnecessaryListComprehensionSet,
|
||||
};
|
||||
pub use unnecessary_literal_dict::{unnecessary_literal_dict, UnnecessaryLiteralDict};
|
||||
pub use unnecessary_literal_set::{unnecessary_literal_set, UnnecessaryLiteralSet};
|
||||
pub use unnecessary_literal_within_list_call::{
|
||||
unnecessary_literal_within_list_call, UnnecessaryLiteralWithinListCall,
|
||||
};
|
||||
pub use unnecessary_literal_within_tuple_call::{
|
||||
unnecessary_literal_within_tuple_call, UnnecessaryLiteralWithinTupleCall,
|
||||
};
|
||||
pub use unnecessary_map::{unnecessary_map, UnnecessaryMap};
|
||||
pub use unnecessary_subscript_reversal::{
|
||||
unnecessary_subscript_reversal, UnnecessarySubscriptReversal,
|
||||
};
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
use super::helpers;
|
||||
use crate::ast::types::Range;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::define_violation;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::rules::flake8_comprehensions::fixes;
|
||||
use crate::violation::AlwaysAutofixableViolation;
|
||||
use log::error;
|
||||
use ruff_macros::derive_message_formats;
|
||||
use rustpython_ast::{Expr, ExprKind};
|
||||
|
||||
define_violation!(
|
||||
pub struct UnnecessaryCallAroundSorted {
|
||||
pub func: String,
|
||||
}
|
||||
);
|
||||
impl AlwaysAutofixableViolation for UnnecessaryCallAroundSorted {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let UnnecessaryCallAroundSorted { func } = self;
|
||||
format!("Unnecessary `{func}` call around `sorted()`")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
let UnnecessaryCallAroundSorted { func } = self;
|
||||
format!("Remove unnecessary `{func}` call")
|
||||
}
|
||||
}
|
||||
|
||||
/// C413
|
||||
pub fn unnecessary_call_around_sorted(
|
||||
checker: &mut Checker,
|
||||
expr: &Expr,
|
||||
func: &Expr,
|
||||
args: &[Expr],
|
||||
) {
|
||||
let Some(outer) = helpers::function_name(func) else {
|
||||
return;
|
||||
};
|
||||
if !(outer == "list" || outer == "reversed") {
|
||||
return;
|
||||
}
|
||||
let Some(arg) = args.first() else {
|
||||
return;
|
||||
};
|
||||
let ExprKind::Call { func, .. } = &arg.node else {
|
||||
return;
|
||||
};
|
||||
let Some(inner) = helpers::function_name(func) else {
|
||||
return;
|
||||
};
|
||||
if inner != "sorted" {
|
||||
return;
|
||||
}
|
||||
if !checker.is_builtin(inner) || !checker.is_builtin(outer) {
|
||||
return;
|
||||
}
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
UnnecessaryCallAroundSorted {
|
||||
func: outer.to_string(),
|
||||
},
|
||||
Range::from_located(expr),
|
||||
);
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
match fixes::fix_unnecessary_call_around_sorted(checker.locator, checker.stylist, expr) {
|
||||
Ok(fix) => {
|
||||
diagnostic.amend(fix);
|
||||
}
|
||||
Err(e) => error!("Failed to generate fix: {e}"),
|
||||
}
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
use super::helpers;
|
||||
use crate::ast::types::Range;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::define_violation;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::rules::flake8_comprehensions::fixes;
|
||||
use crate::violation::AlwaysAutofixableViolation;
|
||||
use log::error;
|
||||
use ruff_macros::derive_message_formats;
|
||||
use rustpython_ast::{Expr, Keyword};
|
||||
|
||||
define_violation!(
|
||||
pub struct UnnecessaryCollectionCall {
|
||||
pub obj_type: String,
|
||||
}
|
||||
);
|
||||
impl AlwaysAutofixableViolation for UnnecessaryCollectionCall {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let UnnecessaryCollectionCall { obj_type } = self;
|
||||
format!("Unnecessary `{obj_type}` call (rewrite as a literal)")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
"Rewrite as a literal".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// C408
|
||||
pub fn unnecessary_collection_call(
|
||||
checker: &mut Checker,
|
||||
expr: &Expr,
|
||||
func: &Expr,
|
||||
args: &[Expr],
|
||||
keywords: &[Keyword],
|
||||
) {
|
||||
if !args.is_empty() {
|
||||
return;
|
||||
}
|
||||
let Some(id) = helpers::function_name(func) else {
|
||||
return;
|
||||
};
|
||||
match id {
|
||||
"dict" if keywords.is_empty() || keywords.iter().all(|kw| kw.node.arg.is_some()) => {
|
||||
// `dict()` or `dict(a=1)` (as opposed to `dict(**a)`)
|
||||
}
|
||||
"list" | "tuple" => {
|
||||
// `list()` or `tuple()`
|
||||
}
|
||||
_ => return,
|
||||
};
|
||||
if !checker.is_builtin(id) {
|
||||
return;
|
||||
}
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
UnnecessaryCollectionCall {
|
||||
obj_type: id.to_string(),
|
||||
},
|
||||
Range::from_located(expr),
|
||||
);
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
match fixes::fix_unnecessary_collection_call(checker.locator, checker.stylist, expr) {
|
||||
Ok(fix) => {
|
||||
diagnostic.amend(fix);
|
||||
}
|
||||
Err(e) => error!("Failed to generate fix: {e}"),
|
||||
}
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
use super::helpers;
|
||||
use crate::ast::types::Range;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::define_violation;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::rules::flake8_comprehensions::fixes;
|
||||
use crate::violation::AlwaysAutofixableViolation;
|
||||
use log::error;
|
||||
use ruff_macros::derive_message_formats;
|
||||
use rustpython_ast::{Comprehension, Expr, ExprKind};
|
||||
|
||||
define_violation!(
|
||||
pub struct UnnecessaryComprehension {
|
||||
pub obj_type: String,
|
||||
}
|
||||
);
|
||||
impl AlwaysAutofixableViolation for UnnecessaryComprehension {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let UnnecessaryComprehension { obj_type } = self;
|
||||
format!("Unnecessary `{obj_type}` comprehension (rewrite using `{obj_type}()`)")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
let UnnecessaryComprehension { obj_type } = self;
|
||||
format!("Rewrite using `{obj_type}()`")
|
||||
}
|
||||
}
|
||||
|
||||
/// C416
|
||||
pub fn unnecessary_comprehension(
|
||||
checker: &mut Checker,
|
||||
expr: &Expr,
|
||||
elt: &Expr,
|
||||
generators: &[Comprehension],
|
||||
) {
|
||||
if generators.len() != 1 {
|
||||
return;
|
||||
}
|
||||
let generator = &generators[0];
|
||||
if !(generator.ifs.is_empty() && generator.is_async == 0) {
|
||||
return;
|
||||
}
|
||||
let Some(elt_id) = helpers::function_name(elt) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(target_id) = helpers::function_name(&generator.target) else {
|
||||
return;
|
||||
};
|
||||
if elt_id != target_id {
|
||||
return;
|
||||
}
|
||||
let id = match &expr.node {
|
||||
ExprKind::ListComp { .. } => "list",
|
||||
ExprKind::SetComp { .. } => "set",
|
||||
_ => return,
|
||||
};
|
||||
if !checker.is_builtin(id) {
|
||||
return;
|
||||
}
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
UnnecessaryComprehension {
|
||||
obj_type: id.to_string(),
|
||||
},
|
||||
Range::from_located(expr),
|
||||
);
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
match fixes::fix_unnecessary_comprehension(checker.locator, checker.stylist, expr) {
|
||||
Ok(fix) => {
|
||||
diagnostic.amend(fix);
|
||||
}
|
||||
Err(e) => error!("Failed to generate fix: {e}"),
|
||||
}
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
use super::helpers;
|
||||
use crate::ast::types::Range;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::define_violation;
|
||||
use crate::registry::Diagnostic;
|
||||
|
||||
use crate::violation::Violation;
|
||||
use ruff_macros::derive_message_formats;
|
||||
use rustpython_ast::{Expr, ExprKind};
|
||||
|
||||
define_violation!(
|
||||
pub struct UnnecessaryDoubleCastOrProcess {
|
||||
pub inner: String,
|
||||
pub outer: String,
|
||||
}
|
||||
);
|
||||
impl Violation for UnnecessaryDoubleCastOrProcess {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let UnnecessaryDoubleCastOrProcess { inner, outer } = self;
|
||||
format!("Unnecessary `{inner}` call within `{outer}()`")
|
||||
}
|
||||
}
|
||||
|
||||
/// C414
|
||||
pub fn unnecessary_double_cast_or_process(
|
||||
checker: &mut Checker,
|
||||
expr: &Expr,
|
||||
func: &Expr,
|
||||
args: &[Expr],
|
||||
) {
|
||||
fn diagnostic(inner: &str, outer: &str, location: Range) -> Diagnostic {
|
||||
Diagnostic::new(
|
||||
UnnecessaryDoubleCastOrProcess {
|
||||
inner: inner.to_string(),
|
||||
outer: outer.to_string(),
|
||||
},
|
||||
location,
|
||||
)
|
||||
}
|
||||
|
||||
let Some(outer) = helpers::function_name(func) else {
|
||||
return;
|
||||
};
|
||||
if !(outer == "list"
|
||||
|| outer == "tuple"
|
||||
|| outer == "set"
|
||||
|| outer == "reversed"
|
||||
|| outer == "sorted")
|
||||
{
|
||||
return;
|
||||
}
|
||||
let Some(arg) = args.first() else {
|
||||
return;
|
||||
};
|
||||
let ExprKind::Call { func, .. } = &arg.node else {
|
||||
return;
|
||||
};
|
||||
let Some(inner) = helpers::function_name(func) else {
|
||||
return;
|
||||
};
|
||||
if !checker.is_builtin(inner) || !checker.is_builtin(outer) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ex) set(tuple(...))
|
||||
if (outer == "set" || outer == "sorted")
|
||||
&& (inner == "list" || inner == "tuple" || inner == "reversed" || inner == "sorted")
|
||||
{
|
||||
checker
|
||||
.diagnostics
|
||||
.push(diagnostic(inner, outer, Range::from_located(expr)));
|
||||
return;
|
||||
}
|
||||
|
||||
// Ex) list(tuple(...))
|
||||
if (outer == "list" || outer == "tuple") && (inner == "list" || inner == "tuple") {
|
||||
checker
|
||||
.diagnostics
|
||||
.push(diagnostic(inner, outer, Range::from_located(expr)));
|
||||
return;
|
||||
}
|
||||
|
||||
// Ex) set(set(...))
|
||||
if outer == "set" && inner == "set" {
|
||||
checker
|
||||
.diagnostics
|
||||
.push(diagnostic(inner, outer, Range::from_located(expr)));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
use super::helpers;
|
||||
use crate::ast::types::Range;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::define_violation;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::rules::flake8_comprehensions::fixes;
|
||||
use crate::violation::AlwaysAutofixableViolation;
|
||||
use log::error;
|
||||
use ruff_macros::derive_message_formats;
|
||||
use rustpython_ast::{Expr, ExprKind, Keyword};
|
||||
|
||||
define_violation!(
|
||||
pub struct UnnecessaryGeneratorDict;
|
||||
);
|
||||
impl AlwaysAutofixableViolation for UnnecessaryGeneratorDict {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Unnecessary generator (rewrite as a `dict` comprehension)")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
"Rewrite as a `dict` comprehension".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// C402 (`dict((x, y) for x, y in iterable)`)
|
||||
pub fn unnecessary_generator_dict(
|
||||
checker: &mut Checker,
|
||||
expr: &Expr,
|
||||
func: &Expr,
|
||||
args: &[Expr],
|
||||
keywords: &[Keyword],
|
||||
) {
|
||||
let Some(argument) = helpers::exactly_one_argument_with_matching_function("dict", func, args, keywords) else {
|
||||
return;
|
||||
};
|
||||
if let ExprKind::GeneratorExp { elt, .. } = argument {
|
||||
match &elt.node {
|
||||
ExprKind::Tuple { elts, .. } if elts.len() == 2 => {
|
||||
let mut diagnostic =
|
||||
Diagnostic::new(UnnecessaryGeneratorDict, Range::from_located(expr));
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
match fixes::fix_unnecessary_generator_dict(
|
||||
checker.locator,
|
||||
checker.stylist,
|
||||
expr,
|
||||
) {
|
||||
Ok(fix) => {
|
||||
diagnostic.amend(fix);
|
||||
}
|
||||
Err(e) => error!("Failed to generate fix: {e}"),
|
||||
}
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
use super::helpers;
|
||||
use crate::ast::types::Range;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::define_violation;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::rules::flake8_comprehensions::fixes;
|
||||
use crate::violation::AlwaysAutofixableViolation;
|
||||
use log::error;
|
||||
use ruff_macros::derive_message_formats;
|
||||
use rustpython_ast::{Expr, ExprKind, Keyword};
|
||||
|
||||
define_violation!(
|
||||
pub struct UnnecessaryGeneratorList;
|
||||
);
|
||||
impl AlwaysAutofixableViolation for UnnecessaryGeneratorList {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Unnecessary generator (rewrite as a `list` comprehension)")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
"Rewrite as a `list` comprehension".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// C400 (`list(generator)`)
|
||||
pub fn unnecessary_generator_list(
|
||||
checker: &mut Checker,
|
||||
expr: &Expr,
|
||||
func: &Expr,
|
||||
args: &[Expr],
|
||||
keywords: &[Keyword],
|
||||
) {
|
||||
let Some(argument) = helpers::exactly_one_argument_with_matching_function("list", func, args, keywords) else {
|
||||
return;
|
||||
};
|
||||
if !checker.is_builtin("list") {
|
||||
return;
|
||||
}
|
||||
if let ExprKind::GeneratorExp { .. } = argument {
|
||||
let mut diagnostic = Diagnostic::new(UnnecessaryGeneratorList, Range::from_located(expr));
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
match fixes::fix_unnecessary_generator_list(checker.locator, checker.stylist, expr) {
|
||||
Ok(fix) => {
|
||||
diagnostic.amend(fix);
|
||||
}
|
||||
Err(e) => error!("Failed to generate fix: {e}"),
|
||||
}
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
use super::helpers;
|
||||
use crate::ast::types::Range;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::define_violation;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::rules::flake8_comprehensions::fixes;
|
||||
use crate::violation::AlwaysAutofixableViolation;
|
||||
use log::error;
|
||||
use ruff_macros::derive_message_formats;
|
||||
use rustpython_ast::{Expr, ExprKind, Keyword};
|
||||
|
||||
define_violation!(
|
||||
pub struct UnnecessaryGeneratorSet;
|
||||
);
|
||||
impl AlwaysAutofixableViolation for UnnecessaryGeneratorSet {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Unnecessary generator (rewrite as a `set` comprehension)")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
"Rewrite as a `set` comprehension".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// C401 (`set(generator)`)
|
||||
pub fn unnecessary_generator_set(
|
||||
checker: &mut Checker,
|
||||
expr: &Expr,
|
||||
func: &Expr,
|
||||
args: &[Expr],
|
||||
keywords: &[Keyword],
|
||||
) {
|
||||
let Some(argument) = helpers::exactly_one_argument_with_matching_function("set", func, args, keywords) else {
|
||||
return;
|
||||
};
|
||||
if !checker.is_builtin("set") {
|
||||
return;
|
||||
}
|
||||
if let ExprKind::GeneratorExp { .. } = argument {
|
||||
let mut diagnostic = Diagnostic::new(UnnecessaryGeneratorSet, Range::from_located(expr));
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
match fixes::fix_unnecessary_generator_set(checker.locator, checker.stylist, expr) {
|
||||
Ok(fix) => {
|
||||
diagnostic.amend(fix);
|
||||
}
|
||||
Err(e) => error!("Failed to generate fix: {e}"),
|
||||
}
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
use super::helpers;
|
||||
use crate::ast::types::Range;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::define_violation;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::rules::flake8_comprehensions::fixes;
|
||||
use crate::violation::AlwaysAutofixableViolation;
|
||||
use log::error;
|
||||
use ruff_macros::derive_message_formats;
|
||||
use rustpython_ast::{Expr, ExprKind};
|
||||
|
||||
define_violation!(
|
||||
pub struct UnnecessaryListCall;
|
||||
);
|
||||
impl AlwaysAutofixableViolation for UnnecessaryListCall {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Unnecessary `list` call (remove the outer call to `list()`)")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
"Remove outer `list` call".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// C411
|
||||
pub fn unnecessary_list_call(checker: &mut Checker, expr: &Expr, func: &Expr, args: &[Expr]) {
|
||||
let Some(argument) = helpers::first_argument_with_matching_function("list", func, args) else {
|
||||
return;
|
||||
};
|
||||
if !checker.is_builtin("list") {
|
||||
return;
|
||||
}
|
||||
if !matches!(argument, ExprKind::ListComp { .. }) {
|
||||
return;
|
||||
}
|
||||
let mut diagnostic = Diagnostic::new(UnnecessaryListCall, Range::from_located(expr));
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
match fixes::fix_unnecessary_list_call(checker.locator, checker.stylist, expr) {
|
||||
Ok(fix) => {
|
||||
diagnostic.amend(fix);
|
||||
}
|
||||
Err(e) => error!("Failed to generate fix: {e}"),
|
||||
}
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
use super::helpers;
|
||||
use crate::ast::types::Range;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::define_violation;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::rules::flake8_comprehensions::fixes;
|
||||
use crate::violation::AlwaysAutofixableViolation;
|
||||
use log::error;
|
||||
use ruff_macros::derive_message_formats;
|
||||
use rustpython_ast::{Expr, ExprKind, Keyword};
|
||||
|
||||
define_violation!(
|
||||
pub struct UnnecessaryListComprehensionDict;
|
||||
);
|
||||
impl AlwaysAutofixableViolation for UnnecessaryListComprehensionDict {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Unnecessary `list` comprehension (rewrite as a `dict` comprehension)")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
"Rewrite as a `dict` comprehension".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// C404 (`dict([...])`)
|
||||
pub fn unnecessary_list_comprehension_dict(
|
||||
checker: &mut Checker,
|
||||
expr: &Expr,
|
||||
func: &Expr,
|
||||
args: &[Expr],
|
||||
keywords: &[Keyword],
|
||||
) {
|
||||
let Some(argument) = helpers::exactly_one_argument_with_matching_function("dict", func, args, keywords) else {
|
||||
return;
|
||||
};
|
||||
if !checker.is_builtin("dict") {
|
||||
return;
|
||||
}
|
||||
let ExprKind::ListComp { elt, .. } = &argument else {
|
||||
return;
|
||||
};
|
||||
let ExprKind::Tuple { elts, .. } = &elt.node else {
|
||||
return;
|
||||
};
|
||||
if elts.len() != 2 {
|
||||
return;
|
||||
}
|
||||
let mut diagnostic =
|
||||
Diagnostic::new(UnnecessaryListComprehensionDict, Range::from_located(expr));
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
match fixes::fix_unnecessary_list_comprehension_dict(checker.locator, checker.stylist, expr)
|
||||
{
|
||||
Ok(fix) => {
|
||||
diagnostic.amend(fix);
|
||||
}
|
||||
Err(e) => error!("Failed to generate fix: {e}"),
|
||||
}
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
use super::helpers;
|
||||
use crate::ast::types::Range;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::define_violation;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::rules::flake8_comprehensions::fixes;
|
||||
use crate::violation::AlwaysAutofixableViolation;
|
||||
use log::error;
|
||||
use ruff_macros::derive_message_formats;
|
||||
use rustpython_ast::{Expr, ExprKind, Keyword};
|
||||
|
||||
define_violation!(
|
||||
pub struct UnnecessaryListComprehensionSet;
|
||||
);
|
||||
impl AlwaysAutofixableViolation for UnnecessaryListComprehensionSet {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Unnecessary `list` comprehension (rewrite as a `set` comprehension)")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
"Rewrite as a `set` comprehension".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// C403 (`set([...])`)
|
||||
pub fn unnecessary_list_comprehension_set(
|
||||
checker: &mut Checker,
|
||||
expr: &Expr,
|
||||
func: &Expr,
|
||||
args: &[Expr],
|
||||
keywords: &[Keyword],
|
||||
) {
|
||||
let Some(argument) = helpers::exactly_one_argument_with_matching_function("set", func, args, keywords) else {
|
||||
return;
|
||||
};
|
||||
if !checker.is_builtin("set") {
|
||||
return;
|
||||
}
|
||||
if let ExprKind::ListComp { .. } = &argument {
|
||||
let mut diagnostic =
|
||||
Diagnostic::new(UnnecessaryListComprehensionSet, Range::from_located(expr));
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
match fixes::fix_unnecessary_list_comprehension_set(
|
||||
checker.locator,
|
||||
checker.stylist,
|
||||
expr,
|
||||
) {
|
||||
Ok(fix) => {
|
||||
diagnostic.amend(fix);
|
||||
}
|
||||
Err(e) => error!("Failed to generate fix: {e}"),
|
||||
}
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
use super::helpers;
|
||||
use crate::ast::types::Range;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::define_violation;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::rules::flake8_comprehensions::fixes;
|
||||
use crate::violation::AlwaysAutofixableViolation;
|
||||
use log::error;
|
||||
use ruff_macros::derive_message_formats;
|
||||
use rustpython_ast::{Expr, ExprKind, Keyword};
|
||||
|
||||
define_violation!(
|
||||
pub struct UnnecessaryLiteralDict {
|
||||
pub obj_type: String,
|
||||
}
|
||||
);
|
||||
impl AlwaysAutofixableViolation for UnnecessaryLiteralDict {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let UnnecessaryLiteralDict { obj_type } = self;
|
||||
format!("Unnecessary `{obj_type}` literal (rewrite as a `dict` literal)")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
"Rewrite as a `dict` literal".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// C406 (`dict([(1, 2)])`)
|
||||
pub fn unnecessary_literal_dict(
|
||||
checker: &mut Checker,
|
||||
expr: &Expr,
|
||||
func: &Expr,
|
||||
args: &[Expr],
|
||||
keywords: &[Keyword],
|
||||
) {
|
||||
let Some(argument) = helpers::exactly_one_argument_with_matching_function("dict", func, args, keywords) else {
|
||||
return;
|
||||
};
|
||||
if !checker.is_builtin("dict") {
|
||||
return;
|
||||
}
|
||||
let (kind, elts) = match argument {
|
||||
ExprKind::Tuple { elts, .. } => ("tuple", elts),
|
||||
ExprKind::List { elts, .. } => ("list", elts),
|
||||
_ => return,
|
||||
};
|
||||
// Accept `dict((1, 2), ...))` `dict([(1, 2), ...])`.
|
||||
if !elts
|
||||
.iter()
|
||||
.all(|elt| matches!(&elt.node, ExprKind::Tuple { elts, .. } if elts.len() == 2))
|
||||
{
|
||||
return;
|
||||
}
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
UnnecessaryLiteralDict {
|
||||
obj_type: kind.to_string(),
|
||||
},
|
||||
Range::from_located(expr),
|
||||
);
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
match fixes::fix_unnecessary_literal_dict(checker.locator, checker.stylist, expr) {
|
||||
Ok(fix) => {
|
||||
diagnostic.amend(fix);
|
||||
}
|
||||
Err(e) => error!("Failed to generate fix: {e}"),
|
||||
}
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
use super::helpers;
|
||||
use crate::ast::types::Range;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::define_violation;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::rules::flake8_comprehensions::fixes;
|
||||
use crate::violation::AlwaysAutofixableViolation;
|
||||
use log::error;
|
||||
use ruff_macros::derive_message_formats;
|
||||
use rustpython_ast::{Expr, ExprKind, Keyword};
|
||||
|
||||
define_violation!(
|
||||
pub struct UnnecessaryLiteralSet {
|
||||
pub obj_type: String,
|
||||
}
|
||||
);
|
||||
impl AlwaysAutofixableViolation for UnnecessaryLiteralSet {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let UnnecessaryLiteralSet { obj_type } = self;
|
||||
format!("Unnecessary `{obj_type}` literal (rewrite as a `set` literal)")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
"Rewrite as a `set` literal".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// C405 (`set([1, 2])`)
|
||||
pub fn unnecessary_literal_set(
|
||||
checker: &mut Checker,
|
||||
expr: &Expr,
|
||||
func: &Expr,
|
||||
args: &[Expr],
|
||||
keywords: &[Keyword],
|
||||
) {
|
||||
let Some(argument) = helpers::exactly_one_argument_with_matching_function("set", func, args, keywords) else {
|
||||
return;
|
||||
};
|
||||
if !checker.is_builtin("set") {
|
||||
return;
|
||||
}
|
||||
let kind = match argument {
|
||||
ExprKind::List { .. } => "list",
|
||||
ExprKind::Tuple { .. } => "tuple",
|
||||
_ => return,
|
||||
};
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
UnnecessaryLiteralSet {
|
||||
obj_type: kind.to_string(),
|
||||
},
|
||||
Range::from_located(expr),
|
||||
);
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
match fixes::fix_unnecessary_literal_set(checker.locator, checker.stylist, expr) {
|
||||
Ok(fix) => {
|
||||
diagnostic.amend(fix);
|
||||
}
|
||||
Err(e) => error!("Failed to generate fix: {e}"),
|
||||
}
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
use super::helpers;
|
||||
use crate::ast::types::Range;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::define_violation;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::rules::flake8_comprehensions::fixes;
|
||||
use crate::violation::AlwaysAutofixableViolation;
|
||||
use log::error;
|
||||
use ruff_macros::derive_message_formats;
|
||||
use rustpython_ast::{Expr, ExprKind};
|
||||
|
||||
define_violation!(
|
||||
pub struct UnnecessaryLiteralWithinListCall {
|
||||
pub literal: String,
|
||||
}
|
||||
);
|
||||
impl AlwaysAutofixableViolation for UnnecessaryLiteralWithinListCall {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let UnnecessaryLiteralWithinListCall { literal } = self;
|
||||
if literal == "list" {
|
||||
format!(
|
||||
"Unnecessary `{literal}` literal passed to `list()` (remove the outer call to \
|
||||
`list()`)"
|
||||
)
|
||||
} else {
|
||||
format!(
|
||||
"Unnecessary `{literal}` literal passed to `list()` (rewrite as a `list` literal)"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
let UnnecessaryLiteralWithinListCall { literal } = self;
|
||||
{
|
||||
if literal == "list" {
|
||||
"Remove outer `list` call".to_string()
|
||||
} else {
|
||||
"Rewrite as a `list` literal".to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// C410
|
||||
pub fn unnecessary_literal_within_list_call(
|
||||
checker: &mut Checker,
|
||||
expr: &Expr,
|
||||
func: &Expr,
|
||||
args: &[Expr],
|
||||
) {
|
||||
let Some(argument) = helpers::first_argument_with_matching_function("list", func, args) else {
|
||||
return;
|
||||
};
|
||||
if !checker.is_builtin("list") {
|
||||
return;
|
||||
}
|
||||
let argument_kind = match argument {
|
||||
ExprKind::Tuple { .. } => "tuple",
|
||||
ExprKind::List { .. } => "list",
|
||||
_ => return,
|
||||
};
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
UnnecessaryLiteralWithinListCall {
|
||||
literal: argument_kind.to_string(),
|
||||
},
|
||||
Range::from_located(expr),
|
||||
);
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
match fixes::fix_unnecessary_literal_within_list_call(
|
||||
checker.locator,
|
||||
checker.stylist,
|
||||
expr,
|
||||
) {
|
||||
Ok(fix) => {
|
||||
diagnostic.amend(fix);
|
||||
}
|
||||
Err(e) => error!("Failed to generate fix: {e}"),
|
||||
}
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
use super::helpers;
|
||||
use crate::ast::types::Range;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::define_violation;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::rules::flake8_comprehensions::fixes;
|
||||
use crate::violation::AlwaysAutofixableViolation;
|
||||
use log::error;
|
||||
use ruff_macros::derive_message_formats;
|
||||
use rustpython_ast::{Expr, ExprKind};
|
||||
|
||||
define_violation!(
|
||||
pub struct UnnecessaryLiteralWithinTupleCall {
|
||||
pub literal: String,
|
||||
}
|
||||
);
|
||||
impl AlwaysAutofixableViolation for UnnecessaryLiteralWithinTupleCall {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let UnnecessaryLiteralWithinTupleCall { literal } = self;
|
||||
if literal == "list" {
|
||||
format!(
|
||||
"Unnecessary `{literal}` literal passed to `tuple()` (rewrite as a `tuple` \
|
||||
literal)"
|
||||
)
|
||||
} else {
|
||||
format!(
|
||||
"Unnecessary `{literal}` literal passed to `tuple()` (remove the outer call to \
|
||||
`tuple()`)"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
let UnnecessaryLiteralWithinTupleCall { literal } = self;
|
||||
{
|
||||
if literal == "list" {
|
||||
"Rewrite as a `tuple` literal".to_string()
|
||||
} else {
|
||||
"Remove outer `tuple` call".to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// C409
|
||||
pub fn unnecessary_literal_within_tuple_call(
|
||||
checker: &mut Checker,
|
||||
expr: &Expr,
|
||||
func: &Expr,
|
||||
args: &[Expr],
|
||||
) {
|
||||
let Some(argument) = helpers::first_argument_with_matching_function("tuple", func, args) else {
|
||||
return;
|
||||
};
|
||||
if !checker.is_builtin("tuple") {
|
||||
return;
|
||||
}
|
||||
let argument_kind = match argument {
|
||||
ExprKind::Tuple { .. } => "tuple",
|
||||
ExprKind::List { .. } => "list",
|
||||
_ => return,
|
||||
};
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
UnnecessaryLiteralWithinTupleCall {
|
||||
literal: argument_kind.to_string(),
|
||||
},
|
||||
Range::from_located(expr),
|
||||
);
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
match fixes::fix_unnecessary_literal_within_tuple_call(
|
||||
checker.locator,
|
||||
checker.stylist,
|
||||
expr,
|
||||
) {
|
||||
Ok(fix) => {
|
||||
diagnostic.amend(fix);
|
||||
}
|
||||
Err(e) => error!("Failed to generate fix: {e}"),
|
||||
}
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
use super::helpers;
|
||||
use crate::ast::types::Range;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::define_violation;
|
||||
use crate::registry::Diagnostic;
|
||||
|
||||
use crate::violation::Violation;
|
||||
use ruff_macros::derive_message_formats;
|
||||
use rustpython_ast::{Expr, ExprKind};
|
||||
|
||||
define_violation!(
|
||||
pub struct UnnecessaryMap {
|
||||
pub obj_type: String,
|
||||
}
|
||||
);
|
||||
impl Violation for UnnecessaryMap {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let UnnecessaryMap { obj_type } = self;
|
||||
if obj_type == "generator" {
|
||||
format!("Unnecessary `map` usage (rewrite using a generator expression)")
|
||||
} else {
|
||||
format!("Unnecessary `map` usage (rewrite using a `{obj_type}` comprehension)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// C417
|
||||
pub fn unnecessary_map(checker: &mut Checker, expr: &Expr, func: &Expr, args: &[Expr]) {
|
||||
fn diagnostic(kind: &str, location: Range) -> Diagnostic {
|
||||
Diagnostic::new(
|
||||
UnnecessaryMap {
|
||||
obj_type: kind.to_string(),
|
||||
},
|
||||
location,
|
||||
)
|
||||
}
|
||||
|
||||
let Some(id) = helpers::function_name(func) else {
|
||||
return;
|
||||
};
|
||||
match id {
|
||||
"map" => {
|
||||
if !checker.is_builtin(id) {
|
||||
return;
|
||||
}
|
||||
|
||||
if args.len() == 2 && matches!(&args[0].node, ExprKind::Lambda { .. }) {
|
||||
checker
|
||||
.diagnostics
|
||||
.push(diagnostic("generator", Range::from_located(expr)));
|
||||
}
|
||||
}
|
||||
"list" | "set" => {
|
||||
if !checker.is_builtin(id) {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(arg) = args.first() {
|
||||
if let ExprKind::Call { func, args, .. } = &arg.node {
|
||||
let Some(argument) = helpers::first_argument_with_matching_function("map", func, args) else {
|
||||
return;
|
||||
};
|
||||
if let ExprKind::Lambda { .. } = argument {
|
||||
checker
|
||||
.diagnostics
|
||||
.push(diagnostic(id, Range::from_located(expr)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"dict" => {
|
||||
if !checker.is_builtin(id) {
|
||||
return;
|
||||
}
|
||||
|
||||
if args.len() == 1 {
|
||||
if let ExprKind::Call { func, args, .. } = &args[0].node {
|
||||
let Some(argument) = helpers::first_argument_with_matching_function("map", func, args) else {
|
||||
return;
|
||||
};
|
||||
if let ExprKind::Lambda { body, .. } = &argument {
|
||||
if matches!(&body.node, ExprKind::Tuple { elts, .. } | ExprKind::List { elts, .. } if elts.len() == 2)
|
||||
{
|
||||
checker
|
||||
.diagnostics
|
||||
.push(diagnostic(id, Range::from_located(expr)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
use super::helpers;
|
||||
use crate::ast::types::Range;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::define_violation;
|
||||
use crate::registry::Diagnostic;
|
||||
|
||||
use crate::violation::Violation;
|
||||
use num_bigint::BigInt;
|
||||
use ruff_macros::derive_message_formats;
|
||||
use rustpython_ast::{Constant, Expr, ExprKind, Unaryop};
|
||||
|
||||
define_violation!(
|
||||
pub struct UnnecessarySubscriptReversal {
|
||||
pub func: String,
|
||||
}
|
||||
);
|
||||
impl Violation for UnnecessarySubscriptReversal {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let UnnecessarySubscriptReversal { func } = self;
|
||||
format!("Unnecessary subscript reversal of iterable within `{func}()`")
|
||||
}
|
||||
}
|
||||
|
||||
/// C415
|
||||
pub fn unnecessary_subscript_reversal(
|
||||
checker: &mut Checker,
|
||||
expr: &Expr,
|
||||
func: &Expr,
|
||||
args: &[Expr],
|
||||
) {
|
||||
let Some(first_arg) = args.first() else {
|
||||
return;
|
||||
};
|
||||
let Some(id) = helpers::function_name(func) else {
|
||||
return;
|
||||
};
|
||||
if !(id == "set" || id == "sorted" || id == "reversed") {
|
||||
return;
|
||||
}
|
||||
if !checker.is_builtin(id) {
|
||||
return;
|
||||
}
|
||||
let ExprKind::Subscript { slice, .. } = &first_arg.node else {
|
||||
return;
|
||||
};
|
||||
let ExprKind::Slice { lower, upper, step } = &slice.node else {
|
||||
return;
|
||||
};
|
||||
if lower.is_some() || upper.is_some() {
|
||||
return;
|
||||
}
|
||||
let Some(step) = step.as_ref() else {
|
||||
return;
|
||||
};
|
||||
let ExprKind::UnaryOp {
|
||||
op: Unaryop::USub,
|
||||
operand,
|
||||
} = &step.node else {
|
||||
return;
|
||||
};
|
||||
let ExprKind::Constant {
|
||||
value: Constant::Int(val),
|
||||
..
|
||||
} = &operand.node else {
|
||||
return;
|
||||
};
|
||||
if *val != BigInt::from(1) {
|
||||
return;
|
||||
};
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
UnnecessarySubscriptReversal {
|
||||
func: id.to_string(),
|
||||
},
|
||||
Range::from_located(expr),
|
||||
));
|
||||
}
|
||||
|
|
@ -1396,290 +1396,6 @@ impl Violation for BlindExcept {
|
|||
}
|
||||
}
|
||||
|
||||
// flake8-comprehensions
|
||||
|
||||
define_violation!(
|
||||
pub struct UnnecessaryGeneratorList;
|
||||
);
|
||||
impl AlwaysAutofixableViolation for UnnecessaryGeneratorList {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Unnecessary generator (rewrite as a `list` comprehension)")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
"Rewrite as a `list` comprehension".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
pub struct UnnecessaryGeneratorSet;
|
||||
);
|
||||
impl AlwaysAutofixableViolation for UnnecessaryGeneratorSet {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Unnecessary generator (rewrite as a `set` comprehension)")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
"Rewrite as a `set` comprehension".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
pub struct UnnecessaryGeneratorDict;
|
||||
);
|
||||
impl AlwaysAutofixableViolation for UnnecessaryGeneratorDict {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Unnecessary generator (rewrite as a `dict` comprehension)")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
"Rewrite as a `dict` comprehension".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
pub struct UnnecessaryListComprehensionSet;
|
||||
);
|
||||
impl AlwaysAutofixableViolation for UnnecessaryListComprehensionSet {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Unnecessary `list` comprehension (rewrite as a `set` comprehension)")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
"Rewrite as a `set` comprehension".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
pub struct UnnecessaryListComprehensionDict;
|
||||
);
|
||||
impl AlwaysAutofixableViolation for UnnecessaryListComprehensionDict {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Unnecessary `list` comprehension (rewrite as a `dict` comprehension)")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
"Rewrite as a `dict` comprehension".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
pub struct UnnecessaryLiteralSet {
|
||||
pub obj_type: String,
|
||||
}
|
||||
);
|
||||
impl AlwaysAutofixableViolation for UnnecessaryLiteralSet {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let UnnecessaryLiteralSet { obj_type } = self;
|
||||
format!("Unnecessary `{obj_type}` literal (rewrite as a `set` literal)")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
"Rewrite as a `set` literal".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
pub struct UnnecessaryLiteralDict {
|
||||
pub obj_type: String,
|
||||
}
|
||||
);
|
||||
impl AlwaysAutofixableViolation for UnnecessaryLiteralDict {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let UnnecessaryLiteralDict { obj_type } = self;
|
||||
format!("Unnecessary `{obj_type}` literal (rewrite as a `dict` literal)")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
"Rewrite as a `dict` literal".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
pub struct UnnecessaryCollectionCall {
|
||||
pub obj_type: String,
|
||||
}
|
||||
);
|
||||
impl AlwaysAutofixableViolation for UnnecessaryCollectionCall {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let UnnecessaryCollectionCall { obj_type } = self;
|
||||
format!("Unnecessary `{obj_type}` call (rewrite as a literal)")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
"Rewrite as a literal".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
pub struct UnnecessaryLiteralWithinTupleCall {
|
||||
pub literal: String,
|
||||
}
|
||||
);
|
||||
impl AlwaysAutofixableViolation for UnnecessaryLiteralWithinTupleCall {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let UnnecessaryLiteralWithinTupleCall { literal } = self;
|
||||
if literal == "list" {
|
||||
format!(
|
||||
"Unnecessary `{literal}` literal passed to `tuple()` (rewrite as a `tuple` \
|
||||
literal)"
|
||||
)
|
||||
} else {
|
||||
format!(
|
||||
"Unnecessary `{literal}` literal passed to `tuple()` (remove the outer call to \
|
||||
`tuple()`)"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
let UnnecessaryLiteralWithinTupleCall { literal } = self;
|
||||
{
|
||||
if literal == "list" {
|
||||
"Rewrite as a `tuple` literal".to_string()
|
||||
} else {
|
||||
"Remove outer `tuple` call".to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
pub struct UnnecessaryLiteralWithinListCall {
|
||||
pub literal: String,
|
||||
}
|
||||
);
|
||||
impl AlwaysAutofixableViolation for UnnecessaryLiteralWithinListCall {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let UnnecessaryLiteralWithinListCall { literal } = self;
|
||||
if literal == "list" {
|
||||
format!(
|
||||
"Unnecessary `{literal}` literal passed to `list()` (remove the outer call to \
|
||||
`list()`)"
|
||||
)
|
||||
} else {
|
||||
format!(
|
||||
"Unnecessary `{literal}` literal passed to `list()` (rewrite as a `list` literal)"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
let UnnecessaryLiteralWithinListCall { literal } = self;
|
||||
{
|
||||
if literal == "list" {
|
||||
"Remove outer `list` call".to_string()
|
||||
} else {
|
||||
"Rewrite as a `list` literal".to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
pub struct UnnecessaryListCall;
|
||||
);
|
||||
impl AlwaysAutofixableViolation for UnnecessaryListCall {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Unnecessary `list` call (remove the outer call to `list()`)")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
"Remove outer `list` call".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
pub struct UnnecessaryCallAroundSorted {
|
||||
pub func: String,
|
||||
}
|
||||
);
|
||||
impl AlwaysAutofixableViolation for UnnecessaryCallAroundSorted {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let UnnecessaryCallAroundSorted { func } = self;
|
||||
format!("Unnecessary `{func}` call around `sorted()`")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
let UnnecessaryCallAroundSorted { func } = self;
|
||||
format!("Remove unnecessary `{func}` call")
|
||||
}
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
pub struct UnnecessaryDoubleCastOrProcess {
|
||||
pub inner: String,
|
||||
pub outer: String,
|
||||
}
|
||||
);
|
||||
impl Violation for UnnecessaryDoubleCastOrProcess {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let UnnecessaryDoubleCastOrProcess { inner, outer } = self;
|
||||
format!("Unnecessary `{inner}` call within `{outer}()`")
|
||||
}
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
pub struct UnnecessarySubscriptReversal {
|
||||
pub func: String,
|
||||
}
|
||||
);
|
||||
impl Violation for UnnecessarySubscriptReversal {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let UnnecessarySubscriptReversal { func } = self;
|
||||
format!("Unnecessary subscript reversal of iterable within `{func}()`")
|
||||
}
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
pub struct UnnecessaryComprehension {
|
||||
pub obj_type: String,
|
||||
}
|
||||
);
|
||||
impl AlwaysAutofixableViolation for UnnecessaryComprehension {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let UnnecessaryComprehension { obj_type } = self;
|
||||
format!("Unnecessary `{obj_type}` comprehension (rewrite using `{obj_type}()`)")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
let UnnecessaryComprehension { obj_type } = self;
|
||||
format!("Rewrite using `{obj_type}()`")
|
||||
}
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
pub struct UnnecessaryMap {
|
||||
pub obj_type: String,
|
||||
}
|
||||
);
|
||||
impl Violation for UnnecessaryMap {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let UnnecessaryMap { obj_type } = self;
|
||||
if obj_type == "generator" {
|
||||
format!("Unnecessary `map` usage (rewrite using a generator expression)")
|
||||
} else {
|
||||
format!("Unnecessary `map` usage (rewrite using a `{obj_type}` comprehension)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// flake8-debugger
|
||||
|
||||
define_violation!(
|
||||
|
|
|
|||
Loading…
Reference in New Issue