Skip to content

Commit

Permalink
feat(transformer/class-properties): transform private field expressio…
Browse files Browse the repository at this point in the history
…n which refers to private method
  • Loading branch information
Dunqing committed Dec 28, 2024
1 parent d88a83a commit 8fac581
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 67 deletions.
1 change: 1 addition & 0 deletions .typos.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ extend-exclude = [
"tasks/prettier_conformance/snapshots",
"tasks/transform_conformance/tests/**/output.js",
"tasks/transform_conformance/overrides",
"tasks/transform_conformance/snapshots",
"npm/oxc-wasm/oxc_wasm.js",
]

Expand Down
40 changes: 25 additions & 15 deletions crates/oxc_transformer/src/es2022/class_properties/private_field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,18 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
is_declaration,
} = self.classes_stack.find_private_prop(&field_expr.field);

let span = field_expr.span;

if is_method || is_accessor {
return None;
let prop_ident = prop_binding.create_read_expression(ctx);
return if is_assignment {
// TODO: Handle assignment to private method or accessor
None
} else {
Some(self.create_assert_class_brand_for_private_method(prop_ident, span, ctx))
};
};

let span = field_expr.span;
let object = ctx.ast.move_expression(&mut field_expr.object);

if self.private_fields_as_properties {
Expand Down Expand Up @@ -268,11 +275,12 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
is_declaration,
} = self.classes_stack.find_private_prop(&field_expr.field);

let span = field_expr.span;
let prop_ident = prop_binding.create_read_expression(ctx);

if is_method || is_accessor {
return (
self.create_assert_class_brand_for_private_method(prop_ident, ctx),
self.create_assert_class_brand_for_private_method(prop_ident, span, ctx),
ctx.ast.expression_this(SPAN),
);
};
Expand Down Expand Up @@ -301,8 +309,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
.is_some()
{
// `_prop._`
let callee =
Self::create_underscore_member_expression(prop_ident, field_expr.span, ctx);
let callee = Self::create_underscore_member_expression(prop_ident, span, ctx);
(callee, object)
} else {
let class_binding = class_bindings.get_or_init_static_binding(ctx);
Expand All @@ -316,7 +323,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
class_ident,
object1,
prop_ident,
field_expr.span,
span,
ctx,
);
(assert_obj, object2)
Expand All @@ -327,7 +334,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
let (object1, object2) = self.duplicate_object(object, ctx);

// `_classPrivateFieldGet2(_prop, object)`
let get_call = self.create_private_field_get(prop_ident, object1, field_expr.span, ctx);
let get_call = self.create_private_field_get(prop_ident, object1, span, ctx);
(get_call, object2)
};

Expand Down Expand Up @@ -533,7 +540,8 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
// Replace right side of assignment with `_assertClassBrand(Class, object, _prop)`
// TODO: Ensure there are tests for nested classes with references to private static props
// of outer class inside inner class, to make sure we're getting the right `class_binding`.
assign_expr.right = self.create_assert_class_brand(class_ident, object, value, ctx);
assign_expr.right =
self.create_assert_class_brand(class_ident, object, value, SPAN, ctx);
} else {
let class_ident = class_binding.create_read_expression(ctx);
let value = ctx.ast.move_expression(&mut assign_expr.right);
Expand Down Expand Up @@ -563,7 +571,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
let value = ctx.ast.expression_binary(SPAN, get_expr, operator, value);
// `_assertClassBrand(Class, object, _assertClassBrand(Class, object, _prop)._ + value)`
assign_expr.right =
self.create_assert_class_brand(class_ident2, object1, value, ctx);
self.create_assert_class_brand(class_ident2, object1, value, SPAN, ctx);
} else if let Some(operator) = operator.to_logical_operator() {
// `object.#prop &&= value`
// -> `_assertClassBrand(Class, object, _prop)._ && (_prop._ = _assertClassBrand(Class, object, value))`
Expand All @@ -585,7 +593,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
assign_expr.span = SPAN;
assign_expr.operator = AssignmentOperator::Assign;
assign_expr.right =
self.create_assert_class_brand(class_ident2, object2, value, ctx);
self.create_assert_class_brand(class_ident2, object2, value, SPAN, ctx);
let right = ctx.ast.move_expression(expr);
// `_assertClassBrand(Class, object, _prop)._ && (_prop._ = _assertClassBrand(Class, object, value))`
*expr = ctx.ast.expression_logical(span, left, operator, right);
Expand Down Expand Up @@ -869,7 +877,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {

// If no shortcut, wrap in `_assertClassBrand(Class, object, <value>)`
if let Some(class_ident) = class_ident {
value = self.create_assert_class_brand(class_ident, object, value, ctx);
value = self.create_assert_class_brand(class_ident, object, value, SPAN, ctx);
}

// `_prop._ = <value>`
Expand Down Expand Up @@ -899,7 +907,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {

// If no shortcut, wrap in `_assertClassBrand(Class, object, <value>)`
if let Some(class_ident) = class_ident {
value = self.create_assert_class_brand(class_ident, object, value, ctx);
value = self.create_assert_class_brand(class_ident, object, value, SPAN, ctx);
}

// `_prop._ = <value>`
Expand Down Expand Up @@ -1772,11 +1780,12 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
class_ident: Expression<'a>,
object: Expression<'a>,
value_or_prop_ident: Expression<'a>,
span: Span,
ctx: &mut TraverseCtx<'a>,
) -> Expression<'a> {
self.ctx.helper_call_expr(
Helper::AssertClassBrand,
SPAN,
span,
ctx.ast.vec_from_array([
Argument::from(class_ident),
Argument::from(object),
Expand All @@ -1791,11 +1800,12 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
fn create_assert_class_brand_for_private_method(
&self,
value_or_prop_ident: Expression<'a>,
span: Span,
ctx: &mut TraverseCtx<'a>,
) -> Expression<'a> {
let class_ident = self.current_class().bindings.brand().create_read_expression(ctx);
let object = ctx.ast.expression_this(SPAN);
self.create_assert_class_brand(class_ident, object, value_or_prop_ident, ctx)
self.create_assert_class_brand(class_ident, object, value_or_prop_ident, span, ctx)
}

/// `_assertClassBrand(Class, object, _prop)._`
Expand All @@ -1807,7 +1817,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
span: Span,
ctx: &mut TraverseCtx<'a>,
) -> Expression<'a> {
let func_call = self.create_assert_class_brand(class_ident, object, prop_ident, ctx);
let func_call = self.create_assert_class_brand(class_ident, object, prop_ident, SPAN, ctx);
Self::create_underscore_member_expression(func_call, span, ctx)
}

Expand Down
10 changes: 2 additions & 8 deletions tasks/transform_conformance/snapshots/babel.snap.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
commit: 54a8389f

Passed: 628/1095
Passed: 630/1095

# All Passed:
* babel-plugin-transform-logical-assignment-operators
Expand Down Expand Up @@ -462,7 +462,7 @@ x Output mismatch
x Output mismatch


# babel-plugin-transform-private-methods (13/148)
# babel-plugin-transform-private-methods (15/148)
* accessors/arguments/input.js
x Output mismatch

Expand Down Expand Up @@ -571,15 +571,9 @@ x Output mismatch
* private-method/class-expression/input.js
x Output mismatch

* private-method/context/input.js
x Output mismatch

* private-method/destructuring/input.js
x Output mismatch

* private-method/exfiltrated/input.js
x Output mismatch

* private-method/read-only/input.js
x Output mismatch

Expand Down
Loading

0 comments on commit 8fac581

Please sign in to comment.