Skip to content

Commit c0de6a3

Browse files
committed
add support for Immutable Record
1 parent 609b16b commit c0de6a3

File tree

3 files changed

+23
-3
lines changed

3 files changed

+23
-3
lines changed

javascript/ql/src/semmle/javascript/frameworks/Immutable.qll

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,15 @@ private module Immutable {
3232

3333
/**
3434
* An instance of any immutable collection.
35+
*
36+
* This predicate keeps track of which values in the program are Immutable collections.
3537
*/
3638
API::Node immutableCollection() {
37-
// keep this list in sync with the constructors defined in `storeStep`.
39+
// keep this predicate in sync with the constructors defined in `storeStep`.
3840
result = immutableImport().getMember(["Map", "OrderedMap", "List", "fromJS"]).getReturn()
3941
or
42+
result = immutableImport().getMember("Record").getReturn().getReturn()
43+
or
4044
result = immutableCollection().getMember(["set", "map", "filter", "push"]).getReturn()
4145
}
4246

@@ -77,6 +81,15 @@ private module Immutable {
7781
result = call and
7882
prop = DataFlow::PseudoProperties::arrayElement()
7983
)
84+
or
85+
// Immutable.Record({defaults})({values}).
86+
exists(API::CallNode factoryCall, API::CallNode recordCall |
87+
factoryCall = immutableImport().getMember("Record").getACall() and
88+
recordCall = factoryCall.getReturn().getACall()
89+
|
90+
pred = [factoryCall, recordCall].getOptionArgument(0, prop) and
91+
result = recordCall
92+
)
8093
}
8194

8295
/**

javascript/ql/test/library-tests/frameworks/Immutable/immutable.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
var obj = { a: source("a"), b: source("b1") };
22
sink(obj["a"]); // NOT OK
33

4-
const { Map, fromJS, List, OrderedMap } = require('immutable');
4+
const { Map, fromJS, List, OrderedMap, Record } = require('immutable');
55

66
const map1 = Map(obj);
77

@@ -34,4 +34,9 @@ List(["safe"]).push(source()).forEach(x => sink(x)); // NOT OK
3434

3535

3636
const map4 = OrderedMap({}).set("f", source());
37-
sink(map4.get("f")); // NOT OK
37+
sink(map4.get("f")); // NOT OK
38+
39+
const map5 = Record({a: source(), b: null, c: null})({b: source()});
40+
sink(map5.get("a")); // NOT OK
41+
sink(map5.get("b")); // NOT OK
42+
sink(map5.get("c")); // OK

javascript/ql/test/library-tests/frameworks/Immutable/tests.expected

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,5 @@
1111
| immutable.js:31:7:31:14 | source() | immutable.js:31:75:31:75 | x |
1212
| immutable.js:33:21:33:28 | source() | immutable.js:33:49:33:49 | x |
1313
| immutable.js:36:38:36:45 | source() | immutable.js:37:6:37:18 | map4.get("f") |
14+
| immutable.js:39:25:39:32 | source() | immutable.js:40:6:40:18 | map5.get("a") |
15+
| immutable.js:39:58:39:65 | source() | immutable.js:41:6:41:18 | map5.get("b") |

0 commit comments

Comments
 (0)