From e0151eafc8862ed916b203fbca4dc44db10bc292 Mon Sep 17 00:00:00 2001 From: YunfeiHe Date: Fri, 18 Nov 2022 19:01:03 +0800 Subject: [PATCH] Add case for respecting side-effect of getter and setter --- crates/swc_atoms/words.txt | 1 + .../src/compress/optimize/mod.rs | 2 ++ .../tests/fixture/issues/6422/1/config.json | 5 +++ .../tests/fixture/issues/6422/1/input.js | 21 +++++++++++++ .../tests/fixture/issues/6422/1/output.js | 18 +++++++++++ crates/swc_ecma_utils/src/lib.rs | 31 +++++++++++++------ 6 files changed, 68 insertions(+), 10 deletions(-) create mode 100644 crates/swc_ecma_minifier/tests/fixture/issues/6422/1/config.json create mode 100644 crates/swc_ecma_minifier/tests/fixture/issues/6422/1/input.js create mode 100644 crates/swc_ecma_minifier/tests/fixture/issues/6422/1/output.js diff --git a/crates/swc_atoms/words.txt b/crates/swc_atoms/words.txt index 07b7a5fe01b0..dcdf635a8ace 100644 --- a/crates/swc_atoms/words.txt +++ b/crates/swc_atoms/words.txt @@ -1369,3 +1369,4 @@ ychannelselector yield zoomAndPan zoomandpan +__proto__ \ No newline at end of file diff --git a/crates/swc_ecma_minifier/src/compress/optimize/mod.rs b/crates/swc_ecma_minifier/src/compress/optimize/mod.rs index 1da8a3bde6af..9435775c5f80 100644 --- a/crates/swc_ecma_minifier/src/compress/optimize/mod.rs +++ b/crates/swc_ecma_minifier/src/compress/optimize/mod.rs @@ -1918,6 +1918,7 @@ where #[cfg(feature = "debug")] let start = dump(&n.expr, true); + // Fix https://github.com/swc-project/swc/issues/6422 let is_object_lit_with_spread = n .expr .as_object() @@ -2572,6 +2573,7 @@ where if can_be_removed { self.changed = true; report_change!("unused: Dropping an expression without side effect"); + tracing::debug!("unused: Dropping \n{}\n", dump(&*expr, false)); dump_change_detail!("unused: Dropping \n{}\n", dump(&*expr, false)); *s = Stmt::Empty(EmptyStmt { span: DUMMY_SP }); return; diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/6422/1/config.json b/crates/swc_ecma_minifier/tests/fixture/issues/6422/1/config.json new file mode 100644 index 000000000000..480beee76639 --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/issues/6422/1/config.json @@ -0,0 +1,5 @@ +{ + "collapse_vars": true, + "unused": true, + "toplevel": true +} \ No newline at end of file diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/6422/1/input.js b/crates/swc_ecma_minifier/tests/fixture/issues/6422/1/input.js new file mode 100644 index 000000000000..84de0d303429 --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/issues/6422/1/input.js @@ -0,0 +1,21 @@ +let getter_effect = 'FAIL'; +let setter_effect = 'FAIL'; +let proto = { + get foo() { + getter_effect = 'PASS'; + }, + set bar(value) { + setter_effect = 'PASS'; + } +}; +let obj1 = { + __proto__: proto +}; +let obj2 = { + __proto__: proto +}; +let unused = obj1.foo; +obj2.bar = 0; + +assert.strictEqual(getter_effect, 'PASS'); +assert.strictEqual(setter_effect, 'PASS'); \ No newline at end of file diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/6422/1/output.js b/crates/swc_ecma_minifier/tests/fixture/issues/6422/1/output.js new file mode 100644 index 000000000000..e3d96e8a2cbc --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/issues/6422/1/output.js @@ -0,0 +1,18 @@ +let getter_effect = 'FAIL'; +let setter_effect = 'FAIL'; +let proto = { + get foo () { + getter_effect = 'PASS'; + }, + set bar (value){ + setter_effect = 'PASS'; + } +}; +({ + __proto__: proto +}).foo; +({ + __proto__: proto +}).bar = 0; +assert.strictEqual(getter_effect, 'PASS'); +assert.strictEqual(setter_effect, 'PASS'); diff --git a/crates/swc_ecma_utils/src/lib.rs b/crates/swc_ecma_utils/src/lib.rs index f2aa790f538a..e16f3c2beaf0 100644 --- a/crates/swc_ecma_utils/src/lib.rs +++ b/crates/swc_ecma_utils/src/lib.rs @@ -1375,18 +1375,29 @@ pub trait ExprExt { } } Expr::Object(obj) => { - let is_static_accessor = |prop: &PropOrSpread| { - if let PropOrSpread::Prop(prop) = prop { - if let Prop::Getter(_) | Prop::Setter(_) = &**prop { - true - } else { - false - } - } else { - false + let is_prop_could_has_side_effect = |prop: &PropOrSpread| { + match prop { + // ({ ...{ __proto__: { get foo() { a = 1; } } } }).foo + PropOrSpread::Spread(_) => true, + PropOrSpread::Prop(prop) => match prop.as_ref() { + Prop::Shorthand(ident) => ident.sym == js_word!("__proto__"), + Prop::KeyValue(KeyValueProp { key, value, .. }) => match key { + PropName::Ident(ident) => { + ident.sym == js_word!("__proto__") + } + PropName::Str(str) => str.value == js_word!("__proto__"), + PropName::Computed(_) => true, + _ => false, + }, + Prop::Getter(..) | Prop::Setter(..) => true, + Prop::Method(prop) => true, + Prop::Assign(_) => { + unreachable!("This is **invalid** for object literal") + } + }, } }; - if obj.props.iter().any(is_static_accessor) { + if obj.props.iter().any(is_prop_could_has_side_effect) { return true; } }