JS: update queries and tests for improved type inference

This commit is contained in:
Esben Sparre Andreasen
2018-08-16 13:23:05 +02:00
parent 3692667af2
commit 6f5fb2a9fe
10 changed files with 231 additions and 7 deletions

View File

@@ -170,6 +170,28 @@ string getTypeDescription(string message1, string message2, int complexity1, int
result = message1
}
/**
* Holds if `e` directly uses a parameter's initial value as passed in from the caller.
*/
predicate isInitialParameterUse(Expr e) {
exists (SimpleParameter p, SsaExplicitDefinition ssa |
ssa.getAContributingVarDef() = p and
ssa.getVariable().getAUse() = e and
not p.isRestParameter()
)
}
/**
* Holds if `e` is an expression that should not be considered in a heterogeneous comparison.
*
* We currently whitelist these kinds of expressions:
*
* - parameters, as passed in from the caller
*/
predicate whitelist(Expr e) {
isInitialParameterUse(e)
}
from ASTNode cmp,
DataFlow::AnalyzedNode left, DataFlow::AnalyzedNode right,
string leftTypes, string rightTypes,
@@ -177,6 +199,8 @@ from ASTNode cmp,
int leftTypeCount, int rightTypeCount ,
string leftTypeDescription, string rightTypeDescription
where isHeterogeneousComparison(cmp, left, right, leftTypes, rightTypes) and
not whitelist(left.asExpr()) and
not whitelist(right.asExpr()) and
leftExprDescription = capitalize(getDescription(left.asExpr(), "this expression")) and
rightExprDescription = getDescription(right.asExpr(), "an expression") and
leftTypeCount = strictcount(left.getAType()) and

View File

@@ -14,6 +14,7 @@
import javascript
import semmle.javascript.RestrictedLocations
import semmle.javascript.dataflow.Refinements
/**
* Holds if `va` is a defensive truthiness check that may be worth keeping, even if it
@@ -62,19 +63,52 @@ predicate isConstant(Expr e) {
isSymbolicConstant(e.(VarAccess).getVariable())
}
/**
* Holds if `e` directly uses a parameter's initial value as passed in from the caller.
*/
predicate isInitialParameterUse(Expr e) {
exists (SimpleParameter p, SsaExplicitDefinition ssa |
ssa.getAContributingVarDef() = p and
ssa.getVariable().getAUse() = e and
not p.isRestParameter()
)
or
isInitialParameterUse(e.(LogNotExpr).getOperand())
}
/**
* Holds if `e` directly uses the returned value from a function call that returns a constant boolean value.
*/
predicate isConstantBooleanReturnValue(Expr e) {
exists (DataFlow::CallNode call |
exists (call.analyze().getTheBooleanValue()) |
e = call.asExpr() or
exists (SsaExplicitDefinition ssa |
ssa.getDef().getSource() = call.asExpr() and
ssa.getVariable().getAUse() = e
)
)
or
isConstantBooleanReturnValue(e.(LogNotExpr).getOperand())
}
/**
* Holds if `e` is an expression that should not be flagged as a useless condition.
*
* We currently whitelist three kinds of expressions:
* We currently whitelist these kinds of expressions:
*
* - constants (including references to literal constants);
* - negations of constants;
* - defensive checks.
* - defensive checks;
* - parameters, as passed in from the caller;
* - constant boolean returned values
*/
predicate whitelist(Expr e) {
isConstant(e) or
isConstant(e.(LogNotExpr).getOperand()) or
isDefensiveInit(e)
isDefensiveInit(e) or
isInitialParameterUse(e) or
isConstantBooleanReturnValue(e)
}
/**
@@ -107,4 +141,4 @@ where isConditional(cond, op.asExpr()) and
msg = "This expression always evaluates to " + cv + "."
)
select sel, msg
select sel, msg