Repository: jshint/jshint
Pull request #3530 (2021-02-06 22:10:31)

[[FIX]] Correct location reported for directive
Extend the internal data structure used to track directives so that it
can be used to correctly report location information. Document the type
of this structure in the source file where it is initialized.

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

Coverage remained the same at 100.0% when pulling **51d83e55ebd78d713636fb436b6577016d28cf6a on jugglinmike:fix-usd-location** into **2d4a3d1601f96151023532ba1b1db5710c74d23e on jshint:master**.


Patch:
diff --git a/src/jshint.js b/src/jshint.js
index 08f8d8f0..9ff280a8 100644
--- a/src/jshint.js
+++ b/src/jshint.js
@@ -2054,8 +2054,7 @@ var JSHINT = (function() {
         error("E065", state.tokens.curr);
       }
 
-      // there's no directive negation, so always set to true
-      state.directive[directive] = true;
+      state.directive[directive] = state.tokens.curr;
 
       parseFinalSemicolon(current);
     }
@@ -3046,14 +3045,17 @@ var JSHINT = (function() {
 
     if (left) {
       if (left.type === "(identifier)") {
-        if (left.value.match(/^[A-Z]([A-Z0-9_$]*[a-z][A-Za-z0-9_$]*)?$/)) {
-          if ("Array Number String Boolean Date Object Error Symbol".indexOf(left.value) === -1) {
-            if (left.value === "Math") {
-              /* istanbul ignore next */
-              warning("W063", left);
-            } else if (state.option.newcap) {
-              warning("W064", left);
-            }
+        var newcapRe = /^[A-Z]([A-Z0-9_$]*[a-z][A-Za-z0-9_$]*)?$/;
+        var newcapIgnore = [
+          "Array", "Boolean", "Date", "Error", "Number",
+          "Object", "RegExp", "String", "Symbol"
+        ];
+        if (newcapRe.test(left.value) && newcapIgnore.indexOf(left.value) === -1) {
+          if (left.value === "Math") {
+            /* istanbul ignore next */
+            warning("W063", left);
+          } else if (state.option.newcap) {
+            warning("W064", left);
           }
         }
       }
@@ -6506,7 +6508,7 @@ var JSHINT = (function() {
 
         if (state.directive["use strict"]) {
           if (!state.allowsGlobalUsd()) {
-            warning("W097", state.tokens.prev);
+            warning("W097", state.directive["use strict"]);
           }
         }
 
diff --git a/src/state.js b/src/state.js
index c2c6bc46..cd5b247a 100644
--- a/src/state.js
+++ b/src/state.js
@@ -10,7 +10,7 @@ var state = {
    * @returns {boolean}
    */
   isStrict: function() {
-    return this.directive["use strict"] || this.inClassBody ||
+    return !!this.directive["use strict"] || this.inClassBody ||
       this.option.module || this.option.strict === "implied";
   },
 
@@ -177,6 +177,10 @@ var state = {
     this.esVersion = 5;
     this.funct = null;
     this.ignored = {};
+    /**
+     * A lookup table for active directives whose keys are the value of the
+     * directives and whose values are the tokens which enabled the directives.
+     */
     this.directive = Object.create(null);
     this.jsonMode = false;
     this.lines = [];


Test patch:
diff --git a/tests/unit/fixtures/newcap.js b/tests/unit/fixtures/newcap.js
index 15b1ae9c..852ac068 100644
--- a/tests/unit/fixtures/newcap.js
+++ b/tests/unit/fixtures/newcap.js
@@ -19,8 +19,13 @@ bat = myAnimal();
 
 // Make sure we don't warn on Error, Number, etc.
 Array();
+Boolean();
+Date();
 Error();
 Number();
+/*jshint -W010 */
+Object();
+/*jshint +W010 */
+RegExp();
 String();
-Boolean();
 Symbol();
diff --git a/tests/unit/options.js b/tests/unit/options.js
index 65aa31a0..e3dcdd09 100644
--- a/tests/unit/options.js
+++ b/tests/unit/options.js
@@ -2046,6 +2046,19 @@ exports.strict = function (test) {
     .addError(1, 6, "Missing \"use strict\" statement.")
     .test("a = 2;", { strict: "global" });
 
+  TestRun(test, "Warning location, missing semicolon (gh-3528)")
+    .addError(1, 1, "Use the function form of \"use strict\".")
+    .addError(1, 13, "Missing semicolon.")
+    .test("'use strict'\n");
+
+  TestRun(test, "Warning location among other directives")
+    .addError(2, 1, "Use the function form of \"use strict\".")
+    .test([
+      "'use another-directive';",
+      "'use strict';",
+      "'use a-third-directive';"
+    ]);
+
   test.done();
 };