From 94ff94cd34b9977c1b7eed03ccdaf1650409029b Mon Sep 17 00:00:00 2001 From: Dunqing <29533304+Dunqing@users.noreply.github.com> Date: Mon, 2 Sep 2024 18:06:08 +0000 Subject: [PATCH] fix(transformer/arrow-functions): reaches `unreachable` when `` is inside an arrow function (#5356) Fixes: https://github.com/oxc-project/oxc/issues/5353#issuecomment-2321792915 --- .../src/es2015/arrow_functions.rs | 39 ++++++++++++------- crates/oxc_transformer/src/es2015/mod.rs | 10 +++++ crates/oxc_transformer/src/lib.rs | 8 ++++ tasks/transform_conformance/oxc.snap.md | 11 +++++- .../with-this-member-expression/input.jsx | 3 ++ .../with-this-member-expression/output.js | 4 ++ 6 files changed, 58 insertions(+), 17 deletions(-) create mode 100644 tasks/transform_conformance/tests/babel-plugin-transform-arrow-functions/test/fixtures/with-this-member-expression/input.jsx create mode 100644 tasks/transform_conformance/tests/babel-plugin-transform-arrow-functions/test/fixtures/with-this-member-expression/output.js diff --git a/crates/oxc_transformer/src/es2015/arrow_functions.rs b/crates/oxc_transformer/src/es2015/arrow_functions.rs index f9b60ce3c..c124bacd0 100644 --- a/crates/oxc_transformer/src/es2015/arrow_functions.rs +++ b/crates/oxc_transformer/src/es2015/arrow_functions.rs @@ -137,22 +137,31 @@ impl<'a> Traverse<'a> for ArrowFunctions<'a> { return; } - let ident = match name { - JSXElementName::Identifier(ident) => ident, - JSXElementName::MemberExpression(member_expr) => { - member_expr.get_object_identifier_mut() + if let JSXElementName::Identifier(ident) = name { + if ident.name == "this" { + let mut new_ident = self.get_this_name(ctx).create_read_reference(ctx); + new_ident.span = ident.span; + *name = self.ctx.ast.jsx_element_name_from_identifier_reference(new_ident); + } + } + } + + /// Change to <_this.foo>, and mark it as found + fn enter_jsx_member_expression_object( + &mut self, + node: &mut JSXMemberExpressionObject<'a>, + ctx: &mut TraverseCtx<'a>, + ) { + if !self.is_inside_arrow_function() { + return; + } + + if let JSXMemberExpressionObject::IdentifierReference(ident) = node { + if ident.name == "this" { + let mut new_ident = self.get_this_name(ctx).create_read_reference(ctx); + new_ident.span = ident.span; + *node = ctx.ast.jsx_member_expression_object_from_identifier_reference(new_ident); } - JSXElementName::IdentifierReference(_) | JSXElementName::NamespacedName(_) => return, - }; - if ident.name == "this" { - // We can't produce a proper identifier with a `ReferenceId` because `JSXIdentifier` - // lacks that field. https://github.com/oxc-project/oxc/issues/3528 - // So generate a reference and just use its name. - // If JSX transform is enabled, that transform runs before this and will have converted - // this to a proper `ThisExpression`, and this visitor won't run. - // So only a problem if JSX transform is disabled. - let new_ident = self.get_this_name(ctx).create_read_reference(ctx); - ident.name = new_ident.name; } } diff --git a/crates/oxc_transformer/src/es2015/mod.rs b/crates/oxc_transformer/src/es2015/mod.rs index 39861c5ac..3905e0641 100644 --- a/crates/oxc_transformer/src/es2015/mod.rs +++ b/crates/oxc_transformer/src/es2015/mod.rs @@ -57,6 +57,16 @@ impl<'a> Traverse<'a> for ES2015<'a> { } } + fn enter_jsx_member_expression_object( + &mut self, + node: &mut JSXMemberExpressionObject<'a>, + ctx: &mut TraverseCtx<'a>, + ) { + if self.options.arrow_function.is_some() { + self.arrow_functions.enter_jsx_member_expression_object(node, ctx); + } + } + fn enter_declaration(&mut self, decl: &mut Declaration<'a>, ctx: &mut TraverseCtx<'a>) { if self.options.arrow_function.is_some() { self.arrow_functions.enter_declaration(decl, ctx); diff --git a/crates/oxc_transformer/src/lib.rs b/crates/oxc_transformer/src/lib.rs index 0f64bb4eb..5da9a284f 100644 --- a/crates/oxc_transformer/src/lib.rs +++ b/crates/oxc_transformer/src/lib.rs @@ -240,6 +240,14 @@ impl<'a> Traverse<'a> for Transformer<'a> { self.x3_es2015.enter_jsx_element_name(elem, ctx); } + fn enter_jsx_member_expression_object( + &mut self, + node: &mut JSXMemberExpressionObject<'a>, + ctx: &mut TraverseCtx<'a>, + ) { + self.x3_es2015.enter_jsx_member_expression_object(node, ctx); + } + fn enter_method_definition( &mut self, def: &mut MethodDefinition<'a>, diff --git a/tasks/transform_conformance/oxc.snap.md b/tasks/transform_conformance/oxc.snap.md index e7f97fc25..02c675b6b 100644 --- a/tasks/transform_conformance/oxc.snap.md +++ b/tasks/transform_conformance/oxc.snap.md @@ -1,10 +1,9 @@ commit: 3bcfee23 -Passed: 10/38 +Passed: 10/39 # All Passed: * babel-plugin-transform-optional-catch-binding -* babel-plugin-transform-arrow-functions # babel-plugin-transform-nullish-coalescing-operator (0/1) @@ -15,6 +14,14 @@ Passed: 10/38 +# babel-plugin-transform-arrow-functions (1/2) +* with-this-member-expression/input.jsx + x Unresolved references mismatch: + | after transform: ["this"] + | rebuilt : [] + + + # babel-plugin-transform-typescript (2/8) * class-property-definition/input.ts x Unresolved references mismatch: diff --git a/tasks/transform_conformance/tests/babel-plugin-transform-arrow-functions/test/fixtures/with-this-member-expression/input.jsx b/tasks/transform_conformance/tests/babel-plugin-transform-arrow-functions/test/fixtures/with-this-member-expression/input.jsx new file mode 100644 index 000000000..7db8b3bc2 --- /dev/null +++ b/tasks/transform_conformance/tests/babel-plugin-transform-arrow-functions/test/fixtures/with-this-member-expression/input.jsx @@ -0,0 +1,3 @@ +() => { + +} \ No newline at end of file diff --git a/tasks/transform_conformance/tests/babel-plugin-transform-arrow-functions/test/fixtures/with-this-member-expression/output.js b/tasks/transform_conformance/tests/babel-plugin-transform-arrow-functions/test/fixtures/with-this-member-expression/output.js new file mode 100644 index 000000000..9cf1a37b4 --- /dev/null +++ b/tasks/transform_conformance/tests/babel-plugin-transform-arrow-functions/test/fixtures/with-this-member-expression/output.js @@ -0,0 +1,4 @@ +var _this = this; +(function() { + <_this.foo>; +}); \ No newline at end of file