mirror of https://github.com/astral-sh/ruff
582 lines
17 KiB
Rust
582 lines
17 KiB
Rust
use rustpython_parser::ast::{
|
|
Alias, Arg, Arguments, Boolop, Cmpop, Comprehension, Constant, Excepthandler,
|
|
ExcepthandlerKind, Expr, ExprContext, ExprKind, Keyword, MatchCase, Operator, Pattern,
|
|
PatternKind, Stmt, StmtKind, Unaryop, Withitem,
|
|
};
|
|
|
|
pub trait Visitor<'a> {
|
|
fn visit_stmt(&mut self, stmt: &'a Stmt) {
|
|
walk_stmt(self, stmt);
|
|
}
|
|
fn visit_annotation(&mut self, expr: &'a Expr) {
|
|
walk_expr(self, expr);
|
|
}
|
|
fn visit_expr(&mut self, expr: &'a Expr) {
|
|
walk_expr(self, expr);
|
|
}
|
|
fn visit_constant(&mut self, constant: &'a Constant) {
|
|
walk_constant(self, constant);
|
|
}
|
|
fn visit_expr_context(&mut self, expr_context: &'a ExprContext) {
|
|
walk_expr_context(self, expr_context);
|
|
}
|
|
fn visit_boolop(&mut self, boolop: &'a Boolop) {
|
|
walk_boolop(self, boolop);
|
|
}
|
|
fn visit_operator(&mut self, operator: &'a Operator) {
|
|
walk_operator(self, operator);
|
|
}
|
|
fn visit_unaryop(&mut self, unaryop: &'a Unaryop) {
|
|
walk_unaryop(self, unaryop);
|
|
}
|
|
fn visit_cmpop(&mut self, cmpop: &'a Cmpop) {
|
|
walk_cmpop(self, cmpop);
|
|
}
|
|
fn visit_comprehension(&mut self, comprehension: &'a Comprehension) {
|
|
walk_comprehension(self, comprehension);
|
|
}
|
|
fn visit_excepthandler(&mut self, excepthandler: &'a Excepthandler) {
|
|
walk_excepthandler(self, excepthandler);
|
|
}
|
|
fn visit_format_spec(&mut self, format_spec: &'a Expr) {
|
|
walk_expr(self, format_spec);
|
|
}
|
|
fn visit_arguments(&mut self, arguments: &'a Arguments) {
|
|
walk_arguments(self, arguments);
|
|
}
|
|
fn visit_arg(&mut self, arg: &'a Arg) {
|
|
walk_arg(self, arg);
|
|
}
|
|
fn visit_keyword(&mut self, keyword: &'a Keyword) {
|
|
walk_keyword(self, keyword);
|
|
}
|
|
fn visit_alias(&mut self, alias: &'a Alias) {
|
|
walk_alias(self, alias);
|
|
}
|
|
fn visit_withitem(&mut self, withitem: &'a Withitem) {
|
|
walk_withitem(self, withitem);
|
|
}
|
|
fn visit_match_case(&mut self, match_case: &'a MatchCase) {
|
|
walk_match_case(self, match_case);
|
|
}
|
|
fn visit_pattern(&mut self, pattern: &'a Pattern) {
|
|
walk_pattern(self, pattern);
|
|
}
|
|
fn visit_body(&mut self, body: &'a [Stmt]) {
|
|
walk_body(self, body);
|
|
}
|
|
}
|
|
|
|
pub fn walk_body<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, body: &'a [Stmt]) {
|
|
for stmt in body {
|
|
visitor.visit_stmt(stmt);
|
|
}
|
|
}
|
|
|
|
pub fn walk_stmt<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, stmt: &'a Stmt) {
|
|
match &stmt.node {
|
|
StmtKind::FunctionDef {
|
|
args,
|
|
body,
|
|
decorator_list,
|
|
returns,
|
|
..
|
|
} => {
|
|
visitor.visit_arguments(args);
|
|
for expr in decorator_list {
|
|
visitor.visit_expr(expr);
|
|
}
|
|
for expr in returns {
|
|
visitor.visit_annotation(expr);
|
|
}
|
|
visitor.visit_body(body);
|
|
}
|
|
StmtKind::AsyncFunctionDef {
|
|
args,
|
|
body,
|
|
decorator_list,
|
|
returns,
|
|
..
|
|
} => {
|
|
visitor.visit_arguments(args);
|
|
for expr in decorator_list {
|
|
visitor.visit_expr(expr);
|
|
}
|
|
for expr in returns {
|
|
visitor.visit_annotation(expr);
|
|
}
|
|
visitor.visit_body(body);
|
|
}
|
|
StmtKind::ClassDef {
|
|
bases,
|
|
keywords,
|
|
body,
|
|
decorator_list,
|
|
..
|
|
} => {
|
|
for expr in bases {
|
|
visitor.visit_expr(expr);
|
|
}
|
|
for keyword in keywords {
|
|
visitor.visit_keyword(keyword);
|
|
}
|
|
for expr in decorator_list {
|
|
visitor.visit_expr(expr);
|
|
}
|
|
visitor.visit_body(body);
|
|
}
|
|
StmtKind::Return { value } => {
|
|
if let Some(expr) = value {
|
|
visitor.visit_expr(expr);
|
|
}
|
|
}
|
|
StmtKind::Delete { targets } => {
|
|
for expr in targets {
|
|
visitor.visit_expr(expr);
|
|
}
|
|
}
|
|
StmtKind::Assign { targets, value, .. } => {
|
|
visitor.visit_expr(value);
|
|
for expr in targets {
|
|
visitor.visit_expr(expr);
|
|
}
|
|
}
|
|
StmtKind::AugAssign { target, op, value } => {
|
|
visitor.visit_expr(target);
|
|
visitor.visit_operator(op);
|
|
visitor.visit_expr(value);
|
|
}
|
|
StmtKind::AnnAssign {
|
|
target,
|
|
annotation,
|
|
value,
|
|
..
|
|
} => {
|
|
visitor.visit_annotation(annotation);
|
|
if let Some(expr) = value {
|
|
visitor.visit_expr(expr);
|
|
}
|
|
visitor.visit_expr(target);
|
|
}
|
|
StmtKind::For {
|
|
target,
|
|
iter,
|
|
body,
|
|
orelse,
|
|
..
|
|
} => {
|
|
visitor.visit_expr(iter);
|
|
visitor.visit_expr(target);
|
|
visitor.visit_body(body);
|
|
visitor.visit_body(orelse);
|
|
}
|
|
StmtKind::AsyncFor {
|
|
target,
|
|
iter,
|
|
body,
|
|
orelse,
|
|
..
|
|
} => {
|
|
visitor.visit_expr(iter);
|
|
visitor.visit_expr(target);
|
|
visitor.visit_body(body);
|
|
visitor.visit_body(orelse);
|
|
}
|
|
StmtKind::While { test, body, orelse } => {
|
|
visitor.visit_expr(test);
|
|
visitor.visit_body(body);
|
|
visitor.visit_body(orelse);
|
|
}
|
|
StmtKind::If { test, body, orelse } => {
|
|
visitor.visit_expr(test);
|
|
visitor.visit_body(body);
|
|
visitor.visit_body(orelse);
|
|
}
|
|
StmtKind::With { items, body, .. } => {
|
|
for withitem in items {
|
|
visitor.visit_withitem(withitem);
|
|
}
|
|
visitor.visit_body(body);
|
|
}
|
|
StmtKind::AsyncWith { items, body, .. } => {
|
|
for withitem in items {
|
|
visitor.visit_withitem(withitem);
|
|
}
|
|
visitor.visit_body(body);
|
|
}
|
|
StmtKind::Match { subject, cases } => {
|
|
visitor.visit_expr(subject);
|
|
for match_case in cases {
|
|
visitor.visit_match_case(match_case);
|
|
}
|
|
}
|
|
StmtKind::Raise { exc, cause } => {
|
|
if let Some(expr) = exc {
|
|
visitor.visit_expr(expr);
|
|
};
|
|
if let Some(expr) = cause {
|
|
visitor.visit_expr(expr);
|
|
};
|
|
}
|
|
StmtKind::Try {
|
|
body,
|
|
handlers,
|
|
orelse,
|
|
finalbody,
|
|
} => {
|
|
visitor.visit_body(body);
|
|
for excepthandler in handlers {
|
|
visitor.visit_excepthandler(excepthandler);
|
|
}
|
|
visitor.visit_body(orelse);
|
|
visitor.visit_body(finalbody);
|
|
}
|
|
StmtKind::TryStar {
|
|
body,
|
|
handlers,
|
|
orelse,
|
|
finalbody,
|
|
} => {
|
|
visitor.visit_body(body);
|
|
for excepthandler in handlers {
|
|
visitor.visit_excepthandler(excepthandler);
|
|
}
|
|
visitor.visit_body(orelse);
|
|
visitor.visit_body(finalbody);
|
|
}
|
|
StmtKind::Assert { test, msg } => {
|
|
visitor.visit_expr(test);
|
|
if let Some(expr) = msg {
|
|
visitor.visit_expr(expr);
|
|
}
|
|
}
|
|
StmtKind::Import { names } => {
|
|
for alias in names {
|
|
visitor.visit_alias(alias);
|
|
}
|
|
}
|
|
StmtKind::ImportFrom { names, .. } => {
|
|
for alias in names {
|
|
visitor.visit_alias(alias);
|
|
}
|
|
}
|
|
StmtKind::Global { .. } => {}
|
|
StmtKind::Nonlocal { .. } => {}
|
|
StmtKind::Expr { value } => visitor.visit_expr(value),
|
|
StmtKind::Pass => {}
|
|
StmtKind::Break => {}
|
|
StmtKind::Continue => {}
|
|
}
|
|
}
|
|
|
|
pub fn walk_expr<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, expr: &'a Expr) {
|
|
match &expr.node {
|
|
ExprKind::BoolOp { op, values } => {
|
|
visitor.visit_boolop(op);
|
|
for expr in values {
|
|
visitor.visit_expr(expr);
|
|
}
|
|
}
|
|
ExprKind::NamedExpr { target, value } => {
|
|
visitor.visit_expr(value);
|
|
visitor.visit_expr(target);
|
|
}
|
|
ExprKind::BinOp { left, op, right } => {
|
|
visitor.visit_expr(left);
|
|
visitor.visit_operator(op);
|
|
visitor.visit_expr(right);
|
|
}
|
|
ExprKind::UnaryOp { op, operand } => {
|
|
visitor.visit_unaryop(op);
|
|
visitor.visit_expr(operand);
|
|
}
|
|
ExprKind::Lambda { args, body } => {
|
|
visitor.visit_arguments(args);
|
|
visitor.visit_expr(body);
|
|
}
|
|
ExprKind::IfExp { test, body, orelse } => {
|
|
visitor.visit_expr(test);
|
|
visitor.visit_expr(body);
|
|
visitor.visit_expr(orelse);
|
|
}
|
|
ExprKind::Dict { keys, values } => {
|
|
for expr in keys.iter().flatten() {
|
|
visitor.visit_expr(expr);
|
|
}
|
|
for expr in values {
|
|
visitor.visit_expr(expr);
|
|
}
|
|
}
|
|
ExprKind::Set { elts } => {
|
|
for expr in elts {
|
|
visitor.visit_expr(expr);
|
|
}
|
|
}
|
|
ExprKind::ListComp { elt, generators } => {
|
|
for comprehension in generators {
|
|
visitor.visit_comprehension(comprehension);
|
|
}
|
|
visitor.visit_expr(elt);
|
|
}
|
|
ExprKind::SetComp { elt, generators } => {
|
|
for comprehension in generators {
|
|
visitor.visit_comprehension(comprehension);
|
|
}
|
|
visitor.visit_expr(elt);
|
|
}
|
|
ExprKind::DictComp {
|
|
key,
|
|
value,
|
|
generators,
|
|
} => {
|
|
for comprehension in generators {
|
|
visitor.visit_comprehension(comprehension);
|
|
}
|
|
visitor.visit_expr(key);
|
|
visitor.visit_expr(value);
|
|
}
|
|
ExprKind::GeneratorExp { elt, generators } => {
|
|
for comprehension in generators {
|
|
visitor.visit_comprehension(comprehension);
|
|
}
|
|
visitor.visit_expr(elt);
|
|
}
|
|
ExprKind::Await { value } => visitor.visit_expr(value),
|
|
ExprKind::Yield { value } => {
|
|
if let Some(expr) = value {
|
|
visitor.visit_expr(expr);
|
|
}
|
|
}
|
|
ExprKind::YieldFrom { value } => visitor.visit_expr(value),
|
|
ExprKind::Compare {
|
|
left,
|
|
ops,
|
|
comparators,
|
|
} => {
|
|
visitor.visit_expr(left);
|
|
for cmpop in ops {
|
|
visitor.visit_cmpop(cmpop);
|
|
}
|
|
for expr in comparators {
|
|
visitor.visit_expr(expr);
|
|
}
|
|
}
|
|
ExprKind::Call {
|
|
func,
|
|
args,
|
|
keywords,
|
|
} => {
|
|
visitor.visit_expr(func);
|
|
for expr in args {
|
|
visitor.visit_expr(expr);
|
|
}
|
|
for keyword in keywords {
|
|
visitor.visit_keyword(keyword);
|
|
}
|
|
}
|
|
ExprKind::FormattedValue {
|
|
value, format_spec, ..
|
|
} => {
|
|
visitor.visit_expr(value);
|
|
if let Some(expr) = format_spec {
|
|
visitor.visit_format_spec(expr);
|
|
}
|
|
}
|
|
ExprKind::JoinedStr { values } => {
|
|
for expr in values {
|
|
visitor.visit_expr(expr);
|
|
}
|
|
}
|
|
ExprKind::Constant { value, .. } => visitor.visit_constant(value),
|
|
ExprKind::Attribute { value, ctx, .. } => {
|
|
visitor.visit_expr(value);
|
|
visitor.visit_expr_context(ctx);
|
|
}
|
|
ExprKind::Subscript { value, slice, ctx } => {
|
|
visitor.visit_expr(value);
|
|
visitor.visit_expr(slice);
|
|
visitor.visit_expr_context(ctx);
|
|
}
|
|
ExprKind::Starred { value, ctx } => {
|
|
visitor.visit_expr(value);
|
|
visitor.visit_expr_context(ctx);
|
|
}
|
|
ExprKind::Name { ctx, .. } => {
|
|
visitor.visit_expr_context(ctx);
|
|
}
|
|
ExprKind::List { elts, ctx } => {
|
|
for expr in elts {
|
|
visitor.visit_expr(expr);
|
|
}
|
|
visitor.visit_expr_context(ctx);
|
|
}
|
|
ExprKind::Tuple { elts, ctx } => {
|
|
for expr in elts {
|
|
visitor.visit_expr(expr);
|
|
}
|
|
visitor.visit_expr_context(ctx);
|
|
}
|
|
ExprKind::Slice { lower, upper, step } => {
|
|
if let Some(expr) = lower {
|
|
visitor.visit_expr(expr);
|
|
}
|
|
if let Some(expr) = upper {
|
|
visitor.visit_expr(expr);
|
|
}
|
|
if let Some(expr) = step {
|
|
visitor.visit_expr(expr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn walk_constant<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, constant: &'a Constant) {
|
|
if let Constant::Tuple(constants) = constant {
|
|
for constant in constants {
|
|
visitor.visit_constant(constant);
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn walk_comprehension<'a, V: Visitor<'a> + ?Sized>(
|
|
visitor: &mut V,
|
|
comprehension: &'a Comprehension,
|
|
) {
|
|
visitor.visit_expr(&comprehension.iter);
|
|
visitor.visit_expr(&comprehension.target);
|
|
for expr in &comprehension.ifs {
|
|
visitor.visit_expr(expr);
|
|
}
|
|
}
|
|
|
|
pub fn walk_excepthandler<'a, V: Visitor<'a> + ?Sized>(
|
|
visitor: &mut V,
|
|
excepthandler: &'a Excepthandler,
|
|
) {
|
|
match &excepthandler.node {
|
|
ExcepthandlerKind::ExceptHandler { type_, body, .. } => {
|
|
if let Some(expr) = type_ {
|
|
visitor.visit_expr(expr);
|
|
}
|
|
visitor.visit_body(body);
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn walk_arguments<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, arguments: &'a Arguments) {
|
|
for arg in &arguments.posonlyargs {
|
|
visitor.visit_arg(arg);
|
|
}
|
|
for arg in &arguments.args {
|
|
visitor.visit_arg(arg);
|
|
}
|
|
if let Some(arg) = &arguments.vararg {
|
|
visitor.visit_arg(arg);
|
|
}
|
|
for arg in &arguments.kwonlyargs {
|
|
visitor.visit_arg(arg);
|
|
}
|
|
for expr in &arguments.kw_defaults {
|
|
visitor.visit_expr(expr);
|
|
}
|
|
if let Some(arg) = &arguments.kwarg {
|
|
visitor.visit_arg(arg);
|
|
}
|
|
for expr in &arguments.defaults {
|
|
visitor.visit_expr(expr);
|
|
}
|
|
}
|
|
|
|
pub fn walk_arg<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, arg: &'a Arg) {
|
|
if let Some(expr) = &arg.node.annotation {
|
|
visitor.visit_annotation(expr);
|
|
}
|
|
}
|
|
|
|
pub fn walk_keyword<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, keyword: &'a Keyword) {
|
|
visitor.visit_expr(&keyword.node.value);
|
|
}
|
|
|
|
pub fn walk_withitem<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, withitem: &'a Withitem) {
|
|
visitor.visit_expr(&withitem.context_expr);
|
|
if let Some(expr) = &withitem.optional_vars {
|
|
visitor.visit_expr(expr);
|
|
}
|
|
}
|
|
|
|
pub fn walk_match_case<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, match_case: &'a MatchCase) {
|
|
visitor.visit_pattern(&match_case.pattern);
|
|
if let Some(expr) = &match_case.guard {
|
|
visitor.visit_expr(expr);
|
|
}
|
|
visitor.visit_body(&match_case.body);
|
|
}
|
|
|
|
pub fn walk_pattern<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, pattern: &'a Pattern) {
|
|
match &pattern.node {
|
|
PatternKind::MatchValue { value } => visitor.visit_expr(value),
|
|
PatternKind::MatchSingleton { value } => visitor.visit_constant(value),
|
|
PatternKind::MatchSequence { patterns } => {
|
|
for pattern in patterns {
|
|
visitor.visit_pattern(pattern);
|
|
}
|
|
}
|
|
PatternKind::MatchMapping { keys, patterns, .. } => {
|
|
for expr in keys {
|
|
visitor.visit_expr(expr);
|
|
}
|
|
for pattern in patterns {
|
|
visitor.visit_pattern(pattern);
|
|
}
|
|
}
|
|
PatternKind::MatchClass {
|
|
cls,
|
|
patterns,
|
|
kwd_patterns,
|
|
..
|
|
} => {
|
|
visitor.visit_expr(cls);
|
|
for pattern in patterns {
|
|
visitor.visit_pattern(pattern);
|
|
}
|
|
|
|
for pattern in kwd_patterns {
|
|
visitor.visit_pattern(pattern);
|
|
}
|
|
}
|
|
PatternKind::MatchStar { .. } => {}
|
|
PatternKind::MatchAs { pattern, .. } => {
|
|
if let Some(pattern) = pattern {
|
|
visitor.visit_pattern(pattern);
|
|
}
|
|
}
|
|
PatternKind::MatchOr { patterns } => {
|
|
for pattern in patterns {
|
|
visitor.visit_pattern(pattern);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[allow(unused_variables)]
|
|
pub fn walk_expr_context<'a, V: Visitor<'a> + ?Sized>(
|
|
visitor: &mut V,
|
|
expr_context: &'a ExprContext,
|
|
) {
|
|
}
|
|
|
|
#[allow(unused_variables)]
|
|
pub fn walk_boolop<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, boolop: &'a Boolop) {}
|
|
|
|
#[allow(unused_variables)]
|
|
pub fn walk_operator<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, operator: &'a Operator) {}
|
|
|
|
#[allow(unused_variables)]
|
|
pub fn walk_unaryop<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, unaryop: &'a Unaryop) {}
|
|
|
|
#[allow(unused_variables)]
|
|
pub fn walk_cmpop<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, cmpop: &'a Cmpop) {}
|
|
|
|
#[allow(unused_variables)]
|
|
pub fn walk_alias<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, alias: &'a Alias) {}
|