compiler/crates/react_compiler/src/entrypoint/validate_source_locations.rs RUST 1,346 lines View on github.com → Search inside
1// Copyright (c) Meta Platforms, Inc. and affiliates.2//3// This source code is licensed under the MIT license found in the4// LICENSE file in the root directory of this source tree.56//! Validates that important source locations from the original code are preserved7//! in the generated AST. This ensures that Istanbul coverage instrumentation can8//! properly map back to the original source code.9//!10//! This validation is test-only, enabled via `@validateSourceLocations` pragma.11//!12//! Analogous to TS `ValidateSourceLocations.ts`.1314use rustc_hash::{FxHashMap, FxHashSet};1516use react_compiler_ast::common::SourceLocation as AstSourceLocation;17use react_compiler_ast::expressions::{18    ArrowFunctionBody, ArrowFunctionExpression, Expression, FunctionExpression,19    ObjectExpressionProperty,20};21use react_compiler_ast::patterns::PatternLike;22use react_compiler_ast::statements::{ForInOfLeft, ForInit, Statement, VariableDeclaration};23use react_compiler_diagnostics::{24    CompilerDiagnostic, CompilerDiagnosticDetail, ErrorCategory, Position as DiagPosition,25    SourceLocation as DiagSourceLocation,26};27use react_compiler_hir::environment::Environment;28use react_compiler_lowering::FunctionNode;29use react_compiler_reactive_scopes::codegen_reactive_function::CodegenFunction;3031/// Validate that important source locations are preserved in the generated AST.32pub fn validate_source_locations(33    func: &FunctionNode<'_>,34    codegen: &CodegenFunction,35    env: &mut Environment,36) {37    // Step 1: Collect important locations from the original source38    let important_original = collect_important_original_locations(func);3940    // Step 2: Collect all locations from the generated AST41    let mut generated = FxHashMap::<String, FxHashSet<String>>::default();42    collect_generated_from_block(&codegen.body.body, &mut generated);43    for outlined in &codegen.outlined {44        collect_generated_from_block(&outlined.func.body.body, &mut generated);45    }4647    // Step 3: Validate that all important locations are preserved48    let strict_node_types: FxHashSet<&str> =49        ["VariableDeclaration", "VariableDeclarator", "Identifier"]50            .into_iter()51            .collect();5253    // Sort entries by source position to match TS output order54    // (JS Map preserves insertion order, which is AST traversal order = source order)55    let mut sorted_entries: Vec<&ImportantLocation> = important_original.values().collect();56    sorted_entries.sort_by(|a, b| {57        a.loc58            .start59            .line60            .cmp(&b.loc.start.line)61            .then(a.loc.start.column.cmp(&b.loc.start.column))62            // Outer nodes (larger spans) before inner nodes, matching depth-first traversal63            .then(b.loc.end.line.cmp(&a.loc.end.line))64            .then(b.loc.end.column.cmp(&a.loc.end.column))65    });6667    for entry in &sorted_entries {68        let generated_node_types = generated.get(&entry.key);6970        if generated_node_types.is_none() {71            // Location is completely missing72            let mut node_types_str: Vec<&str> = entry.node_types.iter().copied().collect();73            node_types_str.sort();74            report_missing_location(env, &entry.loc, &node_types_str.join(", "));75        } else {76            let generated_node_types = generated_node_types.unwrap();77            // Location exists, check each strict node type78            for &node_type in &entry.node_types {79                if strict_node_types.contains(node_type)80                    && !generated_node_types.contains(node_type)81                {82                    // For strict node types, the specific node type must be present.83                    // Check if any generated node type is also an important original node type.84                    let has_valid_node_type = generated_node_types85                        .iter()86                        .any(|gen_type| entry.node_types.contains(gen_type.as_str()));8788                    if has_valid_node_type {89                        report_missing_location(env, &entry.loc, node_type);90                    } else {91                        report_wrong_node_type(env, &entry.loc, node_type, generated_node_types);92                    }93                }94            }95        }96    }97}9899// ---- Types ----100101struct ImportantLocation {102    key: String,103    loc: AstSourceLocation,104    node_types: FxHashSet<&'static str>,105}106107// ---- Location key ----108109fn location_key(loc: &AstSourceLocation) -> String {110    format!(111        "{}:{}-{}:{}",112        loc.start.line, loc.start.column, loc.end.line, loc.end.column113    )114}115116// ---- AST to diagnostics SourceLocation conversion ----117118fn ast_to_diag_loc(loc: &AstSourceLocation) -> DiagSourceLocation {119    DiagSourceLocation {120        start: DiagPosition {121            line: loc.start.line,122            column: loc.start.column,123            index: loc.start.index,124        },125        end: DiagPosition {126            line: loc.end.line,127            column: loc.end.column,128            index: loc.end.index,129        },130    }131}132133// ---- Error reporting ----134135fn report_missing_location(env: &mut Environment, loc: &AstSourceLocation, node_type: &str) {136    let diag_loc = ast_to_diag_loc(loc);137    env.record_diagnostic(138        CompilerDiagnostic::new(139            ErrorCategory::Todo,140            "Important source location missing in generated code",141            Some(format!(142                "Source location for {} is missing in the generated output. \143                 This can cause coverage instrumentation to fail to track this \144                 code properly, resulting in inaccurate coverage reports.",145                node_type146            )),147        )148        .with_detail(CompilerDiagnosticDetail::Error {149            loc: Some(diag_loc),150            message: None,151            identifier_name: None,152        }),153    );154}155156fn report_wrong_node_type(157    env: &mut Environment,158    loc: &AstSourceLocation,159    expected_type: &str,160    actual_types: &FxHashSet<String>,161) {162    let diag_loc = ast_to_diag_loc(loc);163    let mut actual: Vec<&str> = actual_types.iter().map(|s| s.as_str()).collect();164    actual.sort();165    env.record_diagnostic(166        CompilerDiagnostic::new(167            ErrorCategory::Todo,168            "Important source location has wrong node type in generated code",169            Some(format!(170                "Source location for {} exists in the generated output but with wrong \171                 node type(s): {}. This can cause coverage instrumentation to fail to \172                 track this code properly, resulting in inaccurate coverage reports.",173                expected_type,174                actual.join(", ")175            )),176        )177        .with_detail(CompilerDiagnosticDetail::Error {178            loc: Some(diag_loc),179            message: None,180            identifier_name: None,181        }),182    );183}184185// ---- Important type checking ----186187/// Returns the Babel type name if this statement variant is an "important instrumented type".188fn important_statement_type(stmt: &Statement) -> Option<&'static str> {189    match stmt {190        Statement::ExpressionStatement(_) => Some("ExpressionStatement"),191        Statement::BreakStatement(_) => Some("BreakStatement"),192        Statement::ContinueStatement(_) => Some("ContinueStatement"),193        Statement::ReturnStatement(_) => Some("ReturnStatement"),194        Statement::ThrowStatement(_) => Some("ThrowStatement"),195        Statement::TryStatement(_) => Some("TryStatement"),196        Statement::IfStatement(_) => Some("IfStatement"),197        Statement::ForStatement(_) => Some("ForStatement"),198        Statement::ForInStatement(_) => Some("ForInStatement"),199        Statement::ForOfStatement(_) => Some("ForOfStatement"),200        Statement::WhileStatement(_) => Some("WhileStatement"),201        Statement::DoWhileStatement(_) => Some("DoWhileStatement"),202        Statement::SwitchStatement(_) => Some("SwitchStatement"),203        Statement::WithStatement(_) => Some("WithStatement"),204        Statement::FunctionDeclaration(_) => Some("FunctionDeclaration"),205        Statement::LabeledStatement(_) => Some("LabeledStatement"),206        Statement::VariableDeclaration(_) => Some("VariableDeclaration"),207        _ => None,208    }209}210211/// Returns the Babel type name if this expression variant is an "important instrumented type".212fn important_expression_type(expr: &Expression) -> Option<&'static str> {213    match expr {214        Expression::ArrowFunctionExpression(_) => Some("ArrowFunctionExpression"),215        Expression::FunctionExpression(_) => Some("FunctionExpression"),216        Expression::ConditionalExpression(_) => Some("ConditionalExpression"),217        Expression::LogicalExpression(_) => Some("LogicalExpression"),218        Expression::Identifier(_) => Some("Identifier"),219        Expression::AssignmentPattern(_) => Some("AssignmentPattern"),220        _ => None,221    }222}223224// ---- Manual memoization check ----225226fn is_manual_memoization(expr: &Expression) -> bool {227    if let Expression::CallExpression(call) = expr {228        match call.callee.as_ref() {229            Expression::Identifier(id) => id.name == "useMemo" || id.name == "useCallback",230            Expression::MemberExpression(mem) => {231                if let (Expression::Identifier(obj), Expression::Identifier(prop)) =232                    (mem.object.as_ref(), &*mem.property)233                {234                    obj.name == "React" && (prop.name == "useMemo" || prop.name == "useCallback")235                } else {236                    false237                }238            }239            _ => false,240        }241    } else {242        false243    }244}245246// ============================================================================247// Step 1: Collect important original locations248// ============================================================================249250fn collect_important_original_locations(251    func: &FunctionNode<'_>,252) -> FxHashMap<String, ImportantLocation> {253    let mut locations = FxHashMap::default();254255    // Note: TS uses func.traverse() which visits DESCENDANTS only, not the root256    // function node itself. So we don't record the root function as important.257    match func {258        FunctionNode::FunctionDeclaration(f) => {259            if let Some(id) = &f.id {260                record_important("Identifier", &id.base.loc, &mut locations);261            }262            for param in &f.params {263                collect_original_pattern(param, &mut locations);264            }265            collect_original_block(&f.body.body, false, &mut locations);266        }267        FunctionNode::FunctionExpression(f) => {268            if let Some(id) = &f.id {269                record_important("Identifier", &id.base.loc, &mut locations);270            }271            for param in &f.params {272                collect_original_pattern(param, &mut locations);273            }274            collect_original_block(&f.body.body, false, &mut locations);275        }276        FunctionNode::ArrowFunctionExpression(f) => {277            for param in &f.params {278                collect_original_pattern(param, &mut locations);279            }280            match f.body.as_ref() {281                ArrowFunctionBody::BlockStatement(block) => {282                    collect_original_block(&block.body, false, &mut locations);283                }284                ArrowFunctionBody::Expression(expr) => {285                    collect_original_expression(expr, &mut locations);286                }287            }288        }289    }290291    locations292}293294fn record_important(295    node_type: &'static str,296    loc: &Option<AstSourceLocation>,297    locations: &mut FxHashMap<String, ImportantLocation>,298) {299    if let Some(loc) = loc {300        let key = location_key(loc);301        if let Some(existing) = locations.get_mut(&key) {302            existing.node_types.insert(node_type);303        } else {304            let mut node_types = FxHashSet::default();305            node_types.insert(node_type);306            locations.insert(307                key.clone(),308                ImportantLocation {309                    key,310                    loc: loc.clone(),311                    node_types,312                },313            );314        }315    }316}317318fn collect_original_block(319    stmts: &[Statement],320    in_single_return_arrow: bool,321    locations: &mut FxHashMap<String, ImportantLocation>,322) {323    for stmt in stmts {324        collect_original_statement(stmt, in_single_return_arrow, locations);325    }326}327328fn collect_original_statement(329    stmt: &Statement,330    in_single_return_arrow: bool,331    locations: &mut FxHashMap<String, ImportantLocation>,332) {333    // Record this statement if it's an important type334    if let Some(type_name) = important_statement_type(stmt) {335        // Skip return statements inside arrow functions that will be simplified336        // to expression body: () => { return expr } -> () => expr337        if type_name == "ReturnStatement" && in_single_return_arrow {338            if let Statement::ReturnStatement(ret) = stmt {339                if ret.argument.is_some() {340                    // Skip recording, but still recurse into children341                    if let Some(arg) = &ret.argument {342                        collect_original_expression(arg, locations);343                    }344                    return;345                }346            }347        }348349        // Skip manual memoization350        if type_name == "ExpressionStatement" {351            if let Statement::ExpressionStatement(expr_stmt) = stmt {352                if is_manual_memoization(&expr_stmt.expression) {353                    // Still recurse into children354                    collect_original_expression(&expr_stmt.expression, locations);355                    return;356                }357            }358        }359360        let base_loc = statement_loc(stmt);361        record_important(type_name, base_loc, locations);362    }363364    // Recurse into children365    match stmt {366        Statement::BlockStatement(node) => {367            collect_original_block(&node.body, false, locations);368        }369        Statement::ReturnStatement(node) => {370            if let Some(arg) = &node.argument {371                collect_original_expression(arg, locations);372            }373        }374        Statement::ExpressionStatement(node) => {375            collect_original_expression(&node.expression, locations);376        }377        Statement::IfStatement(node) => {378            collect_original_expression(&node.test, locations);379            collect_original_statement(&node.consequent, false, locations);380            if let Some(alt) = &node.alternate {381                collect_original_statement(alt, false, locations);382            }383        }384        Statement::ForStatement(node) => {385            if let Some(init) = &node.init {386                match init.as_ref() {387                    ForInit::VariableDeclaration(decl) => {388                        collect_original_var_declaration(decl, locations);389                    }390                    ForInit::Expression(expr) => {391                        collect_original_expression(expr, locations);392                    }393                }394            }395            if let Some(test) = &node.test {396                collect_original_expression(test, locations);397            }398            if let Some(update) = &node.update {399                collect_original_expression(update, locations);400            }401            collect_original_statement(&node.body, false, locations);402        }403        Statement::WhileStatement(node) => {404            collect_original_expression(&node.test, locations);405            collect_original_statement(&node.body, false, locations);406        }407        Statement::DoWhileStatement(node) => {408            collect_original_statement(&node.body, false, locations);409            collect_original_expression(&node.test, locations);410        }411        Statement::ForInStatement(node) => {412            if let ForInOfLeft::Pattern(pat) = node.left.as_ref() {413                collect_original_pattern(pat, locations);414            }415            collect_original_expression(&node.right, locations);416            collect_original_statement(&node.body, false, locations);417        }418        Statement::ForOfStatement(node) => {419            if let ForInOfLeft::Pattern(pat) = node.left.as_ref() {420                collect_original_pattern(pat, locations);421            }422            collect_original_expression(&node.right, locations);423            collect_original_statement(&node.body, false, locations);424        }425        Statement::SwitchStatement(node) => {426            collect_original_expression(&node.discriminant, locations);427            for case in &node.cases {428                // SwitchCase is an important type429                record_important("SwitchCase", &case.base.loc, locations);430                if let Some(test) = &case.test {431                    collect_original_expression(test, locations);432                }433                collect_original_block(&case.consequent, false, locations);434            }435        }436        Statement::ThrowStatement(node) => {437            collect_original_expression(&node.argument, locations);438        }439        Statement::TryStatement(node) => {440            collect_original_block(&node.block.body, false, locations);441            if let Some(handler) = &node.handler {442                if let Some(param) = &handler.param {443                    collect_original_pattern(param, locations);444                }445                collect_original_block(&handler.body.body, false, locations);446            }447            if let Some(finalizer) = &node.finalizer {448                collect_original_block(&finalizer.body, false, locations);449            }450        }451        Statement::LabeledStatement(node) => {452            // Label identifier453            record_important("Identifier", &node.label.base.loc, locations);454            collect_original_statement(&node.body, false, locations);455        }456        Statement::VariableDeclaration(node) => {457            collect_original_var_declaration(node, locations);458        }459        Statement::FunctionDeclaration(node) => {460            if let Some(id) = &node.id {461                record_important("Identifier", &id.base.loc, locations);462            }463            for param in &node.params {464                collect_original_pattern(param, locations);465            }466            collect_original_block(&node.body.body, false, locations);467        }468        Statement::WithStatement(node) => {469            collect_original_expression(&node.object, locations);470            collect_original_statement(&node.body, false, locations);471        }472        // Non-runtime statements: no children to recurse into473        _ => {}474    }475}476477fn collect_original_var_declaration(478    decl: &VariableDeclaration,479    locations: &mut FxHashMap<String, ImportantLocation>,480) {481    for declarator in &decl.declarations {482        // VariableDeclarator is an important type483        record_important("VariableDeclarator", &declarator.base.loc, locations);484        collect_original_pattern(&declarator.id, locations);485        if let Some(init) = &declarator.init {486            collect_original_expression(init, locations);487        }488    }489}490491fn collect_original_expression(492    expr: &Expression,493    locations: &mut FxHashMap<String, ImportantLocation>,494) {495    // Record this expression if it's an important type496    if let Some(type_name) = important_expression_type(expr) {497        // Skip manual memoization498        if !is_manual_memoization(expr) {499            let base_loc = expression_loc(expr);500            record_important(type_name, base_loc, locations);501        }502    }503504    // Recurse into children505    match expr {506        Expression::Identifier(_) => {507            // Already recorded above if important. No children.508        }509        Expression::CallExpression(node) => {510            collect_original_expression(&node.callee, locations);511            for arg in &node.arguments {512                collect_original_expression(arg, locations);513            }514        }515        Expression::MemberExpression(node) => {516            collect_original_expression(&node.object, locations);517            if node.computed {518                collect_original_expression(&node.property, locations);519            } else {520                // Non-computed property is an Identifier - record it521                if let Expression::Identifier(id) = node.property.as_ref() {522                    record_important("Identifier", &id.base.loc, locations);523                }524            }525        }526        Expression::OptionalCallExpression(node) => {527            collect_original_expression(&node.callee, locations);528            for arg in &node.arguments {529                collect_original_expression(arg, locations);530            }531        }532        Expression::OptionalMemberExpression(node) => {533            collect_original_expression(&node.object, locations);534            if node.computed {535                collect_original_expression(&node.property, locations);536            } else if let Expression::Identifier(id) = node.property.as_ref() {537                record_important("Identifier", &id.base.loc, locations);538            }539        }540        Expression::BinaryExpression(node) => {541            collect_original_expression(&node.left, locations);542            collect_original_expression(&node.right, locations);543        }544        Expression::LogicalExpression(node) => {545            collect_original_expression(&node.left, locations);546            collect_original_expression(&node.right, locations);547        }548        Expression::UnaryExpression(node) => {549            collect_original_expression(&node.argument, locations);550        }551        Expression::UpdateExpression(node) => {552            collect_original_expression(&node.argument, locations);553        }554        Expression::ConditionalExpression(node) => {555            collect_original_expression(&node.test, locations);556            collect_original_expression(&node.consequent, locations);557            collect_original_expression(&node.alternate, locations);558        }559        Expression::AssignmentExpression(node) => {560            collect_original_pattern(&node.left, locations);561            collect_original_expression(&node.right, locations);562        }563        Expression::SequenceExpression(node) => {564            for e in &node.expressions {565                collect_original_expression(e, locations);566            }567        }568        Expression::ArrowFunctionExpression(node) => {569            collect_original_arrow_children(node, locations);570        }571        Expression::FunctionExpression(node) => {572            collect_original_fn_expr_children(node, locations);573        }574        Expression::ObjectExpression(node) => {575            for prop in &node.properties {576                match prop {577                    ObjectExpressionProperty::ObjectProperty(p) => {578                        if p.computed {579                            collect_original_expression(&p.key, locations);580                        } else if let Expression::Identifier(id) = p.key.as_ref() {581                            record_important("Identifier", &id.base.loc, locations);582                        }583                        collect_original_expression(&p.value, locations);584                    }585                    ObjectExpressionProperty::ObjectMethod(m) => {586                        // ObjectMethod is an important type587                        record_important("ObjectMethod", &m.base.loc, locations);588                        for param in &m.params {589                            collect_original_pattern(param, locations);590                        }591                        collect_original_block(&m.body.body, false, locations);592                    }593                    ObjectExpressionProperty::SpreadElement(s) => {594                        collect_original_expression(&s.argument, locations);595                    }596                }597            }598        }599        Expression::ArrayExpression(node) => {600            for elem in node.elements.iter().flatten() {601                collect_original_expression(elem, locations);602            }603        }604        Expression::NewExpression(node) => {605            collect_original_expression(&node.callee, locations);606            for arg in &node.arguments {607                collect_original_expression(arg, locations);608            }609        }610        Expression::TemplateLiteral(node) => {611            for e in &node.expressions {612                collect_original_expression(e, locations);613            }614        }615        Expression::TaggedTemplateExpression(node) => {616            collect_original_expression(&node.tag, locations);617            for e in &node.quasi.expressions {618                collect_original_expression(e, locations);619            }620        }621        Expression::AwaitExpression(node) => {622            collect_original_expression(&node.argument, locations);623        }624        Expression::YieldExpression(node) => {625            if let Some(arg) = &node.argument {626                collect_original_expression(arg, locations);627            }628        }629        Expression::SpreadElement(node) => {630            collect_original_expression(&node.argument, locations);631        }632        Expression::ParenthesizedExpression(node) => {633            collect_original_expression(&node.expression, locations);634        }635        Expression::AssignmentPattern(node) => {636            collect_original_pattern(&node.left, locations);637            collect_original_expression(&node.right, locations);638        }639        Expression::ClassExpression(node) => {640            if let Some(sc) = &node.super_class {641                collect_original_expression(sc, locations);642            }643        }644        // TS/Flow wrappers — traverse inner expression645        Expression::TSAsExpression(node) => {646            collect_original_expression(&node.expression, locations);647        }648        Expression::TSSatisfiesExpression(node) => {649            collect_original_expression(&node.expression, locations);650        }651        Expression::TSNonNullExpression(node) => {652            collect_original_expression(&node.expression, locations);653        }654        Expression::TSTypeAssertion(node) => {655            collect_original_expression(&node.expression, locations);656        }657        Expression::TSInstantiationExpression(node) => {658            collect_original_expression(&node.expression, locations);659        }660        Expression::TypeCastExpression(node) => {661            collect_original_expression(&node.expression, locations);662        }663        // Leaf nodes and JSX664        _ => {}665    }666}667668fn collect_original_arrow_children(669    arrow: &ArrowFunctionExpression,670    locations: &mut FxHashMap<String, ImportantLocation>,671) {672    for param in &arrow.params {673        collect_original_pattern(param, locations);674    }675    match arrow.body.as_ref() {676        ArrowFunctionBody::BlockStatement(block) => {677            let is_single_return = block.body.len() == 1 && block.directives.is_empty();678            collect_original_block(&block.body, is_single_return, locations);679        }680        ArrowFunctionBody::Expression(expr) => {681            collect_original_expression(expr, locations);682        }683    }684}685686fn collect_original_fn_expr_children(687    func: &FunctionExpression,688    locations: &mut FxHashMap<String, ImportantLocation>,689) {690    if let Some(id) = &func.id {691        record_important("Identifier", &id.base.loc, locations);692    }693    for param in &func.params {694        collect_original_pattern(param, locations);695    }696    collect_original_block(&func.body.body, false, locations);697}698699fn collect_original_pattern(700    pattern: &PatternLike,701    locations: &mut FxHashMap<String, ImportantLocation>,702) {703    match pattern {704        PatternLike::Identifier(id) => {705            record_important("Identifier", &id.base.loc, locations);706        }707        PatternLike::AssignmentPattern(ap) => {708            record_important("AssignmentPattern", &ap.base.loc, locations);709            collect_original_pattern(&ap.left, locations);710            collect_original_expression(&ap.right, locations);711        }712        PatternLike::ObjectPattern(op) => {713            for prop in &op.properties {714                match prop {715                    react_compiler_ast::patterns::ObjectPatternProperty::ObjectProperty(p) => {716                        if p.computed {717                            collect_original_expression(&p.key, locations);718                        } else if let Expression::Identifier(id) = p.key.as_ref() {719                            record_important("Identifier", &id.base.loc, locations);720                        }721                        collect_original_pattern(&p.value, locations);722                    }723                    react_compiler_ast::patterns::ObjectPatternProperty::RestElement(r) => {724                        collect_original_pattern(&r.argument, locations);725                    }726                }727            }728        }729        PatternLike::ArrayPattern(ap) => {730            for elem in ap.elements.iter().flatten() {731                collect_original_pattern(elem, locations);732            }733        }734        PatternLike::RestElement(r) => {735            collect_original_pattern(&r.argument, locations);736        }737        PatternLike::MemberExpression(m) => {738            collect_original_expression(&Expression::MemberExpression(m.clone()), locations);739        }740        PatternLike::TSAsExpression(_)741        | PatternLike::TSSatisfiesExpression(_)742        | PatternLike::TSNonNullExpression(_)743        | PatternLike::TSTypeAssertion(_)744        | PatternLike::TypeCastExpression(_) => {}745    }746}747748// ---- Helpers to get loc from statement/expression ----749750fn statement_loc(stmt: &Statement) -> &Option<AstSourceLocation> {751    match stmt {752        Statement::BlockStatement(n) => &n.base.loc,753        Statement::ReturnStatement(n) => &n.base.loc,754        Statement::IfStatement(n) => &n.base.loc,755        Statement::ForStatement(n) => &n.base.loc,756        Statement::WhileStatement(n) => &n.base.loc,757        Statement::DoWhileStatement(n) => &n.base.loc,758        Statement::ForInStatement(n) => &n.base.loc,759        Statement::ForOfStatement(n) => &n.base.loc,760        Statement::SwitchStatement(n) => &n.base.loc,761        Statement::ThrowStatement(n) => &n.base.loc,762        Statement::TryStatement(n) => &n.base.loc,763        Statement::BreakStatement(n) => &n.base.loc,764        Statement::ContinueStatement(n) => &n.base.loc,765        Statement::LabeledStatement(n) => &n.base.loc,766        Statement::ExpressionStatement(n) => &n.base.loc,767        Statement::EmptyStatement(n) => &n.base.loc,768        Statement::DebuggerStatement(n) => &n.base.loc,769        Statement::WithStatement(n) => &n.base.loc,770        Statement::VariableDeclaration(n) => &n.base.loc,771        Statement::FunctionDeclaration(n) => &n.base.loc,772        Statement::ClassDeclaration(n) => &n.base.loc,773        Statement::ImportDeclaration(n) => &n.base.loc,774        Statement::ExportNamedDeclaration(n) => &n.base.loc,775        Statement::ExportDefaultDeclaration(n) => &n.base.loc,776        Statement::ExportAllDeclaration(n) => &n.base.loc,777        Statement::TSTypeAliasDeclaration(n) => &n.base.loc,778        Statement::TSInterfaceDeclaration(n) => &n.base.loc,779        Statement::TSEnumDeclaration(n) => &n.base.loc,780        Statement::TSModuleDeclaration(n) => &n.base.loc,781        Statement::TSDeclareFunction(n) => &n.base.loc,782        Statement::TypeAlias(n) => &n.base.loc,783        Statement::OpaqueType(n) => &n.base.loc,784        Statement::InterfaceDeclaration(n) => &n.base.loc,785        Statement::DeclareVariable(n) => &n.base.loc,786        Statement::DeclareFunction(n) => &n.base.loc,787        Statement::DeclareClass(n) => &n.base.loc,788        Statement::DeclareModule(n) => &n.base.loc,789        Statement::DeclareModuleExports(n) => &n.base.loc,790        Statement::DeclareExportDeclaration(n) => &n.base.loc,791        Statement::DeclareExportAllDeclaration(n) => &n.base.loc,792        Statement::DeclareInterface(n) => &n.base.loc,793        Statement::DeclareTypeAlias(n) => &n.base.loc,794        Statement::DeclareOpaqueType(n) => &n.base.loc,795        Statement::EnumDeclaration(n) => &n.base.loc,796        Statement::Unknown(n) => &n.base().loc,797    }798}799800fn expression_loc(expr: &Expression) -> &Option<AstSourceLocation> {801    match expr {802        Expression::Identifier(n) => &n.base.loc,803        Expression::StringLiteral(n) => &n.base.loc,804        Expression::NumericLiteral(n) => &n.base.loc,805        Expression::BooleanLiteral(n) => &n.base.loc,806        Expression::NullLiteral(n) => &n.base.loc,807        Expression::BigIntLiteral(n) => &n.base.loc,808        Expression::RegExpLiteral(n) => &n.base.loc,809        Expression::CallExpression(n) => &n.base.loc,810        Expression::MemberExpression(n) => &n.base.loc,811        Expression::OptionalCallExpression(n) => &n.base.loc,812        Expression::OptionalMemberExpression(n) => &n.base.loc,813        Expression::BinaryExpression(n) => &n.base.loc,814        Expression::LogicalExpression(n) => &n.base.loc,815        Expression::UnaryExpression(n) => &n.base.loc,816        Expression::UpdateExpression(n) => &n.base.loc,817        Expression::ConditionalExpression(n) => &n.base.loc,818        Expression::AssignmentExpression(n) => &n.base.loc,819        Expression::SequenceExpression(n) => &n.base.loc,820        Expression::ArrowFunctionExpression(n) => &n.base.loc,821        Expression::FunctionExpression(n) => &n.base.loc,822        Expression::ObjectExpression(n) => &n.base.loc,823        Expression::ArrayExpression(n) => &n.base.loc,824        Expression::NewExpression(n) => &n.base.loc,825        Expression::TemplateLiteral(n) => &n.base.loc,826        Expression::TaggedTemplateExpression(n) => &n.base.loc,827        Expression::AwaitExpression(n) => &n.base.loc,828        Expression::YieldExpression(n) => &n.base.loc,829        Expression::SpreadElement(n) => &n.base.loc,830        Expression::MetaProperty(n) => &n.base.loc,831        Expression::ClassExpression(n) => &n.base.loc,832        Expression::PrivateName(n) => &n.base.loc,833        Expression::Super(n) => &n.base.loc,834        Expression::Import(n) => &n.base.loc,835        Expression::ThisExpression(n) => &n.base.loc,836        Expression::ParenthesizedExpression(n) => &n.base.loc,837        Expression::AssignmentPattern(n) => &n.base.loc,838        Expression::JSXElement(n) => &n.base.loc,839        Expression::JSXFragment(n) => &n.base.loc,840        Expression::TSAsExpression(n) => &n.base.loc,841        Expression::TSSatisfiesExpression(n) => &n.base.loc,842        Expression::TSNonNullExpression(n) => &n.base.loc,843        Expression::TSTypeAssertion(n) => &n.base.loc,844        Expression::TSInstantiationExpression(n) => &n.base.loc,845        Expression::TypeCastExpression(n) => &n.base.loc,846    }847}848849// ============================================================================850// Step 2: Collect generated locations (ALL node types, not just important ones)851// ============================================================================852853fn collect_generated_from_block(854    stmts: &[Statement],855    locations: &mut FxHashMap<String, FxHashSet<String>>,856) {857    for stmt in stmts {858        collect_generated_statement(stmt, locations);859    }860}861862fn record_generated(863    type_name: &str,864    loc: &Option<AstSourceLocation>,865    locations: &mut FxHashMap<String, FxHashSet<String>>,866) {867    if let Some(loc) = loc {868        let key = location_key(loc);869        locations870            .entry(key)871            .or_default()872            .insert(type_name.to_string());873    }874}875876fn collect_generated_statement(877    stmt: &Statement,878    locations: &mut FxHashMap<String, FxHashSet<String>>,879) {880    // Record this statement's location881    let type_name = statement_type_name(stmt);882    record_generated(type_name, statement_loc(stmt), locations);883884    // Recurse into children (same structure as original, but record ALL types)885    match stmt {886        Statement::BlockStatement(node) => {887            collect_generated_from_block(&node.body, locations);888        }889        Statement::ReturnStatement(node) => {890            if let Some(arg) = &node.argument {891                collect_generated_expression(arg, locations);892            }893        }894        Statement::ExpressionStatement(node) => {895            collect_generated_expression(&node.expression, locations);896        }897        Statement::IfStatement(node) => {898            collect_generated_expression(&node.test, locations);899            collect_generated_statement(&node.consequent, locations);900            if let Some(alt) = &node.alternate {901                collect_generated_statement(alt, locations);902            }903        }904        Statement::ForStatement(node) => {905            if let Some(init) = &node.init {906                match init.as_ref() {907                    ForInit::VariableDeclaration(decl) => {908                        collect_generated_var_declaration(decl, locations);909                    }910                    ForInit::Expression(expr) => {911                        collect_generated_expression(expr, locations);912                    }913                }914            }915            if let Some(test) = &node.test {916                collect_generated_expression(test, locations);917            }918            if let Some(update) = &node.update {919                collect_generated_expression(update, locations);920            }921            collect_generated_statement(&node.body, locations);922        }923        Statement::WhileStatement(node) => {924            collect_generated_expression(&node.test, locations);925            collect_generated_statement(&node.body, locations);926        }927        Statement::DoWhileStatement(node) => {928            collect_generated_statement(&node.body, locations);929            collect_generated_expression(&node.test, locations);930        }931        Statement::ForInStatement(node) => {932            match node.left.as_ref() {933                ForInOfLeft::VariableDeclaration(decl) => {934                    collect_generated_var_declaration(decl, locations);935                }936                ForInOfLeft::Pattern(pat) => {937                    collect_generated_pattern(pat, locations);938                }939            }940            collect_generated_expression(&node.right, locations);941            collect_generated_statement(&node.body, locations);942        }943        Statement::ForOfStatement(node) => {944            match node.left.as_ref() {945                ForInOfLeft::VariableDeclaration(decl) => {946                    collect_generated_var_declaration(decl, locations);947                }948                ForInOfLeft::Pattern(pat) => {949                    collect_generated_pattern(pat, locations);950                }951            }952            collect_generated_expression(&node.right, locations);953            collect_generated_statement(&node.body, locations);954        }955        Statement::SwitchStatement(node) => {956            collect_generated_expression(&node.discriminant, locations);957            for case in &node.cases {958                record_generated("SwitchCase", &case.base.loc, locations);959                if let Some(test) = &case.test {960                    collect_generated_expression(test, locations);961                }962                collect_generated_from_block(&case.consequent, locations);963            }964        }965        Statement::ThrowStatement(node) => {966            collect_generated_expression(&node.argument, locations);967        }968        Statement::TryStatement(node) => {969            collect_generated_from_block(&node.block.body, locations);970            if let Some(handler) = &node.handler {971                if let Some(param) = &handler.param {972                    collect_generated_pattern(param, locations);973                }974                collect_generated_from_block(&handler.body.body, locations);975            }976            if let Some(finalizer) = &node.finalizer {977                collect_generated_from_block(&finalizer.body, locations);978            }979        }980        Statement::LabeledStatement(node) => {981            record_generated("Identifier", &node.label.base.loc, locations);982            collect_generated_statement(&node.body, locations);983        }984        Statement::VariableDeclaration(node) => {985            collect_generated_var_declaration(node, locations);986        }987        Statement::FunctionDeclaration(node) => {988            if let Some(id) = &node.id {989                record_generated("Identifier", &id.base.loc, locations);990            }991            for param in &node.params {992                collect_generated_pattern(param, locations);993            }994            collect_generated_from_block(&node.body.body, locations);995        }996        Statement::WithStatement(node) => {997            collect_generated_expression(&node.object, locations);998            collect_generated_statement(&node.body, locations);999        }1000        Statement::ClassDeclaration(node) => {1001            if let Some(id) = &node.id {1002                record_generated("Identifier", &id.base.loc, locations);1003            }1004            if let Some(sc) = &node.super_class {1005                collect_generated_expression(sc, locations);1006            }1007        }1008        _ => {}1009    }1010}10111012fn collect_generated_var_declaration(1013    decl: &VariableDeclaration,1014    locations: &mut FxHashMap<String, FxHashSet<String>>,1015) {1016    for declarator in &decl.declarations {1017        record_generated("VariableDeclarator", &declarator.base.loc, locations);1018        collect_generated_pattern(&declarator.id, locations);1019        if let Some(init) = &declarator.init {1020            collect_generated_expression(init, locations);1021        }1022    }1023}10241025fn collect_generated_expression(1026    expr: &Expression,1027    locations: &mut FxHashMap<String, FxHashSet<String>>,1028) {1029    let type_name = expression_type_name(expr);1030    record_generated(type_name, expression_loc(expr), locations);10311032    match expr {1033        Expression::Identifier(_) => {}1034        Expression::CallExpression(node) => {1035            collect_generated_expression(&node.callee, locations);1036            for arg in &node.arguments {1037                collect_generated_expression(arg, locations);1038            }1039        }1040        Expression::MemberExpression(node) => {1041            collect_generated_expression(&node.object, locations);1042            collect_generated_expression(&node.property, locations);1043        }1044        Expression::OptionalCallExpression(node) => {1045            collect_generated_expression(&node.callee, locations);1046            for arg in &node.arguments {1047                collect_generated_expression(arg, locations);1048            }1049        }1050        Expression::OptionalMemberExpression(node) => {1051            collect_generated_expression(&node.object, locations);1052            collect_generated_expression(&node.property, locations);1053        }1054        Expression::BinaryExpression(node) => {1055            collect_generated_expression(&node.left, locations);1056            collect_generated_expression(&node.right, locations);1057        }1058        Expression::LogicalExpression(node) => {1059            collect_generated_expression(&node.left, locations);1060            collect_generated_expression(&node.right, locations);1061        }1062        Expression::UnaryExpression(node) => {1063            collect_generated_expression(&node.argument, locations);1064        }1065        Expression::UpdateExpression(node) => {1066            collect_generated_expression(&node.argument, locations);1067        }1068        Expression::ConditionalExpression(node) => {1069            collect_generated_expression(&node.test, locations);1070            collect_generated_expression(&node.consequent, locations);1071            collect_generated_expression(&node.alternate, locations);1072        }1073        Expression::AssignmentExpression(node) => {1074            collect_generated_pattern(&node.left, locations);1075            collect_generated_expression(&node.right, locations);1076        }1077        Expression::SequenceExpression(node) => {1078            for e in &node.expressions {1079                collect_generated_expression(e, locations);1080            }1081        }1082        Expression::ArrowFunctionExpression(node) => {1083            for param in &node.params {1084                collect_generated_pattern(param, locations);1085            }1086            match node.body.as_ref() {1087                ArrowFunctionBody::BlockStatement(block) => {1088                    collect_generated_from_block(&block.body, locations);1089                }1090                ArrowFunctionBody::Expression(e) => {1091                    collect_generated_expression(e, locations);1092                }1093            }1094        }1095        Expression::FunctionExpression(node) => {1096            if let Some(id) = &node.id {1097                record_generated("Identifier", &id.base.loc, locations);1098            }1099            for param in &node.params {1100                collect_generated_pattern(param, locations);1101            }1102            collect_generated_from_block(&node.body.body, locations);1103        }1104        Expression::ObjectExpression(node) => {1105            for prop in &node.properties {1106                match prop {1107                    ObjectExpressionProperty::ObjectProperty(p) => {1108                        collect_generated_expression(&p.key, locations);1109                        collect_generated_expression(&p.value, locations);1110                    }1111                    ObjectExpressionProperty::ObjectMethod(m) => {1112                        record_generated("ObjectMethod", &m.base.loc, locations);1113                        for param in &m.params {1114                            collect_generated_pattern(param, locations);1115                        }1116                        collect_generated_from_block(&m.body.body, locations);1117                    }1118                    ObjectExpressionProperty::SpreadElement(s) => {1119                        collect_generated_expression(&s.argument, locations);1120                    }1121                }1122            }1123        }1124        Expression::ArrayExpression(node) => {1125            for elem in node.elements.iter().flatten() {1126                collect_generated_expression(elem, locations);1127            }1128        }1129        Expression::NewExpression(node) => {1130            collect_generated_expression(&node.callee, locations);1131            for arg in &node.arguments {1132                collect_generated_expression(arg, locations);1133            }1134        }1135        Expression::TemplateLiteral(node) => {1136            for e in &node.expressions {1137                collect_generated_expression(e, locations);1138            }1139        }1140        Expression::TaggedTemplateExpression(node) => {1141            collect_generated_expression(&node.tag, locations);1142            for e in &node.quasi.expressions {1143                collect_generated_expression(e, locations);1144            }1145        }1146        Expression::AwaitExpression(node) => {1147            collect_generated_expression(&node.argument, locations);1148        }1149        Expression::YieldExpression(node) => {1150            if let Some(arg) = &node.argument {1151                collect_generated_expression(arg, locations);1152            }1153        }1154        Expression::SpreadElement(node) => {1155            collect_generated_expression(&node.argument, locations);1156        }1157        Expression::ParenthesizedExpression(node) => {1158            collect_generated_expression(&node.expression, locations);1159        }1160        Expression::AssignmentPattern(node) => {1161            collect_generated_pattern(&node.left, locations);1162            collect_generated_expression(&node.right, locations);1163        }1164        Expression::ClassExpression(node) => {1165            if let Some(sc) = &node.super_class {1166                collect_generated_expression(sc, locations);1167            }1168        }1169        Expression::TSAsExpression(node) => {1170            collect_generated_expression(&node.expression, locations);1171        }1172        Expression::TSSatisfiesExpression(node) => {1173            collect_generated_expression(&node.expression, locations);1174        }1175        Expression::TSNonNullExpression(node) => {1176            collect_generated_expression(&node.expression, locations);1177        }1178        Expression::TSTypeAssertion(node) => {1179            collect_generated_expression(&node.expression, locations);1180        }1181        Expression::TSInstantiationExpression(node) => {1182            collect_generated_expression(&node.expression, locations);1183        }1184        Expression::TypeCastExpression(node) => {1185            collect_generated_expression(&node.expression, locations);1186        }1187        // Leaf nodes and JSX1188        _ => {}1189    }1190}11911192fn collect_generated_pattern(1193    pattern: &PatternLike,1194    locations: &mut FxHashMap<String, FxHashSet<String>>,1195) {1196    match pattern {1197        PatternLike::Identifier(id) => {1198            record_generated("Identifier", &id.base.loc, locations);1199        }1200        PatternLike::AssignmentPattern(ap) => {1201            record_generated("AssignmentPattern", &ap.base.loc, locations);1202            collect_generated_pattern(&ap.left, locations);1203            collect_generated_expression(&ap.right, locations);1204        }1205        PatternLike::ObjectPattern(op) => {1206            record_generated("ObjectPattern", &op.base.loc, locations);1207            for prop in &op.properties {1208                match prop {1209                    react_compiler_ast::patterns::ObjectPatternProperty::ObjectProperty(p) => {1210                        record_generated("ObjectProperty", &p.base.loc, locations);1211                        collect_generated_expression(&p.key, locations);1212                        collect_generated_pattern(&p.value, locations);1213                    }1214                    react_compiler_ast::patterns::ObjectPatternProperty::RestElement(r) => {1215                        record_generated("RestElement", &r.base.loc, locations);1216                        collect_generated_pattern(&r.argument, locations);1217                    }1218                }1219            }1220        }1221        PatternLike::ArrayPattern(ap) => {1222            record_generated("ArrayPattern", &ap.base.loc, locations);1223            for elem in ap.elements.iter().flatten() {1224                collect_generated_pattern(elem, locations);1225            }1226        }1227        PatternLike::RestElement(r) => {1228            record_generated("RestElement", &r.base.loc, locations);1229            collect_generated_pattern(&r.argument, locations);1230        }1231        PatternLike::MemberExpression(m) => {1232            record_generated("MemberExpression", &m.base.loc, locations);1233            collect_generated_expression(&m.object, locations);1234            collect_generated_expression(&m.property, locations);1235        }1236        PatternLike::TSAsExpression(_)1237        | PatternLike::TSSatisfiesExpression(_)1238        | PatternLike::TSNonNullExpression(_)1239        | PatternLike::TSTypeAssertion(_)1240        | PatternLike::TypeCastExpression(_) => {}1241    }1242}12431244// ---- Type name helpers ----12451246fn statement_type_name(stmt: &Statement) -> &'static str {1247    match stmt {1248        Statement::BlockStatement(_) => "BlockStatement",1249        Statement::ReturnStatement(_) => "ReturnStatement",1250        Statement::IfStatement(_) => "IfStatement",1251        Statement::ForStatement(_) => "ForStatement",1252        Statement::WhileStatement(_) => "WhileStatement",1253        Statement::DoWhileStatement(_) => "DoWhileStatement",1254        Statement::ForInStatement(_) => "ForInStatement",1255        Statement::ForOfStatement(_) => "ForOfStatement",1256        Statement::SwitchStatement(_) => "SwitchStatement",1257        Statement::ThrowStatement(_) => "ThrowStatement",1258        Statement::TryStatement(_) => "TryStatement",1259        Statement::BreakStatement(_) => "BreakStatement",1260        Statement::ContinueStatement(_) => "ContinueStatement",1261        Statement::LabeledStatement(_) => "LabeledStatement",1262        Statement::ExpressionStatement(_) => "ExpressionStatement",1263        Statement::EmptyStatement(_) => "EmptyStatement",1264        Statement::DebuggerStatement(_) => "DebuggerStatement",1265        Statement::WithStatement(_) => "WithStatement",1266        Statement::VariableDeclaration(_) => "VariableDeclaration",1267        Statement::FunctionDeclaration(_) => "FunctionDeclaration",1268        Statement::ClassDeclaration(_) => "ClassDeclaration",1269        Statement::ImportDeclaration(_) => "ImportDeclaration",1270        Statement::ExportNamedDeclaration(_) => "ExportNamedDeclaration",1271        Statement::ExportDefaultDeclaration(_) => "ExportDefaultDeclaration",1272        Statement::ExportAllDeclaration(_) => "ExportAllDeclaration",1273        Statement::TSTypeAliasDeclaration(_) => "TSTypeAliasDeclaration",1274        Statement::TSInterfaceDeclaration(_) => "TSInterfaceDeclaration",1275        Statement::TSEnumDeclaration(_) => "TSEnumDeclaration",1276        Statement::TSModuleDeclaration(_) => "TSModuleDeclaration",1277        Statement::TSDeclareFunction(_) => "TSDeclareFunction",1278        Statement::TypeAlias(_) => "TypeAlias",1279        Statement::OpaqueType(_) => "OpaqueType",1280        Statement::InterfaceDeclaration(_) => "InterfaceDeclaration",1281        Statement::DeclareVariable(_) => "DeclareVariable",1282        Statement::DeclareFunction(_) => "DeclareFunction",1283        Statement::DeclareClass(_) => "DeclareClass",1284        Statement::DeclareModule(_) => "DeclareModule",1285        Statement::DeclareModuleExports(_) => "DeclareModuleExports",1286        Statement::DeclareExportDeclaration(_) => "DeclareExportDeclaration",1287        Statement::DeclareExportAllDeclaration(_) => "DeclareExportAllDeclaration",1288        Statement::DeclareInterface(_) => "DeclareInterface",1289        Statement::DeclareTypeAlias(_) => "DeclareTypeAlias",1290        Statement::DeclareOpaqueType(_) => "DeclareOpaqueType",1291        Statement::EnumDeclaration(_) => "EnumDeclaration",1292        // The real Babel `type` lives in the raw node, but this function1293        // returns &'static str; "Unknown" is the static stand-in.1294        Statement::Unknown(_) => "Unknown",1295    }1296}12971298fn expression_type_name(expr: &Expression) -> &'static str {1299    match expr {1300        Expression::Identifier(_) => "Identifier",1301        Expression::StringLiteral(_) => "StringLiteral",1302        Expression::NumericLiteral(_) => "NumericLiteral",1303        Expression::BooleanLiteral(_) => "BooleanLiteral",1304        Expression::NullLiteral(_) => "NullLiteral",1305        Expression::BigIntLiteral(_) => "BigIntLiteral",1306        Expression::RegExpLiteral(_) => "RegExpLiteral",1307        Expression::CallExpression(_) => "CallExpression",1308        Expression::MemberExpression(_) => "MemberExpression",1309        Expression::OptionalCallExpression(_) => "OptionalCallExpression",1310        Expression::OptionalMemberExpression(_) => "OptionalMemberExpression",1311        Expression::BinaryExpression(_) => "BinaryExpression",1312        Expression::LogicalExpression(_) => "LogicalExpression",1313        Expression::UnaryExpression(_) => "UnaryExpression",1314        Expression::UpdateExpression(_) => "UpdateExpression",1315        Expression::ConditionalExpression(_) => "ConditionalExpression",1316        Expression::AssignmentExpression(_) => "AssignmentExpression",1317        Expression::SequenceExpression(_) => "SequenceExpression",1318        Expression::ArrowFunctionExpression(_) => "ArrowFunctionExpression",1319        Expression::FunctionExpression(_) => "FunctionExpression",1320        Expression::ObjectExpression(_) => "ObjectExpression",1321        Expression::ArrayExpression(_) => "ArrayExpression",1322        Expression::NewExpression(_) => "NewExpression",1323        Expression::TemplateLiteral(_) => "TemplateLiteral",1324        Expression::TaggedTemplateExpression(_) => "TaggedTemplateExpression",1325        Expression::AwaitExpression(_) => "AwaitExpression",1326        Expression::YieldExpression(_) => "YieldExpression",1327        Expression::SpreadElement(_) => "SpreadElement",1328        Expression::MetaProperty(_) => "MetaProperty",1329        Expression::ClassExpression(_) => "ClassExpression",1330        Expression::PrivateName(_) => "PrivateName",1331        Expression::Super(_) => "Super",1332        Expression::Import(_) => "Import",1333        Expression::ThisExpression(_) => "ThisExpression",1334        Expression::ParenthesizedExpression(_) => "ParenthesizedExpression",1335        Expression::AssignmentPattern(_) => "AssignmentPattern",1336        Expression::JSXElement(_) => "JSXElement",1337        Expression::JSXFragment(_) => "JSXFragment",1338        Expression::TSAsExpression(_) => "TSAsExpression",1339        Expression::TSSatisfiesExpression(_) => "TSSatisfiesExpression",1340        Expression::TSNonNullExpression(_) => "TSNonNullExpression",1341        Expression::TSTypeAssertion(_) => "TSTypeAssertion",1342        Expression::TSInstantiationExpression(_) => "TSInstantiationExpression",1343        Expression::TypeCastExpression(_) => "TypeCastExpression",1344    }1345}

Code quality findings 3

Warning: '.unwrap()' will panic on None/Err variants. Prefer using pattern matching (match, if let), combinators (map, and_then), or the '?' operator for robust error handling.
warning correctness unwrap-usage
let generated_node_types = generated_node_types.unwrap();
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 expr {
Performance Info: Frequent cloning, especially of Strings, Vecs, or other heap-allocated types inside loops, can be expensive. Consider using references/borrowing where possible.
info performance clone-in-loop
collect_original_expression(&Expression::MemberExpression(m.clone()), locations);

Get this view in your editor

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