mirror of
https://github.com/github/codeql.git
synced 2026-04-25 16:55:19 +02:00
Merge pull request #3237 from asger-semmle/js/sparse-capture
JS: Add CapturedVariableNode to avoid N^2 edges
This commit is contained in:
@@ -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. */
|
||||
|
||||
@@ -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(_)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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())
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user