Skip to content

Commit 1f496d3

Browse files
committed
JS: Add CapturedVariableNode
1 parent e5d3286 commit 1f496d3

File tree

2 files changed

+52
-11
lines changed

2 files changed

+52
-11
lines changed

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,19 @@ 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 multiple declarations, an arbitrary one is used.
325+
* If it has no declaration, the location of its declaring scope is used.
326+
*/
327+
Location getLocation() {
328+
result = min(Location loc | loc = getADeclaration().getLocation() | loc order by loc.getStartLine(), loc.getStartColumn() )
329+
or
330+
not exists(getADeclaration()) and
331+
result = getDeclaringContainer().getLocation()
332+
}
320333
}
321334

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

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

Lines changed: 39 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,29 @@ 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() {
1234+
result = variable.getDeclaringContainer().getStartBB()
1235+
}
1236+
1237+
override predicate hasLocationInfo(
1238+
string filepath, int startline, int startcolumn, int endline, int endcolumn
1239+
) {
1240+
variable.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
1241+
}
1242+
1243+
override string toString() {
1244+
result = variable.getName()
1245+
}
1246+
}
1247+
12241248
/**
12251249
* Gets the data flow node corresponding to `nd`.
12261250
*
@@ -1434,19 +1458,23 @@ module DataFlow {
14341458
or
14351459
immediateFlowStep(pred, succ)
14361460
or
1461+
// From an assignment or implicit initialization of a captured variable to its flow-insensitive node.
1462+
exists(SsaDefinition predDef |
1463+
pred = TSsaDefNode(predDef) and
1464+
succ = TCapturedVariableNode(predDef.getSourceVariable())
1465+
|
1466+
predDef instanceof SsaExplicitDefinition or
1467+
predDef instanceof SsaImplicitInit
1468+
)
1469+
or
1470+
// From a captured variable node to its flow-sensitive capture nodes
1471+
exists(SsaVariableCapture ssaCapture |
1472+
pred = TCapturedVariableNode(ssaCapture.getSourceVariable()) and
1473+
succ = TSsaDefNode(ssaCapture)
1474+
)
1475+
or
14371476
// Flow through implicit SSA nodes
14381477
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
14501478
// from the inputs of phi and pi nodes into the node itself
14511479
pred = TSsaDefNode(ssa.(SsaPseudoDefinition).getAnInput().getDefinition())
14521480
)

0 commit comments

Comments
 (0)