Skip to content

Commit

Permalink
Unused and implied collections now respect variable hoisting as well. F…
Browse files Browse the repository at this point in the history
…ixes GH-431.
  • Loading branch information
valueof committed Feb 13, 2012
1 parent efbb3af commit 6326498
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 5 deletions.
38 changes: 34 additions & 4 deletions jshint.js
Expand Up @@ -2601,6 +2601,7 @@ loop: for (;;) {
if (typeof a === 'function') {
a = false;
}

if (!a) {
a = [line];
implied[name] = a;
Expand Down Expand Up @@ -4104,22 +4105,52 @@ loop: for (;;) {
}
advance('(end)');

var isDefined = function (name, context) {
var markDefined = function (name, context) {
do {
if (typeof context[name] === 'string')
if (typeof context[name] === 'string') {
// JSHINT marks unused variables as 'unused' and
// unused function declaration as 'unction'. This
// code changes such instances back 'var' and
// 'closure' so that the code in JSHINT.data()
// doesn't think they're unused.

if (context[name] === 'unused')
context[name] = 'var';
else if (context[name] === 'unction')
context[name] = 'closure';

return true;
}

context = context['(context)'];
} while (context);

return false;
};

var clearImplied = function (name, line) {
if (!implied[name])
return;

var newImplied = [];
for (var i = 0; i < implied[name].length; i += 1) {
if (implied[name][i] !== line)
newImplied.push(implied[name][i]);
}

if (newImplied.length === 0)
delete implied[name];
else
implied[name] = newImplied;
};

// Check queued 'x is not defined' instances to see if they're still undefined.
for (i = 0; i < JSHINT.undefs.length; i += 1) {
k = JSHINT.undefs[i].slice(0);

if (!isDefined(k[2].value, k[0])) {
if (markDefined(k[2].value, k[0])) {
clearImplied(k[2].value, k[2].line);
} else {
warning.apply(warning, k.slice(1));
}
}
Expand Down Expand Up @@ -4171,7 +4202,6 @@ loop: for (;;) {
if (globals.length > 0) {
data.globals = globals;
}

for (i = 1; i < functions.length; i += 1) {
f = functions[i];
fu = {};
Expand Down
15 changes: 15 additions & 0 deletions tests/unit/fixtures/gh431.js
@@ -0,0 +1,15 @@
var test = function() {
var fun1 = function (){
fun2();
};

function fun2() {}

var fun3 = function() {
};

function fun5() {}

fun1();
fun4();
};
21 changes: 20 additions & 1 deletion tests/unit/options.js
Expand Up @@ -9,7 +9,8 @@
var JSHINT = require('../../jshint.js').JSHINT,
fs = require('fs'),
TestRun = require('../helpers/testhelper').setup.testRun,
fixture = require('../helpers/fixture').fixture;
fixture = require('../helpers/fixture').fixture,
assert = require('assert');

/**
* Option `shadow` allows you to re-define variables later in code.
Expand Down Expand Up @@ -120,6 +121,24 @@ exports.undefwstrict = function () {
TestRun().test(src, { undef: false });
};

// Regression test for GH-431
exports["implied and unused should respect hoisting"] = function () {
var src = fs.readFileSync(__dirname + '/fixtures/gh431.js', 'utf8');
TestRun()
.addError(14, "'fun4' is not defined.")
.test(src, { undef: true });

JSHINT.flag = true;
JSHINT(src, { undef: true });
var report = JSHINT.data();

assert.eql(report.implieds.length, 1);
assert.eql(report.implieds[0].name, 'fun4');
assert.eql(report.implieds[0].line, [14]);

assert.eql(report.unused.length, 2);
};

/**
* The `proto` and `iterator` options allow you to prohibit the use of the
* special `__proto__` and `__iterator__` properties, respectively.
Expand Down

0 comments on commit 6326498

Please sign in to comment.