JS: Tests and fixes for PartialInvokeNode

This commit is contained in:
Asger F
2019-10-18 17:04:22 +01:00
parent 3dcb134e6b
commit 96b6c83eba
5 changed files with 72 additions and 2 deletions

View File

@@ -1054,7 +1054,13 @@ module PartialInvokeNode {
* A partial call through the built-in `Function.prototype.bind`.
*/
private class BindPartialCall extends PartialInvokeNode::Range, DataFlow::MethodCallNode {
BindPartialCall() { getMethodName() = "bind" }
BindPartialCall() {
getMethodName() = "bind" and
// Avoid overlap with angular.bind and goog.bind
not this = AngularJS::angular().getAMethodCall() and
not getReceiver().accessesGlobal("goog")
}
override predicate isPartialArgument(DataFlow::Node callback, DataFlow::Node argument, int index) {
index >= 0 and
@@ -1086,7 +1092,7 @@ module PartialInvokeNode {
}
override DataFlow::SourceNode getBoundFunction(DataFlow::Node callback, int boundArgs) {
callback = getReceiver() and
callback = getArgument(0) and
boundArgs = getNumArgument() - 1 and
result = this
}

View File

@@ -0,0 +1,5 @@
goog.module('test');
function test(x) {
addEventListener("click", goog.bind(function(x, event) {}, this, x));
}

View File

@@ -0,0 +1,26 @@
getBoundFunction
| closure.js:4:29:4:69 | goog.bi ... his, x) | closure.js:4:39:4:59 | functio ... ent) {} | 1 | closure.js:4:29:4:69 | goog.bi ... his, x) |
| tst.js:5:29:5:63 | functio ... his, x) | tst.js:5:29:5:49 | functio ... ent) {} | 1 | tst.js:5:29:5:63 | functio ... his, x) |
| tst.js:6:29:6:68 | lodash. ... {}, x) | tst.js:6:44:6:64 | functio ... ent) {} | 1 | tst.js:6:29:6:68 | lodash. ... {}, x) |
| tst.js:7:29:7:65 | R.parti ... }, [x]) | tst.js:7:39:7:59 | functio ... ent) {} | 1 | tst.js:7:29:7:65 | R.parti ... }, [x]) |
| tst.js:8:29:8:72 | angular ... {}, x) | tst.js:8:48:8:68 | functio ... ent) {} | 1 | tst.js:8:29:8:72 | angular ... {}, x) |
| tst.js:11:29:11:43 | f.bind(this, x) | tst.js:11:29:11:29 | f | 1 | tst.js:11:29:11:43 | f.bind(this, x) |
isPartialArgument
| closure.js:4:29:4:69 | goog.bi ... his, x) | closure.js:4:39:4:59 | functio ... ent) {} | closure.js:4:68:4:68 | x | 0 |
| tst.js:5:29:5:63 | functio ... his, x) | tst.js:5:29:5:49 | functio ... ent) {} | tst.js:5:62:5:62 | x | 0 |
| tst.js:6:29:6:68 | lodash. ... {}, x) | tst.js:6:44:6:64 | functio ... ent) {} | tst.js:6:67:6:67 | x | 0 |
| tst.js:7:29:7:65 | R.parti ... }, [x]) | tst.js:7:39:7:59 | functio ... ent) {} | tst.js:7:63:7:63 | x | 0 |
| tst.js:8:29:8:72 | angular ... {}, x) | tst.js:8:48:8:68 | functio ... ent) {} | tst.js:8:71:8:71 | x | 0 |
| tst.js:11:29:11:43 | f.bind(this, x) | tst.js:11:29:11:29 | f | tst.js:11:42:11:42 | x | 0 |
getBoundReceiver
| closure.js:4:29:4:69 | goog.bi ... his, x) | closure.js:4:62:4:65 | this |
| tst.js:5:29:5:63 | functio ... his, x) | tst.js:5:56:5:59 | this |
| tst.js:8:29:8:72 | angular ... {}, x) | tst.js:8:42:8:45 | this |
| tst.js:11:29:11:43 | f.bind(this, x) | tst.js:11:36:11:39 | this |
clickEvent
| closure.js:4:51:4:55 | event |
| tst.js:5:41:5:45 | event |
| tst.js:6:56:6:60 | event |
| tst.js:7:51:7:55 | event |
| tst.js:8:60:8:64 | event |
| tst.js:10:17:10:21 | event |

View File

@@ -0,0 +1,21 @@
import javascript
query
DataFlow::Node getBoundFunction(DataFlow::PartialInvokeNode invoke, DataFlow::Node callback, int boundArgs) {
result = invoke.getBoundFunction(callback, boundArgs)
}
query
predicate isPartialArgument(DataFlow::PartialInvokeNode invoke, DataFlow::Node callback, DataFlow::Node argument, int index) {
invoke.isPartialArgument(callback, argument, index)
}
query
DataFlow::Node getBoundReceiver(DataFlow::PartialInvokeNode invoke) {
result = invoke.getBoundReceiver()
}
query
DataFlow::Node clickEvent() {
result = DataFlow::globalVarRef("addEventListener").getACall().getABoundCallbackParameter(1, 0)
}

View File

@@ -0,0 +1,12 @@
let lodash = require('lodash');
let R = require('ramda');
function test(x) {
addEventListener("click", function(x, event) {}.bind(this, x));
addEventListener("click", lodash.partial(function(x, event) {}, x));
addEventListener("click", R.partial(function(x, event) {}, [x]));
addEventListener("click", angular.bind(this, function(x, event) {}, x));
function f(x, event) {}
addEventListener("click", f.bind(this, x));
}