Skip to content

Commit 5751c5e

Browse files
committed
Make 'unused' check smarter about unused arguments.
This patch modifies 'unused' checks so that they ignore arguments that were never used but that were followed by used arguments. For example: function one(a, b) { return b; } In this example, since unused 'a' is followed by used 'b', JSHint assumes that this is a backwards compatibility issue or a specific API pattern and suppresses the warning. But this example, on the other hand, will generate a warning for 'b' because there is no reason to keep it around: function one(a, b) { return a; } References: Closes GH-607
1 parent c035bc5 commit 5751c5e

File tree

3 files changed

+68
-61
lines changed

3 files changed

+68
-61
lines changed

jshint.js

Lines changed: 61 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@
208208
moveTo, mootools, multistr, name, navigator, new, newcap, noarg, node, noempty, nomen,
209209
nonew, nonstandard, nud, onbeforeunload, onblur, onerror, onevar, onecase, onfocus,
210210
onload, onresize, onunload, open, openDatabase, openURL, opener, opera, options, outer, param,
211-
parent, parseFloat, parseInt, passfail, plusplus, postMessage, predef, print, process, prompt,
211+
parent, parseFloat, parseInt, passfail, plusplus, postMessage, pop, predef, print, process, prompt,
212212
proto, prototype, prototypejs, provides, push, quit, quotmark, range, raw, reach, reason, regexp,
213213
readFile, readUrl, regexdash, removeEventListener, replace, report, require,
214214
reserved, resizeBy, resizeTo, resolvePath, resumeUpdates, respond, rhino, right,
@@ -1745,7 +1745,6 @@ klass: do {
17451745

17461746

17471747
function addlabel(t, type, token) {
1748-
17491748
if (t === "hasOwnProperty") {
17501749
warning("'hasOwnProperty' is a really bad name.");
17511750
}
@@ -2340,18 +2339,22 @@ loop: for (;;) {
23402339

23412340
function assignop(s) {
23422341
symbol(s, 20).exps = true;
2342+
23432343
return infix(s, function (left, that) {
23442344
that.left = left;
2345+
23452346
if (predefined[left.value] === false &&
23462347
scope[left.value]["(global)"] === true) {
23472348
warning("Read only.", left);
23482349
} else if (left["function"]) {
23492350
warning("'{a}' is a function.", left, left.value);
23502351
}
2352+
23512353
if (left) {
23522354
if (option.esnext && funct[left.value] === "const") {
23532355
warning("Attempting to override '{a}' which is a constant", left, left.value);
23542356
}
2357+
23552358
if (left.id === "." || left.id === "[") {
23562359
if (!left.left || left.left.value === "arguments") {
23572360
warning("Bad assignment.", that);
@@ -2365,12 +2368,14 @@ loop: for (;;) {
23652368
that.right = expression(19);
23662369
return that;
23672370
}
2371+
23682372
if (left === syntax["function"]) {
23692373
warning(
23702374
"Expected an identifier in an assignment and instead saw a function invocation.",
23712375
token);
23722376
}
23732377
}
2378+
23742379
error("Bad assignment.", that);
23752380
}, 20);
23762381
}
@@ -3330,23 +3335,28 @@ loop: for (;;) {
33303335

33313336

33323337
function functionparams() {
3333-
var i, t = nexttoken, p = [];
3338+
var next = nexttoken;
3339+
var params = [];
3340+
var ident;
3341+
33343342
advance("(");
33353343
nospace();
3344+
33363345
if (nexttoken.id === ")") {
33373346
advance(")");
33383347
return;
33393348
}
3349+
33403350
for (;;) {
3341-
i = identifier(true);
3342-
p.push(i);
3343-
addlabel(i, "unused", token);
3351+
ident = identifier(true);
3352+
params.push(ident);
3353+
addlabel(ident, "unused", token);
33443354
if (nexttoken.id === ",") {
33453355
comma();
33463356
} else {
3347-
advance(")", t);
3357+
advance(")", next);
33483358
nospace(prevtoken, token);
3349-
return p;
3359+
return params;
33503360
}
33513361
}
33523362
}
@@ -4359,30 +4369,35 @@ loop: for (;;) {
43594369
implied[name] = newImplied;
43604370
};
43614371

4372+
var warnUnused = function (name, token) {
4373+
var line = token.line;
4374+
var chr = token.character;
4375+
4376+
if (option.unused)
4377+
warningAt("'{a}' is defined but never used.", line, chr, name);
4378+
4379+
unuseds.push({
4380+
name: name,
4381+
line: line,
4382+
character: chr
4383+
});
4384+
};
4385+
43624386
var checkUnused = function (func, key) {
43634387
var type = func[key];
43644388
var token = func["(tokens)"][key];
43654389

43664390
if (key.charAt(0) === "(")
43674391
return;
43684392

4369-
// 'undefined' is a special case for (function (window, undefined) { ... })();
4370-
// patterns.
4371-
4372-
if (key === "undefined")
4373-
return;
4374-
43754393
if (type !== "unused" && type !== "unction")
43764394
return;
43774395

4378-
if (option.unused)
4379-
warningAt("'{a}' is defined but never used.", token.line, token.character, key);
4396+
// Params are checked separately from other variables.
4397+
if (func["(params)"] && func["(params)"].indexOf(key) !== -1)
4398+
return;
43804399

4381-
unuseds.push({
4382-
name: key,
4383-
line: token.line,
4384-
character: token.character
4385-
});
4400+
warnUnused(key, token);
43864401
};
43874402

43884403
// Check queued 'x is not defined' instances to see if they're still undefined.
@@ -4402,22 +4417,34 @@ loop: for (;;) {
44024417
checkUnused(func, key);
44034418
}
44044419
}
4420+
4421+
if (!func["(params)"])
4422+
return;
4423+
4424+
var params = func["(params)"].slice();
4425+
var param = params.pop();
4426+
var type;
4427+
4428+
while (param) {
4429+
type = func[param];
4430+
4431+
// 'undefined' is a special case for (function (window, undefined) { ... })();
4432+
// patterns.
4433+
4434+
if (param === "undefined")
4435+
return;
4436+
4437+
if (type !== "unused" && type !== "unction")
4438+
return;
4439+
4440+
warnUnused(param, func["(tokens)"][param]);
4441+
param = params.pop();
4442+
}
44054443
});
44064444

44074445
for (var key in declared) {
4408-
if (is_own(declared, key)) {
4409-
if (!is_own(global, key)) {
4410-
if (option.unused) {
4411-
warningAt("'{a}' is defined but never used.",
4412-
declared[key].line, declared[key].character, key);
4413-
}
4414-
4415-
unuseds.push({
4416-
name: key,
4417-
line: declared[key].line,
4418-
character: declared[key].character
4419-
});
4420-
}
4446+
if (is_own(declared, key) && !is_own(global, key)) {
4447+
warnUnused(key, declared[key]);
44214448
}
44224449
}
44234450
} catch (e) {

tests/regression/jquery.js

Lines changed: 5 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,13 @@ exports.jQuery_1_7 = function () {
1010
var globals = { DOMParser: false, ActiveXObject: false, define: false };
1111

1212
TestRun()
13-
.addError(77, "'all' is defined but never used.")
1413
.addError(551, "'name' is defined but never used.")
15-
.addError(903, "'i' is defined but never used.")
1614
.addError(1044, "'actual' is defined but never used.")
1715
.addError(1312, "'pCount' is defined but never used.")
1816
.addError(1369, "'events' is defined but never used.")
1917
.addError(1607, "'table' is defined but never used.")
2018
.addError(1710, "'internalKey' is defined but never used.")
2119
.addError(1813, "'internalKey' is defined but never used.")
22-
.addError(2760, "'i' is defined but never used.")
23-
.addError(2787, "'i' is defined but never used.")
2420
.addError(2818, "Expected an assignment or function call and instead saw an expression.")
2521
.addError(2822, "Expected an assignment or function call and instead saw an expression.")
2622
.addError(2859, "'rnamespaces' is defined but never used.")
@@ -29,36 +25,19 @@ exports.jQuery_1_7 = function () {
2925
.addError(2863, "'rescape' is defined but never used.")
3026
.addError(2900, "'quick' is defined but never used.")
3127
.addError(3269, "'related' is defined but never used.")
32-
.addError(3442, "'data' is defined but never used.")
33-
.addError(3442, "'namespaces' is defined but never used.")
34-
.addError(3449, "'namespaces' is defined but never used.")
3528
.addError(3592, "'selector' is defined but never used.")
36-
.addError(3889, "'i' is defined but never used.")
3729
.addError(4465, "'curLoop' is defined but never used.")
38-
.addError(4496, "'curLoop' is defined but never used.")
39-
.addError(4496, "'inplace' is defined but never used.")
40-
.addError(4496, "'result' is defined but never used.")
41-
.addError(4496, "'not' is defined but never used.")
4230
.addError(4560, "Expected an assignment or function call and instead saw an expression.")
43-
.addError(4574, "'i' is defined but never used.")
44-
.addError(4633, "'elem' is defined but never used.")
45-
.addError(4637, "'elem' is defined but never used.")
46-
.addError(4637, "'match' is defined but never used.")
47-
.addError(4641, "'elem' is defined but never used.")
48-
.addError(4645, "'elem' is defined but never used.")
49-
.addError(4649, "'elem' is defined but never used.")
50-
.addError(4653, "'elem' is defined but never used.")
51-
.addError(4657, "'elem' is defined but never used.")
52-
.addError(4661, "'elem' is defined but never used.")
5331
.addError(4694, "'cache' is defined but never used.")
5432
.addError(4702, "Mixed spaces and tabs.")
5533
.addError(4712, "Expected a 'break' statement before 'case'.")
5634
.addError(4715, "Mixed spaces and tabs.")
57-
.addError(4818, "'all' is defined but never used.")
5835
.addError(4843, "Expected an assignment or function call and instead saw an expression.")
59-
.addError(5552, "'i' is defined but never used.")
60-
.addError(5234, "'nodeCheck' is defined but never used.")
61-
.addError(5267, "'nodeCheck' is defined but never used.")
36+
.addError(5635, "'elem' is defined but never used.")
37+
.addError(5675, "'i' is defined but never used.")
38+
.addError(5691, "'i' is defined but never used.")
39+
.addError(7141, "'i' is defined but never used.")
40+
.addError(6061, "'cur' is defined but never used.")
6241
.addError(9209, "Mixed spaces and tabs.")
6342
.test(src, { undef: true, unused: true }, globals);
6443
};

tests/unit/fixtures/unused.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ function main(e, f) {
1212

1313
main(b);
1414

15-
function foo() {
15+
function foo(err, cb) {
1616
main();
17+
cb();
1718
}

0 commit comments

Comments
 (0)