Skip to content

Commit b373901

Browse files
committed
JS: Avoid leading dot in access paths
1 parent c365833 commit b373901

1 file changed

Lines changed: 21 additions & 13 deletions

File tree

javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,18 @@ module AccessPath {
6868
DataFlow::Node getValue() { result = getSsaDefinition().getRhsNode() }
6969
}
7070

71+
/**
72+
* Appends a single property name onto the access path `base`, where
73+
* the empty string represents the empty access path.
74+
*/
75+
bindingset[base, prop]
76+
private string join(string base, string prop) {
77+
base = "" and result = prop
78+
or
79+
base != "" and
80+
result = base + "." + prop
81+
}
82+
7183
/**
7284
* Gets the access path relative to `root` referred to by `node`.
7385
*
@@ -77,8 +89,8 @@ module AccessPath {
7789
* Examples:
7890
* ```
7991
* function f(x) {
80-
* let a = x.f.g; // access path relative to 'x' is '.f.g'
81-
* let b = a.h; // access path relative to 'x' is '.f.g.h'
92+
* let a = x.f.g; // access path relative to 'x' is 'f.g'
93+
* let b = a.h; // access path relative to 'x' is 'f.g.h'
8294
* }
8395
* ```
8496
*/
@@ -102,7 +114,7 @@ module AccessPath {
102114
or
103115
not node.accessesGlobal(_) and
104116
exists(DataFlow::PropRead prop | node = prop |
105-
result = fromReference(prop.getBase(), root) + "." + prop.getPropertyName()
117+
result = join(fromReference(prop.getBase(), root), prop.getPropertyName())
106118
)
107119
or
108120
exists(Closure::ClosureNamespaceAccess acc | node = acc |
@@ -112,7 +124,7 @@ module AccessPath {
112124
or
113125
exists(PropertyProjection proj | node = proj |
114126
proj.isSingletonProjection() and
115-
result = fromReference(proj.getObject(), root) + "." + proj.getASelector()
127+
result = join(fromReference(proj.getObject(), root), proj.getASelector().getStringValue())
116128
)
117129
or
118130
// Treat 'e || {}' as having the same name as 'e'
@@ -179,7 +191,7 @@ module AccessPath {
179191
* Only holds for the immediate right-hand side of an assignment or property, not
180192
* for nodes that transitively flow there.
181193
*
182-
* For example, the class nodes below all map to `.foo.bar` relative to `x`:
194+
* For example, the class nodes below all map to `foo.bar` relative to `x`:
183195
* ```
184196
* function f(x) {
185197
* x.foo.bar = class {};
@@ -193,7 +205,7 @@ module AccessPath {
193205
private string fromRhs(DataFlow::Node node, Root root) {
194206
exists(DataFlow::PropWrite write, string baseName |
195207
node = write.getRhs() and
196-
result = baseName + "." + write.getPropertyName()
208+
result = join(baseName, write.getPropertyName())
197209
|
198210
baseName = fromReference(write.getBase(), root)
199211
or
@@ -237,13 +249,11 @@ module AccessPath {
237249
*
238250
* This works for direct references as well as for aliases established through local data flow.
239251
*
240-
* Note that non-empty access paths contain an initial `.`, such as in `.foo.bar`.
241-
*
242252
* For example:
243253
* ```
244254
* function f(x) {
245-
* let a = x.f.g; // reference to (x, ".f.g")
246-
* let b = a.h; // reference to (x, ".f.g.h")
255+
* let a = x.f.g; // reference to (x, "f.g")
256+
* let b = a.h; // reference to (x, "f.g.h")
247257
* }
248258
* ```
249259
*/
@@ -279,9 +289,7 @@ module AccessPath {
279289
* Only gets the immediate right-hand side of an assignment or property, not
280290
* nodes that transitively flow there.
281291
*
282-
* Note that access paths contain an initial `.`, such as in `.foo.bar`.
283-
*
284-
* For example, the class nodes below are all assignments to `(x, ".foo.bar")`.
292+
* For example, the class nodes below are all assignments to `(x, "foo.bar")`.
285293
* ```
286294
* function f(x) {
287295
* x.foo.bar = class {};

0 commit comments

Comments
 (0)