improve handling of `eval` (#3776)
authorAlex Lam S.L <alexlamsl@gmail.com>
Fri, 10 Apr 2020 22:36:17 +0000 (23:36 +0100)
committerGitHub <noreply@github.com>
Fri, 10 Apr 2020 22:36:17 +0000 (06:36 +0800)
closes #3768

lib/compress.js
lib/scope.js
test/compress/issue-3768.js
test/compress/issue-782.js
test/compress/issue-973.js

index e9f8373..98724bd 100644 (file)
@@ -996,9 +996,7 @@ merge(Compressor.prototype, {
 
     function needs_unbinding(compressor, val) {
         return val instanceof AST_PropAccess
-            || compressor.has_directive("use strict")
-                && is_undeclared_ref(val)
-                && val.name == "eval";
+            || is_undeclared_ref(val) && val.name == "eval";
     }
 
     // we shouldn't compress (1,func)(something) to
index 35d97e1..ad33c5e 100644 (file)
@@ -162,17 +162,22 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
         }
         if (node instanceof AST_SymbolRef) {
             var name = node.name;
-            if (name == "eval" && tw.parent() instanceof AST_Call) {
-                for (var s = node.scope; s && !s.uses_eval; s = s.parent_scope) {
-                    s.uses_eval = true;
-                }
-            }
             var sym = node.scope.find_variable(name);
             if (!sym) {
                 sym = self.def_global(node);
             } else if (sym.scope instanceof AST_Lambda && name == "arguments") {
                 sym.scope.uses_arguments = true;
             }
+            if (name == "eval") {
+                var parent = tw.parent();
+                if (parent.TYPE == "Call" && parent.expression === node) {
+                    for (var s = node.scope; s && !s.uses_eval; s = s.parent_scope) {
+                        s.uses_eval = true;
+                    }
+                } else if (sym.undeclared) {
+                    self.uses_eval = true;
+                }
+            }
             node.thedef = sym;
             node.reference(options);
             return true;
index c3475ac..c467fa6 100644 (file)
@@ -9,12 +9,12 @@ mangle: {
         })();
     }
     expect: {
-        var o = eval, e = 42;
+        var e = eval, x = 42;
         (function() {
-            console.log(o("typeof x"));
+            console.log(e("typeof x"));
         })();
     }
-    expect_stdout: "undefined"
+    expect_stdout: true
 }
 
 compress: {
@@ -49,7 +49,7 @@ compress: {
         console.log(function() {
             var a = 42;
             return eval("typeof a");
-        }(), eval("typeof a"), function(eval) {
+        }(), (0, eval)("typeof a"), function(eval) {
             var a = false;
             return eval("typeof a");
         }(eval), function(f) {
@@ -66,3 +66,63 @@ compress: {
     }
     expect_stdout: "number undefined boolean string undefined"
 }
+
+call_arg_1: {
+    mangle = {
+        toplevel: true,
+    }
+    input: {
+        var z = "foo";
+        (function() {
+            var z = false;
+            (function(e) {
+                var z = 42;
+                e("console.log(typeof z)");
+            })(eval);
+        })();
+    }
+    expect: {
+        var z = "foo";
+        (function() {
+            var o = false;
+            (function(o) {
+                var a = 42;
+                o("console.log(typeof z)");
+            })(eval);
+        })();
+    }
+    expect_stdout: true
+}
+
+call_arg_2: {
+    mangle = {
+        toplevel: true,
+    }
+    input: {
+        function eval() {
+            console.log("PASS");
+        }
+        var z = "foo";
+        (function() {
+            var z = false;
+            (function(e) {
+                var z = 42;
+                e("console.log(typeof z)");
+            })(eval);
+        })();
+    }
+    expect: {
+        function n() {
+            console.log("PASS");
+        }
+        var o = "foo";
+        (function() {
+            var o = false;
+            (function(o) {
+                var n = 42;
+                o("console.log(typeof z)");
+            })(n);
+        })();
+    }
+    expect_stdout: "PASS"
+}
index 6e1c92f..34baf5f 100644 (file)
@@ -8,7 +8,7 @@ remove_sequence: {
         (0, 1, _decorators.logThis)();
     }
     expect: {
-        eval();
+        (0, eval)();
         logThis();
         (0, _decorators.logThis)();
     }
index e127c10..9307110 100644 (file)
@@ -53,20 +53,23 @@ this_binding_conditionals: {
 this_binding_collapse_vars: {
     options = {
         collapse_vars: true,
-        toplevel: true,
         unused: true,
     }
     input: {
-        "use strict";
-        var c = a; c();
-        var d = a.b; d();
-        var e = eval; e();
+        function f() {
+            "use strict";
+            var c = a; c();
+            var d = a.b; d();
+            var e = eval; e();
+        }
     }
     expect: {
-        "use strict";
-        a();
-        (0, a.b)();
-        (0, eval)();
+        function f() {
+            "use strict";
+            a();
+            (0, a.b)();
+            (0, eval)();
+        }
     }
 }
 
@@ -97,7 +100,7 @@ this_binding_side_effects: {
         (function(foo) {
             foo();
             (0, foo.bar)();
-            eval("console.log(foo);");
+            (0, eval)("console.log(foo);");
         }());
         (function(foo) {
             "use strict";
@@ -144,7 +147,7 @@ this_binding_sequences: {
             return eval("this");
         }()),
         console.log(typeof function() {
-            return eval("this");
+            return (0, eval)("this");
         }()),
         console.log(typeof function() {
             "use strict";