From 6003285cfe33f233d3c0c97374c3ad87f9f8ebc2 Mon Sep 17 00:00:00 2001 From: sapphi-red <49056869+sapphi-red@users.noreply.github.com> Date: Sun, 24 Aug 2025 08:42:50 +0000 Subject: [PATCH] fix(minifier): keep property access before call expressions as-is to preserve `this` value (#13278) `['PASS',f][1]()` was compressed to `f()`. But this is not safe because `f` may access `this` and the value of `this` changes. This PR fixes that by skipping this transformation when the parent is a function call. --- .../src/peephole/replace_known_methods.rs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/crates/oxc_minifier/src/peephole/replace_known_methods.rs b/crates/oxc_minifier/src/peephole/replace_known_methods.rs index 827cc07969f30..7d0c8f2cac568 100644 --- a/crates/oxc_minifier/src/peephole/replace_known_methods.rs +++ b/crates/oxc_minifier/src/peephole/replace_known_methods.rs @@ -357,6 +357,14 @@ impl<'a> PeepholeOptimizations { } pub fn replace_known_property_access(node: &mut Expression<'a>, ctx: &mut Ctx<'a, '_>) { + // property access should be kept to keep `this` value + if matches!( + ctx.parent(), + Ancestor::CallExpressionCallee(_) | Ancestor::TaggedTemplateExpressionTag(_) + ) { + return; + } + let (name, object, span) = match node { Expression::StaticMemberExpression(member) if !member.optional => { (member.property.name.as_str(), &member.object, member.span) @@ -1612,6 +1620,20 @@ mod test { test_same("v = [...a, 1][1]"); test_same("v = [1, ...a][0]"); test("v = [1, ...[1,2]][0]", "v = 1"); + + // property access should be kept to keep `this` value + test_same( + " + function f(){ console.log(this[0]) } + ['PASS',f][1]() + ", + ); + test_same( + " + function f(){ console.log(this[0]) } + ['PASS',f][1]`` + ", + ); } #[test]