33
44use std:: mem;
55
6- use oxc_allocator:: { Box as ArenaBox , CloneIn } ;
6+ use oxc_allocator:: Box as ArenaBox ;
77use oxc_ast:: { ast:: * , NONE } ;
88use oxc_span:: SPAN ;
99use oxc_syntax:: {
1010 reference:: { ReferenceFlags , ReferenceId } ,
1111 symbol:: SymbolId ,
1212} ;
1313use oxc_traverse:: {
14- ast_operations:: get_var_name_from_node, Ancestor , BoundIdentifier , MaybeBoundIdentifier ,
15- TraverseCtx ,
14+ ast_operations:: get_var_name_from_node, Ancestor , BoundIdentifier , TraverseCtx ,
1615} ;
1716
1817use crate :: common:: helper_loader:: Helper ;
1918
2019use super :: {
2120 private_props:: ResolvedPrivateProp ,
2221 utils:: {
23- assert_expr_neither_parenthesis_nor_typescript_syntax, create_assignment,
22+ assert_expr_neither_parenthesis_nor_typescript_syntax, create_array , create_assignment,
2423 create_underscore_ident_name,
2524 } ,
2625 ClassProperties ,
@@ -1106,7 +1105,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
11061105 /// * Unbound Identifier or anything else: `A.B` -> `(_A$B = A.B) === null || _A$B === void 0`
11071106 ///
11081107 /// NOTE: This method will mutate the passed-in `object` to a second copy of
1109- /// [`Self::duplicate_object `]'s return.
1108+ /// [`Self::duplicate_object_twice `]'s return.
11101109 fn transform_expression_to_wrap_nullish_check (
11111110 & mut self ,
11121111 object : & mut Expression < ' a > ,
@@ -1115,14 +1114,9 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
11151114 let owned_object = ctx. ast . move_expression ( object. get_inner_expression_mut ( ) ) ;
11161115 let owned_object =
11171116 Self :: ensure_optional_expression_wrapped_by_chain_expression ( owned_object, ctx) ;
1118- let ( assignment, reference) = self . duplicate_object ( owned_object, ctx) ;
1119- // We cannot use `clone_in` to clone identifier reference because it will lose reference id
1120- * object = if let Expression :: Identifier ( ident) = & reference {
1121- MaybeBoundIdentifier :: from_identifier_reference ( ident, ctx) . create_read_expression ( ctx)
1122- } else {
1123- reference. clone_in ( ctx. ast . allocator )
1124- } ;
1125- self . wrap_nullish_check ( assignment, reference, ctx)
1117+ let ( assignment, reference1, reference2) = self . duplicate_object_twice ( owned_object, ctx) ;
1118+ * object = reference1;
1119+ self . wrap_nullish_check ( assignment, reference2, ctx)
11261120 }
11271121
11281122 /// Converts chain expression to expression
@@ -1456,7 +1450,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
14561450 ///
14571451 /// If `object` may have side effects, create a temp var `_object` and assign to it.
14581452 ///
1459- /// * `this` -> ( `this`, `this`)
1453+ /// * `this` -> `this`, `this`
14601454 /// * Bound identifier `object` -> `object`, `object`
14611455 /// * Unbound identifier `object` -> `_object = object`, `_object`
14621456 /// * Anything else `foo()` -> `_foo = foo()`, `_foo`
@@ -1467,16 +1461,58 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
14671461 object : Expression < ' a > ,
14681462 ctx : & mut TraverseCtx < ' a > ,
14691463 ) -> ( Expression < ' a > , Expression < ' a > ) {
1464+ let ( object1, duplicates) = self . duplicate_object_multiple :: < 1 > ( object, ctx) ;
1465+ let [ object2] = duplicates;
1466+ ( object1, object2)
1467+ }
1468+
1469+ /// Duplicate object to be used in triple.
1470+ ///
1471+ /// If `object` may have side effects, create a temp var `_object` and assign to it.
1472+ ///
1473+ /// * `this` -> `this`, `this`, `this`
1474+ /// * Bound identifier `object` -> `object`, `object`, `object`
1475+ /// * Unbound identifier `object` -> `_object = object`, `_object`, `_object`
1476+ /// * Anything else `foo()` -> `_foo = foo()`, `_foo`, `_foo`
1477+ ///
1478+ /// Returns 3 `Expression`s. The first must be inserted into output first.
1479+ fn duplicate_object_twice (
1480+ & mut self ,
1481+ object : Expression < ' a > ,
1482+ ctx : & mut TraverseCtx < ' a > ,
1483+ ) -> ( Expression < ' a > , Expression < ' a > , Expression < ' a > ) {
1484+ let ( object1, duplicates) = self . duplicate_object_multiple :: < 2 > ( object, ctx) ;
1485+ let [ object2, object3] = duplicates;
1486+ ( object1, object2, object3)
1487+ }
1488+
1489+ /// Duplicate object `N + 1` times.
1490+ ///
1491+ /// If `object` may have side effects, create a temp var `_object` and assign to it.
1492+ ///
1493+ /// * `this` -> `this`, [`this`; N]
1494+ /// * Bound identifier `object` -> `object`, [`object`; N]
1495+ /// * Unbound identifier `object` -> `_object = object`, [`_object`; N]
1496+ /// * Anything else `foo()` -> `_foo = foo()`, [`_foo`; N]
1497+ ///
1498+ /// Returns `N + 1` `Expression`s. The first must be inserted into output first.
1499+ fn duplicate_object_multiple < const N : usize > (
1500+ & mut self ,
1501+ object : Expression < ' a > ,
1502+ ctx : & mut TraverseCtx < ' a > ,
1503+ ) -> ( Expression < ' a > , [ Expression < ' a > ; N ] ) {
14701504 assert_expr_neither_parenthesis_nor_typescript_syntax ( & object) ;
1505+
14711506 // TODO: Handle if in a function's params
14721507 let temp_var_binding = match & object {
14731508 Expression :: Identifier ( ident) => {
14741509 let reference = ctx. symbols_mut ( ) . get_reference_mut ( ident. reference_id ( ) ) ;
14751510 if let Some ( symbol_id) = reference. symbol_id ( ) {
14761511 // Reading bound identifier cannot have side effects, so no need for temp var
14771512 let binding = BoundIdentifier :: new ( ident. name . clone ( ) , symbol_id) ;
1478- let object1 = binding. create_spanned_read_expression ( ident. span , ctx) ;
1479- return ( object1, object) ;
1513+ let duplicates =
1514+ create_array ( || binding. create_spanned_read_expression ( ident. span , ctx) ) ;
1515+ return ( object, duplicates) ;
14801516 }
14811517
14821518 // Previously `x += 1` (`x` read + write), but moving to `_x = x` (`x` read only)
@@ -1486,16 +1522,16 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
14861522 }
14871523 Expression :: ThisExpression ( this) => {
14881524 // Reading `this` cannot have side effects, so no need for temp var
1489- let object1 = ctx. ast . expression_this ( this. span ) ;
1490- return ( object1 , object ) ;
1525+ let duplicates = create_array ( || ctx. ast . expression_this ( this. span ) ) ;
1526+ return ( object , duplicates ) ;
14911527 }
14921528 _ => self . ctx . var_declarations . create_uid_var_based_on_node ( & object, ctx) ,
14931529 } ;
14941530
14951531 let object1 = create_assignment ( & temp_var_binding, object, ctx) ;
1496- let object2 = temp_var_binding. create_read_expression ( ctx) ;
1532+ let references = create_array ( || temp_var_binding. create_read_expression ( ctx) ) ;
14971533
1498- ( object1, object2 )
1534+ ( object1, references )
14991535 }
15001536
15011537 /// `_classPrivateFieldGet2(_prop, object)`
0 commit comments