Skip to content

Commit de44583

Browse files
authored
Merge pull request #7344 from SZFsir/main
JS: Improve inter-procedural type inference for FunctionExpr
2 parents dc27089 + efc9e67 commit de44583

File tree

6 files changed

+51
-5
lines changed

6 files changed

+51
-5
lines changed

javascript/ql/lib/semmle/javascript/dataflow/internal/InterProceduralTypeInference.qll

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,14 @@ private VarAccess getOnlyAccess(FunctionDeclStmt fn, LocalVariable v) {
190190
result = unique(VarAccess acc | acc = v.getAnAccess())
191191
}
192192

193+
private VarAccess getOnlyAccessToFunctionExpr(FunctionExpr fn, LocalVariable v) {
194+
exists(VariableDeclarator decl |
195+
fn = decl.getInit() and
196+
v = decl.getBindingPattern().getVariable() and
197+
result = unique(VarAccess acc | acc = v.getAnAccess())
198+
)
199+
}
200+
193201
/** A function that only is used locally, making it amenable to type inference. */
194202
class LocalFunction extends Function {
195203
DataFlow::Impl::ExplicitInvokeNode invk;
@@ -199,6 +207,9 @@ class LocalFunction extends Function {
199207
getOnlyAccess(this, v) = invk.getCalleeNode().asExpr() and
200208
not exists(v.getAnAssignedExpr()) and
201209
not exists(ExportDeclaration export | export.exportsAs(v, _))
210+
or
211+
getOnlyAccessToFunctionExpr(this, v) = invk.getCalleeNode().asExpr() and
212+
not exists(ExportDeclaration export | export.exportsAs(v, _))
202213
) and
203214
// if the function is non-strict and its `arguments` object is accessed, we
204215
// also assume that there may be other calls (through `arguments.callee`)

javascript/ql/test/library-tests/TypeInference/CallWithAnalyzedReturnFlow/CalleeNodeValue.expected

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@
5858
| tst.js:80:5:80:7 | f20 | file://:0:0:0:0 | undefined |
5959
| tst.js:80:5:80:7 | f20 | tst.js:79:24:79:25 | object literal |
6060
| tst.js:84:17:84:20 | getF | tst.js:83:20:83:31 | function getF |
61-
| tst.js:86:13:86:13 | f | file://:0:0:0:0 | indefinite value (call) |
6261
| tst.js:86:13:86:13 | f | file://:0:0:0:0 | undefined |
6362
| tst.js:89:17:89:20 | getG | tst.js:88:9:88:25 | function getG |
6463
| tst.js:91:13:91:13 | g | file://:0:0:0:0 | undefined |
Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
| LocalFunction.js:4:5:4:19 | function f1(){} | LocalFunction.js:5:5:5:8 | f1() |
22
| LocalFunction.js:11:5:11:19 | function f3(){} | LocalFunction.js:13:5:13:8 | f3() |
33
| LocalFunction.js:12:5:12:19 | function f3(){} | LocalFunction.js:13:5:13:8 | f3() |
4-
| LocalFunction.js:27:5:29:5 | functio ... ;\\n } | LocalFunction.js:33:17:33:24 | f_zero() |
5-
| LocalFunction.js:30:5:32:5 | functio ... ;\\n } | LocalFunction.js:33:5:33:12 | f_null() |
6-
| LocalFunction.js:35:5:37:5 | functio ... ;\\n } | LocalFunction.js:41:5:41:12 | f_id1(0) |
7-
| LocalFunction.js:38:5:40:5 | functio ... ;\\n } | LocalFunction.js:41:17:41:27 | f_id2(null) |
4+
| LocalFunction.js:15:14:15:25 | function(){} | LocalFunction.js:16:5:16:8 | f4() |
5+
| LocalFunction.js:31:5:33:5 | functio ... ;\\n } | LocalFunction.js:37:17:37:24 | f_zero() |
6+
| LocalFunction.js:34:5:36:5 | functio ... ;\\n } | LocalFunction.js:37:5:37:12 | f_null() |
7+
| LocalFunction.js:39:5:41:5 | functio ... ;\\n } | LocalFunction.js:45:5:45:12 | f_id1(0) |
8+
| LocalFunction.js:42:5:44:5 | functio ... ;\\n } | LocalFunction.js:45:17:45:27 | f_id2(null) |
89
| LocalFunction_arguments.js:17:5:20:5 | functio ... e\\n } | LocalFunction_arguments.js:21:5:21:7 | i() |
10+
| LocalFunction_arguments.js:40:14:43:5 | functio ... e\\n } | LocalFunction_arguments.js:44:5:44:8 | i1() |

javascript/ql/test/library-tests/TypeInference/LocalFunction/LocalFunction.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@
2222
function f6(){}
2323
g(f6);
2424
f6();
25+
26+
var f7 = function(){}
27+
f7();
28+
f7();
2529
})();
2630
(function types(){
2731
function f_zero() {
@@ -48,3 +52,9 @@ export default function bar() {
4852

4953
}
5054
bar();
55+
56+
var foo1 = function foo1(){
57+
58+
}
59+
foo1();
60+
export {foo1};

javascript/ql/test/library-tests/TypeInference/LocalFunction/LocalFunction_arguments.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,26 @@
2020
}
2121
i();
2222
})();
23+
24+
(function(){
25+
var f1 = function f1() {
26+
arguments.callee()
27+
}
28+
f1();
29+
var g1 = function g1() {
30+
var args = arguments;
31+
var callee = args.callee;
32+
callee();
33+
}
34+
g1();
35+
var h1 = function h1() {
36+
var args = arguments;
37+
args.callee;
38+
}
39+
h1();
40+
var i1 = function i1() {
41+
"use strict";
42+
arguments.callee(); // does not work in strict mode
43+
}
44+
i1();
45+
})();

javascript/ql/test/query-tests/Expressions/SuspiciousInvocation/SuspiciousInvocation.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
| optional-chaining.js:3:5:3:7 | a() | Callee is not a function: it has type null. |
44
| optional-chaining.js:7:5:7:7 | b() | Callee is not a function: it has type undefined. |
55
| super.js:11:5:11:11 | super() | Callee is not a function: it has type number. |
6+
| unreachable-code.js:5:9:5:11 | f() | Callee is not a function: it has type undefined. |

0 commit comments

Comments
 (0)