Repository: webpack/webpack
Pull request #6071 (2017-12-05 16:31:53)

Add static analysis for bitwise operations and exponential operator
**What kind of change does this PR introduce?**

Feature

**Did you add tests for your changes?**

Yes

**Summary**

Prior this change, static analysis only optimised a subset of binary operators.

**Does this PR introduce a breaking change?**

No



Patch:
diff --git a/lib/Parser.js b/lib/Parser.js
index b5645cf1b..e1d5686c7 100644
--- a/lib/Parser.js
+++ b/lib/Parser.js
@@ -174,6 +174,15 @@ class Parser extends Tapable {
 				res.setNumber(left.number / right.number);
 				res.setRange(expr.range);
 				return res;
+			} else if(expr.operator === "**") {
+				left = this.evaluateExpression(expr.left);
+				right = this.evaluateExpression(expr.right);
+				if(!left || !right) return;
+				if(!left.isNumber() || !right.isNumber()) return;
+				res = new BasicEvaluatedExpression();
+				res.setNumber(Math.pow(left.number, right.number));
+				res.setRange(expr.range);
+				return res;
 			} else if(expr.operator === "==" || expr.operator === "===") {
 				left = this.evaluateExpression(expr.left);
 				right = this.evaluateExpression(expr.right);
@@ -200,6 +209,60 @@ class Parser extends Tapable {
 				} else if(left.isBoolean() && right.isBoolean()) {
 					return res.setBoolean(left.bool !== right.bool);
 				}
+			} else if(expr.operator === "&") {
+				left = this.evaluateExpression(expr.left);
+				right = this.evaluateExpression(expr.right);
+				if(!left || !right) return;
+				if(!left.isNumber() || !right.isNumber()) return;
+				res = new BasicEvaluatedExpression();
+				res.setNumber(left.number & right.number);
+				res.setRange(expr.range);
+				return res;
+			} else if(expr.operator === "|") {
+				left = this.evaluateExpression(expr.left);
+				right = this.evaluateExpression(expr.right);
+				if(!left || !right) return;
+				if(!left.isNumber() || !right.isNumber()) return;
+				res = new BasicEvaluatedExpression();
+				res.setNumber(left.number | right.number);
+				res.setRange(expr.range);
+				return res;
+			} else if(expr.operator === "^") {
+				left = this.evaluateExpression(expr.left);
+				right = this.evaluateExpression(expr.right);
+				if(!left || !right) return;
+				if(!left.isNumber() || !right.isNumber()) return;
+				res = new BasicEvaluatedExpression();
+				res.setNumber(left.number ^ right.number);
+				res.setRange(expr.range);
+				return res;
+			} else if(expr.operator === ">>>") {
+				left = this.evaluateExpression(expr.left);
+				right = this.evaluateExpression(expr.right);
+				if(!left || !right) return;
+				if(!left.isNumber() || !right.isNumber()) return;
+				res = new BasicEvaluatedExpression();
+				res.setNumber(left.number >>> right.number);
+				res.setRange(expr.range);
+				return res;
+			} else if(expr.operator === ">>") {
+				left = this.evaluateExpression(expr.left);
+				right = this.evaluateExpression(expr.right);
+				if(!left || !right) return;
+				if(!left.isNumber() || !right.isNumber()) return;
+				res = new BasicEvaluatedExpression();
+				res.setNumber(left.number >> right.number);
+				res.setRange(expr.range);
+				return res;
+			} else if(expr.operator === "<<") {
+				left = this.evaluateExpression(expr.left);
+				right = this.evaluateExpression(expr.right);
+				if(!left || !right) return;
+				if(!left.isNumber() || !right.isNumber()) return;
+				res = new BasicEvaluatedExpression();
+				res.setNumber(left.number << right.number);
+				res.setRange(expr.range);
+				return res;
 			}
 		});
 		this.plugin("evaluate UnaryExpression", function(expr) {
@@ -242,6 +305,14 @@ class Parser extends Tapable {
 				} else if(argument.isNumber()) {
 					return new BasicEvaluatedExpression().setBoolean(!argument.number).setRange(expr.range);
 				}
+			} else if(expr.operator === "~") {
+				const argument = this.evaluateExpression(expr.argument);
+				if(!argument) return;
+				if(!argument.isNumber()) return;
+				const res = new BasicEvaluatedExpression();
+				res.setNumber(~argument.number);
+				res.setRange(expr.range);
+				return res;
 			}
 		});
 		this.plugin("evaluate typeof undefined", function(expr) {


Test patch:
diff --git a/test/Parser.unittest.js b/test/Parser.unittest.js
index 41435d2be..670712065 100644
--- a/test/Parser.unittest.js
+++ b/test/Parser.unittest.js
@@ -305,6 +305,16 @@ describe("Parser", () => {
 			"1": "number=1",
 			"1 + 3": "number=4",
 			"3 - 1": "number=2",
+			"2 * 3": "number=6",
+			"8 / 2": "number=4",
+			"2 ** 3": "number=8",
+			"12 & 5": "number=4",
+			"12 | 5": "number=13",
+			"12 ^ 5": "number=9",
+			"9 >>> 2": "number=2",
+			"9 >> 2": "number=2",
+			"9 << 2": "number=36",
+			"~3": "number=-4",
 			"1 == 1": "bool=true",
 			"1 === 1": "bool=true",
 			"3 != 1": "bool=true",