|
3 | 3 |
|
4 | 4 | use std::mem; |
5 | 5 |
|
6 | | -use oxc_allocator::Box as ArenaBox; |
| 6 | +use oxc_allocator::{Box as ArenaBox, CloneIn}; |
7 | 7 | use oxc_ast::{ast::*, NONE}; |
8 | 8 | use oxc_span::SPAN; |
9 | 9 | use oxc_syntax::{ |
@@ -1102,34 +1102,26 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { |
1102 | 1102 | /// |
1103 | 1103 | /// Returns: |
1104 | 1104 | /// * Bound Identifier: `A` -> `A === null || A === void 0` |
| 1105 | + /// * `this`: `this` -> `this === null || this === void 0` |
1105 | 1106 | /// * Unbound Identifier or anything else: `A.B` -> `(_A$B = A.B) === null || _A$B === void 0` |
1106 | 1107 | /// |
1107 | | - /// NOTE: This method will mutate the passed-in `object` to a temp variable identifier. |
| 1108 | + /// NOTE: This method will mutate the passed-in `object` to a second copy of |
| 1109 | + /// [`Self::duplicate_object`]'s return. |
1108 | 1110 | fn transform_expression_to_wrap_nullish_check( |
1109 | 1111 | &mut self, |
1110 | 1112 | object: &mut Expression<'a>, |
1111 | 1113 | ctx: &mut TraverseCtx<'a>, |
1112 | 1114 | ) -> Expression<'a> { |
1113 | | - // `A` -> `A === null || A === void 0` |
1114 | | - if let Expression::Identifier(ident) = object { |
1115 | | - if let Some(binding) = self.get_existing_binding_for_identifier(ident, ctx) { |
1116 | | - let left1 = binding.create_read_expression(ctx); |
1117 | | - let left2 = binding.create_read_expression(ctx); |
1118 | | - return self.wrap_nullish_check(left1, left2, ctx); |
1119 | | - } |
1120 | | - } |
1121 | | - |
1122 | | - // `A.B` -> `(_A$B = A.B) === null || _A$B === void 0` |
1123 | | - // TODO: should add an API `generate_uid_in_current_hoist_scope_based_on_node` to instead this |
1124 | | - let temp_var_binding = self.ctx.var_declarations.create_uid_var_based_on_node(object, ctx); |
1125 | | - |
1126 | | - let object = mem::replace(object, temp_var_binding.create_read_expression(ctx)); |
1127 | | - let assignment = create_assignment( |
1128 | | - &temp_var_binding, |
1129 | | - Self::ensure_optional_expression_wrapped_by_chain_expression(object, ctx), |
1130 | | - ctx, |
1131 | | - ); |
1132 | | - let reference = temp_var_binding.create_read_expression(ctx); |
| 1115 | + let owned_object = ctx.ast.move_expression(object.get_inner_expression_mut()); |
| 1116 | + let owned_object = |
| 1117 | + 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 | + }; |
1133 | 1125 | self.wrap_nullish_check(assignment, reference, ctx) |
1134 | 1126 | } |
1135 | 1127 |
|
@@ -1159,23 +1151,6 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { |
1159 | 1151 | } |
1160 | 1152 | } |
1161 | 1153 |
|
1162 | | - /// Get an MaybeBoundIdentifier from an bound identifier reference. |
1163 | | - /// |
1164 | | - /// If no temp variable required, returns `MaybeBoundIdentifier` for existing variable/global. |
1165 | | - /// If temp variable is required, returns `None`. |
1166 | | - fn get_existing_binding_for_identifier( |
1167 | | - &self, |
1168 | | - ident: &IdentifierReference<'a>, |
1169 | | - ctx: &TraverseCtx<'a>, |
1170 | | - ) -> Option<MaybeBoundIdentifier<'a>> { |
1171 | | - let binding = MaybeBoundIdentifier::from_identifier_reference(ident, ctx); |
1172 | | - if self.ctx.assumptions.pure_getters || binding.to_bound_identifier().is_some() { |
1173 | | - Some(binding) |
1174 | | - } else { |
1175 | | - None |
1176 | | - } |
1177 | | - } |
1178 | | - |
1179 | 1154 | /// Ensure that the expression is wrapped by a chain expression. |
1180 | 1155 | /// |
1181 | 1156 | /// If the given expression contains optional expression, it will be wrapped by |
|
0 commit comments