From f639a30bd2410d1d40f63f5ca0080eb2ba5fe84d Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Tue, 11 Jan 2022 05:13:46 +0000 Subject: [PATCH] fix corner cases in `typeofs` (#5286) --- lib/compress.js | 36 ++++++++-- test/compress/typeof.js | 143 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 174 insertions(+), 5 deletions(-) diff --git a/lib/compress.js b/lib/compress.js index 8c9e3f76..b1838a1c 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -8764,14 +8764,40 @@ Compressor.prototype.compress = function(node) { return; } if (!body) return; + var abort = false; var def = sym.definition(); - var tw = new TreeWalker(function(node) { - if (node instanceof AST_Scope) { - var parent = tw.parent(); - if (parent instanceof AST_Call && parent.expression === node) return; + var fn; + var tw = new TreeWalker(function(node, descend) { + if (abort) return true; + if (node instanceof AST_Assign) { + var ref = node.left; + if (!(ref instanceof AST_SymbolRef && ref.definition() === def)) return; + node.right.walk(tw); + switch (node.operator) { + case "=": + case "&&=": + abort = true; + } + return true; + } + if (node instanceof AST_Call) { + descend(); + fn = node.expression.tail_node(); + if (fn instanceof AST_Lambda) { + fn.walk(tw); + } else { + abort = true; + } + return true; + } + if (node instanceof AST_Scope) { + if (node === fn) return; + return true; + } + if (node instanceof AST_SymbolRef) { + if (node.definition() === def) node.defined = true; return true; } - if (node instanceof AST_SymbolRef && node.definition() === def) node.defined = true; }); body.walk(tw); diff --git a/test/compress/typeof.js b/test/compress/typeof.js index 320817ee..6b4b8d25 100644 --- a/test/compress/typeof.js +++ b/test/compress/typeof.js @@ -436,6 +436,149 @@ emberjs_global: { expect_stdout: Error("PASS") } +reassign: { + options = { + comparisons: true, + conditionals: true, + passes: 2, + typeofs: true, + } + input: { + A = console; + if ("undefined" == typeof A) + console.log("FAIL 1"); + else { + A = void 0; + while (console.log(void 0 === A ? "PASS" : "FAIL 2")); + } + } + expect: { + A = console; + if ("undefined" == typeof A) + console.log("FAIL 1"); + else { + A = void 0; + while (console.log(void 0 === A ? "PASS" : "FAIL 2")); + } + } + expect_stdout: "PASS" +} + +reassign_call: { + options = { + comparisons: true, + conditionals: true, + passes: 2, + typeofs: true, + } + input: { + A = console; + function f() { + A = void 0; + } + if ("undefined" == typeof A) + console.log("FAIL 1"); + else { + f(); + while (console.log(void 0 === A ? "PASS" : "FAIL 2")); + } + } + expect: { + A = console; + function f() { + A = void 0; + } + if ("undefined" == typeof A) + console.log("FAIL 1"); + else { + f(); + while (console.log(void 0 === A ? "PASS" : "FAIL 2")); + } + } + expect_stdout: "PASS" +} + +reassign_conditional: { + options = { + comparisons: true, + conditionals: true, + passes: 2, + typeofs: true, + } + input: { + A = console; + if ("undefined" == typeof A) + console.log("FAIL 1"); + else { + A &&= void 0; + while (console.log(void 0 === A ? "PASS" : "FAIL 2")); + } + } + expect: { + A = console; + if ("undefined" == typeof A) + console.log("FAIL 1"); + else { + A &&= void 0; + while (console.log(void 0 === A ? "PASS" : "FAIL 2")); + } + } + expect_stdout: "PASS" + node_version: ">=15" +} + +reassign_iife: { + options = { + comparisons: true, + conditionals: true, + passes: 2, + typeofs: true, + } + input: { + A = console; + if ("undefined" == typeof A) + console.log("FAIL 1"); + else (function() { + A = void 0; + })(console.log(void 0 === A ? "FAIL 2" : "PASS")); + } + expect: { + A = console; + "undefined" == typeof A ? console.log("FAIL 1") : function() { + A = void 0; + }(console.log((A, false) ? "FAIL 2" : "PASS")); + } + expect_stdout: "PASS" +} + +reassign_property: { + options = { + comparisons: true, + conditionals: true, + passes: 2, + typeofs: true, + } + input: { + A = console; + if ("undefined" == typeof A) + console.log("FAIL 1"); + else { + A.p = void 0; + while (console.log(void 0 === A ? "FAIL 2" : "PASS")); + } + } + expect: { + A = console; + if ("undefined" == typeof A) + console.log("FAIL 1"); + else { + A.p = void 0; + while (console.log((A, false) ? "FAIL 2" : "PASS")); + } + } + expect_stdout: "PASS" +} + issue_3817: { options = { comparisons: true,