compiler/crates/react_compiler_ast/src/visitor.rs RUST 1,489 lines View on github.com → Search inside
1//! AST visitor with automatic scope tracking.2//!3//! Provides a [`Visitor`] trait with enter/leave hooks for specific node types,4//! and an [`AstWalker`] that traverses the AST while tracking the active scope5//! via the scope tree's `node_to_scope` map.67use crate::Program;8use crate::declarations::*;9use crate::expressions::*;10use crate::jsx::*;11use crate::patterns::*;12use crate::scope::ScopeId;13use crate::scope::ScopeInfo;14use crate::statements::*;1516/// Trait for visiting Babel AST nodes. All methods default to no-ops.17/// Override specific methods to intercept nodes of interest.18///19/// The `'ast` lifetime ties visitor hooks to the AST being walked, allowing20/// visitors to store references into the AST (e.g., for deferred processing).21///22/// The `scope_stack` parameter provides the current scope context during traversal.23/// The active scope is `scope_stack.last()`.24pub trait Visitor<'ast> {25    /// Controls whether the walker recurses into function/arrow/method bodies.26    /// Returns `true` by default. Override to `false` to skip function bodies27    /// (similar to Babel's `path.skip()` in traverse visitors).28    ///29    /// When `false`, the walker still calls `enter_*` / `leave_*` for functions30    /// but does not walk their params or body.31    fn traverse_function_bodies(&self) -> bool {32        true33    }3435    fn enter_function_declaration(36        &mut self,37        _node: &'ast FunctionDeclaration,38        _scope_stack: &[ScopeId],39    ) {40    }41    fn leave_function_declaration(42        &mut self,43        _node: &'ast FunctionDeclaration,44        _scope_stack: &[ScopeId],45    ) {46    }47    fn enter_function_expression(48        &mut self,49        _node: &'ast FunctionExpression,50        _scope_stack: &[ScopeId],51    ) {52    }53    fn leave_function_expression(54        &mut self,55        _node: &'ast FunctionExpression,56        _scope_stack: &[ScopeId],57    ) {58    }59    fn enter_arrow_function_expression(60        &mut self,61        _node: &'ast ArrowFunctionExpression,62        _scope_stack: &[ScopeId],63    ) {64    }65    fn leave_arrow_function_expression(66        &mut self,67        _node: &'ast ArrowFunctionExpression,68        _scope_stack: &[ScopeId],69    ) {70    }71    fn enter_class_declaration(72        &mut self,73        _node: &'ast crate::statements::ClassDeclaration,74        _scope_stack: &[ScopeId],75    ) {76    }77    fn enter_class_expression(&mut self, _node: &'ast ClassExpression, _scope_stack: &[ScopeId]) {}78    fn enter_object_method(&mut self, _node: &'ast ObjectMethod, _scope_stack: &[ScopeId]) {}79    fn leave_object_method(&mut self, _node: &'ast ObjectMethod, _scope_stack: &[ScopeId]) {}80    fn enter_assignment_expression(81        &mut self,82        _node: &'ast AssignmentExpression,83        _scope_stack: &[ScopeId],84    ) {85    }86    fn enter_update_expression(&mut self, _node: &'ast UpdateExpression, _scope_stack: &[ScopeId]) {87    }88    fn enter_identifier(&mut self, _node: &'ast Identifier, _scope_stack: &[ScopeId]) {}89    fn enter_jsx_identifier(&mut self, _node: &'ast JSXIdentifier, _scope_stack: &[ScopeId]) {}90    fn enter_jsx_opening_element(91        &mut self,92        _node: &'ast JSXOpeningElement,93        _scope_stack: &[ScopeId],94    ) {95    }96    fn leave_jsx_opening_element(97        &mut self,98        _node: &'ast JSXOpeningElement,99        _scope_stack: &[ScopeId],100    ) {101    }102103    fn enter_variable_declarator(104        &mut self,105        _node: &'ast VariableDeclarator,106        _scope_stack: &[ScopeId],107    ) {108    }109    fn leave_variable_declarator(110        &mut self,111        _node: &'ast VariableDeclarator,112        _scope_stack: &[ScopeId],113    ) {114    }115116    fn enter_call_expression(&mut self, _node: &'ast CallExpression, _scope_stack: &[ScopeId]) {}117    fn leave_call_expression(&mut self, _node: &'ast CallExpression, _scope_stack: &[ScopeId]) {}118119    /// Called when the walker enters a loop expression context (while.test,120    /// do-while.test, for-in.right, for-of.right). Functions found in these121    /// positions are treated as non-program-scope by Babel, even though the122    /// walker doesn't push a scope for them.123    fn enter_loop_expression(&mut self) {}124    fn leave_loop_expression(&mut self) {}125}126127/// Walks the AST while tracking scope context via `node_to_scope`.128pub struct AstWalker<'a> {129    scope_info: &'a ScopeInfo,130    scope_stack: Vec<ScopeId>,131    /// Depth counter for loop/iteration expression positions (while.test,132    /// do-while.test, for-in.right, for-of.right). These positions are133    /// NOT inside a scope in the walker's model, but Babel's scope analysis134    /// treats them as non-program-scope. Visitors can check this via135    /// `in_loop_expression_depth()` to implement Babel-compatible scope checks.136    loop_expression_depth: usize,137}138139impl<'a> AstWalker<'a> {140    pub fn new(scope_info: &'a ScopeInfo) -> Self {141        AstWalker {142            scope_info,143            scope_stack: Vec::new(),144            loop_expression_depth: 0,145        }146    }147148    /// Create a walker with an initial scope already on the stack.149    pub fn with_initial_scope(scope_info: &'a ScopeInfo, initial_scope: ScopeId) -> Self {150        AstWalker {151            scope_info,152            scope_stack: vec![initial_scope],153            loop_expression_depth: 0,154        }155    }156157    pub fn scope_stack(&self) -> &[ScopeId] {158        &self.scope_stack159    }160161    /// Returns the current loop-expression depth. Non-zero when the walker is162    /// inside a loop's test/right expression (while.test, do-while.test,163    /// for-in.right, for-of.right). Visitors can use this to implement164    /// Babel-compatible scope checks in 'all' compilation mode.165    pub fn loop_expression_depth(&self) -> usize {166        self.loop_expression_depth167    }168169    /// Try to push a scope for a node. Returns true if a scope was pushed.170    fn try_push_scope(&mut self, _start: Option<u32>, node_id: Option<u32>) -> bool {171        let scope = self.scope_info.resolve_scope_for_node(node_id);172        if let Some(scope_id) = scope {173            self.scope_stack.push(scope_id);174            return true;175        }176        false177    }178179    // ---- Public walk methods ----180181    pub fn walk_program<'ast>(&mut self, v: &mut impl Visitor<'ast>, node: &'ast Program) {182        let pushed = self.try_push_scope(node.base.start, node.base.node_id);183        for stmt in &node.body {184            self.walk_statement(v, stmt);185        }186        if pushed {187            self.scope_stack.pop();188        }189    }190191    pub fn walk_block_statement<'ast>(192        &mut self,193        v: &mut impl Visitor<'ast>,194        node: &'ast BlockStatement,195    ) {196        let pushed = self.try_push_scope(node.base.start, node.base.node_id);197        for stmt in &node.body {198            self.walk_statement(v, stmt);199        }200        if pushed {201            self.scope_stack.pop();202        }203    }204205    pub fn walk_statement<'ast>(&mut self, v: &mut impl Visitor<'ast>, stmt: &'ast Statement) {206        match stmt {207            Statement::BlockStatement(node) => self.walk_block_statement(v, node),208            Statement::ReturnStatement(node) => {209                if let Some(arg) = &node.argument {210                    self.walk_expression(v, arg);211                }212            }213            Statement::ExpressionStatement(node) => {214                self.walk_expression(v, &node.expression);215            }216            Statement::IfStatement(node) => {217                self.walk_expression(v, &node.test);218                self.walk_statement(v, &node.consequent);219                if let Some(alt) = &node.alternate {220                    self.walk_statement(v, alt);221                }222            }223            Statement::ForStatement(node) => {224                let pushed = self.try_push_scope(node.base.start, node.base.node_id);225                if let Some(init) = &node.init {226                    match init.as_ref() {227                        ForInit::VariableDeclaration(decl) => {228                            self.walk_variable_declaration(v, decl)229                        }230                        ForInit::Expression(expr) => self.walk_expression(v, expr),231                    }232                }233                if let Some(test) = &node.test {234                    self.walk_expression(v, test);235                }236                if let Some(update) = &node.update {237                    self.walk_expression(v, update);238                }239                self.walk_statement(v, &node.body);240                if pushed {241                    self.scope_stack.pop();242                }243            }244            Statement::WhileStatement(node) => {245                self.loop_expression_depth += 1;246                v.enter_loop_expression();247                self.walk_expression(v, &node.test);248                v.leave_loop_expression();249                self.loop_expression_depth -= 1;250                self.walk_statement(v, &node.body);251            }252            Statement::DoWhileStatement(node) => {253                self.walk_statement(v, &node.body);254                self.loop_expression_depth += 1;255                v.enter_loop_expression();256                self.walk_expression(v, &node.test);257                v.leave_loop_expression();258                self.loop_expression_depth -= 1;259            }260            Statement::ForInStatement(node) => {261                let pushed = self.try_push_scope(node.base.start, node.base.node_id);262                self.walk_for_in_of_left(v, &node.left);263                self.loop_expression_depth += 1;264                v.enter_loop_expression();265                self.walk_expression(v, &node.right);266                v.leave_loop_expression();267                self.loop_expression_depth -= 1;268                self.walk_statement(v, &node.body);269                if pushed {270                    self.scope_stack.pop();271                }272            }273            Statement::ForOfStatement(node) => {274                let pushed = self.try_push_scope(node.base.start, node.base.node_id);275                self.walk_for_in_of_left(v, &node.left);276                self.loop_expression_depth += 1;277                v.enter_loop_expression();278                self.walk_expression(v, &node.right);279                v.leave_loop_expression();280                self.loop_expression_depth -= 1;281                self.walk_statement(v, &node.body);282                if pushed {283                    self.scope_stack.pop();284                }285            }286            Statement::SwitchStatement(node) => {287                let pushed = self.try_push_scope(node.base.start, node.base.node_id);288                self.walk_expression(v, &node.discriminant);289                for case in &node.cases {290                    if let Some(test) = &case.test {291                        self.walk_expression(v, test);292                    }293                    for consequent in &case.consequent {294                        self.walk_statement(v, consequent);295                    }296                }297                if pushed {298                    self.scope_stack.pop();299                }300            }301            Statement::ThrowStatement(node) => {302                self.walk_expression(v, &node.argument);303            }304            Statement::TryStatement(node) => {305                self.walk_block_statement(v, &node.block);306                if let Some(handler) = &node.handler {307                    let pushed = self.try_push_scope(handler.base.start, handler.base.node_id);308                    if let Some(param) = &handler.param {309                        self.walk_pattern(v, param);310                    }311                    self.walk_block_statement(v, &handler.body);312                    if pushed {313                        self.scope_stack.pop();314                    }315                }316                if let Some(finalizer) = &node.finalizer {317                    self.walk_block_statement(v, finalizer);318                }319            }320            Statement::LabeledStatement(node) => {321                self.walk_statement(v, &node.body);322            }323            Statement::VariableDeclaration(node) => {324                self.walk_variable_declaration(v, node);325            }326            Statement::FunctionDeclaration(node) => {327                self.walk_function_declaration_inner(v, node);328            }329            Statement::ClassDeclaration(node) => {330                // Call the visitor hook so consumers can index the class name,331                // but skip walking the class body (no compilable functions inside)332                v.enter_class_declaration(node, &self.scope_stack);333            }334            Statement::WithStatement(node) => {335                self.walk_expression(v, &node.object);336                self.walk_statement(v, &node.body);337            }338            Statement::ExportNamedDeclaration(node) => {339                if let Some(decl) = &node.declaration {340                    self.walk_declaration(v, decl);341                }342            }343            Statement::ExportDefaultDeclaration(node) => {344                self.walk_export_default_decl(v, &node.declaration);345            }346            // No runtime expressions to traverse347            Statement::BreakStatement(_)348            | Statement::ContinueStatement(_)349            | Statement::EmptyStatement(_)350            | Statement::DebuggerStatement(_)351            | Statement::ImportDeclaration(_)352            | Statement::ExportAllDeclaration(_)353            | Statement::TSTypeAliasDeclaration(_)354            | Statement::TSInterfaceDeclaration(_)355            | Statement::TSEnumDeclaration(_)356            | Statement::TSModuleDeclaration(_)357            | Statement::TSDeclareFunction(_)358            | Statement::TypeAlias(_)359            | Statement::OpaqueType(_)360            | Statement::InterfaceDeclaration(_)361            | Statement::DeclareVariable(_)362            | Statement::DeclareFunction(_)363            | Statement::DeclareClass(_)364            | Statement::DeclareModule(_)365            | Statement::DeclareModuleExports(_)366            | Statement::DeclareExportDeclaration(_)367            | Statement::DeclareExportAllDeclaration(_)368            | Statement::DeclareInterface(_)369            | Statement::DeclareTypeAlias(_)370            | Statement::DeclareOpaqueType(_)371            | Statement::EnumDeclaration(_)372            // Unmodeled raw node: opaque, no compilable children to traverse.373            | Statement::Unknown(_) => {}374        }375    }376377    pub fn walk_expression<'ast>(&mut self, v: &mut impl Visitor<'ast>, expr: &'ast Expression) {378        match expr {379            Expression::Identifier(node) => {380                v.enter_identifier(node, &self.scope_stack);381            }382            Expression::CallExpression(node) => {383                v.enter_call_expression(node, &self.scope_stack);384                self.walk_expression(v, &node.callee);385                for arg in &node.arguments {386                    self.walk_expression(v, arg);387                }388                v.leave_call_expression(node, &self.scope_stack);389            }390            Expression::MemberExpression(node) => {391                self.walk_expression(v, &node.object);392                if node.computed {393                    self.walk_expression(v, &node.property);394                }395            }396            Expression::OptionalCallExpression(node) => {397                self.walk_expression(v, &node.callee);398                for arg in &node.arguments {399                    self.walk_expression(v, arg);400                }401            }402            Expression::OptionalMemberExpression(node) => {403                self.walk_expression(v, &node.object);404                if node.computed {405                    self.walk_expression(v, &node.property);406                }407            }408            Expression::BinaryExpression(node) => {409                self.walk_expression(v, &node.left);410                self.walk_expression(v, &node.right);411            }412            Expression::LogicalExpression(node) => {413                self.walk_expression(v, &node.left);414                self.walk_expression(v, &node.right);415            }416            Expression::UnaryExpression(node) => {417                self.walk_expression(v, &node.argument);418            }419            Expression::UpdateExpression(node) => {420                v.enter_update_expression(node, &self.scope_stack);421                self.walk_expression(v, &node.argument);422            }423            Expression::ConditionalExpression(node) => {424                self.walk_expression(v, &node.test);425                self.walk_expression(v, &node.consequent);426                self.walk_expression(v, &node.alternate);427            }428            Expression::AssignmentExpression(node) => {429                v.enter_assignment_expression(node, &self.scope_stack);430                self.walk_pattern(v, &node.left);431                self.walk_expression(v, &node.right);432            }433            Expression::SequenceExpression(node) => {434                for expr in &node.expressions {435                    self.walk_expression(v, expr);436                }437            }438            Expression::ArrowFunctionExpression(node) => {439                let pushed = self.try_push_scope(node.base.start, node.base.node_id);440                v.enter_arrow_function_expression(node, &self.scope_stack);441                if v.traverse_function_bodies() {442                    for param in &node.params {443                        self.walk_pattern(v, param);444                    }445                    match node.body.as_ref() {446                        ArrowFunctionBody::BlockStatement(block) => {447                            self.walk_block_statement(v, block);448                        }449                        ArrowFunctionBody::Expression(expr) => {450                            self.walk_expression(v, expr);451                        }452                    }453                }454                v.leave_arrow_function_expression(node, &self.scope_stack);455                if pushed {456                    self.scope_stack.pop();457                }458            }459            Expression::FunctionExpression(node) => {460                let pushed = self.try_push_scope(node.base.start, node.base.node_id);461                v.enter_function_expression(node, &self.scope_stack);462                if v.traverse_function_bodies() {463                    for param in &node.params {464                        self.walk_pattern(v, param);465                    }466                    self.walk_block_statement(v, &node.body);467                }468                v.leave_function_expression(node, &self.scope_stack);469                if pushed {470                    self.scope_stack.pop();471                }472            }473            Expression::ObjectExpression(node) => {474                for prop in &node.properties {475                    self.walk_object_expression_property(v, prop);476                }477            }478            Expression::ArrayExpression(node) => {479                for element in &node.elements {480                    if let Some(el) = element {481                        self.walk_expression(v, el);482                    }483                }484            }485            Expression::NewExpression(node) => {486                self.walk_expression(v, &node.callee);487                for arg in &node.arguments {488                    self.walk_expression(v, arg);489                }490            }491            Expression::TemplateLiteral(node) => {492                for expr in &node.expressions {493                    self.walk_expression(v, expr);494                }495            }496            Expression::TaggedTemplateExpression(node) => {497                self.walk_expression(v, &node.tag);498                for expr in &node.quasi.expressions {499                    self.walk_expression(v, expr);500                }501            }502            Expression::AwaitExpression(node) => {503                self.walk_expression(v, &node.argument);504            }505            Expression::YieldExpression(node) => {506                if let Some(arg) = &node.argument {507                    self.walk_expression(v, arg);508                }509            }510            Expression::SpreadElement(node) => {511                self.walk_expression(v, &node.argument);512            }513            Expression::ParenthesizedExpression(node) => {514                self.walk_expression(v, &node.expression);515            }516            Expression::AssignmentPattern(node) => {517                self.walk_pattern(v, &node.left);518                self.walk_expression(v, &node.right);519            }520            Expression::ClassExpression(node) => {521                // Call the visitor hook so consumers can index the class name,522                // but skip walking the class body523                v.enter_class_expression(node, &self.scope_stack);524            }525            // JSX526            Expression::JSXElement(node) => self.walk_jsx_element(v, node),527            Expression::JSXFragment(node) => self.walk_jsx_fragment(v, node),528            // TS/Flow wrappers - traverse inner expression529            Expression::TSAsExpression(node) => self.walk_expression(v, &node.expression),530            Expression::TSSatisfiesExpression(node) => self.walk_expression(v, &node.expression),531            Expression::TSNonNullExpression(node) => self.walk_expression(v, &node.expression),532            Expression::TSTypeAssertion(node) => self.walk_expression(v, &node.expression),533            Expression::TSInstantiationExpression(node) => {534                self.walk_expression(v, &node.expression)535            }536            Expression::TypeCastExpression(node) => self.walk_expression(v, &node.expression),537            // Leaf nodes538            Expression::StringLiteral(_)539            | Expression::NumericLiteral(_)540            | Expression::BooleanLiteral(_)541            | Expression::NullLiteral(_)542            | Expression::BigIntLiteral(_)543            | Expression::RegExpLiteral(_)544            | Expression::MetaProperty(_)545            | Expression::PrivateName(_)546            | Expression::Super(_)547            | Expression::Import(_)548            | Expression::ThisExpression(_) => {}549        }550    }551552    pub fn walk_pattern<'ast>(&mut self, v: &mut impl Visitor<'ast>, pat: &'ast PatternLike) {553        match pat {554            PatternLike::Identifier(node) => {555                v.enter_identifier(node, &self.scope_stack);556            }557            PatternLike::ObjectPattern(node) => {558                for prop in &node.properties {559                    match prop {560                        ObjectPatternProperty::ObjectProperty(p) => {561                            if p.computed {562                                self.walk_expression(v, &p.key);563                            }564                            self.walk_pattern(v, &p.value);565                        }566                        ObjectPatternProperty::RestElement(p) => {567                            self.walk_pattern(v, &p.argument);568                        }569                    }570                }571            }572            PatternLike::ArrayPattern(node) => {573                for element in &node.elements {574                    if let Some(el) = element {575                        self.walk_pattern(v, el);576                    }577                }578            }579            PatternLike::AssignmentPattern(node) => {580                self.walk_pattern(v, &node.left);581                self.walk_expression(v, &node.right);582            }583            PatternLike::RestElement(node) => {584                self.walk_pattern(v, &node.argument);585            }586            PatternLike::MemberExpression(node) => {587                self.walk_expression(v, &node.object);588                if node.computed {589                    self.walk_expression(v, &node.property);590                }591            }592            PatternLike::TSAsExpression(node) => self.walk_expression(v, &node.expression),593            PatternLike::TSSatisfiesExpression(node) => self.walk_expression(v, &node.expression),594            PatternLike::TSNonNullExpression(node) => self.walk_expression(v, &node.expression),595            PatternLike::TSTypeAssertion(node) => self.walk_expression(v, &node.expression),596            PatternLike::TypeCastExpression(node) => self.walk_expression(v, &node.expression),597        }598    }599600    // ---- Private helper walk methods ----601602    fn walk_for_in_of_left<'ast>(&mut self, v: &mut impl Visitor<'ast>, left: &'ast ForInOfLeft) {603        match left {604            ForInOfLeft::VariableDeclaration(decl) => self.walk_variable_declaration(v, decl),605            ForInOfLeft::Pattern(pat) => self.walk_pattern(v, pat),606        }607    }608609    fn walk_variable_declaration<'ast>(610        &mut self,611        v: &mut impl Visitor<'ast>,612        decl: &'ast VariableDeclaration,613    ) {614        for declarator in &decl.declarations {615            v.enter_variable_declarator(declarator, &self.scope_stack);616            self.walk_pattern(v, &declarator.id);617            if let Some(init) = &declarator.init {618                self.walk_expression(v, init);619            }620            v.leave_variable_declarator(declarator, &self.scope_stack);621        }622    }623624    fn walk_function_declaration_inner<'ast>(625        &mut self,626        v: &mut impl Visitor<'ast>,627        node: &'ast FunctionDeclaration,628    ) {629        let pushed = self.try_push_scope(node.base.start, node.base.node_id);630        v.enter_function_declaration(node, &self.scope_stack);631        if v.traverse_function_bodies() {632            for param in &node.params {633                self.walk_pattern(v, param);634            }635            self.walk_block_statement(v, &node.body);636        }637        v.leave_function_declaration(node, &self.scope_stack);638        if pushed {639            self.scope_stack.pop();640        }641    }642643    fn walk_object_expression_property<'ast>(644        &mut self,645        v: &mut impl Visitor<'ast>,646        prop: &'ast ObjectExpressionProperty,647    ) {648        match prop {649            ObjectExpressionProperty::ObjectProperty(p) => {650                if p.computed {651                    self.walk_expression(v, &p.key);652                }653                self.walk_expression(v, &p.value);654            }655            ObjectExpressionProperty::ObjectMethod(node) => {656                let pushed = self.try_push_scope(node.base.start, node.base.node_id);657                v.enter_object_method(node, &self.scope_stack);658                if v.traverse_function_bodies() {659                    if node.computed {660                        self.walk_expression(v, &node.key);661                    }662                    for param in &node.params {663                        self.walk_pattern(v, param);664                    }665                    self.walk_block_statement(v, &node.body);666                }667                v.leave_object_method(node, &self.scope_stack);668                if pushed {669                    self.scope_stack.pop();670                }671            }672            ObjectExpressionProperty::SpreadElement(p) => {673                self.walk_expression(v, &p.argument);674            }675        }676    }677678    fn walk_declaration<'ast>(&mut self, v: &mut impl Visitor<'ast>, decl: &'ast Declaration) {679        match decl {680            Declaration::FunctionDeclaration(node) => {681                self.walk_function_declaration_inner(v, node);682            }683            Declaration::VariableDeclaration(node) => {684                self.walk_variable_declaration(v, node);685            }686            // TS/Flow declarations - no runtime expressions687            _ => {}688        }689    }690691    fn walk_export_default_decl<'ast>(692        &mut self,693        v: &mut impl Visitor<'ast>,694        decl: &'ast ExportDefaultDecl,695    ) {696        match decl {697            ExportDefaultDecl::FunctionDeclaration(node) => {698                self.walk_function_declaration_inner(v, node);699            }700            ExportDefaultDecl::ClassDeclaration(node) => {701                // Call the visitor hook, but skip the class body702                v.enter_class_declaration(node, &self.scope_stack);703            }704            ExportDefaultDecl::EnumDeclaration(_) => {705                // Flow enum declarations are opaque — no visitor hooks needed706            }707            ExportDefaultDecl::Expression(expr) => {708                self.walk_expression(v, expr);709            }710        }711    }712713    fn walk_jsx_element<'ast>(&mut self, v: &mut impl Visitor<'ast>, node: &'ast JSXElement) {714        v.enter_jsx_opening_element(&node.opening_element, &self.scope_stack);715        self.walk_jsx_element_name(v, &node.opening_element.name);716        v.leave_jsx_opening_element(&node.opening_element, &self.scope_stack);717        for attr in &node.opening_element.attributes {718            match attr {719                JSXAttributeItem::JSXAttribute(a) => {720                    if let Some(value) = &a.value {721                        match value {722                            JSXAttributeValue::JSXExpressionContainer(c) => {723                                self.walk_jsx_expr_container(v, c);724                            }725                            JSXAttributeValue::JSXElement(el) => {726                                self.walk_jsx_element(v, el);727                            }728                            JSXAttributeValue::JSXFragment(f) => {729                                self.walk_jsx_fragment(v, f);730                            }731                            JSXAttributeValue::StringLiteral(_) => {}732                        }733                    }734                }735                JSXAttributeItem::JSXSpreadAttribute(a) => {736                    self.walk_expression(v, &a.argument);737                }738            }739        }740        for child in &node.children {741            self.walk_jsx_child(v, child);742        }743    }744745    fn walk_jsx_fragment<'ast>(&mut self, v: &mut impl Visitor<'ast>, node: &'ast JSXFragment) {746        for child in &node.children {747            self.walk_jsx_child(v, child);748        }749    }750751    fn walk_jsx_child<'ast>(&mut self, v: &mut impl Visitor<'ast>, child: &'ast JSXChild) {752        match child {753            JSXChild::JSXElement(el) => self.walk_jsx_element(v, el),754            JSXChild::JSXFragment(f) => self.walk_jsx_fragment(v, f),755            JSXChild::JSXExpressionContainer(c) => self.walk_jsx_expr_container(v, c),756            JSXChild::JSXSpreadChild(s) => self.walk_expression(v, &s.expression),757            JSXChild::JSXText(_) => {}758        }759    }760761    fn walk_jsx_expr_container<'ast>(762        &mut self,763        v: &mut impl Visitor<'ast>,764        node: &'ast JSXExpressionContainer,765    ) {766        match &node.expression {767            JSXExpressionContainerExpr::Expression(expr) => self.walk_expression(v, expr),768            JSXExpressionContainerExpr::JSXEmptyExpression(_) => {}769        }770    }771772    fn walk_jsx_element_name<'ast>(773        &mut self,774        v: &mut impl Visitor<'ast>,775        name: &'ast JSXElementName,776    ) {777        match name {778            JSXElementName::JSXIdentifier(id) => {779                v.enter_jsx_identifier(id, &self.scope_stack);780            }781            JSXElementName::JSXMemberExpression(expr) => {782                self.walk_jsx_member_expression(v, expr);783            }784            JSXElementName::JSXNamespacedName(_) => {}785        }786    }787788    fn walk_jsx_member_expression<'ast>(789        &mut self,790        v: &mut impl Visitor<'ast>,791        expr: &'ast JSXMemberExpression,792    ) {793        match &*expr.object {794            JSXMemberExprObject::JSXIdentifier(id) => {795                v.enter_jsx_identifier(id, &self.scope_stack);796            }797            JSXMemberExprObject::JSXMemberExpression(inner) => {798                self.walk_jsx_member_expression(v, inner);799            }800        }801        v.enter_jsx_identifier(&expr.property, &self.scope_stack);802    }803}804805// =============================================================================806// Mutable visitor807// =============================================================================808809/// Result from a mutable visitor hook.810#[derive(Debug, Clone, Copy, PartialEq, Eq)]811pub enum VisitResult {812    /// Continue traversal to children.813    Continue,814    /// Stop traversal immediately.815    Stop,816}817818impl VisitResult {819    pub fn is_stop(self) -> bool {820        self == VisitResult::Stop821    }822}823824/// Trait for mutating Babel AST nodes during traversal.825///826/// Override hooks to intercept and mutate specific node types.827/// Return [`VisitResult::Stop`] from any hook to halt the walk.828/// Hooks are called *before* the walker recurses into children,829/// so returning `Stop` prevents child traversal.830pub trait MutVisitor {831    /// Called for every statement before recursing into its children.832    fn visit_statement(&mut self, _stmt: &mut Statement) -> VisitResult {833        VisitResult::Continue834    }835836    /// Called for every expression before recursing into its children.837    fn visit_expression(&mut self, _expr: &mut Expression) -> VisitResult {838        VisitResult::Continue839    }840841    /// Called for identifiers in expression position.842    fn visit_identifier(&mut self, _node: &mut Identifier) -> VisitResult {843        VisitResult::Continue844    }845}846847/// Walk a program's body mutably, calling visitor hooks for each node.848pub fn walk_program_mut(v: &mut impl MutVisitor, program: &mut Program) -> VisitResult {849    for stmt in program.body.iter_mut() {850        if walk_statement_mut(v, stmt).is_stop() {851            return VisitResult::Stop;852        }853    }854    VisitResult::Continue855}856857/// Walk a single statement mutably, calling visitor hooks and recursing into children.858pub fn walk_statement_mut(v: &mut impl MutVisitor, stmt: &mut Statement) -> VisitResult {859    if v.visit_statement(stmt).is_stop() {860        return VisitResult::Stop;861    }862    match stmt {863        Statement::BlockStatement(node) => {864            for s in node.body.iter_mut() {865                if walk_statement_mut(v, s).is_stop() {866                    return VisitResult::Stop;867                }868            }869        }870        Statement::ReturnStatement(node) => {871            if let Some(ref mut arg) = node.argument {872                if walk_expression_mut(v, arg).is_stop() {873                    return VisitResult::Stop;874                }875            }876        }877        Statement::ExpressionStatement(node) => {878            if walk_expression_mut(v, &mut node.expression).is_stop() {879                return VisitResult::Stop;880            }881        }882        Statement::IfStatement(node) => {883            if walk_expression_mut(v, &mut node.test).is_stop() {884                return VisitResult::Stop;885            }886            if walk_statement_mut(v, &mut node.consequent).is_stop() {887                return VisitResult::Stop;888            }889            if let Some(ref mut alt) = node.alternate {890                if walk_statement_mut(v, alt).is_stop() {891                    return VisitResult::Stop;892                }893            }894        }895        Statement::ForStatement(node) => {896            if let Some(ref mut init) = node.init {897                match init.as_mut() {898                    ForInit::VariableDeclaration(decl) => {899                        if walk_variable_declaration_mut(v, decl).is_stop() {900                            return VisitResult::Stop;901                        }902                    }903                    ForInit::Expression(expr) => {904                        if walk_expression_mut(v, expr).is_stop() {905                            return VisitResult::Stop;906                        }907                    }908                }909            }910            if let Some(ref mut test) = node.test {911                if walk_expression_mut(v, test).is_stop() {912                    return VisitResult::Stop;913                }914            }915            if let Some(ref mut update) = node.update {916                if walk_expression_mut(v, update).is_stop() {917                    return VisitResult::Stop;918                }919            }920            if walk_statement_mut(v, &mut node.body).is_stop() {921                return VisitResult::Stop;922            }923        }924        Statement::WhileStatement(node) => {925            if walk_expression_mut(v, &mut node.test).is_stop() {926                return VisitResult::Stop;927            }928            if walk_statement_mut(v, &mut node.body).is_stop() {929                return VisitResult::Stop;930            }931        }932        Statement::DoWhileStatement(node) => {933            if walk_statement_mut(v, &mut node.body).is_stop() {934                return VisitResult::Stop;935            }936            if walk_expression_mut(v, &mut node.test).is_stop() {937                return VisitResult::Stop;938            }939        }940        Statement::ForInStatement(node) => {941            if walk_expression_mut(v, &mut node.right).is_stop() {942                return VisitResult::Stop;943            }944            if walk_statement_mut(v, &mut node.body).is_stop() {945                return VisitResult::Stop;946            }947        }948        Statement::ForOfStatement(node) => {949            if walk_expression_mut(v, &mut node.right).is_stop() {950                return VisitResult::Stop;951            }952            if walk_statement_mut(v, &mut node.body).is_stop() {953                return VisitResult::Stop;954            }955        }956        Statement::SwitchStatement(node) => {957            if walk_expression_mut(v, &mut node.discriminant).is_stop() {958                return VisitResult::Stop;959            }960            for case in node.cases.iter_mut() {961                if let Some(ref mut test) = case.test {962                    if walk_expression_mut(v, test).is_stop() {963                        return VisitResult::Stop;964                    }965                }966                for s in case.consequent.iter_mut() {967                    if walk_statement_mut(v, s).is_stop() {968                        return VisitResult::Stop;969                    }970                }971            }972        }973        Statement::ThrowStatement(node) => {974            if walk_expression_mut(v, &mut node.argument).is_stop() {975                return VisitResult::Stop;976            }977        }978        Statement::TryStatement(node) => {979            for s in node.block.body.iter_mut() {980                if walk_statement_mut(v, s).is_stop() {981                    return VisitResult::Stop;982                }983            }984            if let Some(ref mut handler) = node.handler {985                for s in handler.body.body.iter_mut() {986                    if walk_statement_mut(v, s).is_stop() {987                        return VisitResult::Stop;988                    }989                }990            }991            if let Some(ref mut finalizer) = node.finalizer {992                for s in finalizer.body.iter_mut() {993                    if walk_statement_mut(v, s).is_stop() {994                        return VisitResult::Stop;995                    }996                }997            }998        }999        Statement::LabeledStatement(node) => {1000            if walk_statement_mut(v, &mut node.body).is_stop() {1001                return VisitResult::Stop;1002            }1003        }1004        Statement::VariableDeclaration(node) => {1005            if walk_variable_declaration_mut(v, node).is_stop() {1006                return VisitResult::Stop;1007            }1008        }1009        Statement::FunctionDeclaration(node) => {1010            for s in node.body.body.iter_mut() {1011                if walk_statement_mut(v, s).is_stop() {1012                    return VisitResult::Stop;1013                }1014            }1015        }1016        Statement::ClassDeclaration(node) => {1017            if let Some(ref mut sc) = node.super_class {1018                if walk_expression_mut(v, sc).is_stop() {1019                    return VisitResult::Stop;1020                }1021            }1022        }1023        Statement::WithStatement(node) => {1024            if walk_expression_mut(v, &mut node.object).is_stop() {1025                return VisitResult::Stop;1026            }1027            if walk_statement_mut(v, &mut node.body).is_stop() {1028                return VisitResult::Stop;1029            }1030        }1031        Statement::ExportNamedDeclaration(node) => {1032            if let Some(ref mut decl) = node.declaration {1033                if walk_declaration_mut(v, decl).is_stop() {1034                    return VisitResult::Stop;1035                }1036            }1037        }1038        Statement::ExportDefaultDeclaration(node) => {1039            if walk_export_default_decl_mut(v, &mut node.declaration).is_stop() {1040                return VisitResult::Stop;1041            }1042        }1043        // No runtime expressions to traverse1044        Statement::BreakStatement(_)1045        | Statement::ContinueStatement(_)1046        | Statement::EmptyStatement(_)1047        | Statement::DebuggerStatement(_)1048        | Statement::ImportDeclaration(_)1049        | Statement::ExportAllDeclaration(_)1050        | Statement::TSTypeAliasDeclaration(_)1051        | Statement::TSInterfaceDeclaration(_)1052        | Statement::TSEnumDeclaration(_)1053        | Statement::TSModuleDeclaration(_)1054        | Statement::TSDeclareFunction(_)1055        | Statement::TypeAlias(_)1056        | Statement::OpaqueType(_)1057        | Statement::InterfaceDeclaration(_)1058        | Statement::DeclareVariable(_)1059        | Statement::DeclareFunction(_)1060        | Statement::DeclareClass(_)1061        | Statement::DeclareModule(_)1062        | Statement::DeclareModuleExports(_)1063        | Statement::DeclareExportDeclaration(_)1064        | Statement::DeclareExportAllDeclaration(_)1065        | Statement::DeclareInterface(_)1066        | Statement::DeclareTypeAlias(_)1067        | Statement::DeclareOpaqueType(_)1068        | Statement::EnumDeclaration(_)1069        // Unmodeled raw node: opaque, no compilable children to traverse.1070        | Statement::Unknown(_) => {}1071    }1072    VisitResult::Continue1073}10741075/// Walk an expression mutably, calling visitor hooks and recursing into children.1076pub fn walk_expression_mut(v: &mut impl MutVisitor, expr: &mut Expression) -> VisitResult {1077    if v.visit_expression(expr).is_stop() {1078        return VisitResult::Stop;1079    }1080    match expr {1081        Expression::Identifier(node) => {1082            if v.visit_identifier(node).is_stop() {1083                return VisitResult::Stop;1084            }1085        }1086        Expression::CallExpression(node) => {1087            if walk_expression_mut(v, &mut node.callee).is_stop() {1088                return VisitResult::Stop;1089            }1090            for arg in node.arguments.iter_mut() {1091                if walk_expression_mut(v, arg).is_stop() {1092                    return VisitResult::Stop;1093                }1094            }1095        }1096        Expression::MemberExpression(node) => {1097            if walk_expression_mut(v, &mut node.object).is_stop() {1098                return VisitResult::Stop;1099            }1100            if node.computed {1101                if walk_expression_mut(v, &mut node.property).is_stop() {1102                    return VisitResult::Stop;1103                }1104            }1105        }1106        Expression::OptionalCallExpression(node) => {1107            if walk_expression_mut(v, &mut node.callee).is_stop() {1108                return VisitResult::Stop;1109            }1110            for arg in node.arguments.iter_mut() {1111                if walk_expression_mut(v, arg).is_stop() {1112                    return VisitResult::Stop;1113                }1114            }1115        }1116        Expression::OptionalMemberExpression(node) => {1117            if walk_expression_mut(v, &mut node.object).is_stop() {1118                return VisitResult::Stop;1119            }1120            if node.computed {1121                if walk_expression_mut(v, &mut node.property).is_stop() {1122                    return VisitResult::Stop;1123                }1124            }1125        }1126        Expression::BinaryExpression(node) => {1127            if walk_expression_mut(v, &mut node.left).is_stop() {1128                return VisitResult::Stop;1129            }1130            if walk_expression_mut(v, &mut node.right).is_stop() {1131                return VisitResult::Stop;1132            }1133        }1134        Expression::LogicalExpression(node) => {1135            if walk_expression_mut(v, &mut node.left).is_stop() {1136                return VisitResult::Stop;1137            }1138            if walk_expression_mut(v, &mut node.right).is_stop() {1139                return VisitResult::Stop;1140            }1141        }1142        Expression::UnaryExpression(node) => {1143            if walk_expression_mut(v, &mut node.argument).is_stop() {1144                return VisitResult::Stop;1145            }1146        }1147        Expression::UpdateExpression(node) => {1148            if walk_expression_mut(v, &mut node.argument).is_stop() {1149                return VisitResult::Stop;1150            }1151        }1152        Expression::ConditionalExpression(node) => {1153            if walk_expression_mut(v, &mut node.test).is_stop() {1154                return VisitResult::Stop;1155            }1156            if walk_expression_mut(v, &mut node.consequent).is_stop() {1157                return VisitResult::Stop;1158            }1159            if walk_expression_mut(v, &mut node.alternate).is_stop() {1160                return VisitResult::Stop;1161            }1162        }1163        Expression::AssignmentExpression(node) => {1164            if walk_expression_mut(v, &mut node.right).is_stop() {1165                return VisitResult::Stop;1166            }1167        }1168        Expression::SequenceExpression(node) => {1169            for e in node.expressions.iter_mut() {1170                if walk_expression_mut(v, e).is_stop() {1171                    return VisitResult::Stop;1172                }1173            }1174        }1175        Expression::ArrowFunctionExpression(node) => match node.body.as_mut() {1176            ArrowFunctionBody::BlockStatement(block) => {1177                for s in block.body.iter_mut() {1178                    if walk_statement_mut(v, s).is_stop() {1179                        return VisitResult::Stop;1180                    }1181                }1182            }1183            ArrowFunctionBody::Expression(e) => {1184                if walk_expression_mut(v, e).is_stop() {1185                    return VisitResult::Stop;1186                }1187            }1188        },1189        Expression::FunctionExpression(node) => {1190            for s in node.body.body.iter_mut() {1191                if walk_statement_mut(v, s).is_stop() {1192                    return VisitResult::Stop;1193                }1194            }1195        }1196        Expression::ObjectExpression(node) => {1197            for prop in node.properties.iter_mut() {1198                match prop {1199                    ObjectExpressionProperty::ObjectProperty(p) => {1200                        if p.computed {1201                            if walk_expression_mut(v, &mut p.key).is_stop() {1202                                return VisitResult::Stop;1203                            }1204                        }1205                        if walk_expression_mut(v, &mut p.value).is_stop() {1206                            return VisitResult::Stop;1207                        }1208                    }1209                    ObjectExpressionProperty::ObjectMethod(m) => {1210                        for s in m.body.body.iter_mut() {1211                            if walk_statement_mut(v, s).is_stop() {1212                                return VisitResult::Stop;1213                            }1214                        }1215                    }1216                    ObjectExpressionProperty::SpreadElement(s) => {1217                        if walk_expression_mut(v, &mut s.argument).is_stop() {1218                            return VisitResult::Stop;1219                        }1220                    }1221                }1222            }1223        }1224        Expression::ArrayExpression(node) => {1225            for elem in node.elements.iter_mut().flatten() {1226                if walk_expression_mut(v, elem).is_stop() {1227                    return VisitResult::Stop;1228                }1229            }1230        }1231        Expression::NewExpression(node) => {1232            if walk_expression_mut(v, &mut node.callee).is_stop() {1233                return VisitResult::Stop;1234            }1235            for arg in node.arguments.iter_mut() {1236                if walk_expression_mut(v, arg).is_stop() {1237                    return VisitResult::Stop;1238                }1239            }1240        }1241        Expression::TemplateLiteral(node) => {1242            for e in node.expressions.iter_mut() {1243                if walk_expression_mut(v, e).is_stop() {1244                    return VisitResult::Stop;1245                }1246            }1247        }1248        Expression::TaggedTemplateExpression(node) => {1249            if walk_expression_mut(v, &mut node.tag).is_stop() {1250                return VisitResult::Stop;1251            }1252            for e in node.quasi.expressions.iter_mut() {1253                if walk_expression_mut(v, e).is_stop() {1254                    return VisitResult::Stop;1255                }1256            }1257        }1258        Expression::AwaitExpression(node) => {1259            if walk_expression_mut(v, &mut node.argument).is_stop() {1260                return VisitResult::Stop;1261            }1262        }1263        Expression::YieldExpression(node) => {1264            if let Some(ref mut arg) = node.argument {1265                if walk_expression_mut(v, arg).is_stop() {1266                    return VisitResult::Stop;1267                }1268            }1269        }1270        Expression::SpreadElement(node) => {1271            if walk_expression_mut(v, &mut node.argument).is_stop() {1272                return VisitResult::Stop;1273            }1274        }1275        Expression::ParenthesizedExpression(node) => {1276            if walk_expression_mut(v, &mut node.expression).is_stop() {1277                return VisitResult::Stop;1278            }1279        }1280        Expression::AssignmentPattern(node) => {1281            if walk_expression_mut(v, &mut node.right).is_stop() {1282                return VisitResult::Stop;1283            }1284        }1285        Expression::ClassExpression(node) => {1286            if let Some(ref mut sc) = node.super_class {1287                if walk_expression_mut(v, sc).is_stop() {1288                    return VisitResult::Stop;1289                }1290            }1291        }1292        Expression::JSXElement(node) => {1293            if walk_jsx_mut(v, &mut node.opening_element.attributes, &mut node.children).is_stop() {1294                return VisitResult::Stop;1295            }1296        }1297        Expression::JSXFragment(node) => {1298            if walk_jsx_children_mut(v, &mut node.children).is_stop() {1299                return VisitResult::Stop;1300            }1301        }1302        // TS/Flow wrappers — traverse inner expression1303        Expression::TSAsExpression(node) => {1304            if walk_expression_mut(v, &mut node.expression).is_stop() {1305                return VisitResult::Stop;1306            }1307        }1308        Expression::TSSatisfiesExpression(node) => {1309            if walk_expression_mut(v, &mut node.expression).is_stop() {1310                return VisitResult::Stop;1311            }1312        }1313        Expression::TSNonNullExpression(node) => {1314            if walk_expression_mut(v, &mut node.expression).is_stop() {1315                return VisitResult::Stop;1316            }1317        }1318        Expression::TSTypeAssertion(node) => {1319            if walk_expression_mut(v, &mut node.expression).is_stop() {1320                return VisitResult::Stop;1321            }1322        }1323        Expression::TSInstantiationExpression(node) => {1324            if walk_expression_mut(v, &mut node.expression).is_stop() {1325                return VisitResult::Stop;1326            }1327        }1328        Expression::TypeCastExpression(node) => {1329            if walk_expression_mut(v, &mut node.expression).is_stop() {1330                return VisitResult::Stop;1331            }1332        }1333        // Leaf nodes1334        Expression::StringLiteral(_)1335        | Expression::NumericLiteral(_)1336        | Expression::BooleanLiteral(_)1337        | Expression::NullLiteral(_)1338        | Expression::BigIntLiteral(_)1339        | Expression::RegExpLiteral(_)1340        | Expression::MetaProperty(_)1341        | Expression::PrivateName(_)1342        | Expression::Super(_)1343        | Expression::Import(_)1344        | Expression::ThisExpression(_) => {}1345    }1346    VisitResult::Continue1347}13481349fn walk_jsx_mut(1350    v: &mut impl MutVisitor,1351    attrs: &mut [crate::jsx::JSXAttributeItem],1352    children: &mut [crate::jsx::JSXChild],1353) -> VisitResult {1354    for attr in attrs.iter_mut() {1355        match attr {1356            crate::jsx::JSXAttributeItem::JSXAttribute(a) => {1357                if let Some(ref mut val) = a.value {1358                    match val {1359                        crate::jsx::JSXAttributeValue::JSXExpressionContainer(c) => {1360                            if let crate::jsx::JSXExpressionContainerExpr::Expression(ref mut e) =1361                                c.expression1362                            {1363                                if walk_expression_mut(v, e).is_stop() {1364                                    return VisitResult::Stop;1365                                }1366                            }1367                        }1368                        _ => {}1369                    }1370                }1371            }1372            crate::jsx::JSXAttributeItem::JSXSpreadAttribute(s) => {1373                if walk_expression_mut(v, &mut s.argument).is_stop() {1374                    return VisitResult::Stop;1375                }1376            }1377        }1378    }1379    walk_jsx_children_mut(v, children)1380}13811382fn walk_jsx_children_mut(1383    v: &mut impl MutVisitor,1384    children: &mut [crate::jsx::JSXChild],1385) -> VisitResult {1386    for child in children.iter_mut() {1387        match child {1388            crate::jsx::JSXChild::JSXElement(el) => {1389                if walk_jsx_mut(v, &mut el.opening_element.attributes, &mut el.children).is_stop() {1390                    return VisitResult::Stop;1391                }1392            }1393            crate::jsx::JSXChild::JSXFragment(f) => {1394                if walk_jsx_children_mut(v, &mut f.children).is_stop() {1395                    return VisitResult::Stop;1396                }1397            }1398            crate::jsx::JSXChild::JSXExpressionContainer(c) => {1399                if let crate::jsx::JSXExpressionContainerExpr::Expression(ref mut e) = c.expression1400                {1401                    if walk_expression_mut(v, e).is_stop() {1402                        return VisitResult::Stop;1403                    }1404                }1405            }1406            crate::jsx::JSXChild::JSXSpreadChild(s) => {1407                if walk_expression_mut(v, &mut s.expression).is_stop() {1408                    return VisitResult::Stop;1409                }1410            }1411            _ => {}1412        }1413    }1414    VisitResult::Continue1415}14161417// ---- Private helper walk-mut functions ----14181419fn walk_variable_declaration_mut(1420    v: &mut impl MutVisitor,1421    decl: &mut VariableDeclaration,1422) -> VisitResult {1423    for declarator in decl.declarations.iter_mut() {1424        if let Some(ref mut init) = declarator.init {1425            if walk_expression_mut(v, init).is_stop() {1426                return VisitResult::Stop;1427            }1428        }1429    }1430    VisitResult::Continue1431}14321433fn walk_declaration_mut(v: &mut impl MutVisitor, decl: &mut Declaration) -> VisitResult {1434    match decl {1435        Declaration::FunctionDeclaration(node) => {1436            for s in node.body.body.iter_mut() {1437                if walk_statement_mut(v, s).is_stop() {1438                    return VisitResult::Stop;1439                }1440            }1441        }1442        Declaration::VariableDeclaration(node) => {1443            if walk_variable_declaration_mut(v, node).is_stop() {1444                return VisitResult::Stop;1445            }1446        }1447        Declaration::ClassDeclaration(node) => {1448            if let Some(ref mut sc) = node.super_class {1449                if walk_expression_mut(v, sc).is_stop() {1450                    return VisitResult::Stop;1451                }1452            }1453        }1454        _ => {}1455    }1456    VisitResult::Continue1457}14581459fn walk_export_default_decl_mut(1460    v: &mut impl MutVisitor,1461    decl: &mut ExportDefaultDecl,1462) -> VisitResult {1463    match decl {1464        ExportDefaultDecl::FunctionDeclaration(node) => {1465            for s in node.body.body.iter_mut() {1466                if walk_statement_mut(v, s).is_stop() {1467                    return VisitResult::Stop;1468                }1469            }1470        }1471        ExportDefaultDecl::Expression(expr) => {1472            if walk_expression_mut(v, expr).is_stop() {1473                return VisitResult::Stop;1474            }1475        }1476        ExportDefaultDecl::ClassDeclaration(node) => {1477            if let Some(ref mut sc) = node.super_class {1478                if walk_expression_mut(v, sc).is_stop() {1479                    return VisitResult::Stop;1480                }1481            }1482        }1483        ExportDefaultDecl::EnumDeclaration(_) => {1484            // Flow enum declarations are opaque — nothing to walk1485        }1486    }1487    VisitResult::Continue1488}

Code quality findings 14

Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
//! Provides a [`Visitor`] trait with enter/leave hooks for specific node types,
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
//! and an [`AstWalker`] that traverses the AST while tracking the active scope
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
/// Return [`VisitResult::Stop`] from any hook to halt the walk.
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
attrs: &mut [crate::jsx::JSXAttributeItem],
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
children: &mut [crate::jsx::JSXChild],
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
children: &mut [crate::jsx::JSXChild],
Info: Wildcard imports (`use some::path::*;`) can obscure the origin of names and lead to conflicts. Prefer importing specific items explicitly.
info maintainability wildcard-import
use crate::declarations::*;
Info: Wildcard imports (`use some::path::*;`) can obscure the origin of names and lead to conflicts. Prefer importing specific items explicitly.
info maintainability wildcard-import
use crate::expressions::*;
Info: Wildcard imports (`use some::path::*;`) can obscure the origin of names and lead to conflicts. Prefer importing specific items explicitly.
info maintainability wildcard-import
use crate::jsx::*;
Info: Wildcard imports (`use some::path::*;`) can obscure the origin of names and lead to conflicts. Prefer importing specific items explicitly.
info maintainability wildcard-import
use crate::patterns::*;
Info: Wildcard imports (`use some::path::*;`) can obscure the origin of names and lead to conflicts. Prefer importing specific items explicitly.
info maintainability wildcard-import
use crate::statements::*;
Performance Info: Calling .push() repeatedly inside a loop without prior capacity reservation can lead to multiple reallocations. Consider using `Vec::with_capacity(n)` or `vec.reserve(n)` if the approximate number of elements is known.
info performance push-without-reserve
self.scope_stack.push(scope_id);
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
match decl {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
match val {

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.