Skip to content

Commit

Permalink
[[FIX]] Correct impl of built-in bindings
Browse files Browse the repository at this point in the history
commit fd5d9c4
Author: Mike Pennisi <mike@mikepennisi.com>
Date:   Mon Sep 11 00:22:26 2017 -0400

    fixup! [[FIX]] Correct impl of built-in bindings

commit 2cf6000
Author: Mike Pennisi <mike@mikepennisi.com>
Date:   Sat Sep 9 23:30:05 2017 -0400

    fixup! [[FIX]] Correct impl of built-in bindings

commit 5e62731
Author: Mike Pennisi <mike@mikepennisi.com>
Date:   Sat Sep 9 19:52:57 2017 -0400

    fixup! [[FIX]] Correct impl of built-in bindings

commit 7d360ff
Author: Mike Pennisi <mike@mikepennisi.com>
Date:   Sat Sep 9 19:29:12 2017 -0400

    fixup! [[FIX]] Correct impl of built-in bindings

commit 9411c79
Author: Mike Pennisi <mike@mikepennisi.com>
Date:   Sun Sep 3 00:35:03 2017 -0400

    fixup! [[FIX]] Correct impl of built-in bindings

commit e58c37a
Author: Mike Pennisi <mike@mikepennisi.com>
Date:   Sat Sep 2 18:59:56 2017 -0400

    fixup! [[FIX]] Correct impl of built-in bindings

commit 506d98a
Author: Mike Pennisi <mike@mikepennisi.com>
Date:   Sun Aug 27 11:51:05 2017 -0400

    [[FIX]] Correct impl of built-in bindings

    Refactor internals to recognize `undefined`, `Infinity`, `arguments`,
    and `eval` as built-in bindings, not reserved words.

commit fba285a
Author: Mike Pennisi <mike@mikepennisi.com>
Date:   Sun Aug 27 11:50:52 2017 -0400

    [[FIX]] Correct restrictions on inc/dec

    The `checkLeftSideAssign` function enforces many restrictions on
    assignment targets, but the previous implementation of the increment and
    decrement operators only enforced a subset of those restrictions. Re-use
    `checkLeftSideAassign` when parsing increment and decrement operators in
    order to reduce duplication and promote correctness. Update tests
    accordingly (note that the change in test expectations is between two
    different errors, making this correction backwards-compatible with prior
    releases).
  • Loading branch information
jugglinmike authored and rwaldron committed Nov 2, 2017
1 parent c4370d9 commit a11d631
Show file tree
Hide file tree
Showing 8 changed files with 213 additions and 121 deletions.
111 changes: 54 additions & 57 deletions src/jshint.js
Original file line number Diff line number Diff line change
Expand Up @@ -1099,17 +1099,10 @@ var JSHINT = (function() {
if (this.id === "++" || this.id === "--") {
if (state.option.plusplus) {
warning("W016", this, this.id);
} else if (this.right && (!this.right.identifier || isReserved(this.right)) &&
this.right.id !== "." && this.right.id !== "[") {
warning("W017", this);
}

if (this.right && this.right.isMetaProperty) {
error("E031", this);
// detect increment/decrement of a const
// in the case of a.b, right will be the "." punctuator
} else if (this.right && this.right.identifier) {
state.funct["(scope)"].block.modify(this.right.value, this);
if (this.right) {
checkLeftSideAssign(this.right, this);
}
}

Expand Down Expand Up @@ -1367,7 +1360,8 @@ var JSHINT = (function() {
}

return true;
} else if (left.identifier && !isReserved(left) && !left.isMetaProperty) {
} else if (left.identifier && !isReserved(left) && !left.isMetaProperty &&
left.value !== "eval" && left.value !== "arguments") {
if (state.funct["(scope)"].labeltype(left.value) === "exception") {
warning("W022", left);
}
Expand Down Expand Up @@ -1434,29 +1428,18 @@ var JSHINT = (function() {
// left = symbol operated e.g. "a" identifier or "a.b" punctuator
if (state.option.plusplus) {
warning("W016", this, this.id);
} else if ((!left.identifier || isReserved(left)) && left.id !== "." && left.id !== "[") {
warning("W017", this);
}

if (left.isMetaProperty) {
error("E031", this);
// detect increment/decrement of a const
// in the case of a.b, left will be the "." punctuator
} else if (left && left.identifier) {
state.funct["(scope)"].block.modify(left.value, left);
}
checkLeftSideAssign(left, this);

this.left = left;
return this;
};
return x;
}

// fnparam means that this identifier is being defined as a function
// argument (see identifier())
// prop means that this identifier is that of an object property

function optionalidentifier(fnparam, prop, preserve) {
function optionalidentifier(prop, preserve) {
if (!state.tokens.next.identifier) {
return;
}
Expand All @@ -1478,19 +1461,13 @@ var JSHINT = (function() {
}
}

if (fnparam && val === "undefined") {
return val;
}

warning("W024", state.tokens.curr, state.tokens.curr.id);
return val;
}

// fnparam means that this identifier is being defined as a function
// argument
// prop means that this identifier is that of an object property
function identifier(fnparam, prop) {
var i = optionalidentifier(fnparam, prop, false);
function identifier(prop) {
var i = optionalidentifier(prop, false);
if (i) {
return i;
}
Expand All @@ -1514,7 +1491,7 @@ var JSHINT = (function() {
return;
}

return identifier(fnparam, prop);
return identifier(prop);
} else {
error("E030", state.tokens.next, state.tokens.next.value);

Expand Down Expand Up @@ -1980,14 +1957,8 @@ var JSHINT = (function() {
reserve("catch");
reserve("default").reach = true;
reserve("finally");
reservevar("arguments", function(x) {
if (state.isStrict() && state.funct["(global)"]) {
warning("E008", x);
}
});
reservevar("eval");
reservevar("false");
reservevar("Infinity");
reserve("true", function() { return this; });
reserve("false", function() { return this; });
reservevar("null");
reservevar("this", function(x) {
if (state.isStrict() && !isMethod() &&
Expand All @@ -1996,8 +1967,6 @@ var JSHINT = (function() {
warning("W040", x);
}
});
reservevar("true");
reservevar("undefined");

assignop("=", "assign", 20);
assignop("+=", "assignadd", 20);
Expand Down Expand Up @@ -2351,7 +2320,7 @@ var JSHINT = (function() {
prefix("void").exps = true;

infix(".", function(left, that) {
var m = identifier(false, true);
var m = identifier(true);

if (typeof m === "string") {
countMember(m);
Expand Down Expand Up @@ -2584,7 +2553,9 @@ var JSHINT = (function() {
application("=>");

infix("[", function(left, that) {
var e = expression(10), s;
var e = expression(10);
var s, canUseDot;

if (e && e.type === "(string)") {
if (!state.option.evil && (e.value === "eval" || e.value === "execScript")) {
if (isGlobalEval(left, state)) {
Expand All @@ -2595,7 +2566,20 @@ var JSHINT = (function() {
countMember(e.value);
if (!state.option.sub && reg.identifier.test(e.value)) {
s = state.syntax[e.value];
if (!s || !isReserved(s)) {

if (s) {
canUseDot = !isReserved(s);
} else {
// This branch exists to preserve legacy behavior with version 2.9.5
// and earlier. In those releases, `eval` and `arguments` were
// incorrectly interpreted as reserved keywords, so Member
// Expressions such as `object["eval"]` did not trigger warning W069.
//
// TODO: Remove in JSHint 3
canUseDot = e.value !== "eval" && e.value !== "arguments";
}

if (canUseDot) {
warning("W069", state.tokens.prev, e.value);
}
}
Expand Down Expand Up @@ -2745,7 +2729,7 @@ var JSHINT = (function() {
id = preserveOrToken;
} else {
preserve = preserveOrToken;
id = optionalidentifier(false, true, preserve);
id = optionalidentifier(true, preserve);
}

if (!id) {
Expand Down Expand Up @@ -2828,7 +2812,7 @@ var JSHINT = (function() {
}
} else {
if (checkPunctuator(state.tokens.next, "...")) pastRest = true;
ident = identifier(true);
ident = identifier();
if (ident) {
paramsIds.push(ident);
currentParams.push([ident, state.tokens.curr]);
Expand Down Expand Up @@ -3021,6 +3005,10 @@ var JSHINT = (function() {
classExprBinding ? "class" : "function", state.tokens.curr, false);
}

if (!isArrow) {
state.funct["(scope)"].funct.add("arguments", "var", token, false);
}

// create the param scope (params added in functionparams)
state.funct["(scope)"].stack("functionparams");

Expand Down Expand Up @@ -3424,7 +3412,7 @@ var JSHINT = (function() {
}
id = state.tokens.prev;
value = expression(10);
if (value && value.type === "undefined") {
if (value && value.identifier && value.value === "undefined") {
warning("W080", id, id.value);
}
}
Expand All @@ -3447,7 +3435,7 @@ var JSHINT = (function() {
advance("=");
id = state.tokens.prev;
value = expression(10);
if (value && value.type === "undefined") {
if (value && value.identifier && value.value === "undefined") {
warning("W080", id, id.value);
}
}
Expand Down Expand Up @@ -3546,7 +3534,7 @@ var JSHINT = (function() {
var id = state.tokens.prev;
// don't accept `in` in expression if prefix is used for ForIn/Of loop.
value = expression(prefix ? 120 : 10);
if (!prefix && value && value.type === "undefined") {
if (!prefix && value && value.identifier && value.value === "undefined") {
warning("W080", id, id.value);
}
if (!lone) {
Expand Down Expand Up @@ -3597,7 +3585,7 @@ var JSHINT = (function() {
var varstatement = stmt("var", function(context) {
var prefix = context && context.prefix;
var inexport = context && context.inexport;
var tokens, lone, value;
var tokens, lone, value, id;

this.first = [];
for (;;) {
Expand All @@ -3606,7 +3594,13 @@ var JSHINT = (function() {
tokens = destructuringPattern();
lone = false;
} else {
tokens = [ { id: identifier(), token: state.tokens.curr } ];
tokens = [];
id = identifier();

if (id) {
tokens.push({ id: id, token: state.tokens.curr });
}

lone = true;
}

Expand Down Expand Up @@ -3653,10 +3647,11 @@ var JSHINT = (function() {
warning("W120", state.tokens.next, state.tokens.next.value);
}
}
var id = state.tokens.prev;
id = state.tokens.prev;
// don't accept `in` in expression if prefix is used for ForIn/Of loop.
value = expression(prefix ? 120 : 10);
if (value && !prefix && !state.funct["(loopage)"] && value.type === "undefined") {
if (value && !prefix && !state.funct["(loopage)"] &&
value.identifier && value.value === "undefined") {
warning("W080", id, id.value);
}
if (!lone) {
Expand All @@ -3681,6 +3676,9 @@ var JSHINT = (function() {
function classdef(rbp, isStatement) {

/*jshint validthis:true */
var wasInClassBody = state.inClassBody;
state.inClassBody = true;

if (!state.inES6()) {
warning("W104", state.tokens.curr, "class", "6");
}
Expand All @@ -3702,6 +3700,8 @@ var JSHINT = (function() {

classtail(this);

state.inClassBody = wasInClassBody;

if (isStatement) {
state.funct["(scope)"].initialize(this.name);
}
Expand All @@ -3710,19 +3710,16 @@ var JSHINT = (function() {
}

function classtail(c) {
var wasInClassBody = state.inClassBody;
// ClassHeritage(opt)
if (state.tokens.next.value === "extends") {
advance("extends");
expression(10);
}

state.inClassBody = true;
advance("{");
// ClassBody(opt)
classbody(c);
advance("}");
state.inClassBody = wasInClassBody;
}

function classbody(c) {
Expand Down
14 changes: 13 additions & 1 deletion src/scope-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,10 @@ var scopeManager = function(state, predefined, exported, declared) {
warning("W002", state.tokens.next, labelName);
}
}

if (state.isStrict() && (labelName === "arguments" || labelName === "eval")) {
warning("E008", token);
}
}

// The variable was declared in the current scope
Expand Down Expand Up @@ -498,13 +502,17 @@ var scopeManager = function(state, predefined, exported, declared) {
currentFunctParamScope["(params)"].forEach(function(labelName) {
var label = currentFunctParamScope["(labels)"][labelName];

if (label && label.duplicated) {
if (label.duplicated) {
if (isStrict || isArrow) {
warning("E011", label["(token)"], labelName);
} else if (state.option.shadow !== true) {
warning("W004", label["(token)"], labelName);
}
}

if (isStrict && (labelName === "arguments" || labelName === "eval")) {
warning("E008", label["(token)"]);
}
});
},

Expand Down Expand Up @@ -633,6 +641,10 @@ var scopeManager = function(state, predefined, exported, declared) {
// outer shadow check (inner is only on non-block scoped)
_checkOuterShadow(labelName, token);

if (state.isStrict() && (labelName === "arguments" || labelName === "eval")) {
warning("E008", token);
}

if (isblockscoped) {

var declaredInCurrentScope = _current["(labels)"][labelName];
Expand Down
7 changes: 5 additions & 2 deletions src/vars.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
// Identifiers provided by the ECMAScript standard.

exports.reservedVars = {
arguments : false,
NaN : false
NaN : false,
undefined : false
};

exports.ecmaIdentifiers = {
Expand All @@ -23,6 +23,7 @@ exports.ecmaIdentifiers = {
EvalError : false,
Function : false,
hasOwnProperty : false,
Infinity : false,
isFinite : false,
isNaN : false,
Math : false,
Expand Down Expand Up @@ -442,6 +443,7 @@ exports.couch = {
exports.node = {
__filename : false,
__dirname : false,
arguments : false,
GLOBAL : false,
global : false,
module : false,
Expand Down Expand Up @@ -504,6 +506,7 @@ exports.qunit = {
};

exports.rhino = {
arguments : false,
defineClass : false,
deserialize : false,
gc : false,
Expand Down

0 comments on commit a11d631

Please sign in to comment.