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

View File

@@ -274,3 +274,24 @@ private class TypeInferredMethodWithAnalyzedReturnFlow extends CallWithNonLocalA
override AnalyzedFunction getACallee() { result = fun } 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()
}
}