Skip to content

Commit 34d40b5

Browse files
authored
Merge pull request github#3237 from asger-semmle/js/sparse-capture
JS: Add CapturedVariableNode to avoid N^2 edges
2 parents b603a3d + c178eec commit 34d40b5

File tree

8 files changed

+145
-93
lines changed

8 files changed

+145
-93
lines changed

javascript/ql/src/semmle/javascript/Variables.qll

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,24 @@ class LocalVariable extends Variable {
317317
else result = d.getContainer()
318318
)
319319
}
320+
321+
/**
322+
* Gets the ___location of a declaration of this variable.
323+
*
324+
* If the variable has one or more declarations, the ___location of the first declaration is used.
325+
* If the variable has no declaration, the entry point of its declaring container is used.
326+
*/
327+
Location getLocation() {
328+
result =
329+
min(Location loc |
330+
loc = getADeclaration().getLocation()
331+
|
332+
loc order by loc.getStartLine(), loc.getStartColumn()
333+
)
334+
or
335+
not exists(getADeclaration()) and
336+
result = getDeclaringContainer().getEntry().getLocation()
337+
}
320338
}
321339

322340
/** A local variable that is not captured. */

javascript/ql/src/semmle/javascript/dataflow/Configuration.qll

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1462,6 +1462,9 @@ class MidPathNode extends PathNode, MkMidNode {
14621462
or
14631463
// Skip the synthetic 'this' node, as a ThisExpr will be the next node anyway
14641464
nd = DataFlow::thisNode(_)
1465+
or
1466+
// Skip captured variable nodes as the successor will be a use of that variable anyway.
1467+
nd = DataFlow::capturedVariableNode(_)
14651468
}
14661469
}
14671470

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

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ module DataFlow {
2727
private newtype TNode =
2828
TValueNode(AST::ValueNode nd) or
2929
TSsaDefNode(SsaDefinition d) or
30+
TCapturedVariableNode(LocalVariable v) { v.isCaptured() } or
3031
TPropNode(@property p) or
3132
TRestPatternNode(DestructuringPattern dp, Expr rest) { rest = dp.getRest() } or
3233
TDestructuringPatternNode(DestructuringPattern dp) or
@@ -1221,6 +1222,32 @@ module DataFlow {
12211222
}
12221223
}
12231224

1225+
/**
1226+
* A data flow node representing a captured variable.
1227+
*/
1228+
private class CapturedVariableNode extends Node, TCapturedVariableNode {
1229+
LocalVariable variable;
1230+
1231+
CapturedVariableNode() { this = TCapturedVariableNode(variable) }
1232+
1233+
override BasicBlock getBasicBlock() { result = variable.getDeclaringContainer().getStartBB() }
1234+
1235+
override predicate hasLocationInfo(
1236+
string filepath, int startline, int startcolumn, int endline, int endcolumn
1237+
) {
1238+
variable.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
1239+
}
1240+
1241+
override string toString() { result = variable.getName() }
1242+
}
1243+
1244+
/**
1245+
* INTERNAL. DO NOT USE.
1246+
*
1247+
* Gets a data flow node representing the given captured variable.
1248+
*/
1249+
Node capturedVariableNode(LocalVariable variable) { result = TCapturedVariableNode(variable) }
1250+
12241251
/**
12251252
* Gets the data flow node corresponding to `nd`.
12261253
*
@@ -1434,19 +1461,23 @@ module DataFlow {
14341461
or
14351462
immediateFlowStep(pred, succ)
14361463
or
1464+
// From an assignment or implicit initialization of a captured variable to its flow-insensitive node.
1465+
exists(SsaDefinition predDef |
1466+
pred = TSsaDefNode(predDef) and
1467+
succ = TCapturedVariableNode(predDef.getSourceVariable())
1468+
|
1469+
predDef instanceof SsaExplicitDefinition or
1470+
predDef instanceof SsaImplicitInit
1471+
)
1472+
or
1473+
// From a captured variable node to its flow-sensitive capture nodes
1474+
exists(SsaVariableCapture ssaCapture |
1475+
pred = TCapturedVariableNode(ssaCapture.getSourceVariable()) and
1476+
succ = TSsaDefNode(ssaCapture)
1477+
)
1478+
or
14371479
// Flow through implicit SSA nodes
14381480
exists(SsaImplicitDefinition ssa | succ = TSsaDefNode(ssa) |
1439-
// from any explicit definition or implicit init of a captured variable into
1440-
// the capturing definition
1441-
exists(SsaSourceVariable v, SsaDefinition predDef |
1442-
v = ssa.(SsaVariableCapture).getSourceVariable() and
1443-
predDef.getSourceVariable() = v and
1444-
pred = TSsaDefNode(predDef)
1445-
|
1446-
predDef instanceof SsaExplicitDefinition or
1447-
predDef instanceof SsaImplicitInit
1448-
)
1449-
or
14501481
// from the inputs of phi and pi nodes into the node itself
14511482
pred = TSsaDefNode(ssa.(SsaPseudoDefinition).getAnInput().getDefinition())
14521483
)

javascript/ql/test/library-tests/DataFlow/flowStep.expected

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@
1313
| sources.js:11:12:11:18 | key | sources.js:11:32:11:34 | key |
1414
| sources.js:11:14:11:16 | key | sources.js:11:12:11:18 | key |
1515
| tst2.ts:1:1:1:1 | A | tst2.ts:1:18:1:18 | A |
16-
| tst2.ts:1:1:1:1 | A | tst2.ts:7:1:7:0 | A |
17-
| tst2.ts:1:8:5:1 | A | tst2.ts:7:1:7:0 | A |
16+
| tst2.ts:1:1:1:1 | A | tst2.ts:1:18:1:18 | A |
17+
| tst2.ts:1:8:5:1 | A | tst2.ts:1:18:1:18 | A |
1818
| tst2.ts:1:8:5:1 | A | tst2.ts:11:11:11:11 | A |
1919
| tst2.ts:1:8:5:1 | namespa ... lysed\\n} | tst2.ts:1:8:5:1 | A |
20+
| tst2.ts:1:18:1:18 | A | tst2.ts:7:1:7:0 | A |
2021
| tst2.ts:2:14:2:19 | x | tst2.ts:4:3:4:3 | x |
2122
| tst2.ts:2:18:2:19 | 42 | tst2.ts:2:14:2:19 | x |
2223
| tst2.ts:7:1:7:0 | A | tst2.ts:8:3:8:3 | A |
@@ -26,19 +27,19 @@
2627
| tst2.ts:11:11:11:13 | A.x | tst2.ts:11:11:11:23 | A.x as number |
2728
| tst2.ts:13:26:13:29 | List | tst2.ts:13:26:13:37 | List<string> |
2829
| tst2.ts:13:39:13:38 | args | tst2.ts:13:39:13:38 | args |
29-
| tst.js:1:1:1:1 | x | tst.js:28:2:28:1 | x |
30-
| tst.js:1:1:1:1 | x | tst.js:32:1:32:0 | x |
30+
| tst.js:1:1:1:1 | x | tst.js:3:5:3:5 | x |
3131
| tst.js:1:10:1:11 | fs | tst.js:1:10:1:11 | fs |
3232
| tst.js:1:10:1:11 | fs | tst.js:7:1:7:2 | fs |
3333
| tst.js:1:10:1:11 | fs | tst.js:22:24:22:25 | fs |
34+
| tst.js:3:5:3:5 | x | tst.js:28:2:28:1 | x |
35+
| tst.js:3:5:3:5 | x | tst.js:32:1:32:0 | x |
36+
| tst.js:3:5:3:10 | x | tst.js:3:5:3:5 | x |
3437
| tst.js:3:5:3:10 | x | tst.js:8:1:8:1 | x |
3538
| tst.js:3:5:3:10 | x | tst.js:9:2:9:2 | x |
3639
| tst.js:3:5:3:10 | x | tst.js:10:1:10:1 | x |
3740
| tst.js:3:5:3:10 | x | tst.js:11:1:11:1 | x |
3841
| tst.js:3:5:3:10 | x | tst.js:11:1:11:1 | x |
3942
| tst.js:3:5:3:10 | x | tst.js:11:1:11:1 | x |
40-
| tst.js:3:5:3:10 | x | tst.js:28:2:28:1 | x |
41-
| tst.js:3:5:3:10 | x | tst.js:32:1:32:0 | x |
4243
| tst.js:3:9:3:10 | 42 | tst.js:3:5:3:10 | x |
4344
| tst.js:4:5:4:12 | y | tst.js:10:4:10:4 | y |
4445
| tst.js:4:5:4:12 | y | tst.js:11:6:11:6 | y |
@@ -75,9 +76,8 @@
7576
| tst.js:22:5:22:25 | readFileSync | tst.js:23:1:23:12 | readFileSync |
7677
| tst.js:22:7:22:18 | readFileSync | tst.js:22:5:22:25 | readFileSync |
7778
| tst.js:22:24:22:25 | fs | tst.js:22:5:22:20 | { readFileSync } |
79+
| tst.js:25:1:25:3 | x | tst.js:3:5:3:5 | x |
7880
| tst.js:25:1:25:3 | x | tst.js:26:1:26:1 | x |
79-
| tst.js:25:1:25:3 | x | tst.js:28:2:28:1 | x |
80-
| tst.js:25:1:25:3 | x | tst.js:32:1:32:0 | x |
8181
| tst.js:25:1:25:3 | x | tst.js:57:7:57:7 | x |
8282
| tst.js:25:1:25:3 | x | tst.js:58:11:58:11 | x |
8383
| tst.js:25:1:25:3 | x | tst.js:105:1:105:1 | x |
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
| tst.js:4:3:4:27 | (typeof ... nction' | x |
2-
| tst.js:8:3:8:23 | (typeof ... === 'u' | x |
1+
| tst.js:4:3:4:27 | (typeof ... nction' | tst.js:3:12:3:12 | x |
2+
| tst.js:8:3:8:23 | (typeof ... === 'u' | tst.js:3:12:3:12 | x |
Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
| tst.js:2:7:2:13 | a = g() | a | tst.js:2:11:2:13 | g() |
2-
| tst.js:4:7:4:24 | { propB: b } = g() | b | tst.js:4:9:4:16 | propB: b |
3-
| tst.js:6:7:6:34 | { propC ... } = g() | c | tst.js:6:9:6:16 | propC: c |
4-
| tst.js:6:7:6:34 | { propC ... } = g() | d | tst.js:6:19:6:26 | propD: d |
5-
| tst.js:8:7:8:41 | { array ... } = g() | elm1 | tst.js:8:22:8:25 | elm1 |
6-
| tst.js:8:7:8:41 | { array ... } = g() | elm2 | tst.js:8:28:8:31 | elm2 |
7-
| tst.js:17:3:17:22 | ({ propB: b }) = g() | b | tst.js:17:6:17:13 | propB: b |
8-
| tst.js:19:3:19:32 | ({ prop ... ) = g() | c | tst.js:19:6:19:13 | propC: c |
9-
| tst.js:19:3:19:32 | ({ prop ... ) = g() | d | tst.js:19:16:19:23 | propD: d |
10-
| tst.js:21:3:21:22 | [ elm1, elm2 ] = g() | elm1 | tst.js:21:5:21:8 | elm1 |
11-
| tst.js:21:3:21:22 | [ elm1, elm2 ] = g() | elm2 | tst.js:21:11:21:14 | elm2 |
12-
| tst.js:31:12:31:23 | [elm1, elm2] | elm1 | tst.js:31:13:31:16 | elm1 |
13-
| tst.js:31:12:31:23 | [elm1, elm2] | elm2 | tst.js:31:19:31:22 | elm2 |
14-
| tst.js:31:26:31:40 | { prop: value } | value | tst.js:31:28:31:38 | prop: value |
1+
| tst.js:2:7:2:13 | a = g() | tst.js:2:7:2:7 | a | tst.js:2:11:2:13 | g() |
2+
| tst.js:4:7:4:24 | { propB: b } = g() | tst.js:4:16:4:16 | b | tst.js:4:9:4:16 | propB: b |
3+
| tst.js:6:7:6:34 | { propC ... } = g() | tst.js:6:16:6:16 | c | tst.js:6:9:6:16 | propC: c |
4+
| tst.js:6:7:6:34 | { propC ... } = g() | tst.js:6:26:6:26 | d | tst.js:6:19:6:26 | propD: d |
5+
| tst.js:8:7:8:41 | { array ... } = g() | tst.js:8:22:8:25 | elm1 | tst.js:8:22:8:25 | elm1 |
6+
| tst.js:8:7:8:41 | { array ... } = g() | tst.js:8:28:8:31 | elm2 | tst.js:8:28:8:31 | elm2 |
7+
| tst.js:17:3:17:22 | ({ propB: b }) = g() | tst.js:4:16:4:16 | b | tst.js:17:6:17:13 | propB: b |
8+
| tst.js:19:3:19:32 | ({ prop ... ) = g() | tst.js:6:16:6:16 | c | tst.js:19:6:19:13 | propC: c |
9+
| tst.js:19:3:19:32 | ({ prop ... ) = g() | tst.js:6:26:6:26 | d | tst.js:19:16:19:23 | propD: d |
10+
| tst.js:21:3:21:22 | [ elm1, elm2 ] = g() | tst.js:8:22:8:25 | elm1 | tst.js:21:5:21:8 | elm1 |
11+
| tst.js:21:3:21:22 | [ elm1, elm2 ] = g() | tst.js:8:28:8:31 | elm2 | tst.js:21:11:21:14 | elm2 |
12+
| tst.js:31:12:31:23 | [elm1, elm2] | tst.js:31:13:31:16 | elm1 | tst.js:31:13:31:16 | elm1 |
13+
| tst.js:31:12:31:23 | [elm1, elm2] | tst.js:31:19:31:22 | elm2 | tst.js:31:19:31:22 | elm2 |
14+
| tst.js:31:26:31:40 | { prop: value } | tst.js:31:34:31:38 | value | tst.js:31:28:31:38 | prop: value |
Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
| cm1 |
2-
| cm2 |
3-
| cm3 |
4-
| cm4 |
5-
| cm5 |
6-
| cm6 |
7-
| cm7 |
8-
| cm8 |
9-
| dm1 |
10-
| m |
11-
| mcm1 |
12-
| rm1 |
1+
| module-refs.js:3:9:3:11 | dm1 |
2+
| module-refs.js:6:9:6:11 | rm1 |
3+
| module-refs.js:9:9:9:11 | cm1 |
4+
| module-refs.js:10:9:10:11 | cm2 |
5+
| module-refs.js:11:9:11:11 | cm3 |
6+
| module-refs.js:12:9:12:11 | cm4 |
7+
| module-refs.js:13:9:13:11 | cm5 |
8+
| module-refs.js:14:9:14:11 | cm6 |
9+
| module-refs.js:15:9:15:11 | cm7 |
10+
| module-refs.js:16:9:16:11 | cm8 |
11+
| module-refs.js:22:9:22:12 | mcm1 |
12+
| tst.js:19:7:19:7 | m |
Lines changed: 46 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,46 @@
1-
| arguments | arrayPatternDefault.js:1:2:4:1 | functio ... bal2;\\n} |
2-
| arguments | assignments.js:3:1:6:1 | functio ... = 56;\\n} |
3-
| arguments | assignments.js:4:10:4:24 | function h() {} |
4-
| arguments | defaultargs.js:1:2:5:1 | functio ... ]) {}\\n} |
5-
| arguments | defaultargs.js:3:3:3:25 | functio ... = x) {} |
6-
| arguments | defaultargs.js:4:3:4:51 | functio ... [0]) {} |
7-
| arguments | for.js:1:2:5:1 | functio ... x;\\n} |
8-
| arguments | let.js:14:1:21:1 | functio ... }\\n} |
9-
| arguments | typeoftype.ts:1:1:6:1 | functio ... x\\n }\\n} |
10-
| arguments | typeoftype.ts:3:3:5:3 | functio ... e x\\n } |
11-
| arguments | variables.js:8:1:12:1 | functio ... ar x;\\n} |
12-
| arguments | variables.js:13:1:23:1 | functio ... z;\\n\\t}\\n} |
13-
| arguments | variables.js:16:2:22:2 | functio ... y+z;\\n\\t} |
14-
| f | defaultargs.js:1:2:5:1 | functio ... ]) {}\\n} |
15-
| g | assignments.js:3:1:6:1 | functio ... = 56;\\n} |
16-
| g | defaultargs.js:1:2:5:1 | functio ... ]) {}\\n} |
17-
| g | typeoftype.ts:1:1:6:1 | functio ... x\\n }\\n} |
18-
| h | assignments.js:4:10:4:24 | function h() {} |
19-
| h | variables.js:13:1:23:1 | functio ... z;\\n\\t}\\n} |
20-
| o | arrayPatternDefault.js:1:2:4:1 | functio ... bal2;\\n} |
21-
| o | for.js:1:2:5:1 | functio ... x;\\n} |
22-
| x | arrayPatternDefault.js:1:2:4:1 | functio ... bal2;\\n} |
23-
| x | defaultargs.js:1:2:5:1 | functio ... ]) {}\\n} |
24-
| x | defaultargs.js:3:3:3:25 | functio ... = x) {} |
25-
| x | defaultargs.js:4:3:4:51 | functio ... [0]) {} |
26-
| x | for.js:1:2:5:1 | functio ... x;\\n} |
27-
| x | legacyletstmt.js:1:1:8:0 | <toplevel> |
28-
| x | let.js:1:1:22:0 | <toplevel> |
29-
| x | let.js:1:1:22:0 | <toplevel> |
30-
| x | let.js:1:1:22:0 | <toplevel> |
31-
| x | let.js:1:1:22:0 | <toplevel> |
32-
| x | let.js:1:1:22:0 | <toplevel> |
33-
| x | let.js:14:1:21:1 | functio ... }\\n} |
34-
| x | typeoftype.ts:1:1:6:1 | functio ... x\\n }\\n} |
35-
| x | variables.js:8:1:12:1 | functio ... ar x;\\n} |
36-
| x | variables.js:13:1:23:1 | functio ... z;\\n\\t}\\n} |
37-
| y | defaultargs.js:3:3:3:25 | functio ... = x) {} |
38-
| y | defaultargs.js:4:3:4:51 | functio ... [0]) {} |
39-
| y | legacyletstmt.js:1:1:8:0 | <toplevel> |
40-
| y | let.js:1:1:22:0 | <toplevel> |
41-
| y | let.js:14:1:21:1 | functio ... }\\n} |
42-
| y | typeoftype.ts:3:3:5:3 | functio ... e x\\n } |
43-
| y | variables.js:13:1:23:1 | functio ... z;\\n\\t}\\n} |
44-
| y | variables.js:16:2:22:2 | functio ... y+z;\\n\\t} |
45-
| z | variables.js:13:1:23:1 | functio ... z;\\n\\t}\\n} |
46-
| z | variables.js:16:2:22:2 | functio ... y+z;\\n\\t} |
1+
| arrayPatternDefault.js:1:2:1:1 | arguments | arrayPatternDefault.js:1:2:4:1 | functio ... bal2;\\n} |
2+
| arrayPatternDefault.js:1:11:1:11 | o | arrayPatternDefault.js:1:2:4:1 | functio ... bal2;\\n} |
3+
| arrayPatternDefault.js:2:8:2:8 | x | arrayPatternDefault.js:1:2:4:1 | functio ... bal2;\\n} |
4+
| assignments.js:3:1:3:0 | arguments | assignments.js:3:1:6:1 | functio ... = 56;\\n} |
5+
| assignments.js:4:6:4:6 | g | assignments.js:3:1:6:1 | functio ... = 56;\\n} |
6+
| assignments.js:4:10:4:9 | arguments | assignments.js:4:10:4:24 | function h() {} |
7+
| assignments.js:4:19:4:19 | h | assignments.js:4:10:4:24 | function h() {} |
8+
| defaultargs.js:2:7:2:7 | x | defaultargs.js:1:2:5:1 | functio ... ]) {}\\n} |
9+
| defaultargs.js:2:10:2:18 | arguments | defaultargs.js:1:2:5:1 | functio ... ]) {}\\n} |
10+
| defaultargs.js:3:3:3:2 | arguments | defaultargs.js:3:3:3:25 | functio ... = x) {} |
11+
| defaultargs.js:3:12:3:12 | f | defaultargs.js:1:2:5:1 | functio ... ]) {}\\n} |
12+
| defaultargs.js:3:14:3:14 | x | defaultargs.js:3:3:3:25 | functio ... = x) {} |
13+
| defaultargs.js:3:17:3:17 | y | defaultargs.js:3:3:3:25 | functio ... = x) {} |
14+
| defaultargs.js:4:3:4:2 | arguments | defaultargs.js:4:3:4:51 | functio ... [0]) {} |
15+
| defaultargs.js:4:12:4:12 | g | defaultargs.js:1:2:5:1 | functio ... ]) {}\\n} |
16+
| defaultargs.js:4:14:4:14 | x | defaultargs.js:4:3:4:51 | functio ... [0]) {} |
17+
| defaultargs.js:4:32:4:32 | y | defaultargs.js:4:3:4:51 | functio ... [0]) {} |
18+
| for.js:1:2:1:1 | arguments | for.js:1:2:5:1 | functio ... x;\\n} |
19+
| for.js:1:11:1:11 | o | for.js:1:2:5:1 | functio ... x;\\n} |
20+
| for.js:2:7:2:7 | x | for.js:1:2:5:1 | functio ... x;\\n} |
21+
| legacyletstmt.js:3:6:3:6 | x | legacyletstmt.js:1:1:8:0 | <toplevel> |
22+
| legacyletstmt.js:3:14:3:14 | y | legacyletstmt.js:1:1:8:0 | <toplevel> |
23+
| let.js:2:9:2:9 | x | let.js:1:1:22:0 | <toplevel> |
24+
| let.js:4:13:4:13 | x | let.js:1:1:22:0 | <toplevel> |
25+
| let.js:5:18:5:18 | x | let.js:1:1:22:0 | <toplevel> |
26+
| let.js:5:26:5:26 | y | let.js:1:1:22:0 | <toplevel> |
27+
| let.js:6:17:6:17 | x | let.js:1:1:22:0 | <toplevel> |
28+
| let.js:9:18:9:18 | x | let.js:1:1:22:0 | <toplevel> |
29+
| let.js:14:1:14:0 | arguments | let.js:14:1:21:1 | functio ... }\\n} |
30+
| let.js:14:14:14:14 | x | let.js:14:1:21:1 | functio ... }\\n} |
31+
| let.js:17:11:17:11 | y | let.js:14:1:21:1 | functio ... }\\n} |
32+
| typeoftype.ts:1:1:1:0 | arguments | typeoftype.ts:1:1:6:1 | functio ... x\\n }\\n} |
33+
| typeoftype.ts:2:7:2:7 | x | typeoftype.ts:1:1:6:1 | functio ... x\\n }\\n} |
34+
| typeoftype.ts:3:3:3:2 | arguments | typeoftype.ts:3:3:5:3 | functio ... e x\\n } |
35+
| typeoftype.ts:3:12:3:12 | g | typeoftype.ts:1:1:6:1 | functio ... x\\n }\\n} |
36+
| typeoftype.ts:4:9:4:9 | y | typeoftype.ts:3:3:5:3 | functio ... e x\\n } |
37+
| variables.js:8:1:8:0 | arguments | variables.js:8:1:12:1 | functio ... ar x;\\n} |
38+
| variables.js:9:6:9:6 | x | variables.js:8:1:12:1 | functio ... ar x;\\n} |
39+
| variables.js:13:1:13:0 | arguments | variables.js:13:1:23:1 | functio ... z;\\n\\t}\\n} |
40+
| variables.js:13:12:13:12 | y | variables.js:13:1:23:1 | functio ... z;\\n\\t}\\n} |
41+
| variables.js:13:15:13:15 | z | variables.js:13:1:23:1 | functio ... z;\\n\\t}\\n} |
42+
| variables.js:15:6:15:6 | x | variables.js:13:1:23:1 | functio ... z;\\n\\t}\\n} |
43+
| variables.js:16:2:16:1 | arguments | variables.js:16:2:22:2 | functio ... y+z;\\n\\t} |
44+
| variables.js:16:11:16:11 | h | variables.js:13:1:23:1 | functio ... z;\\n\\t}\\n} |
45+
| variables.js:16:13:16:13 | z | variables.js:16:2:22:2 | functio ... y+z;\\n\\t} |
46+
| variables.js:18:11:18:11 | y | variables.js:16:2:22:2 | functio ... y+z;\\n\\t} |

0 commit comments

Comments
 (0)