mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-29 13:25:17 +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",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "annotate-snippets"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7021ce4924a3f25f802b2cccd1af585e39ea1a363a1aa2e72afe54b67a3a7a7"
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.60"
|
||||
|
@ -359,6 +365,15 @@ version = "1.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "chrono"
|
||||
version = "0.4.21"
|
||||
|
@ -1062,9 +1077,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.10.3"
|
||||
version = "0.10.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
|
||||
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
@ -1153,6 +1168,30 @@ version = "0.2.127"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "linked-hash-map"
|
||||
version = "0.5.6"
|
||||
|
@ -1379,9 +1418,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.13.1"
|
||||
version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "074864da206b4973b84eb91683020dbefd6a8c3f0f38e054d93954e891935e4e"
|
||||
checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1"
|
||||
|
||||
[[package]]
|
||||
name = "opaque-debug"
|
||||
|
@ -1430,6 +1469,12 @@ dependencies = [
|
|||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1"
|
||||
|
||||
[[package]]
|
||||
name = "path-absolutize"
|
||||
version = "3.0.13"
|
||||
|
@ -1448,6 +1493,33 @@ dependencies = [
|
|||
"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]]
|
||||
name = "percent-encoding"
|
||||
version = "2.1.0"
|
||||
|
@ -1815,6 +1887,7 @@ dependencies = [
|
|||
"glob",
|
||||
"insta",
|
||||
"itertools",
|
||||
"libcst",
|
||||
"log",
|
||||
"notify",
|
||||
"once_cell",
|
||||
|
@ -2187,18 +2260,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.32"
|
||||
version = "1.0.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f5f6586b7f764adc0231f4c79be7b920e766bb2f3e51b3661cdb263828f19994"
|
||||
checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.32"
|
||||
version = "1.0.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12bafc5b54507e0149cdf1b145a5d80ab80a90bcd9275df43d4fff68460f6c21"
|
||||
checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
|
@ -19,7 +19,8 @@ dirs = { version = "4.0.0" }
|
|||
fern = { version = "0.6.1" }
|
||||
filetime = { version = "0.2.17" }
|
||||
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" }
|
||||
notify = { version = "4.0.17" }
|
||||
once_cell = { version = "1.13.1" }
|
||||
|
|
|
@ -698,15 +698,26 @@ pub fn check_builtin_shadowing(
|
|||
|
||||
// flake8-super
|
||||
/// Check that `super()` has no args
|
||||
pub fn check_super_args(expr: &Expr, args: &Vec<Expr>) -> Option<Check> {
|
||||
if let ExprKind::Name { id, .. } = &expr.node {
|
||||
pub fn check_super_args(
|
||||
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() {
|
||||
return Some(Check::new(
|
||||
let mut check = Check::new(
|
||||
CheckKind::SuperCallWithParameters,
|
||||
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
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
let mut offset = 0;
|
||||
for i in self.content.lines() {
|
||||
|
@ -147,4 +147,19 @@ impl<'a> SourceCodeLocator<'a> {
|
|||
let offset = self.offsets[location.row() - 1] + location.column() - 1;
|
||||
&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::lexer;
|
||||
use rustpython_parser::token::Tok;
|
||||
|
@ -25,7 +26,7 @@ pub fn remove_class_def_base(
|
|||
bases: &[Expr],
|
||||
keywords: &[Keyword],
|
||||
) -> 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.
|
||||
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
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -712,6 +712,7 @@ impl CheckKind {
|
|||
CheckKind::NoAssertEquals
|
||||
| CheckKind::UselessObjectInheritance(_)
|
||||
| CheckKind::UnusedNOQA(_)
|
||||
| CheckKind::SuperCallWithParameters
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,22 +8,46 @@ expression: checks
|
|||
column: 18
|
||||
end_location:
|
||||
row: 17
|
||||
column: 23
|
||||
fix: ~
|
||||
column: 36
|
||||
fix:
|
||||
content: super()
|
||||
location:
|
||||
row: 17
|
||||
column: 18
|
||||
end_location:
|
||||
row: 17
|
||||
column: 36
|
||||
applied: false
|
||||
- kind: SuperCallWithParameters
|
||||
location:
|
||||
row: 18
|
||||
column: 9
|
||||
end_location:
|
||||
row: 18
|
||||
column: 14
|
||||
fix: ~
|
||||
column: 27
|
||||
fix:
|
||||
content: super()
|
||||
location:
|
||||
row: 18
|
||||
column: 9
|
||||
end_location:
|
||||
row: 18
|
||||
column: 27
|
||||
applied: false
|
||||
- kind: SuperCallWithParameters
|
||||
location:
|
||||
row: 19
|
||||
column: 9
|
||||
end_location:
|
||||
row: 19
|
||||
column: 14
|
||||
fix: ~
|
||||
row: 22
|
||||
column: 10
|
||||
fix:
|
||||
content: super()
|
||||
location:
|
||||
row: 19
|
||||
column: 9
|
||||
end_location:
|
||||
row: 22
|
||||
column: 10
|
||||
applied: false
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue