Skip to content

Commit 18e6a54

Browse files
committed
recognize tagged templates as DataFlow::CallNode
1 parent 951ed01 commit 18e6a54

File tree

3 files changed

+51
-0
lines changed

3 files changed

+51
-0
lines changed

javascript/ql/lib/semmle/javascript/dataflow/DataFlow.qll

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1277,6 +1277,41 @@ module DataFlow {
12771277
result >= 0 and kind = "call" and result = originalCall.getNumArgument() - 1
12781278
}
12791279
}
1280+
1281+
/**
1282+
* A data flow node representing a call with a tagged template literal.
1283+
*/
1284+
private class TaggedTemplateLiteralCallNode extends CallNodeDef, ValueNode {
1285+
override TaggedTemplateExpr astNode;
1286+
1287+
override InvokeExpr getInvokeExpr() { none() } // There is no InvokeExpr for this.
1288+
1289+
override string getCalleeName() {
1290+
result = astNode.getTag().getUnderlyingValue().(Identifier).getName()
1291+
}
1292+
1293+
override DataFlow::Node getCalleeNode() { result = DataFlow::valueNode(astNode.getTag()) }
1294+
1295+
override DataFlow::Node getArgument(int i) {
1296+
// the first parameter send to the function is the string parts, which we don't model.
1297+
// rank is 1-indexed, which is perfect here.
1298+
result =
1299+
DataFlow::valueNode(rank[i](Expr e, int index |
1300+
e = astNode.getTemplate().getElement(index) and not e instanceof TemplateElement
1301+
|
1302+
e order by index
1303+
))
1304+
}
1305+
1306+
override DataFlow::Node getAnArgument() { result = this.getArgument(_) }
1307+
1308+
override DataFlow::Node getASpreadArgument() { none() }
1309+
1310+
// we don't model the string constants as arguments, but we still count them.
1311+
override int getNumArgument() { result = count(this.getArgument(_)) + 1 }
1312+
1313+
override DataFlow::Node getReceiver() { none() }
1314+
}
12801315
}
12811316

12821317
/**
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
function fooTag(strings, par1, par2) {
2+
3+
}
4+
5+
fooTag`hello ${arg1} world ${arg2}`

javascript/ql/test/library-tests/CallGraphs/FullTest/tests.expected

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ test_getAFunctionValue
126126
| strict.js:1:1:8:2 | (functi ... ode.\\n}) | strict.js:1:2:8:1 | functio ... mode.\\n} |
127127
| strict.js:1:2:8:1 | functio ... mode.\\n} | strict.js:1:2:8:1 | functio ... mode.\\n} |
128128
| strict.js:3:5:5:5 | functio ... ;\\n } | strict.js:3:5:5:5 | functio ... ;\\n } |
129+
| taggedTemplate.js:1:1:3:1 | functio ... 2) {\\n\\n} | taggedTemplate.js:1:1:3:1 | functio ... 2) {\\n\\n} |
130+
| taggedTemplate.js:5:1:5:6 | fooTag | taggedTemplate.js:1:1:3:1 | functio ... 2) {\\n\\n} |
129131
| tst3.js:1:1:1:22 | functio ... fn() {} | tst3.js:1:1:1:22 | functio ... fn() {} |
130132
| tst3.js:2:1:2:23 | functio ... n2() {} | tst3.js:2:1:2:23 | functio ... n2() {} |
131133
| tst.js:1:1:1:15 | function f() {} | tst.js:1:1:1:15 | function f() {} |
@@ -221,6 +223,8 @@ test_getArgument
221223
| reflection.js:7:1:7:22 | reflective call | 1 | reflection.js:7:20:7:21 | 19 |
222224
| reflection.js:8:1:8:25 | add.app ... 3, 19]) | 0 | reflection.js:8:11:8:14 | null |
223225
| reflection.js:8:1:8:25 | add.app ... 3, 19]) | 1 | reflection.js:8:17:8:24 | [23, 19] |
226+
| taggedTemplate.js:5:1:5:35 | fooTag` ... {arg2}` | 1 | taggedTemplate.js:5:16:5:19 | arg1 |
227+
| taggedTemplate.js:5:1:5:35 | fooTag` ... {arg2}` | 2 | taggedTemplate.js:5:30:5:33 | arg2 |
224228
| tst.js:22:1:22:4 | l(k) | 0 | tst.js:22:3:22:3 | k |
225229
| tst.js:42:2:42:29 | functio ... x; }(o) | 0 | tst.js:42:28:42:28 | o |
226230
test_getNumArgument
@@ -259,6 +263,7 @@ test_getNumArgument
259263
| strict2.js:9:10:9:14 | foo() | 0 |
260264
| strict.js:1:1:8:4 | (functi ... e.\\n})() | 0 |
261265
| strict.js:7:10:7:14 | foo() | 0 |
266+
| taggedTemplate.js:5:1:5:35 | fooTag` ... {arg2}` | 3 |
262267
| tst.js:6:1:6:3 | f() | 0 |
263268
| tst.js:7:1:7:3 | g() | 0 |
264269
| tst.js:8:1:8:3 | h() | 0 |
@@ -362,6 +367,7 @@ test_getCalleeNode
362367
| strict2.js:9:10:9:14 | foo() | strict2.js:9:10:9:12 | foo |
363368
| strict.js:1:1:8:4 | (functi ... e.\\n})() | strict.js:1:1:8:2 | (functi ... ode.\\n}) |
364369
| strict.js:7:10:7:14 | foo() | strict.js:7:10:7:12 | foo |
370+
| taggedTemplate.js:5:1:5:35 | fooTag` ... {arg2}` | taggedTemplate.js:5:1:5:6 | fooTag |
365371
| tst.js:6:1:6:3 | f() | tst.js:6:1:6:1 | f |
366372
| tst.js:7:1:7:3 | g() | tst.js:7:1:7:1 | g |
367373
| tst.js:8:1:8:3 | h() | tst.js:8:1:8:1 | h |
@@ -400,6 +406,7 @@ test_getLastArgument
400406
| reflection.js:7:1:7:22 | add.cal ... 23, 19) | reflection.js:7:20:7:21 | 19 |
401407
| reflection.js:7:1:7:22 | reflective call | reflection.js:7:20:7:21 | 19 |
402408
| reflection.js:8:1:8:25 | add.app ... 3, 19]) | reflection.js:8:17:8:24 | [23, 19] |
409+
| taggedTemplate.js:5:1:5:35 | fooTag` ... {arg2}` | taggedTemplate.js:5:30:5:33 | arg2 |
403410
| tst.js:22:1:22:4 | l(k) | tst.js:22:3:22:3 | k |
404411
| tst.js:42:2:42:29 | functio ... x; }(o) | tst.js:42:28:42:28 | o |
405412
test_getAnArgument
@@ -420,6 +427,8 @@ test_getAnArgument
420427
| reflection.js:7:1:7:22 | reflective call | reflection.js:7:20:7:21 | 19 |
421428
| reflection.js:8:1:8:25 | add.app ... 3, 19]) | reflection.js:8:11:8:14 | null |
422429
| reflection.js:8:1:8:25 | add.app ... 3, 19]) | reflection.js:8:17:8:24 | [23, 19] |
430+
| taggedTemplate.js:5:1:5:35 | fooTag` ... {arg2}` | taggedTemplate.js:5:16:5:19 | arg1 |
431+
| taggedTemplate.js:5:1:5:35 | fooTag` ... {arg2}` | taggedTemplate.js:5:30:5:33 | arg2 |
423432
| tst.js:22:1:22:4 | l(k) | tst.js:22:3:22:3 | k |
424433
| tst.js:42:2:42:29 | functio ... x; }(o) | tst.js:42:28:42:28 | o |
425434
test_getACallee
@@ -449,6 +458,7 @@ test_getACallee
449458
| reflection.js:8:1:8:25 | reflective call | reflection.js:1:1:3:1 | functio ... x+y;\\n} |
450459
| strict2.js:2:1:10:4 | (functi ... e.\\n})() | strict2.js:2:2:10:1 | functio ... mode.\\n} |
451460
| strict.js:1:1:8:4 | (functi ... e.\\n})() | strict.js:1:2:8:1 | functio ... mode.\\n} |
461+
| taggedTemplate.js:5:1:5:35 | fooTag` ... {arg2}` | taggedTemplate.js:1:1:3:1 | functio ... 2) {\\n\\n} |
452462
| tst.js:6:1:6:3 | f() | tst.js:1:1:1:15 | function f() {} |
453463
| tst.js:7:1:7:3 | g() | tst.js:2:9:2:21 | function() {} |
454464
| tst.js:8:1:8:3 | h() | tst.js:3:5:3:17 | function() {} |
@@ -509,6 +519,7 @@ test_getCalleeName
509519
| reflection.js:8:1:8:25 | add.app ... 3, 19]) | apply |
510520
| strict2.js:9:10:9:14 | foo() | foo |
511521
| strict.js:7:10:7:14 | foo() | foo |
522+
| taggedTemplate.js:5:1:5:35 | fooTag` ... {arg2}` | fooTag |
512523
| tst.js:6:1:6:3 | f() | f |
513524
| tst.js:7:1:7:3 | g() | g |
514525
| tst.js:8:1:8:3 | h() | h |

0 commit comments

Comments
 (0)