Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

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
  • Loading branch information...
commit 5751c5ed249b7a035758a3ae876cfa1a360fd144 1 parent c035bc5
@valueof valueof authored
View
95 jshint.js
@@ -208,7 +208,7 @@
moveTo, mootools, multistr, name, navigator, new, newcap, noarg, node, noempty, nomen,
nonew, nonstandard, nud, onbeforeunload, onblur, onerror, onevar, onecase, onfocus,
onload, onresize, onunload, open, openDatabase, openURL, opener, opera, options, outer, param,
- parent, parseFloat, parseInt, passfail, plusplus, postMessage, predef, print, process, prompt,
+ parent, parseFloat, parseInt, passfail, plusplus, postMessage, pop, predef, print, process, prompt,
proto, prototype, prototypejs, provides, push, quit, quotmark, range, raw, reach, reason, regexp,
readFile, readUrl, regexdash, removeEventListener, replace, report, require,
reserved, resizeBy, resizeTo, resolvePath, resumeUpdates, respond, rhino, right,
@@ -1745,7 +1745,6 @@ klass: do {
function addlabel(t, type, token) {
-
if (t === "hasOwnProperty") {
warning("'hasOwnProperty' is a really bad name.");
}
@@ -2340,18 +2339,22 @@ loop: for (;;) {
function assignop(s) {
symbol(s, 20).exps = true;
+
return infix(s, function (left, that) {
that.left = left;
+
if (predefined[left.value] === false &&
scope[left.value]["(global)"] === true) {
warning("Read only.", left);
} else if (left["function"]) {
warning("'{a}' is a function.", left, left.value);
}
+
if (left) {
if (option.esnext && funct[left.value] === "const") {
warning("Attempting to override '{a}' which is a constant", left, left.value);
}
+
if (left.id === "." || left.id === "[") {
if (!left.left || left.left.value === "arguments") {
warning("Bad assignment.", that);
@@ -2365,12 +2368,14 @@ loop: for (;;) {
that.right = expression(19);
return that;
}
+
if (left === syntax["function"]) {
warning(
"Expected an identifier in an assignment and instead saw a function invocation.",
token);
}
}
+
error("Bad assignment.", that);
}, 20);
}
@@ -3330,23 +3335,28 @@ loop: for (;;) {
function functionparams() {
- var i, t = nexttoken, p = [];
+ var next = nexttoken;
+ var params = [];
+ var ident;
+
advance("(");
nospace();
+
if (nexttoken.id === ")") {
advance(")");
return;
}
+
for (;;) {
- i = identifier(true);
- p.push(i);
- addlabel(i, "unused", token);
+ ident = identifier(true);
+ params.push(ident);
+ addlabel(ident, "unused", token);
if (nexttoken.id === ",") {
comma();
} else {
- advance(")", t);
+ advance(")", next);
nospace(prevtoken, token);
- return p;
+ return params;
}
}
}
@@ -4359,6 +4369,20 @@ loop: for (;;) {
implied[name] = newImplied;
};
+ var warnUnused = function (name, token) {
+ var line = token.line;
+ var chr = token.character;
+
+ if (option.unused)
+ warningAt("'{a}' is defined but never used.", line, chr, name);
+
+ unuseds.push({
+ name: name,
+ line: line,
+ character: chr
+ });
+ };
+
var checkUnused = function (func, key) {
var type = func[key];
var token = func["(tokens)"][key];
@@ -4366,23 +4390,14 @@ loop: for (;;) {
if (key.charAt(0) === "(")
return;
- // 'undefined' is a special case for (function (window, undefined) { ... })();
- // patterns.
-
- if (key === "undefined")
- return;
-
if (type !== "unused" && type !== "unction")
return;
- if (option.unused)
- warningAt("'{a}' is defined but never used.", token.line, token.character, key);
+ // Params are checked separately from other variables.
+ if (func["(params)"] && func["(params)"].indexOf(key) !== -1)
+ return;
- unuseds.push({
- name: key,
- line: token.line,
- character: token.character
- });
+ warnUnused(key, token);
};
// Check queued 'x is not defined' instances to see if they're still undefined.
@@ -4402,22 +4417,34 @@ loop: for (;;) {
checkUnused(func, key);
}
}
+
+ if (!func["(params)"])
+ return;
+
+ var params = func["(params)"].slice();
+ var param = params.pop();
+ var type;
+
+ while (param) {
+ type = func[param];
+
+ // 'undefined' is a special case for (function (window, undefined) { ... })();
+ // patterns.
+
+ if (param === "undefined")
+ return;
+
+ if (type !== "unused" && type !== "unction")
+ return;
+
+ warnUnused(param, func["(tokens)"][param]);
+ param = params.pop();
+ }
});
for (var key in declared) {
- if (is_own(declared, key)) {
- if (!is_own(global, key)) {
- if (option.unused) {
- warningAt("'{a}' is defined but never used.",
- declared[key].line, declared[key].character, key);
- }
-
- unuseds.push({
- name: key,
- line: declared[key].line,
- character: declared[key].character
- });
- }
+ if (is_own(declared, key) && !is_own(global, key)) {
+ warnUnused(key, declared[key]);
}
}
} catch (e) {
View
31 tests/regression/jquery.js
@@ -10,17 +10,13 @@ exports.jQuery_1_7 = function () {
var globals = { DOMParser: false, ActiveXObject: false, define: false };
TestRun()
- .addError(77, "'all' is defined but never used.")
.addError(551, "'name' is defined but never used.")
- .addError(903, "'i' is defined but never used.")
.addError(1044, "'actual' is defined but never used.")
.addError(1312, "'pCount' is defined but never used.")
.addError(1369, "'events' is defined but never used.")
.addError(1607, "'table' is defined but never used.")
.addError(1710, "'internalKey' is defined but never used.")
.addError(1813, "'internalKey' is defined but never used.")
- .addError(2760, "'i' is defined but never used.")
- .addError(2787, "'i' is defined but never used.")
.addError(2818, "Expected an assignment or function call and instead saw an expression.")
.addError(2822, "Expected an assignment or function call and instead saw an expression.")
.addError(2859, "'rnamespaces' is defined but never used.")
@@ -29,36 +25,19 @@ exports.jQuery_1_7 = function () {
.addError(2863, "'rescape' is defined but never used.")
.addError(2900, "'quick' is defined but never used.")
.addError(3269, "'related' is defined but never used.")
- .addError(3442, "'data' is defined but never used.")
- .addError(3442, "'namespaces' is defined but never used.")
- .addError(3449, "'namespaces' is defined but never used.")
.addError(3592, "'selector' is defined but never used.")
- .addError(3889, "'i' is defined but never used.")
.addError(4465, "'curLoop' is defined but never used.")
- .addError(4496, "'curLoop' is defined but never used.")
- .addError(4496, "'inplace' is defined but never used.")
- .addError(4496, "'result' is defined but never used.")
- .addError(4496, "'not' is defined but never used.")
.addError(4560, "Expected an assignment or function call and instead saw an expression.")
- .addError(4574, "'i' is defined but never used.")
- .addError(4633, "'elem' is defined but never used.")
- .addError(4637, "'elem' is defined but never used.")
- .addError(4637, "'match' is defined but never used.")
- .addError(4641, "'elem' is defined but never used.")
- .addError(4645, "'elem' is defined but never used.")
- .addError(4649, "'elem' is defined but never used.")
- .addError(4653, "'elem' is defined but never used.")
- .addError(4657, "'elem' is defined but never used.")
- .addError(4661, "'elem' is defined but never used.")
.addError(4694, "'cache' is defined but never used.")
.addError(4702, "Mixed spaces and tabs.")
.addError(4712, "Expected a 'break' statement before 'case'.")
.addError(4715, "Mixed spaces and tabs.")
- .addError(4818, "'all' is defined but never used.")
.addError(4843, "Expected an assignment or function call and instead saw an expression.")
- .addError(5552, "'i' is defined but never used.")
- .addError(5234, "'nodeCheck' is defined but never used.")
- .addError(5267, "'nodeCheck' is defined but never used.")
+ .addError(5635, "'elem' is defined but never used.")
+ .addError(5675, "'i' is defined but never used.")
+ .addError(5691, "'i' is defined but never used.")
+ .addError(7141, "'i' is defined but never used.")
+ .addError(6061, "'cur' is defined but never used.")
.addError(9209, "Mixed spaces and tabs.")
.test(src, { undef: true, unused: true }, globals);
};
View
3  tests/unit/fixtures/unused.js
@@ -12,6 +12,7 @@ function main(e, f) {
main(b);
-function foo() {
+function foo(err, cb) {
main();
+ cb();
}

4 comments on commit 5751c5e

@telendt

Great news! When can I expect the new release tag including this feature and - more important - when can I expect to see it in node-jshint?

@valueof
Owner

Around this Sunday: both for the lib and node-jshint.

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