mirror of
https://github.com/github/codeql.git
synced 2026-04-28 18:25:24 +02:00
Merge pull request #323 from esben-semmle/js/always-return-type-inference
JS: additional return type inference
This commit is contained in:
@@ -756,7 +756,7 @@ module DataFlow {
|
||||
/**
|
||||
* A data flow node representing an explicit (that is, non-reflective) function call.
|
||||
*/
|
||||
private class ExplicitCallNode extends CallNodeDef, ExplicitInvokeNode {
|
||||
class ExplicitCallNode extends CallNodeDef, ExplicitInvokeNode {
|
||||
override CallExpr astNode;
|
||||
}
|
||||
|
||||
|
||||
@@ -91,17 +91,19 @@ class AnalyzedNode extends DataFlow::Node {
|
||||
|
||||
/** Gets a type inferred for this node. */
|
||||
pragma[nomagic] InferredType getAType() {
|
||||
result = getALocalValue().getType()
|
||||
result = getAValue().getType()
|
||||
}
|
||||
|
||||
/** Gets a primitive type to which the value of this node can be coerced. */
|
||||
/**
|
||||
* Gets a primitive type to which the value of this node can be coerced.
|
||||
*/
|
||||
PrimitiveType getAPrimitiveType() {
|
||||
result = getALocalValue().toPrimitive().getType()
|
||||
result = getAValue().toPrimitive().getType()
|
||||
}
|
||||
|
||||
/** Gets a Boolean value that this node evaluates to. */
|
||||
boolean getABooleanValue() {
|
||||
result = getALocalValue().getBooleanValue()
|
||||
result = getAValue().getBooleanValue()
|
||||
}
|
||||
|
||||
/** Gets the unique Boolean value that this node evaluates to, if any. */
|
||||
@@ -166,7 +168,7 @@ class AnalyzedNode extends DataFlow::Node {
|
||||
|
||||
/** Holds if the flow analysis can infer at least one abstract value for this node. */
|
||||
predicate hasFlow() {
|
||||
exists(getALocalValue())
|
||||
exists(getAValue())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -242,18 +242,25 @@ private class AnalyzedBinaryExpr extends DataFlow::AnalyzedValueNode {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a primitive type to which the local value of `e` can be coerced.
|
||||
*/
|
||||
private PrimitiveType getALocalPrimitiveType(Expr e) {
|
||||
result = e.analyze().getALocalValue().toPrimitive().getType()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `e` may hold a string value.
|
||||
*/
|
||||
private predicate maybeString(Expr e) {
|
||||
e.analyze().getAPrimitiveType() = TTString()
|
||||
getALocalPrimitiveType(e) = TTString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `e` may hold a non-string value.
|
||||
*/
|
||||
private predicate maybeNonString(Expr e) {
|
||||
e.analyze().getAPrimitiveType() != TTString()
|
||||
getALocalPrimitiveType(e) != TTString()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,8 +14,7 @@ import semmle.javascript.dataflow.Configuration
|
||||
*/
|
||||
predicate shouldTrackProperties(AbstractValue obj) {
|
||||
obj instanceof AbstractExportsObject or
|
||||
obj instanceof AbstractModuleObject or
|
||||
obj instanceof AbstractObjectLiteral
|
||||
obj instanceof AbstractModuleObject
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -143,6 +143,23 @@ abstract class CallWithAnalyzedReturnFlow extends DataFlow::AnalyzedValueNode {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call with inter-procedural type inference for the return value.
|
||||
*
|
||||
* Unlike `CallWithAnalyzedReturnFlow`, this only contributes to `getAValue()`, not `getALocalValue()`.
|
||||
*/
|
||||
abstract class CallWithNonLocalAnalyzedReturnFlow extends DataFlow::AnalyzedValueNode {
|
||||
|
||||
/**
|
||||
* Gets a called function.
|
||||
*/
|
||||
abstract AnalyzedFunction getACallee();
|
||||
|
||||
override AbstractValue getAValue() {
|
||||
result = getACallee().getAReturnValue()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flow analysis for the return value of IIFEs.
|
||||
*/
|
||||
@@ -210,4 +227,30 @@ private class LocalFunctionCallWithAnalyzedReturnFlow extends CallWithAnalyzedRe
|
||||
result = f.analyze()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate hasExplicitDefiniteCallee(DataFlow::Impl::ExplicitCallNode call, DataFlow::AnalyzedNode callee) {
|
||||
callee = call.getCalleeNode() and
|
||||
not callee.getALocalValue().isIndefinite(_)
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables inter-procedural type inference for the return value of a call to a type-inferred callee.
|
||||
*/
|
||||
private class TypeInferredCalleeWithAnalyzedReturnFlow extends CallWithNonLocalAnalyzedReturnFlow {
|
||||
|
||||
DataFlow::FunctionNode fun;
|
||||
|
||||
TypeInferredCalleeWithAnalyzedReturnFlow() {
|
||||
exists (DataFlow::AnalyzedNode calleeNode |
|
||||
hasExplicitDefiniteCallee(this, calleeNode) and
|
||||
calleeNode.getALocalValue().(AbstractFunction).getFunction().flow() = fun
|
||||
)
|
||||
}
|
||||
|
||||
override AnalyzedFunction getACallee() {
|
||||
result = fun
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user