[Pkg-javascript-commits] [uglifyjs] 38/228: Support marking a call as pure

Jonas Smedegaard dr at jones.dk
Sat Apr 15 14:25:14 UTC 2017


This is an automated email from the git hooks/post-receive script.

js pushed a commit to branch master
in repository uglifyjs.

commit 1e51586996ae4fdac68a8ea597c20ab170809c43
Author: kzc <zaxxon2011 at gmail.com>
Date:   Tue Feb 21 14:24:18 2017 +0800

    Support marking a call as pure
    
    A function call or IIFE with an immediately preceding comment
    containing `@__PURE__` or `#__PURE__` is deemed to be a
    side-effect-free pure function call and can potentially be
    dropped.
    
    Depends on `side_effects` option.
    
    `[#@]__PURE__` hint will be removed from comment when pure
    call is dropped.
    
    fixes #1261
    closes #1448
---
 lib/compress.js             |  20 +++++++-
 test/compress/issue-1261.js | 118 ++++++++++++++++++++++++++++++++++++++++++++
 test/mocha/minify.js        |  15 ++++++
 3 files changed, 151 insertions(+), 2 deletions(-)

diff --git a/lib/compress.js b/lib/compress.js
index 4dfcdcf..95e9c1b 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -1360,6 +1360,22 @@ merge(Compressor.prototype, {
         });
     });
 
+    AST_Call.DEFMETHOD("has_pure_annotation", function(compressor) {
+        if (!compressor.option("side_effects")) return false;
+        if (this.pure !== undefined) return this.pure;
+        var pure = false;
+        var comments, last_comment;
+        if (this.start
+            && (comments = this.start.comments_before)
+            && comments.length
+            && /[@#]__PURE__/.test((last_comment = comments[comments.length - 1]).value)) {
+            compressor.warn("Dropping __PURE__ call [{file}:{line},{col}]", this.start);
+            last_comment.value = last_comment.value.replace(/[@#]__PURE__/g, ' ');
+            pure = true;
+        }
+        return this.pure = pure;
+    });
+
     // determine if expression has side effects
     (function(def){
         def(AST_Node, return_true);
@@ -1369,7 +1385,7 @@ merge(Compressor.prototype, {
         def(AST_This, return_false);
 
         def(AST_Call, function(compressor){
-            if (compressor.pure_funcs(this)) return true;
+            if (!this.has_pure_annotation(compressor) && compressor.pure_funcs(this)) return true;
             for (var i = this.args.length; --i >= 0;) {
                 if (this.args[i].has_side_effects(compressor))
                     return true;
@@ -1904,7 +1920,7 @@ merge(Compressor.prototype, {
         def(AST_Constant, return_null);
         def(AST_This, return_null);
         def(AST_Call, function(compressor, first_in_statement){
-            if (compressor.pure_funcs(this)) return this;
+            if (!this.has_pure_annotation(compressor) && compressor.pure_funcs(this)) return this;
             var args = trim(this.args, compressor, first_in_statement);
             return args && AST_Seq.from_array(args);
         });
diff --git a/test/compress/issue-1261.js b/test/compress/issue-1261.js
new file mode 100644
index 0000000..dfbe210
--- /dev/null
+++ b/test/compress/issue-1261.js
@@ -0,0 +1,118 @@
+pure_function_calls: {
+    options = {
+        evaluate     : true,
+        conditionals : true,
+        comparisons  : true,
+        side_effects : true,
+        booleans     : true,
+        unused       : true,
+        if_return    : true,
+        join_vars    : true,
+        cascade      : true,
+        negate_iife  : true,
+    }
+    input: {
+        // pure top-level IIFE will be dropped
+        // @__PURE__ - comment
+        (function() {
+            console.log("iife0");
+        })();
+
+        // pure top-level IIFE assigned to unreferenced var will not be dropped
+        var iife1 = /*@__PURE__*/(function() {
+            console.log("iife1");
+            function iife1() {}
+            return iife1;
+        })();
+
+        (function(){
+            // pure IIFE in function scope assigned to unreferenced var will be dropped
+            var iife2 = /*#__PURE__*/(function() {
+                console.log("iife2");
+                function iife2() {}
+                return iife2;
+            })();
+        })();
+
+        // comment #__PURE__ comment
+        bar(), baz(), quux();
+        a.b(), /* @__PURE__ */ c.d.e(), f.g();
+    }
+    expect: {
+        var iife1 = function() {
+            console.log("iife1");
+            function iife1() {}
+            return iife1;
+        }();
+
+        baz(), quux();
+        a.b(), f.g();
+    }
+    expect_warnings: [
+        "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:17,8]",
+        "WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:17,8]",
+        "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:30,37]",
+        "WARN: Dropping unused variable iife2 [test/compress/issue-1261.js:30,16]",
+        "WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:28,8]",
+        "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:38,8]",
+        "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:39,31]",
+    ]
+}
+
+pure_function_calls_toplevel: {
+    options = {
+        evaluate     : true,
+        conditionals : true,
+        comparisons  : true,
+        side_effects : true,
+        booleans     : true,
+        unused       : true,
+        if_return    : true,
+        join_vars    : true,
+        cascade      : true,
+        negate_iife  : true,
+        toplevel     : true,
+    }
+    input: {
+        // pure top-level IIFE will be dropped
+        // @__PURE__ - comment
+        (function() {
+            console.log("iife0");
+        })();
+
+        // pure top-level IIFE assigned to unreferenced var will be dropped
+        var iife1 = /*@__PURE__*/(function() {
+            console.log("iife1");
+            function iife1() {}
+            return iife1;
+        })();
+
+        (function(){
+            // pure IIFE in function scope assigned to unreferenced var will be dropped
+            var iife2 = /*#__PURE__*/(function() {
+                console.log("iife2");
+                function iife2() {}
+                return iife2;
+            })();
+        })();
+
+        // comment #__PURE__ comment
+        bar(), baz(), quux();
+        a.b(), /* @__PURE__ */ c.d.e(), f.g();
+    }
+    expect: {
+        baz(), quux();
+        a.b(), f.g();
+    }
+    expect_warnings: [
+        "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:79,8]",
+        "WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:79,8]",
+        "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:92,37]",
+        "WARN: Dropping unused variable iife2 [test/compress/issue-1261.js:92,16]",
+        "WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:90,8]",
+        "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:100,8]",
+        "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:101,31]",
+        "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:84,33]",
+        "WARN: Dropping unused variable iife1 [test/compress/issue-1261.js:84,12]",
+    ]
+}
diff --git a/test/mocha/minify.js b/test/mocha/minify.js
index 70cf73a..8fe1565 100644
--- a/test/mocha/minify.js
+++ b/test/mocha/minify.js
@@ -95,4 +95,19 @@ describe("minify", function() {
             assert.strictEqual(code, "var a=function(n){return n};");
         });
     });
+
+    describe("#__PURE__", function() {
+        it("should drop #__PURE__ hint after use", function() {
+            var result = Uglify.minify('//@__PURE__ comment1 #__PURE__ comment2\n foo(), bar();', {
+                fromString: true,
+                output: {
+                    comments: "all",
+                    beautify: false,
+                }
+            });
+            var code = result.code;
+            assert.strictEqual(code, "//  comment1   comment2\nbar();");
+        });
+    });
+
 });

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/uglifyjs.git



More information about the Pkg-javascript-commits mailing list