Skip to content

Commit

Permalink
feat(transformer/class-properties): transform callee that is referred…
Browse files Browse the repository at this point in the history
… to a private method
  • Loading branch information
Dunqing committed Dec 25, 2024
1 parent adb27ce commit 02c7724
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 73 deletions.
39 changes: 26 additions & 13 deletions crates/oxc_transformer/src/es2022/class_properties/private_field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,9 +206,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
return;
}

let Some((callee, object)) = self.transform_private_field_callee(field_expr, ctx) else {
return;
};
let (callee, object) = self.transform_private_field_callee(field_expr, ctx);
Self::substitute_callee_and_insert_context(call_expr, callee, object, ctx);
}

Expand Down Expand Up @@ -260,7 +258,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
&mut self,
field_expr: &mut PrivateFieldExpression<'a>,
ctx: &mut TraverseCtx<'a>,
) -> Option<(Expression<'a>, Expression<'a>)> {
) -> (Expression<'a>, Expression<'a>) {
let ResolvedPrivateProp {
prop_binding,
class_bindings,
Expand All @@ -270,12 +268,15 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
is_declaration,
} = self.classes_stack.find_private_prop(&field_expr.field);

let prop_ident = prop_binding.create_read_expression(ctx);

if is_method || is_accessor {
return None;
return (
self.create_assert_class_brand_for_private_method(prop_ident, ctx),
ctx.ast.expression_this(SPAN),
);
};

let prop_ident = prop_binding.create_read_expression(ctx);

// `(object.#method)()`
// ^^^^^^^^^^^^^^^^ is a parenthesized expression
let object = ctx.ast.move_expression(field_expr.object.get_inner_expression_mut());
Expand Down Expand Up @@ -330,7 +331,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
(get_call, object2)
};

Some(replacement)
replacement
}

/// Transform assignment to private field.
Expand Down Expand Up @@ -1152,7 +1153,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
if matches!(ctx.ancestor(1), Ancestor::CallExpressionCallee(_)) {
// `(Foo?.#m)();` -> `(Foo === null || Foo === void 0 ? void 0 : _m._.bind(Foo))();`
// ^^^^^^^^^^^^ is a call expression, we need to bind the proper context
*expr = self.transform_bindable_private_field(field_expr, ctx).unwrap();
*expr = self.transform_bindable_private_field(field_expr, ctx);
} else {
self.transform_private_field_expression(expr, ctx);
}
Expand Down Expand Up @@ -1573,16 +1574,16 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
);
Some(Expression::from(replacement))
} else {
self.transform_bindable_private_field(field_expr, ctx)
Some(self.transform_bindable_private_field(field_expr, ctx))
}
}

fn transform_bindable_private_field(
&mut self,
field_expr: &mut PrivateFieldExpression<'a>,
ctx: &mut TraverseCtx<'a>,
) -> Option<Expression<'a>> {
let (callee, context) = self.transform_private_field_callee(field_expr, ctx)?;
) -> Expression<'a> {
let (callee, context) = self.transform_private_field_callee(field_expr, ctx);

// Return `<callee>.bind(object)`, to be substituted as tag of tagged template expression
let callee = Expression::from(ctx.ast.member_expression_static(
Expand All @@ -1592,7 +1593,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
false,
));
let arguments = ctx.ast.vec1(Argument::from(context));
Some(ctx.ast.expression_call(field_expr.span, callee, NONE, arguments, false))
ctx.ast.expression_call(field_expr.span, callee, NONE, arguments, false)
}

/// Transform private field in assignment pattern.
Expand Down Expand Up @@ -1785,6 +1786,18 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
)
}

/// `_assertClassBrand(_Class_brand, object, _prop)`
#[inline]
fn create_assert_class_brand_for_private_method(
&self,
value_or_prop_ident: Expression<'a>,
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)
}

/// `_assertClassBrand(Class, object, _prop)._`
fn create_assert_class_brand_underscore(
&self,
Expand Down
19 changes: 2 additions & 17 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: 623/1095
Passed: 628/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 (8/148)
# babel-plugin-transform-private-methods (13/148)
* accessors/arguments/input.js
x Output mismatch

Expand Down Expand Up @@ -565,15 +565,6 @@ x Output mismatch
* misc/multiple/input.js
x Output mismatch

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

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

* private-method/before-fields/input.js
x Output mismatch

* private-method/class-binding/input.js
x Output mismatch

Expand All @@ -589,9 +580,6 @@ x Output mismatch
* private-method/exfiltrated/input.js
x Output mismatch

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

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

Expand All @@ -601,9 +589,6 @@ x Output mismatch
* private-method/super/input.js
x Output mismatch

* private-method/tagged-template/input.js
x Output mismatch

* private-method-loose/assignment/input.js
x Output mismatch

Expand Down
78 changes: 35 additions & 43 deletions tasks/transform_conformance/snapshots/babel_exec.snap.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ commit: 54a8389f

node: v22.12.0

Passed: 215 of 362 (59.39%)
Passed: 225 of 362 (62.15%)

Failures:

Expand Down Expand Up @@ -62,9 +62,6 @@ TypeError: e.has is not a function
at Function.method (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-class-properties-test-fixtures-private-static-shadow-exec.test.js:12:11)
at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-class-properties-test-fixtures-private-static-shadow-exec.test.js:16:14

./fixtures/babel/babel-plugin-transform-class-properties-test-fixtures-private-tagged-template-exec.test.js
Private field '#tag' must be declared in an enclosing class

./fixtures/babel/babel-plugin-transform-class-properties-test-fixtures-public-computed-toPrimitive-exec.test.js
AssertionError: expected [Function] to throw error including '@@toPrimitive must return a primitive…' but got 'Cannot convert object to primitive va…'
at Proxy.<anonymous> (./node_modules/.pnpm/@vitest[email protected]/node_modules/@vitest/expect/dist/index.js:1438:21)
Expand Down Expand Up @@ -98,7 +95,9 @@ AssertionError: expected [Function Base] to be undefined // Object.is equality
Private field '#bar' must be declared in an enclosing class

./fixtures/babel/babel-plugin-transform-class-static-block-test-fixtures-integration-private-methods-access-exec.test.js
Private field '#foo' must be declared in an enclosing class
ReferenceError: _Foo_brand is not defined
at getFoo (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-class-static-block-test-fixtures-integration-private-methods-access-exec.test.js:17:35)
at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-class-static-block-test-fixtures-integration-private-methods-access-exec.test.js:18:9

./fixtures/babel/babel-plugin-transform-optional-chaining-test-fixtures-assumption-noDocumentAll-parenthesized-expression-member-call-exec.test.js
TypeError: Cannot read properties of undefined (reading 'x')
Expand Down Expand Up @@ -196,33 +195,22 @@ Private field '#privateFieldValue' must be declared in an enclosing class
./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-set-only-getter-exec.test.js
Private field '#privateFieldValue' must be declared in an enclosing class

./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-tagged-template-exec.test.js
Private field '#tag' must be declared in an enclosing class

./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-updates-bigint-exec.test.js
Private field '#privateFieldValue' must be declared in an enclosing class

./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-updates-exec.test.js
Private field '#privateFieldValue' must be declared in an enclosing class

./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-assignment-exec.test.js
Private field '#privateMethod' must be declared in an enclosing class

./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-before-fields-exec.test.js
Private field '#method' must be declared in an enclosing class

./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-class-binding-exec.test.js
Private field '#getA' must be declared in an enclosing class
AssertionError: expected null to be [Function A] // Object.is equality
at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-class-binding-exec.test.js:20:28

./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-context-exec.test.js
Private field '#getStatus' must be declared in an enclosing class

./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-exfiltrated-exec.test.js
Private field '#privateMethod' must be declared in an enclosing class

./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-generator-exec.test.js
Private field '#foo' must be declared in an enclosing class

./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-loose-assignment-exec.test.js
Private field '#privateMethod' must be declared in an enclosing class

Expand Down Expand Up @@ -268,24 +256,16 @@ Private field '#foo' must be declared in an enclosing class
./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-privateFieldsAsProperties-super-exec.test.js
Invalid access to super

./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-privateFieldsAsSymbols-assignment-exec.test.js
Private field '#privateMethod' must be declared in an enclosing class

./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-privateFieldsAsSymbols-before-fields-exec.test.js
Private field '#method' must be declared in an enclosing class

./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-privateFieldsAsSymbols-class-binding-exec.test.js
Private field '#getA' must be declared in an enclosing class
AssertionError: expected null to be [Function A] // Object.is equality
at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-privateFieldsAsSymbols-class-binding-exec.test.js:20:28

./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-privateFieldsAsSymbols-context-exec.test.js
Private field '#getStatus' must be declared in an enclosing class

./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-privateFieldsAsSymbols-exfiltrated-exec.test.js
Private field '#privateMethod' must be declared in an enclosing class

./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-privateFieldsAsSymbols-generator-exec.test.js
Private field '#foo' must be declared in an enclosing class

./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-privateFieldsAsSymbols-super-exec.test.js
Invalid access to super

Expand All @@ -295,26 +275,26 @@ Private field '#method' must be declared in an enclosing class
./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-reassignment-exec.test.js
Private field '#privateFieldValue' must be declared in an enclosing class

./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-scopable-exec.test.js
Private field '#privateMethodA' must be declared in an enclosing class

./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-super-exec.test.js
Invalid access to super

./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-tagged-template-exec.test.js
Private field '#tag' must be declared in an enclosing class

./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-basic-exec.test.js
Private field '#privateStaticMethod' must be declared in an enclosing class
ReferenceError: _Cl_brand is not defined
at new Cl (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-basic-exec.test.js:21:38)
at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-basic-exec.test.js:28:9

./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-class-check-exec.test.js
Private field '#privateStaticMethod' must be declared in an enclosing class
ReferenceError: _Cl_brand is not defined
at new Cl (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-class-check-exec.test.js:8:38)
at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-class-check-exec.test.js:17:13

./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-exfiltrated-exec.test.js
Private field '#privateStaticMethod' must be declared in an enclosing class

./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-generator-exec.test.js
Private field '#foo' must be declared in an enclosing class
ReferenceError: _Cl_brand is not defined
at new Cl (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-generator-exec.test.js:8:38)
at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-generator-exec.test.js:18:14

./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-loose-basic-exec.test.js
Private field '#privateStaticMethod' must be declared in an enclosing class
Expand Down Expand Up @@ -365,22 +345,30 @@ Invalid access to super
Invalid access to super

./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-privateFieldsAsSymbols-basic-exec.test.js
Private field '#privateStaticMethod' must be declared in an enclosing class
ReferenceError: _Cl_brand is not defined
at new Cl (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-privateFieldsAsSymbols-basic-exec.test.js:21:38)
at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-privateFieldsAsSymbols-basic-exec.test.js:28:9

./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-privateFieldsAsSymbols-class-check-exec.test.js
Private field '#privateStaticMethod' must be declared in an enclosing class
ReferenceError: _Cl_brand is not defined
at new Cl (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-privateFieldsAsSymbols-class-check-exec.test.js:8:38)
at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-privateFieldsAsSymbols-class-check-exec.test.js:17:13

./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-privateFieldsAsSymbols-exfiltrated-exec.test.js
Private field '#privateStaticMethod' must be declared in an enclosing class

./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-privateFieldsAsSymbols-generator-exec.test.js
Private field '#foo' must be declared in an enclosing class
ReferenceError: _Cl_brand is not defined
at new Cl (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-privateFieldsAsSymbols-generator-exec.test.js:8:38)
at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-privateFieldsAsSymbols-generator-exec.test.js:18:14

./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-privateFieldsAsSymbols-reassignment-exec.test.js
Private field '#privateStaticMethod' must be declared in an enclosing class

./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-privateFieldsAsSymbols-scopable-exec.test.js
Private field '#privateMethodA' must be declared in an enclosing class
ReferenceError: _Cl_brand is not defined
at new Cl (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-privateFieldsAsSymbols-scopable-exec.test.js:8:38)
at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-privateFieldsAsSymbols-scopable-exec.test.js:22:9

./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-privateFieldsAsSymbols-super-exec.test.js
Invalid access to super
Expand All @@ -395,13 +383,17 @@ Private field '#method' must be declared in an enclosing class
Private field '#privateStaticMethod' must be declared in an enclosing class

./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-scopable-exec.test.js
Private field '#privateMethodA' must be declared in an enclosing class
ReferenceError: _Cl_brand is not defined
at new Cl (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-scopable-exec.test.js:8:38)
at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-scopable-exec.test.js:22:9

./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-super-exec.test.js
Invalid access to super

./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-tagged-template-exec.test.js
Private field '#tag' must be declared in an enclosing class
ReferenceError: _Foo_brand is not defined
at Function.getReceiver (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-tagged-template-exec.test.js:11:29)
at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-tagged-template-exec.test.js:17:13

./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-this-exec.test.js
Invalid access to super
Expand Down

0 comments on commit 02c7724

Please sign in to comment.