|
1 | | -use oxc_allocator::{Allocator, Box, Vec as OxcVec}; |
| 1 | +use oxc_allocator::{Allocator, Vec as OxcVec}; |
2 | 2 | use oxc_ast::{ |
3 | 3 | AstBuilder, NONE, |
4 | | - ast::{Argument, FunctionBody, Statement}, |
| 4 | + ast::{Argument, Statement}, |
5 | 5 | }; |
6 | 6 | use oxc_span::SPAN; |
7 | 7 |
|
8 | 8 | pub fn transform_return_statements<'a>( |
9 | 9 | allocator: &'a Allocator, |
10 | 10 | builder: &AstBuilder<'a>, |
11 | 11 | identifier: &str, |
12 | | - body: &mut Box<'a, FunctionBody<'a>>, |
| 12 | + statements: &mut OxcVec<'a, Statement<'a>>, |
| 13 | +) { |
| 14 | + transform_statements(allocator, builder, identifier, statements); |
| 15 | +} |
| 16 | +fn transform_statements<'a>( |
| 17 | + allocator: &'a Allocator, |
| 18 | + builder: &AstBuilder<'a>, |
| 19 | + identifier: &str, |
| 20 | + statements: &mut OxcVec<'a, Statement<'a>>, |
13 | 21 | ) { |
14 | 22 | // Iterate through the statements in the function body |
| 23 | + for statement in statements { |
| 24 | + transform_statement(allocator, builder, identifier, statement); |
| 25 | + } |
| 26 | +} |
| 27 | + |
| 28 | +fn transform_statement<'a>( |
| 29 | + allocator: &'a Allocator, |
| 30 | + builder: &AstBuilder<'a>, |
| 31 | + identifier: &str, |
| 32 | + statement: &mut Statement<'a>, |
| 33 | +) { |
| 34 | + match statement { |
| 35 | + Statement::ReturnStatement(return_stmt) => { |
| 36 | + let mut instrument_args: OxcVec<'a, Argument<'a>> = builder.vec_with_capacity(3); |
| 37 | + |
| 38 | + // Add the identifier to the arguments |
| 39 | + instrument_args.push(Argument::StringLiteral(builder.alloc_string_literal( |
| 40 | + SPAN, |
| 41 | + allocator.alloc_str(identifier), |
| 42 | + None, |
| 43 | + ))); |
| 44 | + |
| 45 | + // Also pass the function arguments |
| 46 | + instrument_args.push(builder.expression_identifier(SPAN, "arguments").into()); |
| 47 | + |
| 48 | + // Add original return value as the second argument |
| 49 | + let arg_expr = return_stmt |
| 50 | + .argument |
| 51 | + .take() |
| 52 | + .unwrap_or_else(|| builder.expression_identifier(SPAN, "undefined")); |
| 53 | + instrument_args.push(arg_expr.into()); |
15 | 54 |
|
16 | | - // Todo fix subfunctions |
17 | | - for statement in &mut body.statements { |
18 | | - match statement { |
19 | | - Statement::ReturnStatement(return_stmt) => { |
20 | | - let mut instrument_args: OxcVec<'a, Argument<'a>> = builder.vec_with_capacity(3); |
21 | | - |
22 | | - // Add the identifier to the arguments |
23 | | - instrument_args.push(Argument::StringLiteral(builder.alloc_string_literal( |
24 | | - SPAN, |
25 | | - allocator.alloc_str(identifier), |
26 | | - None, |
27 | | - ))); |
28 | | - |
29 | | - // Also pass the function arguments |
30 | | - instrument_args.push(builder.expression_identifier(SPAN, "arguments").into()); |
31 | | - |
32 | | - // Add original return value as the second argument |
33 | | - let arg_expr = return_stmt |
34 | | - .argument |
35 | | - .take() |
36 | | - .unwrap_or_else(|| builder.expression_identifier(SPAN, "undefined")); |
37 | | - instrument_args.push(arg_expr.into()); |
38 | | - |
39 | | - // Add the `this` context as argument |
40 | | - instrument_args.push(builder.expression_identifier(SPAN, "this").into()); |
41 | | - |
42 | | - let new_call_expr = builder.expression_call( |
43 | | - SPAN, |
44 | | - builder.expression_identifier(SPAN, "__instrumentModifyReturnValue"), |
45 | | - NONE, |
46 | | - instrument_args, |
47 | | - false, |
48 | | - ); |
49 | | - |
50 | | - // Replace the return statement with a call to the identifier |
51 | | - return_stmt.argument = Some(new_call_expr); |
| 55 | + // Add the `this` context as argument |
| 56 | + instrument_args.push(builder.expression_identifier(SPAN, "this").into()); |
| 57 | + |
| 58 | + let new_call_expr = builder.expression_call( |
| 59 | + SPAN, |
| 60 | + builder.expression_identifier(SPAN, "__instrumentModifyReturnValue"), |
| 61 | + NONE, |
| 62 | + instrument_args, |
| 63 | + false, |
| 64 | + ); |
| 65 | + |
| 66 | + // Replace the return statement with a call to the identifier |
| 67 | + return_stmt.argument = Some(new_call_expr); |
| 68 | + } |
| 69 | + // Recursively transform nested statements |
| 70 | + Statement::BlockStatement(block_stmt) => { |
| 71 | + transform_statements(allocator, builder, identifier, &mut block_stmt.body); |
| 72 | + } |
| 73 | + Statement::IfStatement(if_stmt) => { |
| 74 | + transform_statement(allocator, builder, identifier, &mut if_stmt.consequent); |
| 75 | + if let Some(alt) = &mut if_stmt.alternate { |
| 76 | + transform_statement(allocator, builder, identifier, alt); |
52 | 77 | } |
53 | | - _ => { |
54 | | - // Ignore |
55 | | - continue; |
| 78 | + } |
| 79 | + Statement::DoWhileStatement(do_while_stmt) => { |
| 80 | + transform_statement(allocator, builder, identifier, &mut do_while_stmt.body); |
| 81 | + } |
| 82 | + Statement::ForStatement(for_stmt) => { |
| 83 | + transform_statement(allocator, builder, identifier, &mut for_stmt.body); |
| 84 | + } |
| 85 | + Statement::ForInStatement(for_in_stmt) => { |
| 86 | + transform_statement(allocator, builder, identifier, &mut for_in_stmt.body); |
| 87 | + } |
| 88 | + Statement::ForOfStatement(for_of_stmt) => { |
| 89 | + transform_statement(allocator, builder, identifier, &mut for_of_stmt.body); |
| 90 | + } |
| 91 | + Statement::WhileStatement(while_stmt) => { |
| 92 | + transform_statement(allocator, builder, identifier, &mut while_stmt.body); |
| 93 | + } |
| 94 | + Statement::SwitchStatement(switch_stmt) => { |
| 95 | + for case in &mut switch_stmt.cases { |
| 96 | + transform_statements(allocator, builder, identifier, &mut case.consequent); |
| 97 | + } |
| 98 | + } |
| 99 | + Statement::TryStatement(try_stmt) => { |
| 100 | + transform_statements(allocator, builder, identifier, &mut try_stmt.block.body); |
| 101 | + if let Some(handler) = &mut try_stmt.handler { |
| 102 | + transform_statements(allocator, builder, identifier, &mut handler.body.body); |
56 | 103 | } |
| 104 | + if let Some(finally_block) = &mut try_stmt.finalizer { |
| 105 | + transform_statements(allocator, builder, identifier, &mut finally_block.body); |
| 106 | + } |
| 107 | + } |
| 108 | + Statement::LabeledStatement(labeled_stmt) => { |
| 109 | + transform_statement(allocator, builder, identifier, &mut labeled_stmt.body); |
| 110 | + } |
| 111 | + _ => { |
| 112 | + // Ignore |
57 | 113 | } |
58 | 114 | } |
59 | 115 | } |
0 commit comments