Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit df97132

Browse files
author
Esben Sparre Andreasen
committed
JS: add model for property projection
1 parent 61bd003 commit df97132

5 files changed

Lines changed: 174 additions & 0 deletions

File tree

javascript/ql/src/javascript.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ import semmle.javascript.frameworks.Logging
6363
import semmle.javascript.frameworks.HttpFrameworks
6464
import semmle.javascript.frameworks.NoSQL
6565
import semmle.javascript.frameworks.PkgCloud
66+
import semmle.javascript.frameworks.PropertyProjection
6667
import semmle.javascript.frameworks.React
6768
import semmle.javascript.frameworks.ReactNative
6869
import semmle.javascript.frameworks.Request
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
/**
2+
* Provides classes for modelling property projection functions.
3+
*
4+
* Subclass `PropertyProjection` to refine the behavior of the analysis on existing property projections.
5+
* Subclass `CustomPropertyProjection` to introduce new kinds of property projections.
6+
*/
7+
8+
import javascript
9+
10+
/**
11+
* A property projection call such as `_.get(o, 'a.b')`, which is equivalent to `o.a.b`.
12+
*/
13+
abstract class CustomPropertyProjection extends DataFlow::CallNode {
14+
15+
/**
16+
* Gets the argument for the object to project properties from, such as `o` in `_.get(o, 'a.b')`.
17+
*/
18+
abstract DataFlow::Node getObject();
19+
20+
/**
21+
* Gets an argument that selects the properties to project, such as `'a.b'` in `_.get(o, 'a.b')`.
22+
*/
23+
abstract DataFlow::Node getASelector();
24+
25+
/**
26+
* Holds if this call returns the value of a single projected property, as opposed to an object that can contain multiple projected properties.
27+
*/
28+
abstract predicate isSingletonProjection();
29+
30+
}
31+
32+
/**
33+
* A property projection call such as `_.get(o, 'a.b')`, which is equivalent to `o.a.b`.
34+
*/
35+
class PropertyProjection extends DataFlow::CallNode {
36+
37+
CustomPropertyProjection custom;
38+
39+
PropertyProjection() { this = custom }
40+
41+
/**
42+
* Gets the argument for the object to project properties from, such as `o` in `_.get(o, 'a.b')`.
43+
*/
44+
DataFlow::Node getObject() { result = custom.getObject() }
45+
46+
/**
47+
* Gets an argument that selects the properties to project, such as `'a.b'` in `_.get(o, 'a.b')`.
48+
*/
49+
DataFlow::Node getASelector() { result = custom.getASelector() }
50+
51+
/**
52+
* Holds if this call returns the value of a single projected property, as opposed to an object that can contain multiple projected properties.
53+
*
54+
* Examples:
55+
* - This predicate holds for `_.get({a: 'b'}, 'a')`, which returns `'b'`,
56+
* - This predicate does not hold for `_.pick({a: 'b', c: 'd'}}, 'a')`, which returns `{a: 'b'}`,
57+
*/
58+
predicate isSingletonProjection() { custom.isSingletonProjection() }
59+
60+
}
61+
62+
/**
63+
* A simple model of common property projection functions.
64+
*/
65+
private class SimplePropertyProjection extends CustomPropertyProjection {
66+
67+
int objectIndex;
68+
int selectorIndex;
69+
boolean singleton;
70+
71+
SimplePropertyProjection() {
72+
exists (DataFlow::SourceNode callee |
73+
this = callee.getACall() |
74+
singleton = false and (
75+
(
76+
callee = LodashUnderscore::member("pick") and
77+
objectIndex = 0 and
78+
selectorIndex = [1..getNumArgument()]
79+
)
80+
or
81+
(
82+
callee = LodashUnderscore::member("pickBy") and
83+
objectIndex = 0 and
84+
selectorIndex = 1
85+
)
86+
or
87+
exists (string name |
88+
name = "pick" or
89+
name = "pickAll" or
90+
name = "pickBy" |
91+
callee = DataFlow::moduleMember("ramda", name) and
92+
objectIndex = 1 and
93+
selectorIndex = 0
94+
)
95+
or
96+
(
97+
callee = DataFlow::moduleMember("dotty", "search") and
98+
objectIndex = 0 and
99+
selectorIndex = 1
100+
)
101+
)
102+
or
103+
singleton = true and (
104+
(
105+
callee = LodashUnderscore::member("get") and
106+
objectIndex = 0 and
107+
selectorIndex = 1
108+
)
109+
or
110+
(
111+
callee = DataFlow::moduleMember("ramda", "path") and
112+
objectIndex = 1 and
113+
selectorIndex = 0
114+
)
115+
or
116+
(
117+
callee = DataFlow::moduleMember("dottie", "get") and
118+
objectIndex = 0 and
119+
selectorIndex = 1
120+
)
121+
or
122+
(
123+
callee = DataFlow::moduleMember("dotty", "get") and
124+
objectIndex = 0 and
125+
selectorIndex = 1
126+
)
127+
)
128+
)
129+
}
130+
131+
override DataFlow::Node getObject() { result = getArgument(objectIndex) }
132+
133+
override DataFlow::Node getASelector() { result = getArgument(selectorIndex) }
134+
135+
override predicate isSingletonProjection() { singleton = true }
136+
137+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
| tst.js:6:1:6:17 | _.pick(o, s1, s2) | tst.js:6:8:6:8 | o | tst.js:6:11:6:12 | s1 | false |
2+
| tst.js:6:1:6:17 | _.pick(o, s1, s2) | tst.js:6:8:6:8 | o | tst.js:6:15:6:16 | s2 | false |
3+
| tst.js:7:1:7:14 | _.pickBy(o, s) | tst.js:7:10:7:10 | o | tst.js:7:13:7:13 | s | false |
4+
| tst.js:9:1:9:12 | R.pick(s, o) | tst.js:9:11:9:11 | o | tst.js:9:8:9:8 | s | false |
5+
| tst.js:10:1:10:14 | R.pickBy(s, o) | tst.js:10:13:10:13 | o | tst.js:10:10:10:10 | s | false |
6+
| tst.js:11:1:11:15 | R.pickAll(s, o) | tst.js:11:14:11:14 | o | tst.js:11:11:11:11 | s | false |
7+
| tst.js:13:1:13:11 | _.get(o, s) | tst.js:13:7:13:7 | o | tst.js:13:10:13:10 | s | true |
8+
| tst.js:15:1:15:12 | R.path(s, o) | tst.js:15:11:15:11 | o | tst.js:15:8:15:8 | s | true |
9+
| tst.js:17:1:17:16 | dottie.get(o, s) | tst.js:17:12:17:12 | o | tst.js:17:15:17:15 | s | true |
10+
| tst.js:19:1:19:15 | dotty.get(o, s) | tst.js:19:11:19:11 | o | tst.js:19:14:19:14 | s | true |
11+
| tst.js:20:1:20:18 | dotty.search(o, s) | tst.js:20:14:20:14 | o | tst.js:20:17:20:17 | s | false |
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import javascript
2+
3+
from PropertyProjection p, boolean singleton
4+
where if p.isSingletonProjection() then singleton = true else singleton = false
5+
select p, p.getObject(), p.getASelector(), singleton
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
var _ = require("lodash"),
2+
dotty = require("dotty"),
3+
dottie = require("dottie"),
4+
R = require("ramda");
5+
6+
_.pick(o, s1, s2);
7+
_.pickBy(o, s);
8+
9+
R.pick(s, o);
10+
R.pickBy(s, o);
11+
R.pickAll(s, o);
12+
13+
_.get(o, s);
14+
15+
R.path(s, o);
16+
17+
dottie.get(o, s);
18+
19+
dotty.get(o, s);
20+
dotty.search(o, s);

0 commit comments

Comments
 (0)