Repository: jshint/jshint
Pull request #2354 (2015-04-29 18:37:36)

[[FIX]] Parse semicolons in class bodies
Although the semicolon token may appear in class bodies in valid ES6
code, it serves no purpose. Extend the parser to accept this token, but
emit the same warning used for unnecessary semicolons appearing
elsewhere. This warning may be disabled by the end user if desired.


Patch:
diff --git a/src/jshint.js b/src/jshint.js
index 96666792..d1aea10f 100644
--- a/src/jshint.js
+++ b/src/jshint.js
@@ -3711,6 +3711,16 @@ var JSHINT = (function() {
       isStatic = false;
       isGenerator = false;
       getset = null;
+
+      // The ES6 grammar for ClassElement includes the `;` token, but it is
+      // defined only as a placeholder to facilitate future language
+      // extensions. In ES6 code, it serves no purpose.
+      if (name.id === ";") {
+        warning("W032");
+        advance(";");
+        continue;
+      }
+
       if (name.id === "*") {
         isGenerator = true;
         advance("*");
@@ -4189,8 +4199,8 @@ var JSHINT = (function() {
       if (state.tokens.next.id === "var") {
         advance("var");
         state.tokens.curr.fud({ prefix: true });
-      } else if (state.tokens.next.id === "let" || state.tokens.next.id === "const") {
-        advance(state.tokens.next.id);
+      } else if (state.tokens.next.id === "let") {
+        advance("let");
         // create a new block scope
         letscope = true;
         funct["(blockscope)"].stack();


Test patch:
diff --git a/tests/unit/parser.js b/tests/unit/parser.js
index 180ba767..20c7c9f5 100644
--- a/tests/unit/parser.js
+++ b/tests/unit/parser.js
@@ -3658,8 +3658,7 @@ exports["for of as esnext"] = function (test) {
     "for (let x of [1,2,3,4]) {",
     "    print(x);",
     "}",
-    "for (let x of [1,2,3,4]) print(x);",
-    "for (const x of [1,2,3,4]) print(x);"
+    "for (let x of [1,2,3,4]) print(x);"
   ];
   TestRun(test)
     .test(code, {esnext: true, undef: true, predef: ["print"]});
@@ -3672,16 +3671,13 @@ exports["for of as es5"] = function (test) {
     "for (let x of [1,2,3,4]) {",
     "    print(x);",
     "}",
-    "for (let x of [1,2,3,4]) print(x);",
-    "for (const x of [1,2,3,4]) print(x);"
+    "for (let x of [1,2,3,4]) print(x);"
   ];
   TestRun(test)
     .addError(1, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).")
     .addError(1, "'let' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).")
     .addError(4, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).")
     .addError(4, "'let' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).")
-    .addError(5, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).")
-    .addError(5, "'const' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).")
     .test(code, {undef: true, predef: ["print"]}); // es5
 
   test.done();
@@ -3692,16 +3688,13 @@ exports["for of as legacy JS"] = function (test) {
     "for (let x of [1,2,3,4]) {",
     "    print(x);",
     "}",
-    "for (let x of [1,2,3,4]) print(x);",
-    "for (const x of [1,2,3,4]) print(x);"
+    "for (let x of [1,2,3,4]) print(x);"
   ];
   TestRun(test)
     .addError(1, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).")
     .addError(1, "'let' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).")
     .addError(4, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).")
     .addError(4, "'let' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).")
-    .addError(5, "'for of' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).")
-    .addError(5, "'const' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).")
     .test(code, {undef: true, predef: ["print"]}); // es5
 
   test.done();
@@ -4677,6 +4670,30 @@ exports.classExpressionThis = function (test) {
   test.done();
 };
 
+exports.classElementEmpty = function (test) {
+  var code = [
+    "class A {",
+    "  ;",
+    "  method() {}",
+    "  ;",
+    "  *methodB() { yield; }",
+    "  ;;",
+    "  methodC() {}",
+    "  ;",
+    "}",
+  ];
+
+  TestRun(test)
+    .addError(2, "Unnecessary semicolon.")
+    .addError(4, "Unnecessary semicolon.")
+    .addError(6, "Unnecessary semicolon.")
+    .addError(6, "Unnecessary semicolon.")
+    .addError(8, "Unnecessary semicolon.")
+    .test(code, { esnext: true });
+
+  test.done();
+};
+
 exports["test for GH-1018"] = function (test) {
   var code = [
     "if (a = 42) {}",