Merge pull request #3237 from asger-semmle/js/sparse-capture

JS: Add CapturedVariableNode to avoid N^2 edges
This commit is contained in:
Asger F
2020-04-15 10:42:48 +01:00
committed by GitHub
8 changed files with 145 additions and 93 deletions

View File

@@ -317,6 +317,24 @@ class LocalVariable extends Variable {
else result = d.getContainer()
)
}
/**
* Gets the location of a declaration of this variable.
*
* If the variable has one or more declarations, the location of the first declaration is used.
* If the variable has no declaration, the entry point of its declaring container is used.
*/
Location getLocation() {
result =
min(Location loc |
loc = getADeclaration().getLocation()
|
loc order by loc.getStartLine(), loc.getStartColumn()
)
or
not exists(getADeclaration()) and
result = getDeclaringContainer().getEntry().getLocation()
}
}
/** A local variable that is not captured. */

View File

@@ -1462,6 +1462,9 @@ class MidPathNode extends PathNode, MkMidNode {
or
// Skip the synthetic 'this' node, as a ThisExpr will be the next node anyway
nd = DataFlow::thisNode(_)
or
// Skip captured variable nodes as the successor will be a use of that variable anyway.
nd = DataFlow::capturedVariableNode(_)
}
}

View File

@@ -27,6 +27,7 @@ module DataFlow {
private newtype TNode =
TValueNode(AST::ValueNode nd) or
TSsaDefNode(SsaDefinition d) or
TCapturedVariableNode(LocalVariable v) { v.isCaptured() } or
TPropNode(@property p) or
TRestPatternNode(DestructuringPattern dp, Expr rest) { rest = dp.getRest() } or
TDestructuringPatternNode(DestructuringPattern dp) or
@@ -1221,6 +1222,32 @@ module DataFlow {
}
}
/**
* A data flow node representing a captured variable.
*/
private class CapturedVariableNode extends Node, TCapturedVariableNode {
LocalVariable variable;
CapturedVariableNode() { this = TCapturedVariableNode(variable) }
override BasicBlock getBasicBlock() { result = variable.getDeclaringContainer().getStartBB() }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
variable.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
override string toString() { result = variable.getName() }
}
/**
* INTERNAL. DO NOT USE.
*
* Gets a data flow node representing the given captured variable.
*/
Node capturedVariableNode(LocalVariable variable) { result = TCapturedVariableNode(variable) }
/**
* Gets the data flow node corresponding to `nd`.
*
@@ -1434,19 +1461,23 @@ module DataFlow {
or
immediateFlowStep(pred, succ)
or
// From an assignment or implicit initialization of a captured variable to its flow-insensitive node.
exists(SsaDefinition predDef |
pred = TSsaDefNode(predDef) and
succ = TCapturedVariableNode(predDef.getSourceVariable())
|
predDef instanceof SsaExplicitDefinition or
predDef instanceof SsaImplicitInit
)
or
// From a captured variable node to its flow-sensitive capture nodes
exists(SsaVariableCapture ssaCapture |
pred = TCapturedVariableNode(ssaCapture.getSourceVariable()) and
succ = TSsaDefNode(ssaCapture)
)
or
// Flow through implicit SSA nodes
exists(SsaImplicitDefinition ssa | succ = TSsaDefNode(ssa) |
// from any explicit definition or implicit init of a captured variable into
// the capturing definition
exists(SsaSourceVariable v, SsaDefinition predDef |
v = ssa.(SsaVariableCapture).getSourceVariable() and
predDef.getSourceVariable() = v and
pred = TSsaDefNode(predDef)
|
predDef instanceof SsaExplicitDefinition or
predDef instanceof SsaImplicitInit
)
or
// from the inputs of phi and pi nodes into the node itself
pred = TSsaDefNode(ssa.(SsaPseudoDefinition).getAnInput().getDefinition())
)