suppress `collapse_vars` of `this` into "use strict" (#2326)
authorAlex Lam S.L <alexlamsl@gmail.com>
Tue, 19 Sep 2017 21:23:20 +0000 (05:23 +0800)
committerGitHub <noreply@github.com>
Tue, 19 Sep 2017 21:23:20 +0000 (05:23 +0800)
fixes #2319

lib/ast.js
lib/compress.js
test/compress/collapse_vars.js

index 0918574..9b243f1 100644 (file)
@@ -134,11 +134,10 @@ var AST_Debugger = DEFNODE("Debugger", null, {
     $documentation: "Represents a debugger statement",
 }, AST_Statement);
 
-var AST_Directive = DEFNODE("Directive", "value scope quote", {
+var AST_Directive = DEFNODE("Directive", "value quote", {
     $documentation: "Represents a directive, like \"use strict\";",
     $propdoc: {
         value: "[string] The value of this directive as a plain string (it's not an AST_String!)",
-        scope: "[AST_Scope/S] The scope that this directive affects",
         quote: "[string] the original quote character"
     },
 }, AST_Statement);
@@ -299,10 +298,9 @@ var AST_With = DEFNODE("With", "expression", {
 
 /* -----[ scope and functions ]----- */
 
-var AST_Scope = DEFNODE("Scope", "directives variables functions uses_with uses_eval parent_scope enclosed cname", {
+var AST_Scope = DEFNODE("Scope", "variables functions uses_with uses_eval parent_scope enclosed cname", {
     $documentation: "Base class for all statements introducing a lexical scope",
     $propdoc: {
-        directives: "[string*/S] an array of directives declared in this scope",
         variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope",
         functions: "[Object/S] like `variables`, but only lists function declarations",
         uses_with: "[boolean/S] tells whether this scope uses the `with` statement",
index 3164c5a..9e516a8 100644 (file)
@@ -842,6 +842,8 @@ merge(Compressor.prototype, {
                     && !fn.uses_eval
                     && (iife = compressor.parent()) instanceof AST_Call
                     && iife.expression === fn) {
+                    var fn_strict = compressor.has_directive("use strict");
+                    if (fn_strict && fn.body.indexOf(fn_strict) < 0) fn_strict = false;
                     var names = Object.create(null);
                     for (var i = fn.argnames.length; --i >= 0;) {
                         var sym = fn.argnames[i];
@@ -859,7 +861,7 @@ merge(Compressor.prototype, {
                                     }
                                     arg = null;
                                 }
-                                if (node instanceof AST_This && !tw.find_parent(AST_Scope)) {
+                                if (node instanceof AST_This && (fn_strict || !tw.find_parent(AST_Scope))) {
                                     arg = null;
                                     return true;
                                 }
index 5e7e982..ecd1861 100644 (file)
@@ -2451,3 +2451,73 @@ issue_2313_2: {
     }
     expect_stdout: "0"
 }
+
+issue_2319_1: {
+    options = {
+        collapse_vars: true,
+        unused: true,
+    }
+    input: {
+        console.log(function(a) {
+            return a;
+        }(!function() {
+            return this;
+        }()));
+    }
+    expect: {
+        console.log(function(a) {
+            return !function() {
+                return this;
+            }();
+        }());
+    }
+    expect_stdout: "false"
+}
+
+issue_2319_2: {
+    options = {
+        collapse_vars: true,
+        unused: true,
+    }
+    input: {
+        console.log(function(a) {
+            "use strict";
+            return a;
+        }(!function() {
+            return this;
+        }()));
+    }
+    expect: {
+        console.log(function(a) {
+            "use strict";
+            return a;
+        }(!function() {
+            return this;
+        }()));
+    }
+    expect_stdout: "false"
+}
+
+issue_2319_3: {
+    options = {
+        collapse_vars: true,
+        unused: true,
+    }
+    input: {
+        "use strict";
+        console.log(function(a) {
+            return a;
+        }(!function() {
+            return this;
+        }()));
+    }
+    expect: {
+        "use strict";
+        console.log(function(a) {
+            return !function() {
+                return this;
+            }();
+        }());
+    }
+    expect_stdout: "true"
+}