Repository: jshint/jshint
Pull request #3376 (2019-03-03 04:31:49)

Correct parsing of block binding declarations in C-style for loops
The first commit is intended to resolve gh-3370. The second fixes an as-yet unreported bug.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/21952226/badge)](https://coveralls.io/builds/21952226)

Coverage increased (+0.0007%) to 98.545% when pulling **e83464eb525e4d71a8eae72344d8b5c1a6c6a6c5 on jugglinmike:block-binding-c-style-for** into **8d71df84d59a3bcc2c96a289dbdc4fdda175b1fe on jshint:master**.


Patch:
diff --git a/src/jshint.js b/src/jshint.js
index 09b06183..40cc3db8 100644
--- a/src/jshint.js
+++ b/src/jshint.js
@@ -4284,8 +4284,9 @@ var JSHINT = (function() {
       // head of for-in and for-of statements. If this binding list is being
       // parsed as part of a `for` statement of any kind, allow the initializer
       // to be omitted. Although this may erroneously allow such forms from
-      // "C-style" `for` statements (i.e. `for (;;) {}`, the `for` statement
-      // logic includes dedicated logic to issue the error for such cases.
+      // "C-style" `for` statements (i.e. `for (const x;;) {}`, the `for`
+      // statement logic includes dedicated logic to issue the error for such
+      // cases.
       if (!noin && isConst && state.tokens.next.id !== "=") {
         warning("E012", state.tokens.curr, state.tokens.curr.value);
       }
@@ -4334,7 +4335,7 @@ var JSHINT = (function() {
       // Bindings are not immediately initialized in for-in and for-of
       // statements. As with `const` initializers (described above), the `for`
       // statement parsing logic includes
-      if (!noin) {
+      if (state.tokens.next.value !== "in" && state.tokens.next.value !== "of") {
         for (t in tokens) {
           if (tokens.hasOwnProperty(t)) {
             t = tokens[t];
@@ -5123,6 +5124,10 @@ var JSHINT = (function() {
       nolinebreak(state.tokens.curr);
       advance(";");
       if (decl) {
+        if (decl.value === "const"  && !decl.hasInitializer) {
+          warning("E012", decl, decl.first[0].value);
+        }
+
         decl.first.forEach(function(token) {
           state.funct["(scope)"].initialize(token.value);
         });


Test patch:
diff --git a/tests/unit/core.js b/tests/unit/core.js
index 6aedbf06..1946e475 100644
--- a/tests/unit/core.js
+++ b/tests/unit/core.js
@@ -2327,3 +2327,34 @@ exports["TDZ within for in/of head"] = function(test) {
 
   test.done();
 };
+
+// regression test for gh-3370
+exports.initializeCStyle = function(test) {
+  TestRun(test)
+    .test([
+      "for (let x, y = x; ;) {}",
+      "for (const x = 0, y = x; ;) {}"
+    ], { esversion: 6 });
+
+  test.done();
+};
+
+exports.constWithoutInit = function(test) {
+  TestRun(test, "single binding")
+    .addError(1, 6, "const 'x' is initialized to 'undefined'.")
+    .test([
+      "for (const x; ;) {",
+      "  void x;",
+      "}"
+    ], { esversion: 6 });
+
+  TestRun(test, "multiple bindings")
+    .addError(1, 6, "const 'y' is initialized to 'undefined'.")
+    .test([
+      "for (const y, z; ;) {",
+      "  void (y, z);",
+      "}"
+    ], { esversion: 6 });
+
+  test.done();
+};