mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-29 05:15:12 +00:00
Enable LibCST-based autofixing for SPR001 (#297)
This commit is contained in:
parent
83f18193c2
commit
558d9fcbe3
8 changed files with 183 additions and 24 deletions
89
Cargo.lock
generated
89
Cargo.lock
generated
|
@ -37,6 +37,12 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "annotate-snippets"
|
||||||
|
version = "0.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c7021ce4924a3f25f802b2cccd1af585e39ea1a363a1aa2e72afe54b67a3a7a7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.60"
|
version = "1.0.60"
|
||||||
|
@ -359,6 +365,15 @@ version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chic"
|
||||||
|
version = "1.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a5b5db619f3556839cb2223ae86ff3f9a09da2c5013be42bc9af08c9589bf70c"
|
||||||
|
dependencies = [
|
||||||
|
"annotate-snippets",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chrono"
|
name = "chrono"
|
||||||
version = "0.4.21"
|
version = "0.4.21"
|
||||||
|
@ -1062,9 +1077,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itertools"
|
name = "itertools"
|
||||||
version = "0.10.3"
|
version = "0.10.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
|
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"either",
|
"either",
|
||||||
]
|
]
|
||||||
|
@ -1153,6 +1168,30 @@ version = "0.2.127"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "505e71a4706fa491e9b1b55f51b95d4037d0821ee40131190475f692b35b009b"
|
checksum = "505e71a4706fa491e9b1b55f51b95d4037d0821ee40131190475f692b35b009b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libcst"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "git+https://github.com/charliermarsh/LibCST?rev=32a044c127668df44582f85699358e67803b0d73#32a044c127668df44582f85699358e67803b0d73"
|
||||||
|
dependencies = [
|
||||||
|
"chic",
|
||||||
|
"itertools",
|
||||||
|
"libcst_derive",
|
||||||
|
"once_cell",
|
||||||
|
"paste",
|
||||||
|
"peg",
|
||||||
|
"regex",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libcst_derive"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "git+https://github.com/charliermarsh/LibCST?rev=32a044c127668df44582f85699358e67803b0d73#32a044c127668df44582f85699358e67803b0d73"
|
||||||
|
dependencies = [
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linked-hash-map"
|
name = "linked-hash-map"
|
||||||
version = "0.5.6"
|
version = "0.5.6"
|
||||||
|
@ -1379,9 +1418,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.13.1"
|
version = "1.15.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "074864da206b4973b84eb91683020dbefd6a8c3f0f38e054d93954e891935e4e"
|
checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "opaque-debug"
|
name = "opaque-debug"
|
||||||
|
@ -1430,6 +1469,12 @@ dependencies = [
|
||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "paste"
|
||||||
|
version = "1.0.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "path-absolutize"
|
name = "path-absolutize"
|
||||||
version = "3.0.13"
|
version = "3.0.13"
|
||||||
|
@ -1448,6 +1493,33 @@ dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "peg"
|
||||||
|
version = "0.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a07f2cafdc3babeebc087e499118343442b742cc7c31b4d054682cc598508554"
|
||||||
|
dependencies = [
|
||||||
|
"peg-macros",
|
||||||
|
"peg-runtime",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "peg-macros"
|
||||||
|
version = "0.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4a90084dc05cf0428428e3d12399f39faad19b0909f64fb9170c9fdd6d9cd49b"
|
||||||
|
dependencies = [
|
||||||
|
"peg-runtime",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "peg-runtime"
|
||||||
|
version = "0.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9fa00462b37ead6d11a82c9d568b26682d78e0477dc02d1966c013af80969739"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "percent-encoding"
|
name = "percent-encoding"
|
||||||
version = "2.1.0"
|
version = "2.1.0"
|
||||||
|
@ -1815,6 +1887,7 @@ dependencies = [
|
||||||
"glob",
|
"glob",
|
||||||
"insta",
|
"insta",
|
||||||
"itertools",
|
"itertools",
|
||||||
|
"libcst",
|
||||||
"log",
|
"log",
|
||||||
"notify",
|
"notify",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
@ -2187,18 +2260,18 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.32"
|
version = "1.0.37"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f5f6586b7f764adc0231f4c79be7b920e766bb2f3e51b3661cdb263828f19994"
|
checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror-impl",
|
"thiserror-impl",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror-impl"
|
name = "thiserror-impl"
|
||||||
version = "1.0.32"
|
version = "1.0.37"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "12bafc5b54507e0149cdf1b145a5d80ab80a90bcd9275df43d4fff68460f6c21"
|
checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|
|
@ -19,7 +19,8 @@ dirs = { version = "4.0.0" }
|
||||||
fern = { version = "0.6.1" }
|
fern = { version = "0.6.1" }
|
||||||
filetime = { version = "0.2.17" }
|
filetime = { version = "0.2.17" }
|
||||||
glob = { version = "0.3.0" }
|
glob = { version = "0.3.0" }
|
||||||
itertools = { version = "0.10.3" }
|
itertools = { version = "0.10.5" }
|
||||||
|
libcst = { git = "https://github.com/charliermarsh/LibCST", rev = "32a044c127668df44582f85699358e67803b0d73" }
|
||||||
log = { version = "0.4.17" }
|
log = { version = "0.4.17" }
|
||||||
notify = { version = "4.0.17" }
|
notify = { version = "4.0.17" }
|
||||||
once_cell = { version = "1.13.1" }
|
once_cell = { version = "1.13.1" }
|
||||||
|
|
|
@ -698,15 +698,26 @@ pub fn check_builtin_shadowing(
|
||||||
|
|
||||||
// flake8-super
|
// flake8-super
|
||||||
/// Check that `super()` has no args
|
/// Check that `super()` has no args
|
||||||
pub fn check_super_args(expr: &Expr, args: &Vec<Expr>) -> Option<Check> {
|
pub fn check_super_args(
|
||||||
if let ExprKind::Name { id, .. } = &expr.node {
|
expr: &Expr,
|
||||||
|
func: &Expr,
|
||||||
|
args: &Vec<Expr>,
|
||||||
|
locator: &mut SourceCodeLocator,
|
||||||
|
autofix: &fixer::Mode,
|
||||||
|
) -> Option<Check> {
|
||||||
|
if let ExprKind::Name { id, .. } = &func.node {
|
||||||
if id == "super" && !args.is_empty() {
|
if id == "super" && !args.is_empty() {
|
||||||
return Some(Check::new(
|
let mut check = Check::new(
|
||||||
CheckKind::SuperCallWithParameters,
|
CheckKind::SuperCallWithParameters,
|
||||||
Range::from_located(expr),
|
Range::from_located(expr),
|
||||||
));
|
);
|
||||||
|
if matches!(autofix, fixer::Mode::Generate | fixer::Mode::Apply) {
|
||||||
|
if let Some(fix) = fixes::remove_super_arguments(locator, expr) {
|
||||||
|
check.amend(fix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Some(check);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,7 +134,7 @@ impl<'a> SourceCodeLocator<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn slice_source_code(&mut self, location: &Location) -> &'a str {
|
pub fn slice_source_code_at(&mut self, location: &Location) -> &'a str {
|
||||||
if !self.initialized {
|
if !self.initialized {
|
||||||
let mut offset = 0;
|
let mut offset = 0;
|
||||||
for i in self.content.lines() {
|
for i in self.content.lines() {
|
||||||
|
@ -147,4 +147,19 @@ impl<'a> SourceCodeLocator<'a> {
|
||||||
let offset = self.offsets[location.row() - 1] + location.column() - 1;
|
let offset = self.offsets[location.row() - 1] + location.column() - 1;
|
||||||
&self.content[offset..]
|
&self.content[offset..]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn slice_source_code_range(&mut self, start: &Location, end: &Location) -> &'a str {
|
||||||
|
if !self.initialized {
|
||||||
|
let mut offset = 0;
|
||||||
|
for i in self.content.lines() {
|
||||||
|
self.offsets.push(offset);
|
||||||
|
offset += i.len();
|
||||||
|
offset += 1;
|
||||||
|
}
|
||||||
|
self.initialized = true;
|
||||||
|
}
|
||||||
|
let start = self.offsets[start.row() - 1] + start.column() - 1;
|
||||||
|
let end = self.offsets[end.row() - 1] + end.column() - 1;
|
||||||
|
&self.content[start..end]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use libcst_native::{Codegen, Expression, SmallStatement, Statement};
|
||||||
use rustpython_parser::ast::{Expr, Keyword, Location};
|
use rustpython_parser::ast::{Expr, Keyword, Location};
|
||||||
use rustpython_parser::lexer;
|
use rustpython_parser::lexer;
|
||||||
use rustpython_parser::token::Tok;
|
use rustpython_parser::token::Tok;
|
||||||
|
@ -25,7 +26,7 @@ pub fn remove_class_def_base(
|
||||||
bases: &[Expr],
|
bases: &[Expr],
|
||||||
keywords: &[Keyword],
|
keywords: &[Keyword],
|
||||||
) -> Option<Fix> {
|
) -> Option<Fix> {
|
||||||
let content = locator.slice_source_code(stmt_at);
|
let content = locator.slice_source_code_at(stmt_at);
|
||||||
|
|
||||||
// Case 1: `object` is the only base.
|
// Case 1: `object` is the only base.
|
||||||
if bases.len() == 1 && keywords.is_empty() {
|
if bases.len() == 1 && keywords.is_empty() {
|
||||||
|
@ -124,3 +125,34 @@ pub fn remove_class_def_base(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn remove_super_arguments(locator: &mut SourceCodeLocator, expr: &Expr) -> Option<Fix> {
|
||||||
|
let contents = locator.slice_source_code_range(&expr.location, &expr.end_location);
|
||||||
|
|
||||||
|
let mut tree = match libcst_native::parse_module(contents, None) {
|
||||||
|
Ok(m) => m,
|
||||||
|
Err(_) => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(Statement::Simple(body)) = tree.body.first_mut() {
|
||||||
|
if let Some(SmallStatement::Expr(body)) = body.body.first_mut() {
|
||||||
|
if let Expression::Call(body) = &mut body.value {
|
||||||
|
body.args = vec![];
|
||||||
|
body.whitespace_before_args = Default::default();
|
||||||
|
body.whitespace_after_func = Default::default();
|
||||||
|
|
||||||
|
let mut state = Default::default();
|
||||||
|
tree.codegen(&mut state);
|
||||||
|
|
||||||
|
return Some(Fix {
|
||||||
|
content: state.to_string(),
|
||||||
|
location: expr.location,
|
||||||
|
end_location: expr.end_location,
|
||||||
|
applied: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
|
@ -742,7 +742,9 @@ where
|
||||||
|
|
||||||
// flake8-super
|
// flake8-super
|
||||||
if self.settings.select.contains(&CheckCode::SPR001) {
|
if self.settings.select.contains(&CheckCode::SPR001) {
|
||||||
if let Some(check) = checks::check_super_args(func, args) {
|
if let Some(check) =
|
||||||
|
checks::check_super_args(expr, func, args, &mut self.locator, self.autofix)
|
||||||
|
{
|
||||||
self.checks.push(check)
|
self.checks.push(check)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -712,6 +712,7 @@ impl CheckKind {
|
||||||
CheckKind::NoAssertEquals
|
CheckKind::NoAssertEquals
|
||||||
| CheckKind::UselessObjectInheritance(_)
|
| CheckKind::UselessObjectInheritance(_)
|
||||||
| CheckKind::UnusedNOQA(_)
|
| CheckKind::UnusedNOQA(_)
|
||||||
|
| CheckKind::SuperCallWithParameters
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,22 +8,46 @@ expression: checks
|
||||||
column: 18
|
column: 18
|
||||||
end_location:
|
end_location:
|
||||||
row: 17
|
row: 17
|
||||||
column: 23
|
column: 36
|
||||||
fix: ~
|
fix:
|
||||||
|
content: super()
|
||||||
|
location:
|
||||||
|
row: 17
|
||||||
|
column: 18
|
||||||
|
end_location:
|
||||||
|
row: 17
|
||||||
|
column: 36
|
||||||
|
applied: false
|
||||||
- kind: SuperCallWithParameters
|
- kind: SuperCallWithParameters
|
||||||
location:
|
location:
|
||||||
row: 18
|
row: 18
|
||||||
column: 9
|
column: 9
|
||||||
end_location:
|
end_location:
|
||||||
row: 18
|
row: 18
|
||||||
column: 14
|
column: 27
|
||||||
fix: ~
|
fix:
|
||||||
|
content: super()
|
||||||
|
location:
|
||||||
|
row: 18
|
||||||
|
column: 9
|
||||||
|
end_location:
|
||||||
|
row: 18
|
||||||
|
column: 27
|
||||||
|
applied: false
|
||||||
- kind: SuperCallWithParameters
|
- kind: SuperCallWithParameters
|
||||||
location:
|
location:
|
||||||
row: 19
|
row: 19
|
||||||
column: 9
|
column: 9
|
||||||
end_location:
|
end_location:
|
||||||
|
row: 22
|
||||||
|
column: 10
|
||||||
|
fix:
|
||||||
|
content: super()
|
||||||
|
location:
|
||||||
row: 19
|
row: 19
|
||||||
column: 14
|
column: 9
|
||||||
fix: ~
|
end_location:
|
||||||
|
row: 22
|
||||||
|
column: 10
|
||||||
|
applied: false
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue