mirror of https://github.com/astral-sh/ruff
Add support for __all__ export bindings (#87)
This commit is contained in:
parent
c0131e65e5
commit
221f4304ad
|
|
@ -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"]
|
||||
|
|
|
|||
|
|
@ -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 ¤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
|
||||
}
|
||||
218
src/check_ast.rs
218
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<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> {
|
||||
settings: &'a Settings,
|
||||
checks: Vec<Check>,
|
||||
|
|
@ -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<Check> {
|
||||
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 {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
mod ast_ops;
|
||||
mod builtins;
|
||||
mod cache;
|
||||
pub mod check_ast;
|
||||
|
|
|
|||
142
src/visitor.rs
142
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<V: Visitor + ?Sized>(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<V: Visitor + ?Sized>(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<V: Visitor + ?Sized>(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<V: Visitor + ?Sized>(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<V: Visitor + ?Sized>(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<V: Visitor + ?Sized>(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<V: Visitor + ?Sized>(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<V: Visitor + ?Sized>(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<V: Visitor + ?Sized>(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<V: Visitor + ?Sized>(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<V: Visitor + ?Sized>(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<V: Visitor + ?Sized>(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<V: Visitor + ?Sized>(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<V: Visitor + ?Sized>(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<V: Visitor + ?Sized>(visitor: &mut V, constant: &Constant)
|
|||
}
|
||||
|
||||
pub fn walk_comprehension<V: Visitor + ?Sized>(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<V: Visitor + ?Sized>(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<V: Visitor + ?Sized>(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<V: Visitor + ?Sized>(visitor: &mut V, arg: &Arg) {
|
|||
}
|
||||
|
||||
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) {
|
||||
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<V: Visitor + ?Sized>(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<V: Visitor + ?Sized>(visitor: &mut V, match_case: &MatchC
|
|||
|
||||
pub fn walk_pattern<V: Visitor + ?Sized>(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<V: Visitor + ?Sized>(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<V: Visitor + ?Sized>(visitor: &mut V, pattern: &Pattern) {
|
|||
kwd_patterns,
|
||||
..
|
||||
} => {
|
||||
visitor.visit_expr(cls);
|
||||
visitor.visit_expr(cls, None);
|
||||
for pattern in patterns {
|
||||
visitor.visit_pattern(pattern);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue