Skip to content

Commit b058854

Browse files
author
Max Schaefer
committed
JavaScript: Teach type inference about AMD imports.
1 parent e77ea62 commit b058854

File tree

5 files changed

+51
-0
lines changed

5 files changed

+51
-0
lines changed

javascript/ql/src/semmle/javascript/dataflow/internal/InterModuleTypeInference.qll

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,42 @@ private class AnalyzedAmdExport extends AnalyzedPropertyWrite, DataFlow::ValueNo
232232
}
233233
}
234234

235+
/**
236+
* Flow analysis for AMD imports, interpreted as an implicit read of
237+
* the `module.exports` property of the imported module.
238+
*/
239+
private class AnalyzedAmdImport extends AnalyzedPropertyRead, DataFlow::Node {
240+
Module required;
241+
242+
AnalyzedAmdImport() {
243+
exists (AMDModule amd, PathExpr dep, Parameter p |
244+
amd.getDefine().dependencyParameter(dep, p) and
245+
this = DataFlow::parameterNode(p) and
246+
required.getFile() = amd.resolve(dep)
247+
)
248+
}
249+
250+
override predicate reads(AbstractValue base, string propName) {
251+
base = TAbstractModuleObject(required) and
252+
propName = "exports"
253+
}
254+
}
255+
256+
/**
257+
* Flow analysis for parameters corresponding to AMD imports.
258+
*/
259+
private class AnalyzedAmdParameter extends AnalyzedVarDef, @vardecl {
260+
AnalyzedAmdImport imp;
261+
262+
AnalyzedAmdParameter() {
263+
imp = DataFlow::parameterNode(this)
264+
}
265+
266+
override AbstractValue getAnRhsValue() {
267+
result = imp.getALocalValue()
268+
}
269+
}
270+
235271
/**
236272
* Flow analysis for exports that export a single value.
237273
*/

javascript/ql/test/library-tests/Flow/AbstractValues.expected

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515
| amd2.js:1:8:3:1 | anonymous function |
1616
| amd2.js:1:8:3:1 | instance of anonymous function |
1717
| amd2.js:2:10:2:22 | object literal |
18+
| amd3.js:1:1:5:0 | exports object of module amd3 |
19+
| amd3.js:1:1:5:0 | module object of module amd3 |
20+
| amd3.js:1:24:4:1 | anonymous function |
21+
| amd3.js:1:24:4:1 | instance of anonymous function |
1822
| amd.js:1:1:7:0 | exports object of module amd |
1923
| amd.js:1:1:7:0 | module object of module amd |
2024
| amd.js:1:31:6:1 | anonymous function |

javascript/ql/test/library-tests/Flow/abseval.expected

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@
77
| a.js:9:5:9:5 | z | a.js:9:9:9:18 | someGlobal | file://:0:0:0:0 | non-zero value |
88
| a.js:9:5:9:5 | z | a.js:9:9:9:18 | someGlobal | file://:0:0:0:0 | true |
99
| a.js:14:12:14:24 | notAlwaysZero | a.js:14:28:14:28 | 0 | file://:0:0:0:0 | 0 |
10+
| amd3.js:2:7:2:8 | _a | amd3.js:2:12:2:12 | a | a.js:1:1:18:0 | exports object of module a |
11+
| amd3.js:2:7:2:8 | _a | amd3.js:2:12:2:12 | a | file://:0:0:0:0 | indefinite value (call) |
12+
| amd3.js:3:7:3:8 | _c | amd3.js:3:12:3:12 | c | c.js:1:1:7:0 | exports object of module c |
13+
| amd3.js:3:7:3:8 | _c | amd3.js:3:12:3:12 | c | c.js:1:18:1:19 | object literal |
14+
| amd3.js:3:7:3:8 | _c | amd3.js:3:12:3:12 | c | file://:0:0:0:0 | indefinite value (call) |
1015
| amd.js:2:7:2:7 | m | amd.js:2:11:2:13 | mod | amd.js:1:1:7:0 | module object of module amd |
1116
| amd.js:2:7:2:7 | m | amd.js:2:11:2:13 | mod | file://:0:0:0:0 | indefinite value (call) |
1217
| amd.js:3:7:3:7 | e | amd.js:3:11:3:13 | exp | amd.js:1:1:7:0 | exports object of module amd |
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
define(['./a', './c'], function(a, c) {
2+
var _a = a;
3+
var _c = c;
4+
});

javascript/ql/test/library-tests/Flow/types.expected

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
| a.js:1:19:1:19 | y | a.js:1:23:1:23 | 0 | number |
44
| a.js:9:5:9:5 | z | a.js:9:9:9:18 | someGlobal | boolean, class, date, function, null, number, object, regular expression,string or undefined |
55
| a.js:14:12:14:24 | notAlwaysZero | a.js:14:28:14:28 | 0 | number |
6+
| amd3.js:2:7:2:8 | _a | amd3.js:2:12:2:12 | a | boolean, class, date, function, null, number, object, regular expression,string or undefined |
7+
| amd3.js:3:7:3:8 | _c | amd3.js:3:12:3:12 | c | boolean, class, date, function, null, number, object, regular expression,string or undefined |
68
| amd.js:2:7:2:7 | m | amd.js:2:11:2:13 | mod | boolean, class, date, function, null, number, object, regular expression,string or undefined |
79
| amd.js:3:7:3:7 | e | amd.js:3:11:3:13 | exp | boolean, class, date, function, null, number, object, regular expression,string or undefined |
810
| arguments.js:2:7:2:7 | y | arguments.js:2:11:2:11 | x | number |

0 commit comments

Comments
 (0)