JS: Rewrite AnalyzedThisInArrayIterationFunction

This commit is contained in:
Asger Feldthaus
2020-02-05 15:28:42 +00:00
parent f942e69482
commit 3b28bdbeed
2 changed files with 32 additions and 18 deletions

View File

@@ -46,33 +46,26 @@ class DirectEval extends CallExpr {
}
/**
* Flow analysis for `this` expressions inside a function that is called with
* `Array.prototype.map` or a similar Array function that binds `this`.
*
* However, since the function could be invoked in another way, we additionally
* still infer the ordinary abstract value.
* Models `Array.prototype.map` and friends as partial invocations that pass their second
* argument as the receiver to the callback.
*/
private class AnalyzedThisInArrayIterationFunction extends AnalyzedNode, DataFlow::ThisNode {
AnalyzedNode thisSource;
AnalyzedThisInArrayIterationFunction() {
exists(DataFlow::MethodCallNode bindingCall, string name |
private class ArrayIterationCallbackAsPartialInvoke extends DataFlow::PartialInvokeNode::Range, DataFlow::MethodCallNode {
ArrayIterationCallbackAsPartialInvoke() {
getNumArgument() = 2 and
// Filter out library methods named 'forEach' etc
not DataFlow::moduleImport(_).flowsTo(getReceiver()) and
exists(string name | name = getMethodName() |
name = "filter" or
name = "forEach" or
name = "map" or
name = "some" or
name = "every"
|
name = bindingCall.getMethodName() and
2 = bindingCall.getNumArgument() and
getBinder() = bindingCall.getCallback(0) and
thisSource = bindingCall.getArgument(1)
)
}
override AbstractValue getALocalValue() {
result = thisSource.getALocalValue() or
result = AnalyzedNode.super.getALocalValue()
override DataFlow::Node getBoundReceiver(DataFlow::Node callback) {
callback = getArgument(0) and
result = getArgument(1)
}
}

View File

@@ -274,3 +274,24 @@ private class TypeInferredMethodWithAnalyzedReturnFlow extends CallWithNonLocalA
override AnalyzedFunction getACallee() { result = fun }
}
/**
* Propagates receivers into locally defined callbacks of partial invocations.
*/
private class AnalyzedThisInPartialInvokeCallback extends AnalyzedNode, DataFlow::ThisNode {
DataFlow::PartialInvokeNode call;
DataFlow::Node receiver;
AnalyzedThisInPartialInvokeCallback() {
exists(DataFlow::Node callbackArg |
receiver = call.getBoundReceiver(callbackArg) and
getBinder().flowsTo(callbackArg)
)
}
override AbstractValue getALocalValue() {
result = receiver.analyze().getALocalValue()
or
result = AnalyzedNode.super.getALocalValue()
}
}