DeepScan vs ESLint
Semantic analysis at your hand
JavaScript has become the most popular language, but static analysis for it has not been around because of the dynamic features of JavaScript.
We have researched JavaScript code analysis for years, and now released "DeepScan". "Deep" means our aim for "Beyond lint".
Beyond Lint
DeepScan comes to semantic analysis that other lint tools can't.
Linter tools like ESLint provide some useful checks by pattern-matching on AST (Abstract Syntax Tree). But, because it does not know the flow of program, it can detect some stylistic issues or only stereotyped errors.
DeepScan uses CFG (Control Flow Graph), and it can follow the execution and data flow of program. So it can detect more useful errors than linter tools do.
Let's see some examples:
What value the variable has
DeepScan tracks possible values of variable at each program point while ESLint can't.
Below code is for destroying an object, but it does not work recursively because type
is "undefined" by uninitialized variable i
.
var destroyObject = function (object) {
var type = Object.prototype.toString.call(object[i]); // Use of uninitialized variable
for (var i in object) {
if (type === '[object Object]' || type === '[object Array]') {
destroyObject(object[i]);
}
object[i] = null;
delete object[i];
}
}
object[i]
as a defect: Variable i
is uninitialized.
This is possible because DeepScan tracks the status and value of variable i
in its scope.
More compact example?
function isStringType(obj) {
var type = 'stringg'; // Mis-typed string
if (typeof obj === type) {
return true;
}
return false;
}
valid-typeof
check, but it can't detect above case because it does not know the value of type
.
Control flow
By return
statement, the loop in the below code is stopped interruptedly at the first iteration.
_checkCacheExpire : function(sKey) {
if (sKey) {
for (var i = 0, n = this._waKeyList.length(); i < n; i++) {
return this._checkCacheExpire(this._waKeyList.get(i));
}
}
}
no-unreachable
check, but it can't detect above case because it does not know the control flow (for
in the above) of the program. It detects only the stereotyped case like:
for (var i = 0, n = this._waKeyList.length(); i < n; i++) {
return this._checkCacheExpire(this._waKeyList.get(i));
console.log('Something to do'); // statement after 'return'
}
Program execution
DeepScan understands program execution while ESLint can't.
In the below, fromArgs
variable is checked in the first if
statement. But it is checked again in the body of else if
statement, which must be false. So contrast to programmer's intent, code guarded by the second check is never executed.
function foo(fromArgs) {
// ...
if (fromArgs) {
// setting date by clicking
this.setValue();
this.element.change();
} else if (this.dates.length) {
// setting date by typing
// DeepScan: Condition 'fromArgs' is always false because it is redundant.
// ESLint: (no detection because it has no knowledge about 'fromArgs' at this point)
if (String(oldDates) !== String(this.dates) && fromArgs) {
// DeepScan: (understands that this code is never executed)
this._trigger('changeDate');
this.element.change();
}
}
}
no-constant-condition
, but it detects only the stereotyped case like:
if (false) {
// do something
}