From 293413fe71bded44176c70721ec1b76f36bea295 Mon Sep 17 00:00:00 2001 From: Dunqing <29533304+Dunqing@users.noreply.github.com> Date: Mon, 26 Aug 2024 03:30:16 +0000 Subject: [PATCH] fix(semantic): implicit return `UpdateExpression` in `ArrowFunctionExpression` does not as read reference (#5161) close: #5158 close: #5156 --- crates/oxc_semantic/src/builder.rs | 14 ++++- .../oxc_semantic/tests/integration/symbols.rs | 54 +++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/crates/oxc_semantic/src/builder.rs b/crates/oxc_semantic/src/builder.rs index 5c68400be..74f4fa777 100644 --- a/crates/oxc_semantic/src/builder.rs +++ b/crates/oxc_semantic/src/builder.rs @@ -2013,7 +2013,19 @@ impl<'a> SemanticBuilder<'a> { for node in self.nodes.iter_parents(self.current_node_id).skip(1) { return match node.kind() { AstKind::ParenthesizedExpression(_) => continue, - AstKind::ExpressionStatement(_) => false, + AstKind::ExpressionStatement(_) => { + if self.current_scope_flags().is_arrow() { + if let Some(node) = self.nodes.iter_parents(node.id()).nth(2) { + // (x) => x++ + // ^^^ implicit return, we need to treat `x` as a read reference + if matches!(node.kind(), AstKind::ArrowFunctionExpression(arrow) if arrow.expression) + { + return true; + } + } + } + false + } _ => true, }; } diff --git a/crates/oxc_semantic/tests/integration/symbols.rs b/crates/oxc_semantic/tests/integration/symbols.rs index baef2aa92..76a061b5f 100644 --- a/crates/oxc_semantic/tests/integration/symbols.rs +++ b/crates/oxc_semantic/tests/integration/symbols.rs @@ -372,3 +372,57 @@ fn test_ts_interface_heritage() { .has_number_of_references(1) .test(); } + +#[test] +fn test_arrow_implicit_return() { + SemanticTester::js("let i = 0; const x = () => i") + .has_root_symbol("i") + .has_number_of_reads(1) + .has_number_of_writes(0) + .test(); + + SemanticTester::js("let i = 0; const x = () => ++i") + .has_root_symbol("i") + .has_number_of_reads(1) + .has_number_of_writes(1) + .test(); + + SemanticTester::js("let i = 0; const x = () => { ++i }") + .has_root_symbol("i") + .has_number_of_reads(0) + .has_number_of_writes(1) + .test(); + + SemanticTester::js("let i = 0; const x = () => (0, ++i)") + .has_root_symbol("i") + .has_number_of_reads(1) + .has_number_of_writes(1) + .test(); + + SemanticTester::js("let i = 0; const x = () => (++i, 0)") + .has_root_symbol("i") + .has_number_of_reads(1) + .has_number_of_writes(1) + .test(); + + SemanticTester::js("let i = 1; const foo = () => () => { i++ }") + .has_root_symbol("i") + .has_number_of_reads(0) + .has_number_of_writes(1) + .test(); +} + +#[test] +fn test_arrow_explicit_return() { + SemanticTester::js("let i = 0; const x = () => { return i }") + .has_root_symbol("i") + .has_number_of_reads(1) + .has_number_of_writes(0) + .test(); + + SemanticTester::js("let i = 0; const x = () => { return ++i }") + .has_root_symbol("i") + .has_number_of_reads(1) + .has_number_of_writes(1) + .test(); +}