Implement F821

This commit is contained in:
Charlie Marsh 2022-08-30 14:24:52 -04:00
parent dd759e4730
commit 89af2eaf92
7 changed files with 85 additions and 1 deletions

View File

@ -0,0 +1,14 @@
def get_name():
return self.name
def get_name():
return (self.name,)
def get_name():
del self.name
def get_name(self):
return self.name

View File

@ -8,6 +8,7 @@ select = [
"F541",
"F634",
"F706",
"F821",
"F831",
"F832",
"F901",

View File

@ -299,7 +299,7 @@ impl Visitor for Checker<'_> {
ExprKind::Name { ctx, .. } => match ctx {
ExprContext::Load => self.handle_node_load(expr),
ExprContext::Store => self.handle_node_store(expr),
ExprContext::Del => {}
ExprContext::Del => self.handle_node_delete(expr),
},
ExprKind::GeneratorExp { .. }
| ExprKind::ListComp { .. }
@ -439,8 +439,16 @@ impl Checker<'_> {
}
if let Some(binding) = scope.values.get_mut(id) {
binding.used = Some(scope_id);
return;
}
}
if self.settings.select.contains(&CheckCode::F821) {
self.checks.push(Check {
kind: CheckKind::UndefinedName(id.clone()),
location: expr.location,
})
}
}
}
@ -480,6 +488,20 @@ impl Checker<'_> {
}
}
fn handle_node_delete(&mut self, expr: &Expr) {
if let ExprKind::Name { id, .. } = &expr.node {
let current = self.scopes.last_mut().expect("No current scope found.");
if current.values.remove(id).is_none()
&& self.settings.select.contains(&CheckCode::F821)
{
self.checks.push(Check {
kind: CheckKind::UndefinedName(id.clone()),
location: expr.location,
})
}
}
}
fn check_deferred(&mut self, path: &str) {
for value in self.deferred.clone() {
if let Ok(expr) = &parser::parse_expression(&value, path) {

View File

@ -13,6 +13,7 @@ pub enum CheckCode {
F541,
F634,
F706,
F821,
F831,
F832,
F901,
@ -29,6 +30,7 @@ impl FromStr for CheckCode {
"F541" => Ok(CheckCode::F541),
"F634" => Ok(CheckCode::F634),
"F706" => Ok(CheckCode::F706),
"F821" => Ok(CheckCode::F821),
"F831" => Ok(CheckCode::F831),
"F832" => Ok(CheckCode::F832),
"F901" => Ok(CheckCode::F901),
@ -46,6 +48,7 @@ impl CheckCode {
CheckCode::F541 => "F541",
CheckCode::F634 => "F634",
CheckCode::F706 => "F706",
CheckCode::F821 => "F821",
CheckCode::F831 => "F831",
CheckCode::F832 => "F832",
CheckCode::F901 => "F901",
@ -61,6 +64,7 @@ impl CheckCode {
CheckCode::F541 => &LintSource::AST,
CheckCode::F634 => &LintSource::AST,
CheckCode::F706 => &LintSource::AST,
CheckCode::F821 => &LintSource::AST,
CheckCode::F831 => &LintSource::AST,
CheckCode::F832 => &LintSource::AST,
CheckCode::F901 => &LintSource::AST,
@ -83,6 +87,7 @@ pub enum CheckKind {
LineTooLong,
RaiseNotImplemented,
ReturnOutsideFunction,
UndefinedName(String),
UndefinedLocal(String),
UnusedImport(String),
}
@ -98,6 +103,7 @@ impl CheckKind {
CheckKind::LineTooLong => &CheckCode::E501,
CheckKind::RaiseNotImplemented => &CheckCode::F901,
CheckKind::ReturnOutsideFunction => &CheckCode::F706,
CheckKind::UndefinedName(_) => &CheckCode::F821,
CheckKind::UndefinedLocal(_) => &CheckCode::F832,
CheckKind::UnusedImport(_) => &CheckCode::F401,
}
@ -123,6 +129,9 @@ impl CheckKind {
CheckKind::ReturnOutsideFunction => {
"a `return` statement outside of a function/method".to_string()
}
CheckKind::UndefinedName(name) => {
format!("Undefined name `{name}`")
}
CheckKind::UndefinedLocal(name) => {
format!("Local variable `{name}` referenced before assignment")
}

View File

@ -248,6 +248,42 @@ mod tests {
Ok(())
}
#[test]
fn f821() -> Result<()> {
let actual = check_path(
&Path::new("./resources/test/src/F821.py"),
&settings::Settings {
line_length: 88,
exclude: vec![],
select: BTreeSet::from([CheckCode::F821]),
},
&cache::Mode::None,
)?;
let expected = vec![
Message {
kind: CheckKind::UndefinedName("self".to_string()),
location: Location::new(2, 12),
filename: "./resources/test/src/F821.py".to_string(),
},
Message {
kind: CheckKind::UndefinedName("self".to_string()),
location: Location::new(6, 13),
filename: "./resources/test/src/F821.py".to_string(),
},
Message {
kind: CheckKind::UndefinedName("self".to_string()),
location: Location::new(10, 9),
filename: "./resources/test/src/F821.py".to_string(),
},
];
assert_eq!(actual.len(), expected.len());
for i in 0..actual.len() {
assert_eq!(actual[i], expected[i]);
}
Ok(())
}
#[test]
fn f831() -> Result<()> {
let actual = check_path(

View File

@ -233,6 +233,7 @@ other-attribute = 1
CheckCode::F541,
CheckCode::F634,
CheckCode::F706,
CheckCode::F821,
CheckCode::F831,
CheckCode::F832,
CheckCode::F901,

View File

@ -48,6 +48,7 @@ impl Settings {
CheckCode::F541,
CheckCode::F634,
CheckCode::F706,
CheckCode::F821,
CheckCode::F831,
CheckCode::F832,
CheckCode::F901,