Repository: jshint/jshint
Pull request #2187 (2015-02-22 18:34:52)

[[FIX]] Do not crash on improper use of `delete`
This should resolve gh-2168

Commit message:

> In valid JavaScript code, when the `delete` token is parsed as a prefix,
> it will be followed by an expression of some kind. Invalid code may
> include any sequence of characters after the `delete` token, and JSHint
> should be capable of gracefully warning about the syntax error.
>
> Avoid crashing in cases where the `delete` appears as a "prefix" token
> but is not followed by an expression.

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

Coverage increased (+0.0%) to 95.5% when pulling **c979afb1fe47efa267c9e4cda3238b2a86320cf4 on jugglinmike:fix-delete-crash** into **69b318788de03623b5750079dad449f8fceddf9e on jshint:master**.


Patch:
diff --git a/src/jshint.js b/src/jshint.js
index 8b09cc88..b86e5055 100644
--- a/src/jshint.js
+++ b/src/jshint.js
@@ -197,12 +197,8 @@ var JSHINT = (function() {
 
     processenforceall();
 
-    if (!state.option.es3) {
-      combine(predefined, vars.ecmaIdentifiers[5]);
-    }
-
     if (state.option.esnext) {
-      combine(predefined, vars.ecmaIdentifiers[6]);
+      combine(predefined, vars.newEcmaIdentifiers);
     }
 
     if (state.option.couch) {
@@ -2228,7 +2224,11 @@ var JSHINT = (function() {
   state.syntax["--"].exps = true;
   prefix("delete", function() {
     var p = expression(10);
-    if (!p || (p.id !== "." && p.id !== "[")) {
+    if (!p) {
+      return this;
+    }
+
+    if (p.id !== "." && p.id !== "[") {
       warning("W051");
     }
     this.first = p;
@@ -3368,15 +3368,8 @@ var JSHINT = (function() {
           if (state.option.inESNext() && funct[t.id] === "const") {
             warning("E011", null, t.id);
           }
-          if (funct["(global)"]) {
-            if (predefined[t.id] === false) {
-              warning("W079", t.token, t.id);
-            } else if (!state.option.futurehostile) {
-              if ((!state.option.inES5() && vars.ecmaIdentifiers[5][t.id] === false) ||
-                (!state.option.inESNext() && vars.ecmaIdentifiers[6][t.id] === false)) {
-                warning("W129", t.token, t.id);
-              }
-            }
+          if (funct["(global)"] && predefined[t.id] === false) {
+            warning("W079", t.token, t.id);
           }
           if (t.id) {
             addlabel(t.id, { type: "unused", token: t.token });
@@ -4930,7 +4923,7 @@ var JSHINT = (function() {
     }
 
     predefined = Object.create(null);
-    combine(predefined, vars.ecmaIdentifiers[3]);
+    combine(predefined, vars.ecmaIdentifiers);
     combine(predefined, vars.reservedVars);
 
     combine(predefined, g || {});
diff --git a/src/messages.js b/src/messages.js
index f5e65749..5aa1f2c5 100644
--- a/src/messages.js
+++ b/src/messages.js
@@ -202,9 +202,7 @@ var warnings = {
   W125: "This line contains non-breaking spaces: http://jshint.com/doc/options/#nonbsp",
   W126: "Unnecessary grouping operator.",
   W127: "Unexpected use of a comma operator.",
-  W128: "Empty array elements require elision=true.",
-  W129: "'{a}' is defined in a future version of JavaScript. Use a " +
-    "different variable name to avoid migration issues."
+  W128: "Empty array elements require elision=true."
 };
 
 var info = {
diff --git a/src/options.js b/src/options.js
index a5175556..3a5cccf2 100644
--- a/src/options.js
+++ b/src/options.js
@@ -352,14 +352,6 @@ exports.bool = {
     */
     evil        : true,
 
-    /**
-     * This option supresses warnings about the use of identifiers which are
-     * defined in future versions of JavaScript. Although overwriting them has
-     * no effect in contexts where they are not implemented, this practice can
-     * cause issues when migrating codebases to newer versions of the language.
-     */
-    futurehostile: true,
-
     /**
      * This option prohibits the use of unary increment and decrement
      * operators.  Some people think that `++` and `--` reduces the quality of
diff --git a/src/vars.js b/src/vars.js
index 08865c21..91ac6565 100644
--- a/src/vars.js
+++ b/src/vars.js
@@ -10,47 +10,51 @@ exports.reservedVars = {
 };
 
 exports.ecmaIdentifiers = {
-  3: {
-    Array              : false,
-    Boolean            : false,
-    Date               : false,
-    decodeURI          : false,
-    decodeURIComponent : false,
-    encodeURI          : false,
-    encodeURIComponent : false,
-    Error              : false,
-    "eval"             : false,
-    EvalError          : false,
-    Function           : false,
-    hasOwnProperty     : false,
-    isFinite           : false,
-    isNaN              : false,
-    Math               : false,
-    Number             : false,
-    Object             : false,
-    parseInt           : false,
-    parseFloat         : false,
-    RangeError         : false,
-    ReferenceError     : false,
-    RegExp             : false,
-    String             : false,
-    SyntaxError        : false,
-    TypeError          : false,
-    URIError           : false
-  },
-  5: {
-    JSON               : false
-  },
-  6: {
-    Map                : false,
-    Promise            : false,
-    Proxy              : false,
-    Reflect            : false,
-    Set                : false,
-    Symbol             : false,
-    WeakMap            : false,
-    WeakSet            : false
-  }
+  Array              : false,
+  Boolean            : false,
+  Date               : false,
+  decodeURI          : false,
+  decodeURIComponent : false,
+  encodeURI          : false,
+  encodeURIComponent : false,
+  Error              : false,
+  "eval"             : false,
+  EvalError          : false,
+  Function           : false,
+  hasOwnProperty     : false,
+  isFinite           : false,
+  isNaN              : false,
+  JSON               : false,
+  Map                : false,
+  Math               : false,
+  Number             : false,
+  Object             : false,
+  Proxy              : false,
+  Promise            : false,
+  parseInt           : false,
+  parseFloat         : false,
+  RangeError         : false,
+  ReferenceError     : false,
+  RegExp             : false,
+  Set                : false,
+  String             : false,
+  SyntaxError        : false,
+  TypeError          : false,
+  URIError           : false,
+  WeakMap            : false,
+  WeakSet            : false
+};
+
+exports.newEcmaIdentifiers = {
+  Set     : false,
+  Map     : false,
+  WeakMap : false,
+  WeakSet : false,
+  Proxy   : false,
+  Promise : false,
+  Reflect : false,
+  Symbol  : false,
+  System  : false
 };
 
 // Global variables commonly provided by a web browser environment.


Test patch:
diff --git a/tests/regression/thirdparty.js b/tests/regression/thirdparty.js
index f5cf927b..45f888cc 100644
--- a/tests/regression/thirdparty.js
+++ b/tests/regression/thirdparty.js
@@ -185,7 +185,7 @@ exports.json2 = function (test) {
   TestRun(test)
     .addError(177, "'key' is defined but never used.")
     .addError(191, "'key' is defined but never used.")
-    .test(src, { singleGroups: true, undef: true, unused: true, laxbreak: true, predef: ["-JSON"] }, { JSON: true });
+    .test(src, { singleGroups: true, undef: true, unused: true, laxbreak: true }, { JSON: true });
 
   test.done();
 };
diff --git a/tests/unit/options.js b/tests/unit/options.js
index 62bf6740..4260762e 100644
--- a/tests/unit/options.js
+++ b/tests/unit/options.js
@@ -1818,7 +1818,8 @@ exports.esnextPredefs = function (test) {
     '/* global alert: true */',
     'var mySym = Symbol("name");',
     'var myBadSym = new Symbol("name");',
-    'alert(Reflect);'
+    'alert(Reflect);',
+    'alert(System);'
   ];
 
   TestRun(test)
@@ -2182,98 +2183,3 @@ exports.badInlineOptionValue = function (test) {
 
   test.done();
 };
-
-exports.futureHostile = function (test) {
-  var code = [
-    "var JSON = {};",
-    "var Map = function() {};",
-    "var Promise = function() {};",
-    "var Proxy = function() {};",
-    "var Reflect = function() {};",
-    "var Set = function() {};",
-    "var Symbol = function() {};",
-    "var WeakMap = function() {};",
-    "var WeakSet = function() {};"
-  ];
-
-  TestRun(test, "ES3 without option")
-    .addError(1, "'JSON' is defined in a future version of JavaScript. Use a different variable name to avoid migration issues.")
-    .addError(2, "'Map' is defined in a future version of JavaScript. Use a different variable name to avoid migration issues.")
-    .addError(3, "'Promise' is defined in a future version of JavaScript. Use a different variable name to avoid migration issues.")
-    .addError(4, "'Proxy' is defined in a future version of JavaScript. Use a different variable name to avoid migration issues.")
-    .addError(5, "'Reflect' is defined in a future version of JavaScript. Use a different variable name to avoid migration issues.")
-    .addError(6, "'Set' is defined in a future version of JavaScript. Use a different variable name to avoid migration issues.")
-    .addError(7, "'Symbol' is defined in a future version of JavaScript. Use a different variable name to avoid migration issues.")
-    .addError(8, "'WeakMap' is defined in a future version of JavaScript. Use a different variable name to avoid migration issues.")
-    .addError(9, "'WeakSet' is defined in a future version of JavaScript. Use a different variable name to avoid migration issues.")
-    .test(code, { es3: true, es5: false });
-
-  TestRun(test, "ES3 with option")
-    .test(code, { es3: true, es5: false, futurehostile: true });
-
-  TestRun(test, "ES5 without option")
-    .addError(1, "Redefinition of 'JSON'.")
-    .addError(2, "'Map' is defined in a future version of JavaScript. Use a different variable name to avoid migration issues.")
-    .addError(3, "'Promise' is defined in a future version of JavaScript. Use a different variable name to avoid migration issues.")
-    .addError(4, "'Proxy' is defined in a future version of JavaScript. Use a different variable name to avoid migration issues.")
-    .addError(5, "'Reflect' is defined in a future version of JavaScript. Use a different variable name to avoid migration issues.")
-    .addError(6, "'Set' is defined in a future version of JavaScript. Use a different variable name to avoid migration issues.")
-    .addError(7, "'Symbol' is defined in a future version of JavaScript. Use a different variable name to avoid migration issues.")
-    .addError(8, "'WeakMap' is defined in a future version of JavaScript. Use a different variable name to avoid migration issues.")
-    .addError(9, "'WeakSet' is defined in a future version of JavaScript. Use a different variable name to avoid migration issues.")
-    .test(code, {});
-
-  TestRun(test, "ES5 with option")
-    .addError(1, "Redefinition of 'JSON'.")
-    .test(code, {
-      futurehostile: true
-    });
-
-  TestRun(test, "ES5 with opt-out")
-    .test(code, {
-      futurehostile: true,
-      predef: ["-JSON"]
-    });
-
-  TestRun(test, "ESNext without option")
-    .addError(1, "Redefinition of 'JSON'.")
-    .addError(2, "Redefinition of 'Map'.")
-    .addError(3, "Redefinition of 'Promise'.")
-    .addError(4, "Redefinition of 'Proxy'.")
-    .addError(5, "Redefinition of 'Reflect'.")
-    .addError(6, "Redefinition of 'Set'.")
-    .addError(7, "Redefinition of 'Symbol'.")
-    .addError(8, "Redefinition of 'WeakMap'.")
-    .addError(9, "Redefinition of 'WeakSet'.")
-    .test(code, { esnext: true });
-
-  TestRun(test, "ESNext with option")
-    .addError(1, "Redefinition of 'JSON'.")
-    .addError(2, "Redefinition of 'Map'.")
-    .addError(3, "Redefinition of 'Promise'.")
-    .addError(4, "Redefinition of 'Proxy'.")
-    .addError(5, "Redefinition of 'Reflect'.")
-    .addError(6, "Redefinition of 'Set'.")
-    .addError(7, "Redefinition of 'Symbol'.")
-    .addError(8, "Redefinition of 'WeakMap'.")
-    .addError(9, "Redefinition of 'WeakSet'.")
-    .test(code, { esnext: true, futurehostile: true });
-
-  TestRun(test, "ESNext with opt-out")
-    .test(code, {
-      esnext: true,
-      predef: [
-        "-JSON",
-        "-Map",
-        "-Promise",
-        "-Proxy",
-        "-Reflect",
-        "-Set",
-        "-Symbol",
-        "-WeakMap",
-        "-WeakSet"
-      ]
-    });
-
-  test.done();
-};
diff --git a/tests/unit/parser.js b/tests/unit/parser.js
index 4f4807b8..3ee6c603 100644
--- a/tests/unit/parser.js
+++ b/tests/unit/parser.js
@@ -5261,3 +5261,12 @@ exports.testStrictDirectiveASI = function (test) {
 
   test.done();
 };
+
+exports.dereferenceDelete = function (test) {
+  TestRun(test)
+    .addError(1, "Expected an identifier and instead saw '.'.")
+    .addError(1, "Missing semicolon.")
+    .test("delete.foo();");
+
+  test.done();
+};