Repository: jshint/jshint
Pull request #3531 (2021-02-08 10:59:47)

[[FIX]] Don't warn when Function() is used without 'new'.
https://262.ecma-international.org/#sec-function-constructor
...
the function call Function(…) is equivalent to the object creation
expression new Function(…) with the same arguments
...

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

Coverage remained the same at 100.0% when pulling **8500c9c90cd9ff494e0549ac19cc10303632b949 on lauriro:fix-function-warn** into **c18a6e48e12e532e60cfcbdaf70f418548193566 on jshint:master**.


Patch:
diff --git a/src/jshint.js b/src/jshint.js
index d6a5f5a6..c868ff8e 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);
     }
@@ -3048,7 +3047,7 @@ var JSHINT = (function() {
       if (left.type === "(identifier)") {
         var newcapRe = /^[A-Z]([A-Z0-9_$]*[a-z][A-Za-z0-9_$]*)?$/;
         var newcapIgnore = [
-          "Array", "Boolean", "Date", "Error", "Number",
+          "Array", "Boolean", "Date", "Error", "Function", "Number",
           "Object", "RegExp", "String", "Symbol"
         ];
         if (newcapRe.test(left.value) && newcapIgnore.indexOf(left.value) === -1) {
@@ -6509,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 852ac068..85988ebc 100644
--- a/tests/unit/fixtures/newcap.js
+++ b/tests/unit/fixtures/newcap.js
@@ -22,6 +22,9 @@ Array();
 Boolean();
 Date();
 Error();
+/*jshint -W061 */
+Function();
+/*jshint +W061 */
 Number();
 /*jshint -W010 */
 Object();
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();
 };