Implement R0205 (#91)

This commit is contained in:
Charlie Marsh 2022-09-03 11:33:54 -04:00 committed by GitHub
parent 3c7716ef27
commit 5041f6530c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 95 additions and 0 deletions

View file

@ -0,0 +1,22 @@
class A:
...
class B(object):
...
class C(B, object):
...
def f():
class D(object):
...
object = A
class E(object):
...

View file

@ -14,4 +14,5 @@ select = [
"F831",
"F841",
"F901",
"R0205",
]

View file

@ -108,11 +108,37 @@ impl Visitor for Checker<'_> {
}
}
StmtKind::ClassDef {
name,
bases,
keywords,
decorator_list,
..
} => {
if self.settings.select.contains(&CheckCode::R0205) {
for expr in bases {
if let ExprKind::Name { id, .. } = &expr.node {
if id == "object" {
let scope = self.scopes.last().expect("No current scope found.");
match scope.values.get(id) {
None
| Some(Binding {
kind: BindingKind::Builtin,
..
}) => {
self.checks.push(Check {
kind: CheckKind::UselessObjectInheritance(
name.to_string(),
),
location: stmt.location,
});
}
_ => {}
}
}
}
}
}
for expr in bases {
self.visit_expr(expr, Some(stmt))
}

View file

@ -20,6 +20,7 @@ pub enum CheckCode {
F831,
F841,
F901,
R0205,
}
impl FromStr for CheckCode {
@ -39,6 +40,7 @@ impl FromStr for CheckCode {
"F831" => Ok(CheckCode::F831),
"F841" => Ok(CheckCode::F841),
"F901" => Ok(CheckCode::F901),
"R0205" => Ok(CheckCode::R0205),
_ => Err(anyhow::anyhow!("Unknown check code: {s}")),
}
}
@ -59,6 +61,7 @@ impl CheckCode {
CheckCode::F831 => "F831",
CheckCode::F841 => "F841",
CheckCode::F901 => "F901",
CheckCode::R0205 => "R0205",
}
}
@ -77,6 +80,7 @@ impl CheckCode {
CheckCode::F831 => &LintSource::AST,
CheckCode::F841 => &LintSource::AST,
CheckCode::F901 => &LintSource::AST,
CheckCode::R0205 => &LintSource::AST,
}
}
}
@ -100,6 +104,7 @@ pub enum CheckKind {
UndefinedName(String),
UnusedImport(String),
UnusedVariable(String),
UselessObjectInheritance(String),
YieldOutsideFunction,
}
@ -118,6 +123,7 @@ impl CheckKind {
CheckKind::UndefinedName(_) => &CheckCode::F821,
CheckKind::UnusedImport(_) => &CheckCode::F401,
CheckKind::UnusedVariable(_) => &CheckCode::F841,
CheckKind::UselessObjectInheritance(_) => &CheckCode::R0205,
CheckKind::YieldOutsideFunction => &CheckCode::F704,
}
}
@ -150,6 +156,9 @@ impl CheckKind {
CheckKind::UnusedVariable(name) => {
format!("Local variable `{name}` is assigned to but never used")
}
CheckKind::UselessObjectInheritance(name) => {
format!("Class {name} inherits from object")
}
CheckKind::YieldOutsideFunction => {
"a `yield` or `yield from` statement outside of a function/method".to_string()
}

View file

@ -451,4 +451,40 @@ mod tests {
Ok(())
}
#[test]
fn r0205() -> Result<()> {
let actual = check_path(
Path::new("./resources/test/src/R0205.py"),
&settings::Settings {
line_length: 88,
exclude: vec![],
select: BTreeSet::from([CheckCode::R0205]),
},
&cache::Mode::None,
)?;
let expected = vec![
Message {
kind: CheckKind::UselessObjectInheritance("B".to_string()),
location: Location::new(5, 1),
filename: "./resources/test/src/R0205.py".to_string(),
},
Message {
kind: CheckKind::UselessObjectInheritance("C".to_string()),
location: Location::new(9, 1),
filename: "./resources/test/src/R0205.py".to_string(),
},
Message {
kind: CheckKind::UselessObjectInheritance("D".to_string()),
location: Location::new(14, 5),
filename: "./resources/test/src/R0205.py".to_string(),
},
];
assert_eq!(actual.len(), expected.len());
for i in 0..actual.len() {
assert_eq!(actual[i], expected[i]);
}
Ok(())
}
}

View file

@ -249,6 +249,7 @@ other-attribute = 1
CheckCode::F831,
CheckCode::F841,
CheckCode::F901,
CheckCode::R0205,
])),
}
);