Skip to content
Browse files

Change how JSHint treats ES5 accessors.

Don't require getter *and* setter, but show a warning when setter
is used without a corresponding getter.

Fixes GH-373
Fixes GH-374
  • Loading branch information...
1 parent 014e26a commit 3585b1eae9b7d218b27cca183d0788bb661a7572 @valueof valueof committed
Showing with 74 additions and 14 deletions.
  1. +40 −10 jshint.js
  2. +11 −1 tests/envs.js
  3. +2 −2 tests/fixtures/es5.funcexpr.js
  4. +21 −1 tests/fixtures/es5.js
View
50 jshint.js
@@ -204,7 +204,7 @@
entityify, eqeqeq, eqnull, errors, es5, escape, esnext, eval, event, evidence, evil,
ex, exception, exec, exps, expr, exports, FileReader, first, floor, focus,
forin, fragment, frames, from, fromCharCode, fud, funcscope, funct, function, functions,
- g, gc, getComputedStyle, getRow, GLOBAL, global, globals, globalstrict,
+ g, gc, getComputedStyle, getRow, getter, GLOBAL, global, globals, globalstrict,
hasOwnProperty, help, history, i, id, identifier, immed, implieds, importPackage, include,
indent, indexOf, init, ins, instanceOf, isAlpha, isApplicationRunning, isArray,
isDigit, isFinite, isNaN, iterator, java, join, jshint,
@@ -219,10 +219,10 @@
readFile, readUrl, regexdash, removeEventListener, replace, report, require,
reserved, resizeBy, resizeTo, resolvePath, resumeUpdates, respond, rhino, right,
runCommand, scroll, screen, scripturl, scrollBy, scrollTo, scrollbar, search, seal,
- send, serialize, sessionStorage, setInterval, setTimeout, shift, slice, smarttabs, sort,
- spawn, split, stack, status, start, strict, sub, substr, supernew, shadow, supplant, sum,
- sync, test, toLowerCase, toString, toUpperCase, toint32, token, top, trailing, type,
- typeOf, Uint16Array, Uint32Array, Uint8Array, undef, undefs, unused, urls, validthis,
+ send, serialize, sessionStorage, setInterval, setTimeout, setter, setterToken, shift, slice,
+ smarttabs, sort, spawn, split, stack, status, start, strict, sub, substr, supernew, shadow,
+ supplant, sum, sync, test, toLowerCase, toString, toUpperCase, toint32, token, top, trailing,
+ type, typeOf, Uint16Array, Uint32Array, Uint8Array, undef, undefs, unused, urls, validthis,
value, valueOf, var, version, WebSocket, white, window, Worker, wsh*/
/*global exports: false */
@@ -3216,6 +3216,22 @@ loop: for (;;) {
(function (x) {
x.nud = function () {
var b, f, i, j, p, seen = {}, t;
+ var prop, acc = {}; // Accessor methods
+
+ function saveSetter(name, token) {
+ if (!acc[name]) {
+ acc[name] = {};
+ }
+ acc[name].setter = true;
+ acc[name].setterToken = token;
+ }
+
+ function saveGetter(name) {
+ if (!acc[name]) {
+ acc[name] = {};
+ }
+ acc[name].getter = true;
+ }
b = token.line !== nexttoken.line;
if (b) {
@@ -3240,6 +3256,7 @@ loop: for (;;) {
if (!i) {
error("Missing property name.");
}
+ saveGetter(i);
t = nexttoken;
adjacent(token, nexttoken);
f = doFunction();
@@ -3251,13 +3268,17 @@ loop: for (;;) {
warning("Unexpected parameter '{a}' in get {b} function.", t, p[0], i);
}
adjacent(token, nexttoken);
- advance(',');
- indentation();
+ } else if (nexttoken.value === 'set' && peek().id !== ':') {
advance('set');
- j = property_name();
- if (i !== j) {
- error("Expected {a} and instead saw {b}.", token, i, j);
+ if (!option.es5) {
+ error("get/set are ES5 features.");
+ }
+ i = property_name();
+ if (!i) {
+ error("Missing property name.");
}
+ saveSetter(i, nexttoken);
+ seen[i] = false;
t = nexttoken;
adjacent(token, nexttoken);
f = doFunction();
@@ -3295,6 +3316,15 @@ loop: for (;;) {
indentation();
}
advance('}', this);
+
+ // Check for lonely setters if in the ES5 mode.
+ if (option.es5) {
+ for (prop in acc) {
+ if (acc.hasOwnProperty(prop) && acc[prop].setter && !acc[prop].getter) {
+ warning("Setter is defined without getter.", acc[prop].setterToken);
+ }
+ }
+ }
return this;
};
x.fud = function () {
View
12 tests/envs.js
@@ -380,8 +380,18 @@ exports.es5 = function () {
.addError(3, "Extra comma.")
.addError(8, "Extra comma.")
.addError(15, "get/set are ES5 features.")
+ .addError(16, "get/set are ES5 features.")
+ .addError(20, "get/set are ES5 features.")
+ .addError(22, "get/set are ES5 features.")
+ .addError(26, "get/set are ES5 features.")
+ .addError(30, "get/set are ES5 features.")
+ .addError(31, "get/set are ES5 features.")
+ .addError(36, "get/set are ES5 features.")
.test(src);
- TestRun().test(src, { es5: true });
+
+ TestRun()
+ .addError(36, "Setter is defined without getter.")
+ .test(src, { es5: true });
// Make sure that JSHint parses getters/setters as function expressions
// (https://github.com/jshint/jshint/issues/96)
View
4 tests/fixtures/es5.funcexpr.js
@@ -7,9 +7,9 @@
var test = (function() {
var func = function() {},
innerTest = {
- get func() { return func;},
+ get func() { return func; },
set func(value) { func = value; }
};
innerTest = func;
return innerTest;
-})();
+})();
View
22 tests/fixtures/es5.js
@@ -15,4 +15,24 @@ var b = {
get x() { return _x; },
set x(value) { _x = value; }
};
-}());
+
+ var obj2 = {
+ get x() { return _x; },
+ name: 'jshint',
+ set x(value) { _x = value; }
+ };
+
+ var onlyGetter1 = {
+ get x() { return _x; }
+ };
+
+ var onlyGetter2 = {
+ get x() { return _x; },
+ get y() { return _x; },
+ a: 1
+ };
+
+ var onlySetter = {
+ set x(value) { _x = value; }
+ };
+}());

0 comments on commit 3585b1e

Please sign in to comment.
Something went wrong with that request. Please try again.