Repository: jshint/jshint
Pull request #3363 (2019-02-16 22:25:50)

[[FIX]] Warn on reassignment of async functions
Correct typo to promote consistency in enforcement of linting rule.

---

@rwaldron since the typo shipped in version 2.10.0, fixing it is technically a breaking change. However, I think this is pretty unambiguously a bug fix, so waiting for the next major doesn't seem appropriate. What do you think?

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

Coverage remained the same at 98.471% when pulling **9b530746f2b42b87c073d06efc2780287abd7674 on jugglinmike:reassign-async-function** into **0e85de5f33f3a4bb18833bbb87b4a08294f16899 on jshint:master**.

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

Coverage remained the same at 98.471% when pulling **9b530746f2b42b87c073d06efc2780287abd7674 on jugglinmike:reassign-async-function** into **0e85de5f33f3a4bb18833bbb87b4a08294f16899 on jshint:master**.


Patch:
diff --git a/src/jshint.js b/src/jshint.js
index 3b2f5871..55612643 100644
--- a/src/jshint.js
+++ b/src/jshint.js
@@ -2776,7 +2776,7 @@ var JSHINT = (function() {
   });
 
   function classBody(classToken, context) {
-    var props = {};
+    var props = Object.create(null);
     var name, accessorType, token, isStatic, inGenerator, hasConstructor;
 
     if (state.tokens.next.value === "{") {
diff --git a/src/lex.js b/src/lex.js
index 1ea296ae..1b1540c7 100644
--- a/src/lex.js
+++ b/src/lex.js
@@ -1582,6 +1582,11 @@ Lexer.prototype = {
         continue;
       }
 
+      if (isCharSet) {
+        index += 1;
+        continue;
+      }
+
       if (char === "{" && !hasInvalidQuantifier) {
         hasInvalidQuantifier = !checkQuantifier();
       }
diff --git a/src/scope-manager.js b/src/scope-manager.js
index 496853b7..f7f92227 100644
--- a/src/scope-manager.js
+++ b/src/scope-manager.js
@@ -345,7 +345,7 @@ var scopeManager = function(state, predefined, exported, declared) {
 
           isFunction = usedLabelType === "function" ||
             usedLabelType === "generator function" ||
-            usedLabelType === "async fuction";
+            usedLabelType === "async function";
 
           // check for re-assigning a function declaration
           if ((isFunction || usedLabelType === "class") && usage["(reassigned)"]) {


Test patch:
diff --git a/tests/unit/parser.js b/tests/unit/parser.js
index c5e049b1..e2f49779 100644
--- a/tests/unit/parser.js
+++ b/tests/unit/parser.js
@@ -866,6 +866,12 @@ exports.regexp.regressions = function (test) {
   TestRun(test).test("var exp = /\\[\\]/;", {esnext: true});
   TestRun(test).test("var exp = /\\[\\]/;", {moz: true});
 
+  // GH-3356
+  TestRun(test).test("void /[/]/;");
+  TestRun(test).test("void /[{]/u;", {esversion: 6});
+  TestRun(test).test("void /[(?=)*]/u;", {esversion: 6});
+  TestRun(test).test("void /[(?!)+]/u;", {esversion: 6});
+
   test.done();
 };
 
@@ -6673,6 +6679,87 @@ exports["class and method naming"] = function (test) {
 
   run.test(code, {esnext: true});
 
+  TestRun(test, "hazardous method names (see gh-3358)")
+    .addError(3, 17, "'hasOwnProperty' is a really bad name.")
+    .test([
+      "void class {",
+      "  constructor() {}",
+      "  hasOwnProperty() {}",
+      "  toString() {}",
+      "  toLocaleString() {}",
+      "  valueOf() {}",
+      "  isPrototypeOf() {}",
+      "  propertyIsEnumerable() {}",
+      "};"
+   ], {esversion: 6});
+
+  TestRun(test, "hazardous method names -- true duplicate (see gh-3358)")
+    .addError(4, 11, "Duplicate class method 'toString'.")
+    .test([
+      "void class {",
+      "  toString() {}",
+      "  x() {}",
+      "  toString() {}",
+      "};"
+   ], {esversion: 6});
+
+  TestRun(test, "hazardous static method names (see gh-3358)")
+    .addError(3, 24, "'hasOwnProperty' is a really bad name.")
+    .test([
+      "void class {",
+      "  static constructor() {}",
+      "  static hasOwnProperty() {}",
+      "  static toString() {}",
+      "  static toLocaleString() {}",
+      "  static valueOf() {}",
+      "  static isPrototypeOf() {}",
+      "  static propertyIsEnumerable() {}",
+      "};"
+   ], {esversion: 6});
+
+  TestRun(test, "hazardous static method names -- true duplicate (see gh-3358)")
+    .addError(4, 18, "Duplicate static class method 'toString'.")
+    .test([
+      "void class {",
+      "  static toString() {}",
+      "  static x() {}",
+      "  static toString() {}",
+      "};"
+   ], {esversion: 6});
+
+  TestRun(test, "hazardous accessor method names (see gh-3358)")
+    .addError(2, 21, "'hasOwnProperty' is a really bad name.")
+    .addError(3, 21, "'hasOwnProperty' is a really bad name.")
+    .test([
+      "void class {",
+      "  get hasOwnProperty() {}",
+      "  set hasOwnProperty(_) {}",
+      "  get toString() {}",
+      "  set toString(_) {}",
+      "  get toLocaleString() {}",
+      "  set toLocaleString(_) {}",
+      "  get valueOf() {}",
+      "  set valueOf(_) {}",
+      "  get isPrototypeOf() {}",
+      "  set isPrototypeOf(_) {}",
+      "  get propertyIsEnumerable() {}",
+      "  set propertyIsEnumerable(_) {}",
+      "};"
+   ], {esversion: 6});
+
+  TestRun(test, "hazardous accessor method names -- true duplicate (see gh-3358)")
+    .addError(5, 15, "Duplicate getter method 'toString'.")
+    .addError(6, 15, "Duplicate setter method 'toString'.")
+    .test([
+      "void class {",
+      "  get toString() {}",
+      "  set toString(_) {}",
+      "  static x() {}",
+      "  get toString() {}",
+      "  set toString(_) {}",
+      "};"
+   ], {esversion: 6});
+
   test.done();
 };
 
@@ -6992,6 +7079,20 @@ exports.functionReassignment = function (test) {
     .addError(10, 3, "Reassignment of 'h', which is a function. Use 'var' or 'let' to declare bindings that may change.")
     .test(src);
 
+  TestRun(test, "generator functions")
+    .addError(2, 1, "Reassignment of 'g', which is a generator function. Use 'var' or 'let' to declare bindings that may change.")
+    .test([
+      "function * g () { yield; }",
+      "g = null;"
+    ], { esversion: 6 });
+
+  TestRun(test, "async functions")
+    .addError(2, 1, "Reassignment of 'a', which is a async function. Use 'var' or 'let' to declare bindings that may change.")
+    .test([
+      "async function a () {}",
+      "a = null;"
+    ], { esversion: 8 });
+
   test.done();
 };