From cda02aefcad60575dc3d1f474177a986ffdb917e Mon Sep 17 00:00:00 2001 From: Mike Pennisi Date: Sat, 24 Jun 2017 16:07:21 -0400 Subject: [PATCH] [[FIX]] Correct invalid function invocation The second parameter of the `expression` function accepts a value that modifies how the next token is parsed. When set to `true`, the token is interpreted as the beginning of a statement; otherwise, it is interpreted as the beginning of an expression. Two call sites within the `for` statement's parsing logic specified the string value `"for"`. Due to inconsistencies in how the parameter was interpreted internally, this causes `expression` to mix parsing strategies. Specifically: - It used the "statement" parsing strategy to mark the token value as beginning a statement. This could be observed in the application of the `singleGroups` linting option. Further, it disqualify it for consideration as a Mozilla "let expression" - It used the "expression" parsing strategy to ignore the token's `fud` method Since the grammar does not allow a statement in either location, the "expression" parsing strategy should be used consistently. Achieve this by removing the argument from the call site, thereby falling back to the default behavior of the `expression` function. Update `expression` to consistently interpret the parameter for "truthiness" in order to discourage similar ambiguity in the future. --- src/jshint.js | 6 +++--- tests/unit/options.js | 12 ++++++++++-- tests/unit/parser.js | 8 ++++++-- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/jshint.js b/src/jshint.js index 9ffda3e033..9f9493d388 100644 --- a/src/jshint.js +++ b/src/jshint.js @@ -924,7 +924,7 @@ var JSHINT = (function() { state.tokens.curr.beginsStmt = true; } - if (initial === true && state.tokens.curr.fud) { + if (initial && state.tokens.curr.fud) { left = state.tokens.curr.fud(); } else { if (state.tokens.curr.nud) { @@ -4514,7 +4514,7 @@ var JSHINT = (function() { state.tokens.curr.fud(); } else { for (;;) { - expression(0, "for"); + expression(0); if (state.tokens.next.id !== ",") { break; } @@ -4538,7 +4538,7 @@ var JSHINT = (function() { } if (state.tokens.next.id !== ")") { for (;;) { - expression(0, "for"); + expression(0); if (state.tokens.next.id !== ",") { break; } diff --git a/tests/unit/options.js b/tests/unit/options.js index 5fce47b755..d81d34ca84 100644 --- a/tests/unit/options.js +++ b/tests/unit/options.js @@ -3330,13 +3330,17 @@ singleGroups.objectLiterals = function (test) { // Invalid forms "var a = ({}).method();", "if (({}).method()) {}", - "var b = { a: ({}).method() };" + "var b = { a: ({}).method() };", + "for (({}); ;) {}", + "for (; ;({})) {}" ]; TestRun(test, "grouping operator not required") .addError(4, 9, "Unnecessary grouping operator.") .addError(5, 5, "Unnecessary grouping operator.") .addError(6, 14, "Unnecessary grouping operator.") + .addError(7, 6, "Unnecessary grouping operator.") + .addError(8, 9, "Unnecessary grouping operator.") .test(code, { singleGroups: true }); test.done(); @@ -3458,13 +3462,17 @@ singleGroups.destructuringAssign = function (test) { "([ x ] = [ 1 ]);", // expressions "1, ({ x } = { x : 1 });", - "1, ([ x ] = [ 1 ]);" + "1, ([ x ] = [ 1 ]);", + "for (({ x } = { X: 1 }); ;) {}", + "for (; ;({ x } = { X: 1 })) {}" ]; TestRun(test) .addError(2, 1, "Unnecessary grouping operator.") .addError(3, 4, "Unnecessary grouping operator.") .addError(4, 4, "Unnecessary grouping operator.") + .addError(5, 6, "Unnecessary grouping operator.") + .addError(6, 9, "Unnecessary grouping operator.") .test(code, { esversion: 6, singleGroups: true, expr: true }); test.done(); diff --git a/tests/unit/parser.js b/tests/unit/parser.js index 7680b477c3..15dfae989d 100644 --- a/tests/unit/parser.js +++ b/tests/unit/parser.js @@ -3148,7 +3148,8 @@ exports["let block and let expression"] = function (test) { "{", " let(t=4) print(x, y, z, t);", " print(let(u=4) u,x);", - "}" + "}", + "for (; ; let (x = 1) x) {}" ]; TestRun(test) @@ -3163,7 +3164,8 @@ exports["let block and let expression as esnext"] = function (test) { "{", " let(t=4) print(x, y, z, t);", " print(let(u=4) u,x);", - "}" + "}", + "for (; ; let (x = 1) x) {}" ]; TestRun(test) @@ -3171,6 +3173,8 @@ exports["let block and let expression as esnext"] = function (test) { .addError(3, 6, "'let block' is only available in Mozilla JavaScript extensions (use moz option).") .addError(4, 9, "'let expressions' is only available in Mozilla JavaScript extensions " + "(use moz option).") + .addError(6, 10, "'let expressions' is only available in Mozilla JavaScript extensions " + + "(use moz option).") .test(code, {esnext: true, unused: true, undef: true, predef: ["print"]}); test.done(); };