Repository: jshint/jshint
Pull request #2270 (2015-03-21 22:55:37)

Fix singleGroups bugs
This addresses two separate issues in everyone's favorite option, `singleGroups`.

The first commit resolves gh-2260
The second commit resolves an as-yet unreported bug regarding the option's behavior with relation operators.


Patch:
diff --git a/src/jshint.js b/src/jshint.js
index b1f8eb1d..1a07afe7 100644
--- a/src/jshint.js
+++ b/src/jshint.js
@@ -1180,7 +1180,8 @@ var JSHINT = (function() {
 
     x.led = function(left) {
       nobreaknonadjacent(state.tokens.prev, state.tokens.curr);
-      var right = expression(100);
+      this.left = left;
+      var right = this.right = expression(100);
 
       if (isIdentifier(left, "NaN") || isIdentifier(right, "NaN")) {
         warning("W019", this);
@@ -1200,8 +1201,6 @@ var JSHINT = (function() {
         warning("W018", right, "!");
       }
 
-      this.left = left;
-      this.right = right;
       return this;
     };
     return x;
@@ -2609,10 +2608,7 @@ var JSHINT = (function() {
           // begin with the `{` and `function` tokens
           (opening.beginsStmt && (ret.id === "{" || triggerFnExpr || isFunctor(ret))) ||
           // Used as the return value of a single-statement arrow function
-          (ret.id === "{" && preceeding.id === "=>") ||
-          // Used to prevent left-to-right application of adjacent addition
-          // operators (the order of which effect type)
-          (first.id === "+" && preceeding.id === "+");
+          (ret.id === "{" && preceeding.id === "=>");
       }
     }
 
@@ -2622,7 +2618,7 @@ var JSHINT = (function() {
       // first expression *or* the current group contains multiple expressions)
       if (!isNecessary && (first.left || ret.exprs)) {
         isNecessary =
-          (!isBeginOfExpr(preceeding) && first.lbp < preceeding.lbp) ||
+          (!isBeginOfExpr(preceeding) && first.lbp <= preceeding.lbp) ||
           (!isEndOfExpr() && last.lbp < state.tokens.next.lbp);
       }
 


Test patch:
diff --git a/tests/unit/options.js b/tests/unit/options.js
index 21413d45..d889298a 100644
--- a/tests/unit/options.js
+++ b/tests/unit/options.js
@@ -1896,9 +1896,12 @@ singleGroups.bindingPower.singleExpr = function (test) {
     "var j = (a += 1) / 2;",
     "var k = 'foo' + ('bar' ? 'baz' : 'qux');",
     "var l = 1 + (0 || 3);",
+    "var u = a / (b * c);",
+    "var v = a % (b / c);",
+    "var w = a * (b * c);",
+    "var x = z === (b === c);",
     // Invalid forms:
     "var j = 2 * ((3 - 4) - 5) * 6;",
-    "var k = 2 * (3 - (4 - 5)) * 6;",
     "var l = 2 * ((3 - 4 - 5)) * 6;",
     "var m = typeof(a.b);",
     "var n = 1 - (2 * 3);",
@@ -1911,7 +1914,6 @@ singleGroups.bindingPower.singleExpr = function (test) {
     "if (a in c || (b in c)) {}",
     "if ((a in c) || b in c) {}",
     "if ((a in c) || (b in c)) {}",
-    "if (a * (b * c)) {}",
     "if ((a * b) * c) {}",
     "if (a + (b * c)) {}",
     "(a ? a : (a=[])).push(b);",
@@ -1919,10 +1921,6 @@ singleGroups.bindingPower.singleExpr = function (test) {
   ];
 
   TestRun(test)
-    .addError(14, "Unnecessary grouping operator.")
-    .addError(15, "Unnecessary grouping operator.")
-    .addError(16, "Unnecessary grouping operator.")
-    .addError(17, "Unnecessary grouping operator.")
     .addError(18, "Unnecessary grouping operator.")
     .addError(19, "Unnecessary grouping operator.")
     .addError(20, "Unnecessary grouping operator.")
@@ -1938,6 +1936,8 @@ singleGroups.bindingPower.singleExpr = function (test) {
     .addError(30, "Unnecessary grouping operator.")
     .addError(31, "Unnecessary grouping operator.")
     .addError(32, "Unnecessary grouping operator.")
+    .addError(33, "Unnecessary grouping operator.")
+    .addError(34, "Unnecessary grouping operator.")
     .test(code, { singleGroups: true });
 
   test.done();