Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5576db3d5a | ||
|
|
f26f38d023 | ||
|
|
578ec4d843 | ||
|
|
2f3bebe5a2 |
@@ -1,6 +1,6 @@
|
||||
repos:
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
rev: v0.0.98
|
||||
rev: v0.0.99
|
||||
hooks:
|
||||
- id: ruff
|
||||
|
||||
|
||||
4
Cargo.lock
generated
4
Cargo.lock
generated
@@ -920,7 +920,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.98-dev.0"
|
||||
version = "0.0.99-dev.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.0.15",
|
||||
@@ -2211,7 +2211,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.98"
|
||||
version = "0.0.99"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"assert_cmd",
|
||||
|
||||
@@ -5,7 +5,7 @@ members = [
|
||||
|
||||
[package]
|
||||
name = "ruff"
|
||||
version = "0.0.98"
|
||||
version = "0.0.99"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
|
||||
@@ -89,7 +89,7 @@ Ruff also works with [pre-commit](https://pre-commit.com):
|
||||
```yaml
|
||||
repos:
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
rev: v0.0.98
|
||||
rev: v0.0.99
|
||||
hooks:
|
||||
- id: ruff
|
||||
```
|
||||
@@ -445,7 +445,7 @@ The 🛠 emoji indicates that a rule is automatically fixable by the `--fix` com
|
||||
| C403 | UnnecessaryListComprehensionSet | Unnecessary `list` comprehension (rewrite as a `set` comprehension) | 🛠 |
|
||||
| C404 | UnnecessaryListComprehensionDict | Unnecessary `list` comprehension (rewrite as a `dict` comprehension) | |
|
||||
| C405 | UnnecessaryLiteralSet | Unnecessary `(list\|tuple)` literal (rewrite as a `set` literal) | 🛠 |
|
||||
| C406 | UnnecessaryLiteralDict | Unnecessary `(list\|tuple)` literal (rewrite as a `dict` literal) | |
|
||||
| C406 | UnnecessaryLiteralDict | Unnecessary `(list\|tuple)` literal (rewrite as a `dict` literal) | 🛠 |
|
||||
| C408 | UnnecessaryCollectionCall | Unnecessary `(dict\|list\|tuple)` call (rewrite as a literal) | 🛠 |
|
||||
| C409 | UnnecessaryLiteralWithinTupleCall | Unnecessary `(list\|tuple)` literal passed to `tuple()` (remove the outer call to `tuple()`) | 🛠 |
|
||||
| C410 | UnnecessaryLiteralWithinListCall | Unnecessary `(list\|tuple)` literal passed to `list()` (rewrite as a `list` literal) | 🛠 |
|
||||
@@ -453,7 +453,7 @@ The 🛠 emoji indicates that a rule is automatically fixable by the `--fix` com
|
||||
| C413 | UnnecessaryCallAroundSorted | Unnecessary `(list\|reversed)` call around `sorted()` | |
|
||||
| C414 | UnnecessaryDoubleCastOrProcess | Unnecessary `(list\|reversed\|set\|sorted\|tuple)` call within `(list\|set\|sorted\|tuple)()` | |
|
||||
| C415 | UnnecessarySubscriptReversal | Unnecessary subscript reversal of iterable within `(reversed\|set\|sorted)()` | |
|
||||
| C416 | UnnecessaryComprehension | Unnecessary `(list\|set)` comprehension (rewrite using `(list\|set)()`) | |
|
||||
| C416 | UnnecessaryComprehension | Unnecessary `(list\|set)` comprehension (rewrite using `(list\|set)()`) | 🛠 |
|
||||
| C417 | UnnecessaryMap | Unnecessary `map` usage (rewrite using a `(list\|set\|dict)` comprehension) | |
|
||||
|
||||
### flake8-bugbear
|
||||
|
||||
4
flake8_to_ruff/Cargo.lock
generated
4
flake8_to_ruff/Cargo.lock
generated
@@ -771,7 +771,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flake8_to_ruff"
|
||||
version = "0.0.98"
|
||||
version = "0.0.99"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@@ -1975,7 +1975,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.98"
|
||||
version = "0.0.99"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.98-dev.0"
|
||||
version = "0.0.99-dev.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
|
||||
@@ -1076,9 +1076,12 @@ where
|
||||
|
||||
if self.settings.enabled.contains(&CheckCode::C406) {
|
||||
if let Some(check) = flake8_comprehensions::checks::unnecessary_literal_dict(
|
||||
expr,
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
self.locator,
|
||||
self.patch(),
|
||||
self.locate_check(Range::from_located(expr)),
|
||||
) {
|
||||
self.checks.push(check);
|
||||
@@ -1363,6 +1366,8 @@ where
|
||||
expr,
|
||||
elt,
|
||||
generators,
|
||||
self.locator,
|
||||
self.patch(),
|
||||
self.locate_check(Range::from_located(expr)),
|
||||
) {
|
||||
self.checks.push(check);
|
||||
|
||||
@@ -1470,11 +1470,13 @@ impl CheckKind {
|
||||
| CheckKind::TypeOfPrimitive(_)
|
||||
| CheckKind::UnnecessaryAbspath
|
||||
| CheckKind::UnnecessaryCollectionCall(_)
|
||||
| CheckKind::UnnecessaryComprehension(_)
|
||||
| CheckKind::UnnecessaryGeneratorDict
|
||||
| CheckKind::UnnecessaryGeneratorList
|
||||
| CheckKind::UnnecessaryGeneratorSet
|
||||
| CheckKind::UnnecessaryListCall
|
||||
| CheckKind::UnnecessaryListComprehensionSet
|
||||
| CheckKind::UnnecessaryLiteralDict(_)
|
||||
| CheckKind::UnnecessaryLiteralSet(_)
|
||||
| CheckKind::UnnecessaryLiteralWithinListCall(_)
|
||||
| CheckKind::UnnecessaryLiteralWithinTupleCall(_)
|
||||
|
||||
@@ -197,9 +197,12 @@ pub fn unnecessary_literal_set(
|
||||
|
||||
/// C406 (`dict([(1, 2)])`)
|
||||
pub fn unnecessary_literal_dict(
|
||||
expr: &Expr,
|
||||
func: &Expr,
|
||||
args: &[Expr],
|
||||
keywords: &[Keyword],
|
||||
locator: &SourceCodeLocator,
|
||||
fix: bool,
|
||||
location: Range,
|
||||
) -> Option<Check> {
|
||||
let argument = exactly_one_argument_with_matching_function("dict", func, args, keywords)?;
|
||||
@@ -208,18 +211,24 @@ pub fn unnecessary_literal_dict(
|
||||
ExprKind::List { elts, .. } => ("list", elts),
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
if let Some(elt) = elts.first() {
|
||||
// dict((1, 2), ...)) or dict([(1, 2), ...])
|
||||
if !matches!(&elt.node, ExprKind::Tuple { elts, .. } if elts.len() == 2) {
|
||||
return None;
|
||||
}
|
||||
// Accept `dict((1, 2), ...))` `dict([(1, 2), ...])`.
|
||||
if !elts
|
||||
.iter()
|
||||
.all(|elt| matches!(&elt.node, ExprKind::Tuple { elts, .. } if elts.len() == 2))
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(Check::new(
|
||||
let mut check = Check::new(
|
||||
CheckKind::UnnecessaryLiteralDict(kind.to_string()),
|
||||
location,
|
||||
))
|
||||
);
|
||||
if fix {
|
||||
match fixes::fix_unnecessary_literal_dict(locator, expr) {
|
||||
Ok(fix) => check.amend(fix),
|
||||
Err(e) => error!("Failed to generate fix: {}", e),
|
||||
}
|
||||
}
|
||||
Some(check)
|
||||
}
|
||||
|
||||
/// C408
|
||||
@@ -250,12 +259,9 @@ pub fn unnecessary_collection_call(
|
||||
location,
|
||||
);
|
||||
if fix {
|
||||
// TODO(charlie): Support fixing `dict(a=1)`.
|
||||
if keywords.is_empty() {
|
||||
match fixes::fix_unnecessary_collection_call(locator, expr) {
|
||||
Ok(fix) => check.amend(fix),
|
||||
Err(e) => error!("Failed to generate fix: {}", e),
|
||||
}
|
||||
match fixes::fix_unnecessary_collection_call(locator, expr) {
|
||||
Ok(fix) => check.amend(fix),
|
||||
Err(e) => error!("Failed to generate fix: {}", e),
|
||||
}
|
||||
}
|
||||
Some(check)
|
||||
@@ -446,6 +452,8 @@ pub fn unnecessary_comprehension(
|
||||
expr: &Expr,
|
||||
elt: &Expr,
|
||||
generators: &[Comprehension],
|
||||
locator: &SourceCodeLocator,
|
||||
fix: bool,
|
||||
location: Range,
|
||||
) -> Option<Check> {
|
||||
if generators.len() != 1 {
|
||||
@@ -465,10 +473,17 @@ pub fn unnecessary_comprehension(
|
||||
ExprKind::SetComp { .. } => "set",
|
||||
_ => return None,
|
||||
};
|
||||
Some(Check::new(
|
||||
let mut check = Check::new(
|
||||
CheckKind::UnnecessaryComprehension(expr_kind.to_string()),
|
||||
location,
|
||||
))
|
||||
);
|
||||
if fix {
|
||||
match fixes::fix_unnecessary_comprehension(locator, expr) {
|
||||
Ok(fix) => check.amend(fix),
|
||||
Err(e) => error!("Failed to generate fix: {}", e),
|
||||
}
|
||||
}
|
||||
Some(check)
|
||||
}
|
||||
|
||||
/// C417
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use anyhow::Result;
|
||||
use libcst_native::{
|
||||
Arg, Call, Codegen, Dict, DictComp, Element, Expr, Expression, LeftCurlyBrace, LeftParen,
|
||||
LeftSquareBracket, List, ListComp, Module, ParenthesizableWhitespace, RightCurlyBrace,
|
||||
RightParen, RightSquareBracket, Set, SetComp, SimpleWhitespace, SmallStatement, Statement,
|
||||
Tuple,
|
||||
Arg, Call, Codegen, Dict, DictComp, DictElement, Element, Expr, Expression, LeftCurlyBrace,
|
||||
LeftParen, LeftSquareBracket, List, ListComp, Module, Name, ParenthesizableWhitespace,
|
||||
RightCurlyBrace, RightParen, RightSquareBracket, Set, SetComp, SimpleString, SimpleWhitespace,
|
||||
SmallStatement, Statement, Tuple,
|
||||
};
|
||||
|
||||
use crate::autofix::Fix;
|
||||
@@ -15,12 +15,10 @@ fn match_expr<'a, 'b>(module: &'a mut Module<'b>) -> Result<&'a mut Expr<'b>> {
|
||||
if let Some(SmallStatement::Expr(expr)) = expr.body.first_mut() {
|
||||
Ok(expr)
|
||||
} else {
|
||||
Err(anyhow::anyhow!(
|
||||
"Expected node to be: SmallStatement::Expr."
|
||||
))
|
||||
Err(anyhow::anyhow!("Expected node to be: SmallStatement::Expr"))
|
||||
}
|
||||
} else {
|
||||
Err(anyhow::anyhow!("Expected node to be: Statement::Simple."))
|
||||
Err(anyhow::anyhow!("Expected node to be: Statement::Simple"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +26,7 @@ fn match_call<'a, 'b>(expr: &'a mut Expr<'b>) -> Result<&'a mut Call<'b>> {
|
||||
if let Expression::Call(call) = &mut expr.value {
|
||||
Ok(call)
|
||||
} else {
|
||||
Err(anyhow::anyhow!("Expected node to be: Expression::Call."))
|
||||
Err(anyhow::anyhow!("Expected node to be: Expression::Call"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +34,7 @@ fn match_arg<'a, 'b>(call: &'a Call<'b>) -> Result<&'a Arg<'b>> {
|
||||
if let Some(arg) = call.args.first() {
|
||||
Ok(arg)
|
||||
} else {
|
||||
Err(anyhow::anyhow!("Expected node to be: Arg."))
|
||||
Err(anyhow::anyhow!("Expected node to be: Arg"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +53,7 @@ pub fn fix_unnecessary_generator_list(
|
||||
generator_exp
|
||||
} else {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Expected node to be: Expression::GeneratorExp."
|
||||
"Expected node to be: Expression::GeneratorExp"
|
||||
));
|
||||
};
|
||||
|
||||
@@ -97,7 +95,7 @@ pub fn fix_unnecessary_generator_set(
|
||||
generator_exp
|
||||
} else {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Expected node to be: Expression::GeneratorExp."
|
||||
"Expected node to be: Expression::GeneratorExp"
|
||||
));
|
||||
};
|
||||
|
||||
@@ -140,26 +138,26 @@ pub fn fix_unnecessary_generator_dict(
|
||||
generator_exp
|
||||
} else {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Expected node to be: Expression::GeneratorExp."
|
||||
"Expected node to be: Expression::GeneratorExp"
|
||||
));
|
||||
};
|
||||
let tuple = if let Expression::Tuple(tuple) = &generator_exp.elt.as_ref() {
|
||||
tuple
|
||||
} else {
|
||||
return Err(anyhow::anyhow!("Expected node to be: Expression::Tuple."));
|
||||
return Err(anyhow::anyhow!("Expected node to be: Expression::Tuple"));
|
||||
};
|
||||
let key = if let Some(Element::Simple { value, .. }) = &tuple.elements.get(0) {
|
||||
value
|
||||
} else {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Expected tuple to contain a key as the first element."
|
||||
"Expected tuple to contain a key as the first element"
|
||||
));
|
||||
};
|
||||
let value = if let Some(Element::Simple { value, .. }) = &tuple.elements.get(1) {
|
||||
value
|
||||
} else {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Expected tuple to contain a key as the second element."
|
||||
"Expected tuple to contain a key as the second element"
|
||||
));
|
||||
};
|
||||
|
||||
@@ -204,9 +202,7 @@ pub fn fix_unnecessary_list_comprehension_set(
|
||||
let list_comp = if let Expression::ListComp(list_comp) = &arg.value {
|
||||
list_comp
|
||||
} else {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Expected node to be: Expression::ListComp."
|
||||
));
|
||||
return Err(anyhow::anyhow!("Expected node to be: Expression::ListComp"));
|
||||
};
|
||||
|
||||
body.value = Expression::SetComp(Box::new(SetComp {
|
||||
@@ -248,7 +244,7 @@ pub fn fix_unnecessary_literal_set(
|
||||
Expression::List(inner) => &inner.elements,
|
||||
_ => {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Expected node to be: Expression::Tuple | Expression::List."
|
||||
"Expected node to be: Expression::Tuple | Expression::List"
|
||||
))
|
||||
}
|
||||
};
|
||||
@@ -279,6 +275,77 @@ pub fn fix_unnecessary_literal_set(
|
||||
))
|
||||
}
|
||||
|
||||
/// (C406) Convert `dict([(1, 2)])` to `{1: 2}`.
|
||||
pub fn fix_unnecessary_literal_dict(
|
||||
locator: &SourceCodeLocator,
|
||||
expr: &rustpython_ast::Expr,
|
||||
) -> Result<Fix> {
|
||||
// Expr(Call(List|Tuple)))) -> Expr(Dict)))
|
||||
let mut tree = match_tree(locator, expr)?;
|
||||
let mut body = match_expr(&mut tree)?;
|
||||
let call = match_call(body)?;
|
||||
let arg = match_arg(call)?;
|
||||
|
||||
let elements = match &arg.value {
|
||||
Expression::Tuple(inner) => &inner.elements,
|
||||
Expression::List(inner) => &inner.elements,
|
||||
_ => {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Expected node to be: Expression::Tuple | Expression::List"
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
let elements: Vec<DictElement> = elements
|
||||
.iter()
|
||||
.map(|element| {
|
||||
if let Element::Simple {
|
||||
value: Expression::Tuple(tuple),
|
||||
comma,
|
||||
} = element
|
||||
{
|
||||
if let Some(Element::Simple { value: key, .. }) = tuple.elements.get(0) {
|
||||
if let Some(Element::Simple { value, .. }) = tuple.elements.get(1) {
|
||||
return Ok(DictElement::Simple {
|
||||
key: key.clone(),
|
||||
value: value.clone(),
|
||||
comma: comma.clone(),
|
||||
whitespace_before_colon: Default::default(),
|
||||
whitespace_after_colon: ParenthesizableWhitespace::SimpleWhitespace(
|
||||
SimpleWhitespace(" "),
|
||||
),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(anyhow::anyhow!(
|
||||
"Expected each argument to be a tuple of length two"
|
||||
))
|
||||
})
|
||||
.collect::<Result<Vec<DictElement>>>()?;
|
||||
|
||||
body.value = Expression::Dict(Box::new(Dict {
|
||||
elements,
|
||||
lbrace: LeftCurlyBrace {
|
||||
whitespace_after: call.whitespace_before_args.clone(),
|
||||
},
|
||||
rbrace: RightCurlyBrace {
|
||||
whitespace_before: arg.whitespace_after_arg.clone(),
|
||||
},
|
||||
lpar: Default::default(),
|
||||
rpar: Default::default(),
|
||||
}));
|
||||
|
||||
let mut state = Default::default();
|
||||
tree.codegen(&mut state);
|
||||
|
||||
Ok(Fix::replacement(
|
||||
state.to_string(),
|
||||
expr.location,
|
||||
expr.end_location.unwrap(),
|
||||
))
|
||||
}
|
||||
|
||||
/// (C408)
|
||||
pub fn fix_unnecessary_collection_call(
|
||||
locator: &SourceCodeLocator,
|
||||
@@ -291,9 +358,13 @@ pub fn fix_unnecessary_collection_call(
|
||||
let name = if let Expression::Name(name) = &call.func.as_ref() {
|
||||
name
|
||||
} else {
|
||||
return Err(anyhow::anyhow!("Expected node to be: Expression::Name."));
|
||||
return Err(anyhow::anyhow!("Expected node to be: Expression::Name"));
|
||||
};
|
||||
|
||||
// Arena allocator used to create formatted strings of sufficient lifetime,
|
||||
// below.
|
||||
let mut arena: Vec<String> = vec![];
|
||||
|
||||
match name.value {
|
||||
"tuple" => {
|
||||
body.value = Expression::Tuple(Box::new(Tuple {
|
||||
@@ -312,17 +383,67 @@ pub fn fix_unnecessary_collection_call(
|
||||
}));
|
||||
}
|
||||
"dict" => {
|
||||
body.value = Expression::Dict(Box::new(Dict {
|
||||
elements: Default::default(),
|
||||
lbrace: Default::default(),
|
||||
rbrace: Default::default(),
|
||||
lpar: Default::default(),
|
||||
rpar: Default::default(),
|
||||
}));
|
||||
if call.args.is_empty() {
|
||||
body.value = Expression::Dict(Box::new(Dict {
|
||||
elements: Default::default(),
|
||||
lbrace: Default::default(),
|
||||
rbrace: Default::default(),
|
||||
lpar: Default::default(),
|
||||
rpar: Default::default(),
|
||||
}));
|
||||
} else {
|
||||
// Quote each argument.
|
||||
for arg in &call.args {
|
||||
let quoted = format!(
|
||||
"\"{}\"",
|
||||
arg.keyword
|
||||
.as_ref()
|
||||
.expect("Expected dictionary argument to be kwarg")
|
||||
.value
|
||||
);
|
||||
arena.push(quoted);
|
||||
}
|
||||
|
||||
let elements = call
|
||||
.args
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, arg)| DictElement::Simple {
|
||||
key: Expression::SimpleString(Box::new(SimpleString {
|
||||
value: &arena[i],
|
||||
lpar: Default::default(),
|
||||
rpar: Default::default(),
|
||||
})),
|
||||
value: arg.value.clone(),
|
||||
comma: arg.comma.clone(),
|
||||
whitespace_before_colon: Default::default(),
|
||||
whitespace_after_colon: ParenthesizableWhitespace::SimpleWhitespace(
|
||||
SimpleWhitespace(" "),
|
||||
),
|
||||
})
|
||||
.collect();
|
||||
|
||||
body.value = Expression::Dict(Box::new(Dict {
|
||||
elements,
|
||||
lbrace: LeftCurlyBrace {
|
||||
whitespace_after: call.whitespace_before_args.clone(),
|
||||
},
|
||||
rbrace: RightCurlyBrace {
|
||||
whitespace_before: call
|
||||
.args
|
||||
.last()
|
||||
.expect("Arguments should be non-empty")
|
||||
.whitespace_after_arg
|
||||
.clone(),
|
||||
},
|
||||
lpar: Default::default(),
|
||||
rpar: Default::default(),
|
||||
}));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(anyhow::anyhow!("Expected function name to be one of: \
|
||||
'tuple', 'list', 'dict'."
|
||||
'tuple', 'list', 'dict'"
|
||||
.to_string()));
|
||||
}
|
||||
};
|
||||
@@ -352,12 +473,12 @@ pub fn fix_unnecessary_literal_within_tuple_call(
|
||||
&inner
|
||||
.lpar
|
||||
.first()
|
||||
.ok_or_else(|| anyhow::anyhow!("Expected at least one set of parentheses."))?
|
||||
.ok_or_else(|| anyhow::anyhow!("Expected at least one set of parentheses"))?
|
||||
.whitespace_after,
|
||||
&inner
|
||||
.rpar
|
||||
.first()
|
||||
.ok_or_else(|| anyhow::anyhow!("Expected at least one set of parentheses."))?
|
||||
.ok_or_else(|| anyhow::anyhow!("Expected at least one set of parentheses"))?
|
||||
.whitespace_before,
|
||||
),
|
||||
Expression::List(inner) => (
|
||||
@@ -367,7 +488,7 @@ pub fn fix_unnecessary_literal_within_tuple_call(
|
||||
),
|
||||
_ => {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Expected node to be: Expression::Tuple | Expression::List."
|
||||
"Expected node to be: Expression::Tuple | Expression::List"
|
||||
))
|
||||
}
|
||||
};
|
||||
@@ -407,12 +528,12 @@ pub fn fix_unnecessary_literal_within_list_call(
|
||||
&inner
|
||||
.lpar
|
||||
.first()
|
||||
.ok_or_else(|| anyhow::anyhow!("Expected at least one set of parentheses."))?
|
||||
.ok_or_else(|| anyhow::anyhow!("Expected at least one set of parentheses"))?
|
||||
.whitespace_after,
|
||||
&inner
|
||||
.rpar
|
||||
.first()
|
||||
.ok_or_else(|| anyhow::anyhow!("Expected at least one set of parentheses."))?
|
||||
.ok_or_else(|| anyhow::anyhow!("Expected at least one set of parentheses"))?
|
||||
.whitespace_before,
|
||||
),
|
||||
Expression::List(inner) => (
|
||||
@@ -422,7 +543,7 @@ pub fn fix_unnecessary_literal_within_list_call(
|
||||
),
|
||||
_ => {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Expected node to be: Expression::Tuple | Expression::List."
|
||||
"Expected node to be: Expression::Tuple | Expression::List"
|
||||
))
|
||||
}
|
||||
};
|
||||
@@ -449,7 +570,7 @@ pub fn fix_unnecessary_literal_within_list_call(
|
||||
))
|
||||
}
|
||||
|
||||
/// (C411) Convert `list([i for i in x])` to `[i for i in x]`.
|
||||
/// (C411) Convert `list([i * i for i in x])` to `[i * i for i in x]`.
|
||||
pub fn fix_unnecessary_list_call(
|
||||
locator: &SourceCodeLocator,
|
||||
expr: &rustpython_ast::Expr,
|
||||
@@ -471,3 +592,73 @@ pub fn fix_unnecessary_list_call(
|
||||
expr.end_location.unwrap(),
|
||||
))
|
||||
}
|
||||
|
||||
/// (C416) Convert `[i for i in x]` to `list(x)`.
|
||||
pub fn fix_unnecessary_comprehension(
|
||||
locator: &SourceCodeLocator,
|
||||
expr: &rustpython_ast::Expr,
|
||||
) -> Result<Fix> {
|
||||
let mut tree = match_tree(locator, expr)?;
|
||||
let mut body = match_expr(&mut tree)?;
|
||||
|
||||
match &body.value {
|
||||
Expression::ListComp(inner) => {
|
||||
body.value = Expression::Call(Box::new(Call {
|
||||
func: Box::new(Expression::Name(Box::new(Name {
|
||||
value: "list",
|
||||
lpar: Default::default(),
|
||||
rpar: Default::default(),
|
||||
}))),
|
||||
args: vec![Arg {
|
||||
value: inner.for_in.iter.clone(),
|
||||
keyword: Default::default(),
|
||||
equal: Default::default(),
|
||||
comma: Default::default(),
|
||||
star: Default::default(),
|
||||
whitespace_after_star: Default::default(),
|
||||
whitespace_after_arg: Default::default(),
|
||||
}],
|
||||
lpar: Default::default(),
|
||||
rpar: Default::default(),
|
||||
whitespace_after_func: Default::default(),
|
||||
whitespace_before_args: Default::default(),
|
||||
}))
|
||||
}
|
||||
Expression::SetComp(inner) => {
|
||||
body.value = Expression::Call(Box::new(Call {
|
||||
func: Box::new(Expression::Name(Box::new(Name {
|
||||
value: "set",
|
||||
lpar: Default::default(),
|
||||
rpar: Default::default(),
|
||||
}))),
|
||||
args: vec![Arg {
|
||||
value: inner.for_in.iter.clone(),
|
||||
keyword: Default::default(),
|
||||
equal: Default::default(),
|
||||
comma: Default::default(),
|
||||
star: Default::default(),
|
||||
whitespace_after_star: Default::default(),
|
||||
whitespace_after_arg: Default::default(),
|
||||
}],
|
||||
lpar: Default::default(),
|
||||
rpar: Default::default(),
|
||||
whitespace_after_func: Default::default(),
|
||||
whitespace_before_args: Default::default(),
|
||||
}))
|
||||
}
|
||||
_ => {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Expected node to be: Expression::ListComp | Expression:SetComp"
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
let mut state = Default::default();
|
||||
tree.codegen(&mut state);
|
||||
|
||||
Ok(Fix::replacement(
|
||||
state.to_string(),
|
||||
expr.location,
|
||||
expr.end_location.unwrap(),
|
||||
))
|
||||
}
|
||||
|
||||
@@ -20,13 +20,13 @@ pub fn remove_unused_imports(
|
||||
let body = if let Some(Statement::Simple(body)) = tree.body.first_mut() {
|
||||
body
|
||||
} else {
|
||||
return Err(anyhow::anyhow!("Expected node to be: Statement::Simple."));
|
||||
return Err(anyhow::anyhow!("Expected node to be: Statement::Simple"));
|
||||
};
|
||||
let body = if let Some(SmallStatement::Import(body)) = body.body.first_mut() {
|
||||
body
|
||||
} else {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Expected node to be: SmallStatement::ImportFrom."
|
||||
"Expected node to be: SmallStatement::ImportFrom"
|
||||
));
|
||||
};
|
||||
let aliases = &mut body.names;
|
||||
@@ -77,20 +77,20 @@ pub fn remove_unused_import_froms(
|
||||
let body = if let Some(Statement::Simple(body)) = tree.body.first_mut() {
|
||||
body
|
||||
} else {
|
||||
return Err(anyhow::anyhow!("Expected node to be: Statement::Simple."));
|
||||
return Err(anyhow::anyhow!("Expected node to be: Statement::Simple"));
|
||||
};
|
||||
let body = if let Some(SmallStatement::ImportFrom(body)) = body.body.first_mut() {
|
||||
body
|
||||
} else {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Expected node to be: SmallStatement::ImportFrom."
|
||||
"Expected node to be: SmallStatement::ImportFrom"
|
||||
));
|
||||
};
|
||||
|
||||
let aliases = if let ImportNames::Aliases(aliases) = &mut body.names {
|
||||
aliases
|
||||
} else {
|
||||
return Err(anyhow::anyhow!("Expected node to be: Aliases."));
|
||||
return Err(anyhow::anyhow!("Expected node to be: Aliases"));
|
||||
};
|
||||
|
||||
// Preserve the trailing comma (or not) from the last entry.
|
||||
|
||||
@@ -10,7 +10,16 @@ expression: checks
|
||||
end_location:
|
||||
row: 1
|
||||
column: 19
|
||||
fix: ~
|
||||
fix:
|
||||
patch:
|
||||
content: "{1: 2}"
|
||||
location:
|
||||
row: 1
|
||||
column: 5
|
||||
end_location:
|
||||
row: 1
|
||||
column: 19
|
||||
applied: false
|
||||
- kind:
|
||||
UnnecessaryLiteralDict: tuple
|
||||
location:
|
||||
@@ -19,7 +28,16 @@ expression: checks
|
||||
end_location:
|
||||
row: 2
|
||||
column: 20
|
||||
fix: ~
|
||||
fix:
|
||||
patch:
|
||||
content: "{1: 2,}"
|
||||
location:
|
||||
row: 2
|
||||
column: 5
|
||||
end_location:
|
||||
row: 2
|
||||
column: 20
|
||||
applied: false
|
||||
- kind:
|
||||
UnnecessaryLiteralDict: list
|
||||
location:
|
||||
@@ -28,7 +46,16 @@ expression: checks
|
||||
end_location:
|
||||
row: 3
|
||||
column: 13
|
||||
fix: ~
|
||||
fix:
|
||||
patch:
|
||||
content: "{}"
|
||||
location:
|
||||
row: 3
|
||||
column: 5
|
||||
end_location:
|
||||
row: 3
|
||||
column: 13
|
||||
applied: false
|
||||
- kind:
|
||||
UnnecessaryLiteralDict: tuple
|
||||
location:
|
||||
@@ -37,5 +64,14 @@ expression: checks
|
||||
end_location:
|
||||
row: 4
|
||||
column: 13
|
||||
fix: ~
|
||||
fix:
|
||||
patch:
|
||||
content: "{}"
|
||||
location:
|
||||
row: 4
|
||||
column: 5
|
||||
end_location:
|
||||
row: 4
|
||||
column: 13
|
||||
applied: false
|
||||
|
||||
|
||||
@@ -64,5 +64,14 @@ expression: checks
|
||||
end_location:
|
||||
row: 4
|
||||
column: 14
|
||||
fix: ~
|
||||
fix:
|
||||
patch:
|
||||
content: "{\"a\": 1}"
|
||||
location:
|
||||
row: 4
|
||||
column: 5
|
||||
end_location:
|
||||
row: 4
|
||||
column: 14
|
||||
applied: false
|
||||
|
||||
|
||||
@@ -10,7 +10,16 @@ expression: checks
|
||||
end_location:
|
||||
row: 2
|
||||
column: 14
|
||||
fix: ~
|
||||
fix:
|
||||
patch:
|
||||
content: list(x)
|
||||
location:
|
||||
row: 2
|
||||
column: 0
|
||||
end_location:
|
||||
row: 2
|
||||
column: 14
|
||||
applied: false
|
||||
- kind:
|
||||
UnnecessaryComprehension: set
|
||||
location:
|
||||
@@ -19,5 +28,14 @@ expression: checks
|
||||
end_location:
|
||||
row: 3
|
||||
column: 14
|
||||
fix: ~
|
||||
fix:
|
||||
patch:
|
||||
content: set(x)
|
||||
location:
|
||||
row: 3
|
||||
column: 0
|
||||
end_location:
|
||||
row: 3
|
||||
column: 14
|
||||
applied: false
|
||||
|
||||
|
||||
Reference in New Issue
Block a user