Add support for __all__ export bindings (#87)

This commit is contained in:
Charlie Marsh 2022-09-02 10:17:31 -04:00 committed by GitHub
parent c0131e65e5
commit 221f4304ad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 302 additions and 182 deletions

View File

@ -11,9 +11,15 @@ import multiprocessing.process
import logging.config import logging.config
import logging.handlers import logging.handlers
from blah import ClassA, ClassB, ClassC
class X: class X:
def a(self) -> "namedtuple": def a(self) -> "namedtuple":
x = os.environ["1"] x = os.environ["1"]
y = Counter() y = Counter()
z = multiprocessing.pool.ThreadPool() z = multiprocessing.pool.ThreadPool()
__all__ = ["ClassA"] + ["ClassB"]
__all__ += ["ClassC"]

117
src/ast_ops.rs Normal file
View File

@ -0,0 +1,117 @@
use std::collections::BTreeMap;
use std::sync::atomic::{AtomicUsize, Ordering};
use rustpython_parser::ast::{Constant, Expr, ExprKind, Location, Stmt, StmtKind};
fn id() -> usize {
static COUNTER: AtomicUsize = AtomicUsize::new(1);
COUNTER.fetch_add(1, Ordering::Relaxed)
}
pub enum ScopeKind {
Class,
Function,
Generator,
Module,
}
pub struct Scope {
pub id: usize,
pub kind: ScopeKind,
pub values: BTreeMap<String, Binding>,
}
impl Scope {
pub fn new(kind: ScopeKind) -> Self {
Scope {
id: id(),
kind,
values: BTreeMap::new(),
}
}
}
#[derive(Clone, Debug)]
pub enum BindingKind {
Argument,
Assignment,
Builtin,
ClassDefinition,
Definition,
Export(Vec<String>),
FutureImportation,
Importation(String),
StarImportation,
SubmoduleImportation(String),
}
#[derive(Clone, Debug)]
pub struct Binding {
pub kind: BindingKind,
pub location: Location,
pub used: Option<usize>,
}
/// Extract the names bound to a given __all__ assignment.
pub fn extract_all_names(stmt: &Stmt, scope: &Scope) -> Vec<String> {
let mut names: Vec<String> = vec![];
fn add_to_names(names: &mut Vec<String>, elts: &[Expr]) {
for elt in elts {
if let ExprKind::Constant {
value: Constant::Str(value),
..
} = &elt.node
{
names.push(value.to_string())
}
}
}
// Grab the existing bound __all__ values.
if let StmtKind::AugAssign { .. } = &stmt.node {
if let Some(binding) = scope.values.get("__all__") {
if let BindingKind::Export(existing) = &binding.kind {
names.extend(existing.clone());
}
}
}
if let Some(value) = match &stmt.node {
StmtKind::Assign { value, .. } => Some(value),
StmtKind::AnnAssign { value, .. } => value.as_ref(),
StmtKind::AugAssign { value, .. } => Some(value),
_ => None,
} {
match &value.node {
ExprKind::List { elts, .. } | ExprKind::Tuple { elts, .. } => {
add_to_names(&mut names, elts)
}
ExprKind::BinOp { left, right, .. } => {
let mut current_left = left;
let mut current_right = right;
while let Some(elts) = match &current_right.node {
ExprKind::List { elts, .. } => Some(elts),
ExprKind::Tuple { elts, .. } => Some(elts),
_ => None,
} {
add_to_names(&mut names, elts);
match &current_left.node {
ExprKind::BinOp { left, right, .. } => {
current_left = left;
current_right = right;
}
ExprKind::List { elts, .. } | ExprKind::Tuple { elts, .. } => {
add_to_names(&mut names, elts);
break;
}
_ => break,
}
}
}
_ => {}
}
}
names
}

View File

@ -1,67 +1,18 @@
use std::collections::{BTreeMap, BTreeSet}; use std::collections::BTreeSet;
use std::sync::atomic::{AtomicUsize, Ordering};
use rustpython_parser::ast::{ use rustpython_parser::ast::{
Arg, Arguments, Constant, Excepthandler, ExcepthandlerKind, Expr, ExprContext, ExprKind, Arg, Arguments, Constant, Excepthandler, ExcepthandlerKind, Expr, ExprContext, ExprKind, Stmt,
Location, Stmt, StmtKind, Suite, StmtKind, Suite,
}; };
use rustpython_parser::parser; use rustpython_parser::parser;
use crate::ast_ops::{extract_all_names, Binding, BindingKind, Scope, ScopeKind};
use crate::builtins::{BUILTINS, MAGIC_GLOBALS}; use crate::builtins::{BUILTINS, MAGIC_GLOBALS};
use crate::check_ast::ScopeKind::{Class, Function, Generator, Module};
use crate::checks::{Check, CheckCode, CheckKind}; use crate::checks::{Check, CheckCode, CheckKind};
use crate::settings::Settings; use crate::settings::Settings;
use crate::visitor; use crate::visitor;
use crate::visitor::{walk_excepthandler, Visitor}; use crate::visitor::{walk_excepthandler, Visitor};
fn id() -> usize {
static COUNTER: AtomicUsize = AtomicUsize::new(1);
COUNTER.fetch_add(1, Ordering::Relaxed)
}
enum ScopeKind {
Class,
Function,
Generator,
Module,
}
struct Scope {
id: usize,
kind: ScopeKind,
values: BTreeMap<String, Binding>,
}
impl Scope {
fn new(kind: ScopeKind) -> Self {
Scope {
id: id(),
kind,
values: BTreeMap::new(),
}
}
}
#[derive(Clone)]
enum BindingKind {
Argument,
Assignment,
Definition,
ClassDefinition,
Builtin,
FutureImportation,
Importation(String),
StarImportation,
SubmoduleImportation(String),
}
#[derive(Clone)]
struct Binding {
kind: BindingKind,
location: Location,
used: Option<usize>,
}
struct Checker<'a> { struct Checker<'a> {
settings: &'a Settings, settings: &'a Settings,
checks: Vec<Check>, checks: Vec<Check>,
@ -123,7 +74,7 @@ impl Visitor for Checker<'_> {
.. ..
} => { } => {
for expr in decorator_list { for expr in decorator_list {
self.visit_expr(expr); self.visit_expr(expr, Some(stmt));
} }
for expr in returns { for expr in returns {
self.visit_annotation(expr); self.visit_annotation(expr);
@ -136,7 +87,7 @@ impl Visitor for Checker<'_> {
location: stmt.location, location: stmt.location,
}, },
); );
self.push_scope(Scope::new(Function)); self.push_scope(Scope::new(ScopeKind::Function));
} }
StmtKind::Return { .. } => { StmtKind::Return { .. } => {
if self if self
@ -146,7 +97,7 @@ impl Visitor for Checker<'_> {
{ {
if let Some(scope) = self.scopes.last() { if let Some(scope) = self.scopes.last() {
match scope.kind { match scope.kind {
Class | Module => { ScopeKind::Class | ScopeKind::Module => {
self.checks.push(Check { self.checks.push(Check {
kind: CheckKind::ReturnOutsideFunction, kind: CheckKind::ReturnOutsideFunction,
location: stmt.location, location: stmt.location,
@ -164,15 +115,15 @@ impl Visitor for Checker<'_> {
.. ..
} => { } => {
for expr in bases { for expr in bases {
self.visit_expr(expr) self.visit_expr(expr, Some(stmt))
} }
for keyword in keywords { for keyword in keywords {
self.visit_keyword(keyword) self.visit_keyword(keyword)
} }
for expr in decorator_list { for expr in decorator_list {
self.visit_expr(expr) self.visit_expr(expr, Some(stmt))
} }
self.push_scope(Scope::new(Class)) self.push_scope(Scope::new(ScopeKind::Class))
} }
StmtKind::Import { names } => { StmtKind::Import { names } => {
for alias in names { for alias in names {
@ -353,23 +304,23 @@ impl Visitor for Checker<'_> {
fn visit_annotation(&mut self, expr: &Expr) { fn visit_annotation(&mut self, expr: &Expr) {
let initial = self.in_annotation; let initial = self.in_annotation;
self.in_annotation = true; self.in_annotation = true;
self.visit_expr(expr); self.visit_expr(expr, None);
self.in_annotation = initial; self.in_annotation = initial;
} }
fn visit_expr(&mut self, expr: &Expr) { fn visit_expr(&mut self, expr: &Expr, parent: Option<&Stmt>) {
let initial = self.in_f_string; let initial = self.in_f_string;
match &expr.node { match &expr.node {
ExprKind::Name { ctx, .. } => match ctx { ExprKind::Name { ctx, .. } => match ctx {
ExprContext::Load => self.handle_node_load(expr), ExprContext::Load => self.handle_node_load(expr),
ExprContext::Store => self.handle_node_store(expr), ExprContext::Store => self.handle_node_store(expr, parent),
ExprContext::Del => self.handle_node_delete(expr), ExprContext::Del => self.handle_node_delete(expr),
}, },
ExprKind::GeneratorExp { .. } ExprKind::GeneratorExp { .. }
| ExprKind::ListComp { .. } | ExprKind::ListComp { .. }
| ExprKind::DictComp { .. } | ExprKind::DictComp { .. }
| ExprKind::SetComp { .. } => self.push_scope(Scope::new(Generator)), | ExprKind::SetComp { .. } => self.push_scope(Scope::new(ScopeKind::Generator)),
ExprKind::Lambda { .. } => self.push_scope(Scope::new(Function)), ExprKind::Lambda { .. } => self.push_scope(Scope::new(ScopeKind::Function)),
ExprKind::Yield { .. } | ExprKind::YieldFrom { .. } => { ExprKind::Yield { .. } | ExprKind::YieldFrom { .. } => {
let scope = self.scopes.last().expect("No current scope found."); let scope = self.scopes.last().expect("No current scope found.");
if self if self
@ -434,24 +385,30 @@ impl Visitor for Checker<'_> {
Some(name) => { Some(name) => {
let scope = self.scopes.last().expect("No current scope found."); let scope = self.scopes.last().expect("No current scope found.");
if scope.values.contains_key(name) { if scope.values.contains_key(name) {
self.handle_node_store(&Expr::new( self.handle_node_store(
&Expr::new(
excepthandler.location,
ExprKind::Name {
id: name.to_string(),
ctx: ExprContext::Store,
},
),
None,
);
}
let scope = self.scopes.last().expect("No current scope found.");
let prev_definition = scope.values.get(name).cloned();
self.handle_node_store(
&Expr::new(
excepthandler.location, excepthandler.location,
ExprKind::Name { ExprKind::Name {
id: name.to_string(), id: name.to_string(),
ctx: ExprContext::Store, ctx: ExprContext::Store,
}, },
)); ),
} None,
);
let scope = self.scopes.last().expect("No current scope found.");
let prev_definition = scope.values.get(name).cloned();
self.handle_node_store(&Expr::new(
excepthandler.location,
ExprKind::Name {
id: name.to_string(),
ctx: ExprContext::Store,
},
));
walk_excepthandler(self, excepthandler); walk_excepthandler(self, excepthandler);
@ -580,7 +537,7 @@ impl Checker<'_> {
let mut first_iter = true; let mut first_iter = true;
let mut in_generators = false; let mut in_generators = false;
for scope in self.scopes.iter_mut().rev() { for scope in self.scopes.iter_mut().rev() {
if matches!(scope.kind, Class) { if matches!(scope.kind, ScopeKind::Class) {
if id == "__class__" { if id == "__class__" {
return; return;
} else if !first_iter && !in_generators { } else if !first_iter && !in_generators {
@ -593,7 +550,7 @@ impl Checker<'_> {
} }
first_iter = false; first_iter = false;
in_generators = matches!(scope.kind, Generator); in_generators = matches!(scope.kind, ScopeKind::Generator);
} }
if self.settings.select.contains(&CheckCode::F821) { if self.settings.select.contains(&CheckCode::F821) {
@ -605,26 +562,29 @@ impl Checker<'_> {
} }
} }
fn handle_node_store(&mut self, expr: &Expr) { fn handle_node_store(&mut self, expr: &Expr, parent: Option<&Stmt>) {
if let ExprKind::Name { id, .. } = &expr.node { if let ExprKind::Name { id, .. } = &expr.node {
if self.settings.select.contains(&CheckCode::F823) { let current = self.scopes.last().expect("No current scope found.");
let current = self.scopes.last().expect("No current scope found.");
if matches!(current.kind, ScopeKind::Function) && !current.values.contains_key(id) { if self.settings.select.contains(&CheckCode::F823)
for scope in self.scopes.iter().rev().skip(1) { && matches!(current.kind, ScopeKind::Function)
if matches!(scope.kind, ScopeKind::Function) || matches!(scope.kind, Module) && !current.values.contains_key(id)
{ {
let used = scope for scope in self.scopes.iter().rev().skip(1) {
.values if matches!(scope.kind, ScopeKind::Function)
.get(id) || matches!(scope.kind, ScopeKind::Module)
.map(|binding| binding.used) {
.unwrap_or_default(); let used = scope
if let Some(scope_id) = used { .values
if scope_id == current.id { .get(id)
self.checks.push(Check { .map(|binding| binding.used)
kind: CheckKind::UndefinedLocal(id.clone()), .unwrap_or_default();
location: expr.location, if let Some(scope_id) = used {
}); if scope_id == current.id {
} self.checks.push(Check {
kind: CheckKind::UndefinedLocal(id.clone()),
location: expr.location,
});
} }
} }
} }
@ -632,14 +592,36 @@ impl Checker<'_> {
} }
// TODO(charlie): Handle alternate binding types (like `Annotation`). // TODO(charlie): Handle alternate binding types (like `Annotation`).
self.add_binding( if id == "__all__"
id.to_string(), && matches!(current.kind, ScopeKind::Module)
Binding { && match parent {
kind: BindingKind::Assignment, None => false,
used: None, Some(stmt) => {
location: expr.location, matches!(stmt.node, StmtKind::Assign { .. })
}, || matches!(stmt.node, StmtKind::AugAssign { .. })
); || matches!(stmt.node, StmtKind::AnnAssign { .. })
}
}
{
// Really need parent here.
self.add_binding(
id.to_string(),
Binding {
kind: BindingKind::Export(extract_all_names(parent.unwrap(), current)),
used: None,
location: expr.location,
},
);
} else {
self.add_binding(
id.to_string(),
Binding {
kind: BindingKind::Assignment,
used: None,
location: expr.location,
},
);
}
} }
} }
@ -660,17 +642,31 @@ impl Checker<'_> {
fn check_deferred(&mut self, path: &str) { fn check_deferred(&mut self, path: &str) {
for value in self.deferred.clone() { for value in self.deferred.clone() {
if let Ok(expr) = &parser::parse_expression(&value, path) { if let Ok(expr) = &parser::parse_expression(&value, path) {
self.visit_expr(expr); self.visit_expr(expr, None);
} }
} }
} }
fn check_dead_scopes(&mut self) { fn check_dead_scopes(&mut self) {
if self.settings.select.contains(&CheckCode::F401) { if self.settings.select.contains(&CheckCode::F401) {
// TODO(charlie): Handle `__all__`.
for scope in &self.dead_scopes { for scope in &self.dead_scopes {
for (_, binding) in scope.values.iter().rev() { let all_binding = match scope.values.get("__all__") {
if binding.used.is_none() { Some(binding) => match &binding.kind {
BindingKind::Export(names) => Some(names),
_ => None,
},
_ => None,
};
println!("{:?}", all_binding);
for (name, binding) in scope.values.iter().rev() {
let used = binding.used.is_some()
|| all_binding
.map(|names| names.contains(name))
.unwrap_or_default();
if !used {
match &binding.kind { match &binding.kind {
BindingKind::Importation(full_name) BindingKind::Importation(full_name)
| BindingKind::SubmoduleImportation(full_name) => { | BindingKind::SubmoduleImportation(full_name) => {
@ -690,7 +686,7 @@ impl Checker<'_> {
pub fn check_ast(python_ast: &Suite, settings: &Settings, path: &str) -> Vec<Check> { pub fn check_ast(python_ast: &Suite, settings: &Settings, path: &str) -> Vec<Check> {
let mut checker = Checker::new(settings); let mut checker = Checker::new(settings);
checker.push_scope(Scope::new(Module)); checker.push_scope(Scope::new(ScopeKind::Module));
checker.bind_builtins(); checker.bind_builtins();
for stmt in python_ast { for stmt in python_ast {

View File

@ -1,3 +1,4 @@
mod ast_ops;
mod builtins; mod builtins;
mod cache; mod cache;
pub mod check_ast; pub mod check_ast;

View File

@ -11,7 +11,7 @@ pub trait Visitor {
fn visit_annotation(&mut self, expr: &Expr) { fn visit_annotation(&mut self, expr: &Expr) {
walk_expr(self, expr); walk_expr(self, expr);
} }
fn visit_expr(&mut self, expr: &Expr) { fn visit_expr(&mut self, expr: &Expr, _parent: Option<&Stmt>) {
walk_expr(self, expr); walk_expr(self, expr);
} }
fn visit_constant(&mut self, constant: &Constant) { fn visit_constant(&mut self, constant: &Constant) {
@ -82,24 +82,24 @@ pub fn walk_stmt<V: Visitor + ?Sized>(visitor: &mut V, stmt: &Stmt) {
} }
StmtKind::Return { value } => { StmtKind::Return { value } => {
if let Some(expr) = value { if let Some(expr) = value {
visitor.visit_expr(expr) visitor.visit_expr(expr, Some(stmt))
} }
} }
StmtKind::Delete { targets } => { StmtKind::Delete { targets } => {
for expr in targets { for expr in targets {
visitor.visit_expr(expr) visitor.visit_expr(expr, Some(stmt))
} }
} }
StmtKind::Assign { targets, value, .. } => { StmtKind::Assign { targets, value, .. } => {
for expr in targets { for expr in targets {
visitor.visit_expr(expr) visitor.visit_expr(expr, Some(stmt))
} }
visitor.visit_expr(value) visitor.visit_expr(value, Some(stmt))
} }
StmtKind::AugAssign { target, op, value } => { StmtKind::AugAssign { target, op, value } => {
visitor.visit_expr(target); visitor.visit_expr(target, Some(stmt));
visitor.visit_operator(op); visitor.visit_operator(op);
visitor.visit_expr(value); visitor.visit_expr(value, Some(stmt));
} }
StmtKind::AnnAssign { StmtKind::AnnAssign {
target, target,
@ -107,10 +107,10 @@ pub fn walk_stmt<V: Visitor + ?Sized>(visitor: &mut V, stmt: &Stmt) {
value, value,
.. ..
} => { } => {
visitor.visit_expr(target); visitor.visit_expr(target, Some(stmt));
visitor.visit_annotation(annotation); visitor.visit_annotation(annotation);
if let Some(expr) = value { if let Some(expr) = value {
visitor.visit_expr(expr) visitor.visit_expr(expr, Some(stmt))
} }
} }
StmtKind::For { StmtKind::For {
@ -120,8 +120,8 @@ pub fn walk_stmt<V: Visitor + ?Sized>(visitor: &mut V, stmt: &Stmt) {
orelse, orelse,
.. ..
} => { } => {
visitor.visit_expr(target); visitor.visit_expr(target, Some(stmt));
visitor.visit_expr(iter); visitor.visit_expr(iter, Some(stmt));
for stmt in body { for stmt in body {
visitor.visit_stmt(stmt) visitor.visit_stmt(stmt)
} }
@ -136,8 +136,8 @@ pub fn walk_stmt<V: Visitor + ?Sized>(visitor: &mut V, stmt: &Stmt) {
orelse, orelse,
.. ..
} => { } => {
visitor.visit_expr(target); visitor.visit_expr(target, Some(stmt));
visitor.visit_expr(iter); visitor.visit_expr(iter, Some(stmt));
for stmt in body { for stmt in body {
visitor.visit_stmt(stmt) visitor.visit_stmt(stmt)
} }
@ -146,7 +146,7 @@ pub fn walk_stmt<V: Visitor + ?Sized>(visitor: &mut V, stmt: &Stmt) {
} }
} }
StmtKind::While { test, body, orelse } => { StmtKind::While { test, body, orelse } => {
visitor.visit_expr(test); visitor.visit_expr(test, Some(stmt));
for stmt in body { for stmt in body {
visitor.visit_stmt(stmt) visitor.visit_stmt(stmt)
} }
@ -155,7 +155,7 @@ pub fn walk_stmt<V: Visitor + ?Sized>(visitor: &mut V, stmt: &Stmt) {
} }
} }
StmtKind::If { test, body, orelse } => { StmtKind::If { test, body, orelse } => {
visitor.visit_expr(test); visitor.visit_expr(test, Some(stmt));
for stmt in body { for stmt in body {
visitor.visit_stmt(stmt) visitor.visit_stmt(stmt)
} }
@ -181,17 +181,17 @@ pub fn walk_stmt<V: Visitor + ?Sized>(visitor: &mut V, stmt: &Stmt) {
} }
StmtKind::Match { subject, cases } => { StmtKind::Match { subject, cases } => {
// TODO(charlie): Handle `cases`. // TODO(charlie): Handle `cases`.
visitor.visit_expr(subject); visitor.visit_expr(subject, Some(stmt));
for match_case in cases { for match_case in cases {
visitor.visit_match_case(match_case); visitor.visit_match_case(match_case);
} }
} }
StmtKind::Raise { exc, cause } => { StmtKind::Raise { exc, cause } => {
if let Some(expr) = exc { if let Some(expr) = exc {
visitor.visit_expr(expr) visitor.visit_expr(expr, Some(stmt))
}; };
if let Some(expr) = cause { if let Some(expr) = cause {
visitor.visit_expr(expr) visitor.visit_expr(expr, Some(stmt))
}; };
} }
StmtKind::Try { StmtKind::Try {
@ -214,9 +214,9 @@ pub fn walk_stmt<V: Visitor + ?Sized>(visitor: &mut V, stmt: &Stmt) {
} }
} }
StmtKind::Assert { test, msg } => { StmtKind::Assert { test, msg } => {
visitor.visit_expr(test); visitor.visit_expr(test, None);
if let Some(expr) = msg { if let Some(expr) = msg {
visitor.visit_expr(expr) visitor.visit_expr(expr, Some(stmt))
} }
} }
StmtKind::Import { names } => { StmtKind::Import { names } => {
@ -231,7 +231,7 @@ pub fn walk_stmt<V: Visitor + ?Sized>(visitor: &mut V, stmt: &Stmt) {
} }
StmtKind::Global { .. } => {} StmtKind::Global { .. } => {}
StmtKind::Nonlocal { .. } => {} StmtKind::Nonlocal { .. } => {}
StmtKind::Expr { value } => visitor.visit_expr(value), StmtKind::Expr { value } => visitor.visit_expr(value, Some(stmt)),
StmtKind::Pass => {} StmtKind::Pass => {}
StmtKind::Break => {} StmtKind::Break => {}
StmtKind::Continue => {} StmtKind::Continue => {}
@ -243,55 +243,55 @@ pub fn walk_expr<V: Visitor + ?Sized>(visitor: &mut V, expr: &Expr) {
ExprKind::BoolOp { op, values } => { ExprKind::BoolOp { op, values } => {
visitor.visit_boolop(op); visitor.visit_boolop(op);
for expr in values { for expr in values {
visitor.visit_expr(expr) visitor.visit_expr(expr, None)
} }
} }
ExprKind::NamedExpr { target, value } => { ExprKind::NamedExpr { target, value } => {
visitor.visit_expr(target); visitor.visit_expr(target, None);
visitor.visit_expr(value); visitor.visit_expr(value, None);
} }
ExprKind::BinOp { left, op, right } => { ExprKind::BinOp { left, op, right } => {
visitor.visit_expr(left); visitor.visit_expr(left, None);
visitor.visit_operator(op); visitor.visit_operator(op);
visitor.visit_expr(right); visitor.visit_expr(right, None);
} }
ExprKind::UnaryOp { op, operand } => { ExprKind::UnaryOp { op, operand } => {
visitor.visit_unaryop(op); visitor.visit_unaryop(op);
visitor.visit_expr(operand); visitor.visit_expr(operand, None);
} }
ExprKind::Lambda { args, body } => { ExprKind::Lambda { args, body } => {
visitor.visit_arguments(args); visitor.visit_arguments(args);
visitor.visit_expr(body); visitor.visit_expr(body, None);
} }
ExprKind::IfExp { test, body, orelse } => { ExprKind::IfExp { test, body, orelse } => {
visitor.visit_expr(test); visitor.visit_expr(test, None);
visitor.visit_expr(body); visitor.visit_expr(body, None);
visitor.visit_expr(orelse); visitor.visit_expr(orelse, None);
} }
ExprKind::Dict { keys, values } => { ExprKind::Dict { keys, values } => {
for expr in keys { for expr in keys {
visitor.visit_expr(expr) visitor.visit_expr(expr, None)
} }
for expr in values { for expr in values {
visitor.visit_expr(expr) visitor.visit_expr(expr, None)
} }
} }
ExprKind::Set { elts } => { ExprKind::Set { elts } => {
for expr in elts { for expr in elts {
visitor.visit_expr(expr) visitor.visit_expr(expr, None)
} }
} }
ExprKind::ListComp { elt, generators } => { ExprKind::ListComp { elt, generators } => {
for comprehension in generators { for comprehension in generators {
visitor.visit_comprehension(comprehension) visitor.visit_comprehension(comprehension)
} }
visitor.visit_expr(elt); visitor.visit_expr(elt, None);
} }
ExprKind::SetComp { elt, generators } => { ExprKind::SetComp { elt, generators } => {
for comprehension in generators { for comprehension in generators {
visitor.visit_comprehension(comprehension) visitor.visit_comprehension(comprehension)
} }
visitor.visit_expr(elt); visitor.visit_expr(elt, None);
} }
ExprKind::DictComp { ExprKind::DictComp {
key, key,
@ -301,33 +301,33 @@ pub fn walk_expr<V: Visitor + ?Sized>(visitor: &mut V, expr: &Expr) {
for comprehension in generators { for comprehension in generators {
visitor.visit_comprehension(comprehension) visitor.visit_comprehension(comprehension)
} }
visitor.visit_expr(key); visitor.visit_expr(key, None);
visitor.visit_expr(value); visitor.visit_expr(value, None);
} }
ExprKind::GeneratorExp { elt, generators } => { ExprKind::GeneratorExp { elt, generators } => {
for comprehension in generators { for comprehension in generators {
visitor.visit_comprehension(comprehension) visitor.visit_comprehension(comprehension)
} }
visitor.visit_expr(elt); visitor.visit_expr(elt, None);
} }
ExprKind::Await { value } => visitor.visit_expr(value), ExprKind::Await { value } => visitor.visit_expr(value, None),
ExprKind::Yield { value } => { ExprKind::Yield { value } => {
if let Some(expr) = value { if let Some(expr) = value {
visitor.visit_expr(expr) visitor.visit_expr(expr, None)
} }
} }
ExprKind::YieldFrom { value } => visitor.visit_expr(value), ExprKind::YieldFrom { value } => visitor.visit_expr(value, None),
ExprKind::Compare { ExprKind::Compare {
left, left,
ops, ops,
comparators, comparators,
} => { } => {
visitor.visit_expr(left); visitor.visit_expr(left, None);
for cmpop in ops { for cmpop in ops {
visitor.visit_cmpop(cmpop); visitor.visit_cmpop(cmpop);
} }
for expr in comparators { for expr in comparators {
visitor.visit_expr(expr) visitor.visit_expr(expr, None)
} }
} }
ExprKind::Call { ExprKind::Call {
@ -335,9 +335,9 @@ pub fn walk_expr<V: Visitor + ?Sized>(visitor: &mut V, expr: &Expr) {
args, args,
keywords, keywords,
} => { } => {
visitor.visit_expr(func); visitor.visit_expr(func, None);
for expr in args { for expr in args {
visitor.visit_expr(expr); visitor.visit_expr(expr, None);
} }
for keyword in keywords { for keyword in keywords {
visitor.visit_keyword(keyword); visitor.visit_keyword(keyword);
@ -346,28 +346,28 @@ pub fn walk_expr<V: Visitor + ?Sized>(visitor: &mut V, expr: &Expr) {
ExprKind::FormattedValue { ExprKind::FormattedValue {
value, format_spec, .. value, format_spec, ..
} => { } => {
visitor.visit_expr(value); visitor.visit_expr(value, None);
if let Some(expr) = format_spec { if let Some(expr) = format_spec {
visitor.visit_expr(expr) visitor.visit_expr(expr, None)
} }
} }
ExprKind::JoinedStr { values } => { ExprKind::JoinedStr { values } => {
for expr in values { for expr in values {
visitor.visit_expr(expr) visitor.visit_expr(expr, None)
} }
} }
ExprKind::Constant { value, .. } => visitor.visit_constant(value), ExprKind::Constant { value, .. } => visitor.visit_constant(value),
ExprKind::Attribute { value, ctx, .. } => { ExprKind::Attribute { value, ctx, .. } => {
visitor.visit_expr(value); visitor.visit_expr(value, None);
visitor.visit_expr_context(ctx); visitor.visit_expr_context(ctx);
} }
ExprKind::Subscript { value, slice, ctx } => { ExprKind::Subscript { value, slice, ctx } => {
visitor.visit_expr(value); visitor.visit_expr(value, None);
visitor.visit_expr(slice); visitor.visit_expr(slice, None);
visitor.visit_expr_context(ctx); visitor.visit_expr_context(ctx);
} }
ExprKind::Starred { value, ctx } => { ExprKind::Starred { value, ctx } => {
visitor.visit_expr(value); visitor.visit_expr(value, None);
visitor.visit_expr_context(ctx); visitor.visit_expr_context(ctx);
} }
ExprKind::Name { ctx, .. } => { ExprKind::Name { ctx, .. } => {
@ -375,25 +375,25 @@ pub fn walk_expr<V: Visitor + ?Sized>(visitor: &mut V, expr: &Expr) {
} }
ExprKind::List { elts, ctx } => { ExprKind::List { elts, ctx } => {
for expr in elts { for expr in elts {
visitor.visit_expr(expr); visitor.visit_expr(expr, None);
} }
visitor.visit_expr_context(ctx); visitor.visit_expr_context(ctx);
} }
ExprKind::Tuple { elts, ctx } => { ExprKind::Tuple { elts, ctx } => {
for expr in elts { for expr in elts {
visitor.visit_expr(expr); visitor.visit_expr(expr, None);
} }
visitor.visit_expr_context(ctx); visitor.visit_expr_context(ctx);
} }
ExprKind::Slice { lower, upper, step } => { ExprKind::Slice { lower, upper, step } => {
if let Some(expr) = lower { if let Some(expr) = lower {
visitor.visit_expr(expr); visitor.visit_expr(expr, None);
} }
if let Some(expr) = upper { if let Some(expr) = upper {
visitor.visit_expr(expr); visitor.visit_expr(expr, None);
} }
if let Some(expr) = step { if let Some(expr) = step {
visitor.visit_expr(expr); visitor.visit_expr(expr, None);
} }
} }
} }
@ -408,10 +408,10 @@ pub fn walk_constant<V: Visitor + ?Sized>(visitor: &mut V, constant: &Constant)
} }
pub fn walk_comprehension<V: Visitor + ?Sized>(visitor: &mut V, comprehension: &Comprehension) { pub fn walk_comprehension<V: Visitor + ?Sized>(visitor: &mut V, comprehension: &Comprehension) {
visitor.visit_expr(&comprehension.target); visitor.visit_expr(&comprehension.target, None);
visitor.visit_expr(&comprehension.iter); visitor.visit_expr(&comprehension.iter, None);
for expr in &comprehension.ifs { for expr in &comprehension.ifs {
visitor.visit_expr(expr); visitor.visit_expr(expr, None);
} }
} }
@ -419,7 +419,7 @@ pub fn walk_excepthandler<V: Visitor + ?Sized>(visitor: &mut V, excepthandler: &
match &excepthandler.node { match &excepthandler.node {
ExcepthandlerKind::ExceptHandler { type_, body, .. } => { ExcepthandlerKind::ExceptHandler { type_, body, .. } => {
if let Some(expr) = type_ { if let Some(expr) = type_ {
visitor.visit_expr(expr); visitor.visit_expr(expr, None);
} }
for stmt in body { for stmt in body {
visitor.visit_stmt(stmt); visitor.visit_stmt(stmt);
@ -442,13 +442,13 @@ pub fn walk_arguments<V: Visitor + ?Sized>(visitor: &mut V, arguments: &Argument
visitor.visit_arg(arg); visitor.visit_arg(arg);
} }
for expr in &arguments.kw_defaults { for expr in &arguments.kw_defaults {
visitor.visit_expr(expr) visitor.visit_expr(expr, None)
} }
if let Some(arg) = &arguments.kwarg { if let Some(arg) = &arguments.kwarg {
visitor.visit_arg(arg) visitor.visit_arg(arg)
} }
for expr in &arguments.defaults { for expr in &arguments.defaults {
visitor.visit_expr(expr) visitor.visit_expr(expr, None)
} }
} }
@ -459,20 +459,20 @@ pub fn walk_arg<V: Visitor + ?Sized>(visitor: &mut V, arg: &Arg) {
} }
pub fn walk_keyword<V: Visitor + ?Sized>(visitor: &mut V, keyword: &Keyword) { pub fn walk_keyword<V: Visitor + ?Sized>(visitor: &mut V, keyword: &Keyword) {
visitor.visit_expr(&keyword.node.value); visitor.visit_expr(&keyword.node.value, None);
} }
pub fn walk_withitem<V: Visitor + ?Sized>(visitor: &mut V, withitem: &Withitem) { pub fn walk_withitem<V: Visitor + ?Sized>(visitor: &mut V, withitem: &Withitem) {
visitor.visit_expr(&withitem.context_expr); visitor.visit_expr(&withitem.context_expr, None);
if let Some(expr) = &withitem.optional_vars { if let Some(expr) = &withitem.optional_vars {
visitor.visit_expr(expr); visitor.visit_expr(expr, None);
} }
} }
pub fn walk_match_case<V: Visitor + ?Sized>(visitor: &mut V, match_case: &MatchCase) { pub fn walk_match_case<V: Visitor + ?Sized>(visitor: &mut V, match_case: &MatchCase) {
visitor.visit_pattern(&match_case.pattern); visitor.visit_pattern(&match_case.pattern);
if let Some(expr) = &match_case.guard { if let Some(expr) = &match_case.guard {
visitor.visit_expr(expr); visitor.visit_expr(expr, None);
} }
for stmt in &match_case.body { for stmt in &match_case.body {
visitor.visit_stmt(stmt); visitor.visit_stmt(stmt);
@ -481,7 +481,7 @@ pub fn walk_match_case<V: Visitor + ?Sized>(visitor: &mut V, match_case: &MatchC
pub fn walk_pattern<V: Visitor + ?Sized>(visitor: &mut V, pattern: &Pattern) { pub fn walk_pattern<V: Visitor + ?Sized>(visitor: &mut V, pattern: &Pattern) {
match &pattern.node { match &pattern.node {
PatternKind::MatchValue { value } => visitor.visit_expr(value), PatternKind::MatchValue { value } => visitor.visit_expr(value, None),
PatternKind::MatchSingleton { value } => visitor.visit_constant(value), PatternKind::MatchSingleton { value } => visitor.visit_constant(value),
PatternKind::MatchSequence { patterns } => { PatternKind::MatchSequence { patterns } => {
for pattern in patterns { for pattern in patterns {
@ -490,7 +490,7 @@ pub fn walk_pattern<V: Visitor + ?Sized>(visitor: &mut V, pattern: &Pattern) {
} }
PatternKind::MatchMapping { keys, patterns, .. } => { PatternKind::MatchMapping { keys, patterns, .. } => {
for expr in keys { for expr in keys {
visitor.visit_expr(expr); visitor.visit_expr(expr, None);
} }
for pattern in patterns { for pattern in patterns {
visitor.visit_pattern(pattern); visitor.visit_pattern(pattern);
@ -502,7 +502,7 @@ pub fn walk_pattern<V: Visitor + ?Sized>(visitor: &mut V, pattern: &Pattern) {
kwd_patterns, kwd_patterns,
.. ..
} => { } => {
visitor.visit_expr(cls); visitor.visit_expr(cls, None);
for pattern in patterns { for pattern in patterns {
visitor.visit_pattern(pattern); visitor.visit_pattern(pattern);
} }