fix corner case in `arguments` (#3421)
authorAlex Lam S.L <alexlamsl@gmail.com>
Sun, 19 May 2019 04:59:40 +0000 (12:59 +0800)
committerGitHub <noreply@github.com>
Sun, 19 May 2019 04:59:40 +0000 (12:59 +0800)
fixes #3420

lib/compress.js
test/compress/arguments.js
test/compress/keep_fargs.js

index b7e5b3d..e1f0105 100644 (file)
@@ -105,10 +105,10 @@ function Compressor(options, false_by_default) {
     }
     if (this.options["inline"] === true) this.options["inline"] = 3;
     var keep_fargs = this.options["keep_fargs"];
-    this.drop_fargs = keep_fargs == "strict" ? function(lambda) {
+    this.drop_fargs = keep_fargs == "strict" ? function(lambda, parent) {
         if (lambda.length_read) return false;
         var name = lambda.name;
-        if (!name) return true;
+        if (!name) return parent && parent.TYPE == "Call";
         if (name.fixed_value() !== lambda) return false;
         var def = name.definition();
         if (def.direct_access) return false;
@@ -527,12 +527,9 @@ merge(Compressor.prototype, {
         function mark_assignment_to_arguments(node) {
             if (!(node instanceof AST_Sub)) return;
             var expr = node.expression;
-            var prop = node.property;
-            if (expr instanceof AST_SymbolRef
-                && is_arguments(expr.definition())
-                && prop instanceof AST_Number) {
-                expr.definition().reassigned = true;
-            }
+            if (!(expr instanceof AST_SymbolRef)) return;
+            var def = expr.definition();
+            if (is_arguments(def) && node.property instanceof AST_Number) def.reassigned = true;
         }
 
         var suppressor = new TreeWalker(function(node) {
@@ -3641,7 +3638,7 @@ merge(Compressor.prototype, {
                 node.name = null;
             }
             if (node instanceof AST_Lambda && !(node instanceof AST_Accessor)) {
-                var trim = compressor.drop_fargs(node);
+                var trim = compressor.drop_fargs(node, parent);
                 for (var a = node.argnames, i = a.length; --i >= 0;) {
                     var sym = a[i];
                     if (!(sym.definition().id in in_use_ids)) {
@@ -3832,6 +3829,7 @@ merge(Compressor.prototype, {
                 };
             }
         });
+        tt.push(compressor.parent());
         self.transform(tt);
 
         function verify_safe_usage(def, read, modified) {
@@ -6682,23 +6680,30 @@ merge(Compressor.prototype, {
                 }
             }
         }
-        var fn;
+        var parent = compressor.parent();
+        var def, fn, fn_parent;
         if (compressor.option("arguments")
             && expr instanceof AST_SymbolRef
-            && is_arguments(expr.definition())
+            && is_arguments(def = expr.definition())
             && prop instanceof AST_Number
-            && (fn = expr.scope) === compressor.find_parent(AST_Lambda)) {
+            && (fn = expr.scope) === find_lambda()) {
             var index = prop.getValue();
+            if (parent instanceof AST_UnaryPrefix && parent.operator == "delete") {
+                if (!def.deleted) def.deleted = [];
+                def.deleted[index] = true;
+            }
             var argname = fn.argnames[index];
-            if (argname && compressor.has_directive("use strict")) {
-                var def = argname.definition();
+            if (def.deleted && def.deleted[index]) {
+                argname = null;
+            } else if (argname && compressor.has_directive("use strict")) {
+                var arg_def = argname.definition();
                 if (!compressor.option("reduce_vars")
-                    || expr.definition().reassigned
-                    || def.assignments
-                    || def.orig.length > 1) {
+                    || def.reassigned
+                    || arg_def.assignments
+                    || arg_def.orig.length > 1) {
                     argname = null;
                 }
-            } else if (!argname && compressor.drop_fargs(fn) && index < fn.argnames.length + 5) {
+            } else if (!argname && index < fn.argnames.length + 5 && compressor.drop_fargs(fn, fn_parent)) {
                 while (index >= fn.argnames.length) {
                     argname = make_node(AST_SymbolFunarg, fn, {
                         name: fn.make_var_name("argument_" + fn.argnames.length),
@@ -6711,14 +6716,14 @@ merge(Compressor.prototype, {
             if (argname && find_if(function(node) {
                 return node.name === argname.name;
             }, fn.argnames) === argname) {
-                expr.definition().reassigned = false;
+                def.reassigned = false;
                 var sym = make_node(AST_SymbolRef, self, argname);
                 sym.reference({});
                 delete argname.__unused;
                 return sym;
             }
         }
-        if (is_lhs(compressor.self(), compressor.parent())) return self;
+        if (is_lhs(compressor.self(), parent)) return self;
         if (key !== prop) {
             var sub = self.flatten_object(property, compressor);
             if (sub) {
@@ -6767,6 +6772,16 @@ merge(Compressor.prototype, {
             return best_of(compressor, ev, self);
         }
         return self;
+
+        function find_lambda() {
+            var i = 0, p;
+            while (p = compressor.parent(i++)) {
+                if (p instanceof AST_Lambda) {
+                    fn_parent = compressor.parent(i);
+                    return p;
+                }
+            }
+        }
     });
 
     AST_Scope.DEFMETHOD("contains_this", function() {
index eaff811..119eaf2 100644 (file)
@@ -622,3 +622,157 @@ issue_3282_2_passes: {
     }
     expect_stdout: true
 }
+
+issue_3420_1: {
+    options = {
+        arguments: true,
+        keep_fargs: "strict",
+    }
+    input: {
+        console.log(function() {
+            return function() {
+                return arguments[0];
+            };
+        }().length);
+    }
+    expect: {
+        console.log(function() {
+            return function() {
+                return arguments[0];
+            };
+        }().length);
+    }
+    expect_stdout: "0"
+}
+
+issue_3420_2: {
+    options = {
+        arguments: true,
+        keep_fargs: "strict",
+    }
+    input: {
+        var foo = function() {
+            delete arguments[0];
+        };
+        foo();
+    }
+    expect: {
+        var foo = function() {
+            delete arguments[0];
+        };
+        foo();
+    }
+    expect_stdout: true
+}
+
+issue_3420_3: {
+    options = {
+        arguments: true,
+        keep_fargs: "strict",
+    }
+    input: {
+        "use strict";
+        var foo = function() {
+            delete arguments[0];
+        };
+        foo();
+    }
+    expect: {
+        "use strict";
+        var foo = function() {
+            delete arguments[0];
+        };
+        foo();
+    }
+    expect_stdout: true
+}
+
+issue_3420_4: {
+    options = {
+        arguments: true,
+        keep_fargs: "strict",
+    }
+    input: {
+        !function() {
+            console.log(arguments[0]);
+            delete arguments[0];
+            console.log(arguments[0]);
+        }(42);
+    }
+    expect: {
+        !function(argument_0) {
+            console.log(argument_0);
+            delete arguments[0];
+            console.log(arguments[0]);
+        }(42);
+    }
+    expect_stdout: [
+        "42",
+        "undefined",
+    ]
+}
+
+issue_3420_5: {
+    options = {
+        arguments: true,
+        keep_fargs: "strict",
+    }
+    input: {
+        "use strict";
+        !function() {
+            console.log(arguments[0]);
+            delete arguments[0];
+            console.log(arguments[0]);
+        }(42);
+    }
+    expect: {
+        "use strict";
+        !function(argument_0) {
+            console.log(argument_0);
+            delete arguments[0];
+            console.log(arguments[0]);
+        }(42);
+    }
+    expect_stdout: [
+        "42",
+        "undefined",
+    ]
+}
+
+issue_3420_6: {
+    options = {
+        arguments: true,
+        keep_fargs: "strict",
+    }
+    input: {
+        console.log(function() {
+            return delete arguments[0];
+        }());
+    }
+    expect: {
+        console.log(function() {
+            return delete arguments[0];
+        }());
+    }
+    expect_stdout: "true"
+}
+
+issue_3420_7: {
+    options = {
+        arguments: true,
+        keep_fargs: "strict",
+    }
+    input: {
+        "use strict";
+        console.log(function() {
+            return delete arguments[0];
+        }());
+    }
+    expect: {
+        "use strict";
+        console.log(function() {
+            return delete arguments[0];
+        }());
+    }
+    expect_stdout: "true"
+}
index b23e96f..558b10b 100644 (file)
@@ -1051,3 +1051,69 @@ function_name_mangle_ie8: {
     expect_exact: "(function(){console.log(typeof function o(){})})();"
     expect_stdout: "function"
 }
+
+issue_3420_1: {
+    options = {
+        keep_fargs: "strict",
+        unused: true,
+    }
+    input: {
+        console.log(function() {
+            return function(a, b, c, d) {
+                return a + b;
+            };
+        }().length);
+    }
+    expect: {
+        console.log(function() {
+            return function(a, b, c, d) {
+                return a + b;
+            };
+        }().length);
+    }
+    expect_stdout: "4"
+}
+
+issue_3420_2: {
+    options = {
+        inline: true,
+        keep_fargs: "strict",
+        unused: true,
+    }
+    input: {
+        console.log(function() {
+            return function(a, b, c, d) {
+                return a + b;
+            };
+        }().length);
+    }
+    expect: {
+        console.log(function(a, b, c, d) {
+            return a + b;
+        }.length);
+    }
+    expect_stdout: "4"
+}
+
+issue_3420_3: {
+    options = {
+        inline: true,
+        keep_fargs: "strict",
+        reduce_vars: true,
+        unused: true,
+    }
+    input: {
+        console.log(function() {
+            function f(a, b, c, d) {
+                return a + b;
+            }
+            return f;
+        }().length);
+    }
+    expect: {
+        console.log(function(a, b, c, d) {
+            return a + b;
+        }.length);
+    }
+    expect_stdout: "4"
+}