fix corner case in parsing directives (#3615)
authorAlex Lam S.L <alexlamsl@gmail.com>
Fri, 29 Nov 2019 10:57:29 +0000 (18:57 +0800)
committerGitHub <noreply@github.com>
Fri, 29 Nov 2019 10:57:29 +0000 (18:57 +0800)
lib/parse.js
test/compress/directives.js [new file with mode: 0644]
test/compress/functions.js
test/mocha/directives.js
test/mocha/number-literal.js

index 16d8dad..c9ee01f 100644 (file)
@@ -787,20 +787,18 @@ function parse($TEXT, options) {
         handle_regexp();
         switch (S.token.type) {
           case "string":
-            if (S.in_directives) {
-                var token = peek();
-                if (S.token.raw.indexOf("\\") == -1
-                    && (is_token(token, "punc", ";")
-                        || is_token(token, "punc", "}")
-                        || has_newline_before(token)
-                        || is_token(token, "eof"))) {
-                    S.input.add_directive(S.token.value);
+            var dir = S.in_directives;
+            var body = expression(true);
+            if (dir) {
+                var token = body.start;
+                if (body instanceof AST_String && token.raw.indexOf("\\") == -1) {
+                    S.input.add_directive(token.value);
                 } else {
-                    S.in_directives = false;
+                    S.in_directives = dir = false;
                 }
             }
-            var dir = S.in_directives, stat = simple_statement();
-            return dir ? new AST_Directive(stat.body) : stat;
+            semicolon();
+            return dir ? new AST_Directive(body) : new AST_SimpleStatement({ body: body });
           case "num":
           case "regexp":
           case "operator":
@@ -965,8 +963,10 @@ function parse($TEXT, options) {
         return new AST_LabeledStatement({ body: stat, label: label });
     }
 
-    function simple_statement(tmp) {
-        return new AST_SimpleStatement({ body: (tmp = expression(true), semicolon(), tmp) });
+    function simple_statement() {
+        var body = expression(true);
+        semicolon();
+        return new AST_SimpleStatement({ body: body });
     }
 
     function break_cont(type) {
diff --git a/test/compress/directives.js b/test/compress/directives.js
new file mode 100644 (file)
index 0000000..590d162
--- /dev/null
@@ -0,0 +1,95 @@
+simple_statement_is_not_a_directive: {
+    input: {
+        "use strict"
+            .split(" ")
+            .forEach(function(s) {
+                console.log(s);
+            });
+        console.log(!this); // is strict mode?
+        (function() {
+            "directive"
+            ""
+            "use strict"
+            "hello world"
+                .split(" ")
+                .forEach(function(s) {
+                    console.log(s);
+                });
+            console.log(!this); // is strict mode?
+        })();
+    }
+    expect: {
+        "use strict".split(" ").forEach(function(s) {
+            console.log(s);
+        });
+        console.log(!this);
+        (function() {
+            "directive";
+            "";
+            "use strict";
+            "hello world".split(" ").forEach(function(s) {
+                console.log(s);
+            });
+            console.log(!this);
+        })();
+    }
+    expect_stdout: [
+        "use",
+        "strict",
+        "false",
+        "hello",
+        "world",
+        "true",
+    ]
+}
+
+drop_lone_use_strict: {
+    options = {
+        directives: true,
+        side_effects: true,
+    }
+    input: {
+        function f1() {
+            "use strict";
+        }
+        function f2() {
+            "use strict";
+            function f3() {
+                "use strict";
+            }
+        }
+        (function f4() {
+            "use strict";
+        })();
+    }
+    expect: {
+        function f1() {
+        }
+        function f2() {
+            "use strict";
+            function f3() {
+            }
+        }
+    }
+}
+
+issue_3166: {
+    options = {
+        directives: true,
+    }
+    input: {
+        "foo";
+        "use strict";
+        function f() {
+            "use strict";
+            "bar";
+            "use asm";
+        }
+    }
+    expect: {
+        "use strict";
+        function f() {
+            "use asm";
+        }
+    }
+}
index 8795afb..4fea42d 100644 (file)
@@ -2004,57 +2004,6 @@ deduplicate_parenthesis: {
     expect_exact: "({}).a=b;({}.a=b)();(function(){}).a=b;(function(){}.a=b)();"
 }
 
-drop_lone_use_strict: {
-    options = {
-        directives: true,
-        side_effects: true,
-    }
-    input: {
-        function f1() {
-            "use strict";
-        }
-        function f2() {
-            "use strict";
-            function f3() {
-                "use strict";
-            }
-        }
-        (function f4() {
-            "use strict";
-        })();
-    }
-    expect: {
-        function f1() {
-        }
-        function f2() {
-            "use strict";
-            function f3() {
-            }
-        }
-    }
-}
-
-issue_3166: {
-    options = {
-        directives: true,
-    }
-    input: {
-        "foo";
-        "use strict";
-        function f() {
-            "use strict";
-            "bar";
-            "use asm";
-        }
-    }
-    expect: {
-        "use strict";
-        function f() {
-            "use asm";
-        }
-    }
-}
-
 issue_3016_1: {
     options = {
         inline: true,
index 74660dc..e872747 100644 (file)
@@ -54,8 +54,8 @@ describe("Directives", function() {
         [
             [
                 '"use strict"\n',
-                [ "use strict"],
-                [ "use asm"]
+                [ "use strict" ],
+                [ "use asm" ]
             ],
             [
                 '"use\\\nstrict";',
@@ -80,8 +80,8 @@ describe("Directives", function() {
             [
                 // no ; or newline
                 '"use strict"',
-                [],
-                [ "use strict", "use\nstrict", "use \nstrict", "use asm" ]
+                [ "use strict" ],
+                [ "use\nstrict", "use \nstrict", "use asm" ]
             ],
             [
                 ';"use strict"',
@@ -116,8 +116,8 @@ describe("Directives", function() {
             ],
             [
                 'var foo = function() {"use strict"', // no ; or newline
-                [],
-                [ "use strict", "use\nstrict", "use \nstrict", "use asm" ]
+                [ "use strict" ],
+                [ "use\nstrict", "use \nstrict", "use asm" ]
             ],
             [
                 'var foo = function() {;"use strict"',
index c7560eb..b87c88b 100644 (file)
@@ -2,10 +2,18 @@ var assert = require("assert");
 var UglifyJS = require("../node");
 
 describe("Number literals", function() {
+    it("Should allow legacy octal literals in non-strict mode", function() {
+        [
+            "'use strict'\n.slice()\n00",
+            '"use strict"\n.slice()\nvar foo = 00',
+        ].forEach(function(input) {
+            UglifyJS.parse(input);
+        });
+    });
     it("Should not allow legacy octal literals in strict mode", function() {
         var inputs = [
             '"use strict";00;',
-            '"use strict"; var foo = 00;'
+            '"use strict"; var foo = 00;',
         ];
         var test = function(input) {
             return function() {