mirror of
https://github.com/github/codeql.git
synced 2026-04-30 11:15:13 +02:00
JS: add type inference for the return value of captured method calls
This commit is contained in:
@@ -7,6 +7,8 @@
|
||||
import javascript
|
||||
import AbstractValuesImpl
|
||||
|
||||
import semmle.javascript.dataflow.CapturedNodes
|
||||
|
||||
/**
|
||||
* Flow analysis for `this` expressions inside functions.
|
||||
*/
|
||||
@@ -230,3 +232,47 @@ private class TypeInferredCalleeWithAnalyzedReturnFlow extends CallWithNonLocalA
|
||||
|
||||
override AnalyzedFunction getACallee() { result = fun }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `call` uses `receiver` as its only receiver value.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate hasDefiniteReceiver(
|
||||
DataFlow::MethodCallNode call, CapturedSource receiver
|
||||
) {
|
||||
call = receiver.getAMethodCall() and
|
||||
exists (DataFlow::AnalyzedNode receiverNode, AbstractValue abstractCapturedReceiver |
|
||||
receiverNode = call.getReceiver() and
|
||||
not receiverNode.getALocalValue().isIndefinite(_) and
|
||||
abstractCapturedReceiver = receiver.analyze().getALocalValue() and
|
||||
forall(DataFlow::AbstractValue v |
|
||||
receiverNode.getALocalValue() = v |
|
||||
v = abstractCapturedReceiver
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables inter-procedural type inference for the return value of a
|
||||
* method call to a flow-insensitively type-inferred callee.
|
||||
*/
|
||||
class TypeInferredMethodWithAnalyzedReturnFlow extends CallWithNonLocalAnalyzedReturnFlow {
|
||||
DataFlow::FunctionNode fun;
|
||||
|
||||
TypeInferredMethodWithAnalyzedReturnFlow() {
|
||||
exists(CapturedSource s, DataFlow::PropWrite w, string name |
|
||||
this.(DataFlow::MethodCallNode).getMethodName() = name and
|
||||
s.hasOwnProperty(name) and
|
||||
hasDefiniteReceiver(this, s) and
|
||||
w = s.getAPropertyWrite() and
|
||||
fun.flowsTo(w.getRhs()) and
|
||||
(
|
||||
not exists(w.getPropertyName())
|
||||
or
|
||||
w.getPropertyName() = name
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override AnalyzedFunction getACallee() { result = fun }
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
| method-calls.js:8:2:8:8 | o1.m1() | boolean, class, date, function, null, number, object, regular expression,string or undefined |
|
||||
| method-calls.js:9:2:9:8 | o1.m2() | boolean, class, date, function, null, number, object, regular expression,string or undefined |
|
||||
| method-calls.js:8:2:8:8 | o1.m1() | object |
|
||||
| method-calls.js:9:2:9:8 | o1.m2() | object |
|
||||
| method-calls.js:12:2:12:7 | o.m3() | boolean, class, date, function, null, number, object, regular expression,string or undefined |
|
||||
| method-calls.js:19:2:19:7 | o2.m() | boolean, class, date, function, null, number, object, regular expression,string or undefined |
|
||||
| method-calls.js:23:11:23:21 | {m: f1}.m() | boolean, class, date, function, null, number, object, regular expression,string or undefined |
|
||||
| method-calls.js:28:11:28:16 | o2.m() | boolean, class, date, function, null, number, object, regular expression,string or undefined |
|
||||
| method-calls.js:32:11:32:23 | ({m: f3}).m() | boolean, class, date, function, null, number, object, regular expression,string or undefined |
|
||||
| method-calls.js:23:11:23:21 | {m: f1}.m() | object |
|
||||
| method-calls.js:28:11:28:16 | o2.m() | object |
|
||||
| method-calls.js:32:11:32:23 | ({m: f3}).m() | object |
|
||||
| method-calls.js:37:11:37:16 | o4.m() | boolean, class, date, function, null, number, object, regular expression,string or undefined |
|
||||
| method-calls.js:43:12:43:16 | o.m() | boolean, class, date, function, null, number, object, regular expression,string or undefined |
|
||||
| method-calls.js:47:12:47:16 | o.m() | boolean, class, date, function, null, number, object, regular expression,string or undefined |
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
| method-calls.js:23:11:23:21 | {m: f1}.m() | method-calls.js:24:2:24:3 | v1 | file://:0:0:0:0 | indefinite value (call) |
|
||||
| method-calls.js:28:11:28:16 | o2.m() | method-calls.js:29:2:29:3 | v2 | file://:0:0:0:0 | indefinite value (call) |
|
||||
| method-calls.js:32:11:32:23 | ({m: f3}).m() | method-calls.js:33:2:33:3 | v3 | file://:0:0:0:0 | indefinite value (call) |
|
||||
| method-calls.js:23:11:23:21 | {m: f1}.m() | method-calls.js:24:2:24:3 | v1 | method-calls.js:22:23:22:24 | object literal |
|
||||
| method-calls.js:28:11:28:16 | o2.m() | method-calls.js:29:2:29:3 | v2 | method-calls.js:26:23:26:24 | object literal |
|
||||
| method-calls.js:32:11:32:23 | ({m: f3}).m() | method-calls.js:33:2:33:3 | v3 | method-calls.js:31:23:31:24 | object literal |
|
||||
| method-calls.js:37:11:37:16 | o4.m() | method-calls.js:38:2:38:3 | v4 | file://:0:0:0:0 | indefinite value (call) |
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
| tst.js:11:5:11:8 | f1() | file://:0:0:0:0 | undefined |
|
||||
| tst.js:14:5:14:8 | f2() | file://:0:0:0:0 | undefined |
|
||||
| tst.js:15:5:15:8 | f2() | file://:0:0:0:0 | undefined |
|
||||
| tst.js:18:5:18:11 | o1.f3() | file://:0:0:0:0 | undefined |
|
||||
| tst.js:23:5:23:8 | f4() | tst.js:21:16:21:30 | function f5 |
|
||||
| tst.js:23:5:23:10 | f4()() | file://:0:0:0:0 | undefined |
|
||||
| tst.js:30:5:30:8 | f6() | tst.js:26:16:28:9 | function f7 |
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
| tst.js:11:5:11:8 | f1() | file://:0:0:0:0 | undefined |
|
||||
| tst.js:14:5:14:8 | f2() | file://:0:0:0:0 | undefined |
|
||||
| tst.js:15:5:15:8 | f2() | file://:0:0:0:0 | undefined |
|
||||
| tst.js:18:5:18:11 | o1.f3() | file://:0:0:0:0 | indefinite value (call) |
|
||||
| tst.js:18:5:18:11 | o1.f3() | file://:0:0:0:0 | undefined |
|
||||
| tst.js:23:5:23:8 | f4() | tst.js:21:16:21:30 | function f5 |
|
||||
| tst.js:23:5:23:10 | f4()() | file://:0:0:0:0 | undefined |
|
||||
| tst.js:30:5:30:8 | f6() | tst.js:26:16:28:9 | function f7 |
|
||||
|
||||
Reference in New Issue
Block a user