main
rs 1,345 lines 55.5 KB
Raw
1 // Copyright (c) Meta Platforms, Inc. and affiliates.
2 //
3 // This source code is licensed under the MIT license found in the
4 // LICENSE file in the root directory of this source tree.
5
6 //! Validates that important source locations from the original code are preserved
7 //! in the generated AST. This ensures that Istanbul coverage instrumentation can
8 //! 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`.
13
14 use rustc_hash::{FxHashMap, FxHashSet};
15
16 use react_compiler_ast::common::SourceLocation as AstSourceLocation;
17 use react_compiler_ast::expressions::{
18 ArrowFunctionBody, ArrowFunctionExpression, Expression, FunctionExpression,
19 ObjectExpressionProperty,
20 };
21 use react_compiler_ast::patterns::PatternLike;
22 use react_compiler_ast::statements::{ForInOfLeft, ForInit, Statement, VariableDeclaration};
23 use react_compiler_diagnostics::{
24 CompilerDiagnostic, CompilerDiagnosticDetail, ErrorCategory, Position as DiagPosition,
25 SourceLocation as DiagSourceLocation,
26 };
27 use react_compiler_hir::environment::Environment;
28 use react_compiler_lowering::FunctionNode;
29 use react_compiler_reactive_scopes::codegen_reactive_function::CodegenFunction;
30
31 /// Validate that important source locations are preserved in the generated AST.
32 pub fn validate_source_locations(
33 func: &FunctionNode<'_>,
34 codegen: &CodegenFunction,
35 env: &mut Environment,
36 ) {
37 // Step 1: Collect important locations from the original source
38 let important_original = collect_important_original_locations(func);
39
40 // Step 2: Collect all locations from the generated AST
41 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 }
46
47 // Step 3: Validate that all important locations are preserved
48 let strict_node_types: FxHashSet<&str> =
49 ["VariableDeclaration", "VariableDeclarator", "Identifier"]
50 .into_iter()
51 .collect();
52
53 // Sort entries by source position to match TS output order
54 // (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.loc
58 .start
59 .line
60 .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 traversal
63 .then(b.loc.end.line.cmp(&a.loc.end.line))
64 .then(b.loc.end.column.cmp(&a.loc.end.column))
65 });
66
67 for entry in &sorted_entries {
68 let generated_node_types = generated.get(&entry.key);
69
70 if generated_node_types.is_none() {
71 // Location is completely missing
72 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 type
78 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_types
85 .iter()
86 .any(|gen_type| entry.node_types.contains(gen_type.as_str()));
87
88 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 }
98
99 // ---- Types ----
100
101 struct ImportantLocation {
102 key: String,
103 loc: AstSourceLocation,
104 node_types: FxHashSet<&'static str>,
105 }
106
107 // ---- Location key ----
108
109 fn location_key(loc: &AstSourceLocation) -> String {
110 format!(
111 "{}:{}-{}:{}",
112 loc.start.line, loc.start.column, loc.end.line, loc.end.column
113 )
114 }
115
116 // ---- AST to diagnostics SourceLocation conversion ----
117
118 fn 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 }
132
133 // ---- Error reporting ----
134
135 fn 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_type
146 )),
147 )
148 .with_detail(CompilerDiagnosticDetail::Error {
149 loc: Some(diag_loc),
150 message: None,
151 identifier_name: None,
152 }),
153 );
154 }
155
156 fn 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 }
184
185 // ---- Important type checking ----
186
187 /// Returns the Babel type name if this statement variant is an "important instrumented type".
188 fn 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 }
210
211 /// Returns the Babel type name if this expression variant is an "important instrumented type".
212 fn 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 }
223
224 // ---- Manual memoization check ----
225
226 fn 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 false
237 }
238 }
239 _ => false,
240 }
241 } else {
242 false
243 }
244 }
245
246 // ============================================================================
247 // Step 1: Collect important original locations
248 // ============================================================================
249
250 fn collect_important_original_locations(
251 func: &FunctionNode<'_>,
252 ) -> FxHashMap<String, ImportantLocation> {
253 let mut locations = FxHashMap::default();
254
255 // Note: TS uses func.traverse() which visits DESCENDANTS only, not the root
256 // 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 }
290
291 locations
292 }
293
294 fn 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 }
317
318 fn 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 }
327
328 fn 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 type
334 if let Some(type_name) = important_statement_type(stmt) {
335 // Skip return statements inside arrow functions that will be simplified
336 // to expression body: () => { return expr } -> () => expr
337 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 children
341 if let Some(arg) = &ret.argument {
342 collect_original_expression(arg, locations);
343 }
344 return;
345 }
346 }
347 }
348
349 // Skip manual memoization
350 if type_name == "ExpressionStatement" {
351 if let Statement::ExpressionStatement(expr_stmt) = stmt {
352 if is_manual_memoization(&expr_stmt.expression) {
353 // Still recurse into children
354 collect_original_expression(&expr_stmt.expression, locations);
355 return;
356 }
357 }
358 }
359
360 let base_loc = statement_loc(stmt);
361 record_important(type_name, base_loc, locations);
362 }
363
364 // Recurse into children
365 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 type
429 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 identifier
453 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 into
473 _ => {}
474 }
475 }
476
477 fn 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 type
483 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 }
490
491 fn collect_original_expression(
492 expr: &Expression,
493 locations: &mut FxHashMap<String, ImportantLocation>,
494 ) {
495 // Record this expression if it's an important type
496 if let Some(type_name) = important_expression_type(expr) {
497 // Skip manual memoization
498 if !is_manual_memoization(expr) {
499 let base_loc = expression_loc(expr);
500 record_important(type_name, base_loc, locations);
501 }
502 }
503
504 // Recurse into children
505 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 it
521 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 type
587 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 expression
645 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 JSX
664 _ => {}
665 }
666 }
667
668 fn 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 }
685
686 fn 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 }
698
699 fn 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 }
747
748 // ---- Helpers to get loc from statement/expression ----
749
750 fn 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 }
799
800 fn 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 }
848
849 // ============================================================================
850 // Step 2: Collect generated locations (ALL node types, not just important ones)
851 // ============================================================================
852
853 fn 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 }
861
862 fn 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 locations
870 .entry(key)
871 .or_default()
872 .insert(type_name.to_string());
873 }
874 }
875
876 fn collect_generated_statement(
877 stmt: &Statement,
878 locations: &mut FxHashMap<String, FxHashSet<String>>,
879 ) {
880 // Record this statement's location
881 let type_name = statement_type_name(stmt);
882 record_generated(type_name, statement_loc(stmt), locations);
883
884 // 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 }
1011
1012 fn 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 }
1024
1025 fn 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);
1031
1032 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 JSX
1188 _ => {}
1189 }
1190 }
1191
1192 fn 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 }
1243
1244 // ---- Type name helpers ----
1245
1246 fn 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 function
1293 // returns &'static str; "Unknown" is the static stand-in.
1294 Statement::Unknown(_) => "Unknown",
1295 }
1296 }
1297
1298 fn 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 }