From 221f4304adc0cf8afb521af17dcd0a08903ace9e Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Fri, 2 Sep 2022 10:17:31 -0400 Subject: [PATCH] Add support for __all__ export bindings (#87) --- resources/test/src/F401.py | 6 + src/ast_ops.rs | 117 ++++++++++++++++++++ src/check_ast.rs | 218 ++++++++++++++++++------------------- src/lib.rs | 1 + src/visitor.rs | 142 ++++++++++++------------ 5 files changed, 302 insertions(+), 182 deletions(-) create mode 100644 src/ast_ops.rs diff --git a/resources/test/src/F401.py b/resources/test/src/F401.py index a2c80fd295..05f5ffa195 100644 --- a/resources/test/src/F401.py +++ b/resources/test/src/F401.py @@ -11,9 +11,15 @@ import multiprocessing.process import logging.config import logging.handlers +from blah import ClassA, ClassB, ClassC + class X: def a(self) -> "namedtuple": x = os.environ["1"] y = Counter() z = multiprocessing.pool.ThreadPool() + + +__all__ = ["ClassA"] + ["ClassB"] +__all__ += ["ClassC"] diff --git a/src/ast_ops.rs b/src/ast_ops.rs new file mode 100644 index 0000000000..cb75536cc7 --- /dev/null +++ b/src/ast_ops.rs @@ -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, +} + +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), + FutureImportation, + Importation(String), + StarImportation, + SubmoduleImportation(String), +} + +#[derive(Clone, Debug)] +pub struct Binding { + pub kind: BindingKind, + pub location: Location, + pub used: Option, +} + +/// Extract the names bound to a given __all__ assignment. +pub fn extract_all_names(stmt: &Stmt, scope: &Scope) -> Vec { + let mut names: Vec = vec![]; + + fn add_to_names(names: &mut Vec, 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 ¤t_right.node { + ExprKind::List { elts, .. } => Some(elts), + ExprKind::Tuple { elts, .. } => Some(elts), + _ => None, + } { + add_to_names(&mut names, elts); + match ¤t_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 +} diff --git a/src/check_ast.rs b/src/check_ast.rs index bc19d79fc4..edaf3b614e 100644 --- a/src/check_ast.rs +++ b/src/check_ast.rs @@ -1,67 +1,18 @@ -use std::collections::{BTreeMap, BTreeSet}; -use std::sync::atomic::{AtomicUsize, Ordering}; +use std::collections::BTreeSet; use rustpython_parser::ast::{ - Arg, Arguments, Constant, Excepthandler, ExcepthandlerKind, Expr, ExprContext, ExprKind, - Location, Stmt, StmtKind, Suite, + Arg, Arguments, Constant, Excepthandler, ExcepthandlerKind, Expr, ExprContext, ExprKind, Stmt, + StmtKind, Suite, }; use rustpython_parser::parser; +use crate::ast_ops::{extract_all_names, Binding, BindingKind, Scope, ScopeKind}; use crate::builtins::{BUILTINS, MAGIC_GLOBALS}; -use crate::check_ast::ScopeKind::{Class, Function, Generator, Module}; use crate::checks::{Check, CheckCode, CheckKind}; use crate::settings::Settings; use crate::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, -} - -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, -} - struct Checker<'a> { settings: &'a Settings, checks: Vec, @@ -123,7 +74,7 @@ impl Visitor for Checker<'_> { .. } => { for expr in decorator_list { - self.visit_expr(expr); + self.visit_expr(expr, Some(stmt)); } for expr in returns { self.visit_annotation(expr); @@ -136,7 +87,7 @@ impl Visitor for Checker<'_> { location: stmt.location, }, ); - self.push_scope(Scope::new(Function)); + self.push_scope(Scope::new(ScopeKind::Function)); } StmtKind::Return { .. } => { if self @@ -146,7 +97,7 @@ impl Visitor for Checker<'_> { { if let Some(scope) = self.scopes.last() { match scope.kind { - Class | Module => { + ScopeKind::Class | ScopeKind::Module => { self.checks.push(Check { kind: CheckKind::ReturnOutsideFunction, location: stmt.location, @@ -164,15 +115,15 @@ impl Visitor for Checker<'_> { .. } => { for expr in bases { - self.visit_expr(expr) + self.visit_expr(expr, Some(stmt)) } for keyword in keywords { self.visit_keyword(keyword) } 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 } => { for alias in names { @@ -353,23 +304,23 @@ impl Visitor for Checker<'_> { fn visit_annotation(&mut self, expr: &Expr) { let initial = self.in_annotation; self.in_annotation = true; - self.visit_expr(expr); + self.visit_expr(expr, None); 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; match &expr.node { ExprKind::Name { ctx, .. } => match ctx { 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), }, ExprKind::GeneratorExp { .. } | ExprKind::ListComp { .. } | ExprKind::DictComp { .. } - | ExprKind::SetComp { .. } => self.push_scope(Scope::new(Generator)), - ExprKind::Lambda { .. } => self.push_scope(Scope::new(Function)), + | ExprKind::SetComp { .. } => self.push_scope(Scope::new(ScopeKind::Generator)), + ExprKind::Lambda { .. } => self.push_scope(Scope::new(ScopeKind::Function)), ExprKind::Yield { .. } | ExprKind::YieldFrom { .. } => { let scope = self.scopes.last().expect("No current scope found."); if self @@ -434,24 +385,30 @@ impl Visitor for Checker<'_> { Some(name) => { let scope = self.scopes.last().expect("No current scope found."); 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, ExprKind::Name { id: name.to_string(), ctx: ExprContext::Store, }, - )); - } - - 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, - }, - )); + ), + None, + ); walk_excepthandler(self, excepthandler); @@ -580,7 +537,7 @@ impl Checker<'_> { let mut first_iter = true; let mut in_generators = false; for scope in self.scopes.iter_mut().rev() { - if matches!(scope.kind, Class) { + if matches!(scope.kind, ScopeKind::Class) { if id == "__class__" { return; } else if !first_iter && !in_generators { @@ -593,7 +550,7 @@ impl Checker<'_> { } first_iter = false; - in_generators = matches!(scope.kind, Generator); + in_generators = matches!(scope.kind, ScopeKind::Generator); } 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 self.settings.select.contains(&CheckCode::F823) { - let current = self.scopes.last().expect("No current scope found."); - if matches!(current.kind, ScopeKind::Function) && !current.values.contains_key(id) { - for scope in self.scopes.iter().rev().skip(1) { - if matches!(scope.kind, ScopeKind::Function) || matches!(scope.kind, Module) - { - let used = scope - .values - .get(id) - .map(|binding| binding.used) - .unwrap_or_default(); - if let Some(scope_id) = used { - if scope_id == current.id { - self.checks.push(Check { - kind: CheckKind::UndefinedLocal(id.clone()), - location: expr.location, - }); - } + let current = self.scopes.last().expect("No current scope found."); + + if self.settings.select.contains(&CheckCode::F823) + && matches!(current.kind, ScopeKind::Function) + && !current.values.contains_key(id) + { + for scope in self.scopes.iter().rev().skip(1) { + if matches!(scope.kind, ScopeKind::Function) + || matches!(scope.kind, ScopeKind::Module) + { + let used = scope + .values + .get(id) + .map(|binding| binding.used) + .unwrap_or_default(); + 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`). - self.add_binding( - id.to_string(), - Binding { - kind: BindingKind::Assignment, - used: None, - location: expr.location, - }, - ); + if id == "__all__" + && matches!(current.kind, ScopeKind::Module) + && match parent { + None => false, + Some(stmt) => { + 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) { for value in self.deferred.clone() { if let Ok(expr) = &parser::parse_expression(&value, path) { - self.visit_expr(expr); + self.visit_expr(expr, None); } } } fn check_dead_scopes(&mut self) { if self.settings.select.contains(&CheckCode::F401) { - // TODO(charlie): Handle `__all__`. for scope in &self.dead_scopes { - for (_, binding) in scope.values.iter().rev() { - if binding.used.is_none() { + let all_binding = match scope.values.get("__all__") { + 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 { BindingKind::Importation(full_name) | BindingKind::SubmoduleImportation(full_name) => { @@ -690,7 +686,7 @@ impl Checker<'_> { pub fn check_ast(python_ast: &Suite, settings: &Settings, path: &str) -> Vec { let mut checker = Checker::new(settings); - checker.push_scope(Scope::new(Module)); + checker.push_scope(Scope::new(ScopeKind::Module)); checker.bind_builtins(); for stmt in python_ast { diff --git a/src/lib.rs b/src/lib.rs index 7d8873ec92..bfb1a8b0d6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ +mod ast_ops; mod builtins; mod cache; pub mod check_ast; diff --git a/src/visitor.rs b/src/visitor.rs index be625870cb..b0fadc8a43 100644 --- a/src/visitor.rs +++ b/src/visitor.rs @@ -11,7 +11,7 @@ pub trait Visitor { fn visit_annotation(&mut self, expr: &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); } fn visit_constant(&mut self, constant: &Constant) { @@ -82,24 +82,24 @@ pub fn walk_stmt(visitor: &mut V, stmt: &Stmt) { } StmtKind::Return { value } => { if let Some(expr) = value { - visitor.visit_expr(expr) + visitor.visit_expr(expr, Some(stmt)) } } StmtKind::Delete { targets } => { for expr in targets { - visitor.visit_expr(expr) + visitor.visit_expr(expr, Some(stmt)) } } StmtKind::Assign { targets, value, .. } => { 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 } => { - visitor.visit_expr(target); + visitor.visit_expr(target, Some(stmt)); visitor.visit_operator(op); - visitor.visit_expr(value); + visitor.visit_expr(value, Some(stmt)); } StmtKind::AnnAssign { target, @@ -107,10 +107,10 @@ pub fn walk_stmt(visitor: &mut V, stmt: &Stmt) { value, .. } => { - visitor.visit_expr(target); + visitor.visit_expr(target, Some(stmt)); visitor.visit_annotation(annotation); if let Some(expr) = value { - visitor.visit_expr(expr) + visitor.visit_expr(expr, Some(stmt)) } } StmtKind::For { @@ -120,8 +120,8 @@ pub fn walk_stmt(visitor: &mut V, stmt: &Stmt) { orelse, .. } => { - visitor.visit_expr(target); - visitor.visit_expr(iter); + visitor.visit_expr(target, Some(stmt)); + visitor.visit_expr(iter, Some(stmt)); for stmt in body { visitor.visit_stmt(stmt) } @@ -136,8 +136,8 @@ pub fn walk_stmt(visitor: &mut V, stmt: &Stmt) { orelse, .. } => { - visitor.visit_expr(target); - visitor.visit_expr(iter); + visitor.visit_expr(target, Some(stmt)); + visitor.visit_expr(iter, Some(stmt)); for stmt in body { visitor.visit_stmt(stmt) } @@ -146,7 +146,7 @@ pub fn walk_stmt(visitor: &mut V, stmt: &Stmt) { } } StmtKind::While { test, body, orelse } => { - visitor.visit_expr(test); + visitor.visit_expr(test, Some(stmt)); for stmt in body { visitor.visit_stmt(stmt) } @@ -155,7 +155,7 @@ pub fn walk_stmt(visitor: &mut V, stmt: &Stmt) { } } StmtKind::If { test, body, orelse } => { - visitor.visit_expr(test); + visitor.visit_expr(test, Some(stmt)); for stmt in body { visitor.visit_stmt(stmt) } @@ -181,17 +181,17 @@ pub fn walk_stmt(visitor: &mut V, stmt: &Stmt) { } StmtKind::Match { subject, cases } => { // TODO(charlie): Handle `cases`. - visitor.visit_expr(subject); + visitor.visit_expr(subject, Some(stmt)); for match_case in cases { visitor.visit_match_case(match_case); } } StmtKind::Raise { exc, cause } => { if let Some(expr) = exc { - visitor.visit_expr(expr) + visitor.visit_expr(expr, Some(stmt)) }; if let Some(expr) = cause { - visitor.visit_expr(expr) + visitor.visit_expr(expr, Some(stmt)) }; } StmtKind::Try { @@ -214,9 +214,9 @@ pub fn walk_stmt(visitor: &mut V, stmt: &Stmt) { } } StmtKind::Assert { test, msg } => { - visitor.visit_expr(test); + visitor.visit_expr(test, None); if let Some(expr) = msg { - visitor.visit_expr(expr) + visitor.visit_expr(expr, Some(stmt)) } } StmtKind::Import { names } => { @@ -231,7 +231,7 @@ pub fn walk_stmt(visitor: &mut V, stmt: &Stmt) { } StmtKind::Global { .. } => {} StmtKind::Nonlocal { .. } => {} - StmtKind::Expr { value } => visitor.visit_expr(value), + StmtKind::Expr { value } => visitor.visit_expr(value, Some(stmt)), StmtKind::Pass => {} StmtKind::Break => {} StmtKind::Continue => {} @@ -243,55 +243,55 @@ pub fn walk_expr(visitor: &mut V, expr: &Expr) { ExprKind::BoolOp { op, values } => { visitor.visit_boolop(op); for expr in values { - visitor.visit_expr(expr) + visitor.visit_expr(expr, None) } } ExprKind::NamedExpr { target, value } => { - visitor.visit_expr(target); - visitor.visit_expr(value); + visitor.visit_expr(target, None); + visitor.visit_expr(value, None); } ExprKind::BinOp { left, op, right } => { - visitor.visit_expr(left); + visitor.visit_expr(left, None); visitor.visit_operator(op); - visitor.visit_expr(right); + visitor.visit_expr(right, None); } ExprKind::UnaryOp { op, operand } => { visitor.visit_unaryop(op); - visitor.visit_expr(operand); + visitor.visit_expr(operand, None); } ExprKind::Lambda { args, body } => { visitor.visit_arguments(args); - visitor.visit_expr(body); + visitor.visit_expr(body, None); } ExprKind::IfExp { test, body, orelse } => { - visitor.visit_expr(test); - visitor.visit_expr(body); - visitor.visit_expr(orelse); + visitor.visit_expr(test, None); + visitor.visit_expr(body, None); + visitor.visit_expr(orelse, None); } ExprKind::Dict { keys, values } => { for expr in keys { - visitor.visit_expr(expr) + visitor.visit_expr(expr, None) } for expr in values { - visitor.visit_expr(expr) + visitor.visit_expr(expr, None) } } ExprKind::Set { elts } => { for expr in elts { - visitor.visit_expr(expr) + visitor.visit_expr(expr, None) } } ExprKind::ListComp { elt, generators } => { for comprehension in generators { visitor.visit_comprehension(comprehension) } - visitor.visit_expr(elt); + visitor.visit_expr(elt, None); } ExprKind::SetComp { elt, generators } => { for comprehension in generators { visitor.visit_comprehension(comprehension) } - visitor.visit_expr(elt); + visitor.visit_expr(elt, None); } ExprKind::DictComp { key, @@ -301,33 +301,33 @@ pub fn walk_expr(visitor: &mut V, expr: &Expr) { for comprehension in generators { visitor.visit_comprehension(comprehension) } - visitor.visit_expr(key); - visitor.visit_expr(value); + visitor.visit_expr(key, None); + visitor.visit_expr(value, None); } ExprKind::GeneratorExp { elt, generators } => { for comprehension in generators { 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 } => { 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 { left, ops, comparators, } => { - visitor.visit_expr(left); + visitor.visit_expr(left, None); for cmpop in ops { visitor.visit_cmpop(cmpop); } for expr in comparators { - visitor.visit_expr(expr) + visitor.visit_expr(expr, None) } } ExprKind::Call { @@ -335,9 +335,9 @@ pub fn walk_expr(visitor: &mut V, expr: &Expr) { args, keywords, } => { - visitor.visit_expr(func); + visitor.visit_expr(func, None); for expr in args { - visitor.visit_expr(expr); + visitor.visit_expr(expr, None); } for keyword in keywords { visitor.visit_keyword(keyword); @@ -346,28 +346,28 @@ pub fn walk_expr(visitor: &mut V, expr: &Expr) { ExprKind::FormattedValue { value, format_spec, .. } => { - visitor.visit_expr(value); + visitor.visit_expr(value, None); if let Some(expr) = format_spec { - visitor.visit_expr(expr) + visitor.visit_expr(expr, None) } } ExprKind::JoinedStr { values } => { for expr in values { - visitor.visit_expr(expr) + visitor.visit_expr(expr, None) } } ExprKind::Constant { value, .. } => visitor.visit_constant(value), ExprKind::Attribute { value, ctx, .. } => { - visitor.visit_expr(value); + visitor.visit_expr(value, None); visitor.visit_expr_context(ctx); } ExprKind::Subscript { value, slice, ctx } => { - visitor.visit_expr(value); - visitor.visit_expr(slice); + visitor.visit_expr(value, None); + visitor.visit_expr(slice, None); visitor.visit_expr_context(ctx); } ExprKind::Starred { value, ctx } => { - visitor.visit_expr(value); + visitor.visit_expr(value, None); visitor.visit_expr_context(ctx); } ExprKind::Name { ctx, .. } => { @@ -375,25 +375,25 @@ pub fn walk_expr(visitor: &mut V, expr: &Expr) { } ExprKind::List { elts, ctx } => { for expr in elts { - visitor.visit_expr(expr); + visitor.visit_expr(expr, None); } visitor.visit_expr_context(ctx); } ExprKind::Tuple { elts, ctx } => { for expr in elts { - visitor.visit_expr(expr); + visitor.visit_expr(expr, None); } visitor.visit_expr_context(ctx); } ExprKind::Slice { lower, upper, step } => { if let Some(expr) = lower { - visitor.visit_expr(expr); + visitor.visit_expr(expr, None); } if let Some(expr) = upper { - visitor.visit_expr(expr); + visitor.visit_expr(expr, None); } if let Some(expr) = step { - visitor.visit_expr(expr); + visitor.visit_expr(expr, None); } } } @@ -408,10 +408,10 @@ pub fn walk_constant(visitor: &mut V, constant: &Constant) } pub fn walk_comprehension(visitor: &mut V, comprehension: &Comprehension) { - visitor.visit_expr(&comprehension.target); - visitor.visit_expr(&comprehension.iter); + visitor.visit_expr(&comprehension.target, None); + visitor.visit_expr(&comprehension.iter, None); for expr in &comprehension.ifs { - visitor.visit_expr(expr); + visitor.visit_expr(expr, None); } } @@ -419,7 +419,7 @@ pub fn walk_excepthandler(visitor: &mut V, excepthandler: & match &excepthandler.node { ExcepthandlerKind::ExceptHandler { type_, body, .. } => { if let Some(expr) = type_ { - visitor.visit_expr(expr); + visitor.visit_expr(expr, None); } for stmt in body { visitor.visit_stmt(stmt); @@ -442,13 +442,13 @@ pub fn walk_arguments(visitor: &mut V, arguments: &Argument visitor.visit_arg(arg); } for expr in &arguments.kw_defaults { - visitor.visit_expr(expr) + visitor.visit_expr(expr, None) } if let Some(arg) = &arguments.kwarg { visitor.visit_arg(arg) } for expr in &arguments.defaults { - visitor.visit_expr(expr) + visitor.visit_expr(expr, None) } } @@ -459,20 +459,20 @@ pub fn walk_arg(visitor: &mut V, arg: &Arg) { } pub fn walk_keyword(visitor: &mut V, keyword: &Keyword) { - visitor.visit_expr(&keyword.node.value); + visitor.visit_expr(&keyword.node.value, None); } pub fn walk_withitem(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 { - visitor.visit_expr(expr); + visitor.visit_expr(expr, None); } } pub fn walk_match_case(visitor: &mut V, match_case: &MatchCase) { visitor.visit_pattern(&match_case.pattern); if let Some(expr) = &match_case.guard { - visitor.visit_expr(expr); + visitor.visit_expr(expr, None); } for stmt in &match_case.body { visitor.visit_stmt(stmt); @@ -481,7 +481,7 @@ pub fn walk_match_case(visitor: &mut V, match_case: &MatchC pub fn walk_pattern(visitor: &mut V, pattern: &Pattern) { 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::MatchSequence { patterns } => { for pattern in patterns { @@ -490,7 +490,7 @@ pub fn walk_pattern(visitor: &mut V, pattern: &Pattern) { } PatternKind::MatchMapping { keys, patterns, .. } => { for expr in keys { - visitor.visit_expr(expr); + visitor.visit_expr(expr, None); } for pattern in patterns { visitor.visit_pattern(pattern); @@ -502,7 +502,7 @@ pub fn walk_pattern(visitor: &mut V, pattern: &Pattern) { kwd_patterns, .. } => { - visitor.visit_expr(cls); + visitor.visit_expr(cls, None); for pattern in patterns { visitor.visit_pattern(pattern); }