From bb3806554f712117892bb533dbbba38e269e4f60 Mon Sep 17 00:00:00 2001 From: overlookmotel <557937+overlookmotel@users.noreply.github.com> Date: Wed, 18 Dec 2024 03:00:04 +0000 Subject: [PATCH] fix(transformer/class-properties): do not transform `super.prop` in nested method within static prop initializer (#7978) Don't transform `super` in static property initializers if it's nested in another method, so is a *different* `super`. ```js class C { static prop = () => { const object = { method() { // `super` here refers to prototype of `object`, not class `C` return super.foo; } }; }; } ``` --- .../class_properties/static_prop_init.rs | 35 +++++++++++++++-- .../snapshots/oxc.snap.md | 4 +- .../super-in-static-prop-initializer/input.js | 37 ++++++++++++++++++ .../output.js | 38 +++++++++++++++++++ 4 files changed, 108 insertions(+), 6 deletions(-) create mode 100644 tasks/transform_conformance/tests/babel-plugin-transform-class-properties/test/fixtures/super-in-static-prop-initializer/input.js create mode 100644 tasks/transform_conformance/tests/babel-plugin-transform-class-properties/test/fixtures/super-in-static-prop-initializer/output.js diff --git a/crates/oxc_transformer/src/es2022/class_properties/static_prop_init.rs b/crates/oxc_transformer/src/es2022/class_properties/static_prop_init.rs index 5dce0179336d0..527c7da2eba50 100644 --- a/crates/oxc_transformer/src/es2022/class_properties/static_prop_init.rs +++ b/crates/oxc_transformer/src/es2022/class_properties/static_prop_init.rs @@ -202,11 +202,11 @@ impl<'a, 'ctx, 'v> VisitMut<'a> for StaticInitializerVisitor<'a, 'ctx, 'v> { } // `super.prop` Expression::StaticMemberExpression(_) => { - self.class_properties.transform_static_member_expression(expr, self.ctx); + self.transform_static_member_expression_if_super(expr); } // `super[prop]` Expression::ComputedMemberExpression(_) => { - self.class_properties.transform_computed_member_expression(expr, self.ctx); + self.transform_computed_member_expression_if_super(expr); } // `object.#prop` Expression::PrivateFieldExpression(_) => { @@ -214,8 +214,7 @@ impl<'a, 'ctx, 'v> VisitMut<'a> for StaticInitializerVisitor<'a, 'ctx, 'v> { } // `super.prop()` or `object.#prop()` Expression::CallExpression(call_expr) => { - self.class_properties - .transform_call_expression_for_super_member_expr(call_expr, self.ctx); + self.transform_call_expression_if_super_member_expression(call_expr); self.class_properties.transform_call_expression(expr, self.ctx); } // `object.#prop = value`, `object.#prop += value`, `object.#prop ??= value` etc @@ -516,4 +515,32 @@ impl<'a, 'ctx, 'v> StaticInitializerVisitor<'a, 'ctx, 'v> { self.ctx.scopes_mut().change_parent_id(scope_id, Some(current_scope_id)); } } + + // `#[inline]` into visitor to keep common path where member expression isn't `super.prop` fast + #[inline] + fn transform_static_member_expression_if_super(&mut self, expr: &mut Expression<'a>) { + if self.this_depth == 0 { + self.class_properties.transform_static_member_expression(expr, self.ctx); + } + } + + // `#[inline]` into visitor to keep common path where member expression isn't `super.prop` fast + #[inline] + fn transform_computed_member_expression_if_super(&mut self, expr: &mut Expression<'a>) { + if self.this_depth == 0 { + self.class_properties.transform_computed_member_expression(expr, self.ctx); + } + } + + // `#[inline]` into visitor to keep common path where call expression isn't `super.prop()` fast + #[inline] + fn transform_call_expression_if_super_member_expression( + &mut self, + call_expr: &mut CallExpression<'a>, + ) { + if self.this_depth == 0 { + self.class_properties + .transform_call_expression_for_super_member_expr(call_expr, self.ctx); + } + } } diff --git a/tasks/transform_conformance/snapshots/oxc.snap.md b/tasks/transform_conformance/snapshots/oxc.snap.md index 19612c36acd99..b44ec0405f484 100644 --- a/tasks/transform_conformance/snapshots/oxc.snap.md +++ b/tasks/transform_conformance/snapshots/oxc.snap.md @@ -1,6 +1,6 @@ commit: 54a8389f -Passed: 111/125 +Passed: 112/126 # All Passed: * babel-plugin-transform-class-static-block @@ -16,7 +16,7 @@ Passed: 111/125 * regexp -# babel-plugin-transform-class-properties (12/14) +# babel-plugin-transform-class-properties (13/15) * typescript/optional-call/input.ts Symbol reference IDs mismatch for "X": after transform: SymbolId(0): [ReferenceId(0), ReferenceId(2), ReferenceId(6), ReferenceId(11), ReferenceId(16)] diff --git a/tasks/transform_conformance/tests/babel-plugin-transform-class-properties/test/fixtures/super-in-static-prop-initializer/input.js b/tasks/transform_conformance/tests/babel-plugin-transform-class-properties/test/fixtures/super-in-static-prop-initializer/input.js new file mode 100644 index 0000000000000..4e75a753c3cf0 --- /dev/null +++ b/tasks/transform_conformance/tests/babel-plugin-transform-class-properties/test/fixtures/super-in-static-prop-initializer/input.js @@ -0,0 +1,37 @@ +class C { + static prop = () => { + // Transform + super.prop; + super[prop]; + super.prop(); + super[prop](); + + const obj = { + method() { + // Don't transform + super.prop; + super[prop]; + super.prop(); + super[prop](); + } + }; + + class Inner { + method() { + // Don't transform + super.prop; + super[prop]; + super.prop(); + super[prop](); + } + + static staticMethod() { + // Don't transform + super.prop; + super[prop]; + super.prop(); + super[prop](); + } + } + }; +} diff --git a/tasks/transform_conformance/tests/babel-plugin-transform-class-properties/test/fixtures/super-in-static-prop-initializer/output.js b/tasks/transform_conformance/tests/babel-plugin-transform-class-properties/test/fixtures/super-in-static-prop-initializer/output.js new file mode 100644 index 0000000000000..1c06e3618270f --- /dev/null +++ b/tasks/transform_conformance/tests/babel-plugin-transform-class-properties/test/fixtures/super-in-static-prop-initializer/output.js @@ -0,0 +1,38 @@ +var _C; +class C {} +_C = C; +babelHelpers.defineProperty(C, "prop", () => { + // Transform + babelHelpers.superPropGet(_C, "prop", _C); + babelHelpers.superPropGet(_C, prop, _C); + babelHelpers.superPropGet(_C, "prop", _C, 2)([]); + babelHelpers.superPropGet(_C, prop, _C, 2)([]); + + const obj = { + method() { + // Don't transform + super.prop; + super[prop]; + super.prop(); + super[prop](); + } + }; + + class Inner { + method() { + // Don't transform + super.prop; + super[prop]; + super.prop(); + super[prop](); + } + + static staticMethod() { + // Don't transform + super.prop; + super[prop]; + super.prop(); + super[prop](); + } + } +});