Switch to using VariableAssign for instanceof and switch dataflow

This commit is contained in:
Chris Smowton
2023-11-15 15:59:21 +00:00
parent 176adf4376
commit 3d980b1684
5 changed files with 58 additions and 56 deletions

View File

@@ -1682,15 +1682,51 @@ class LocalVariableDeclExpr extends Expr, @localvariabledeclexpr {
/** Holds if this is a declaration stemming from a pattern instanceof expression. */
predicate hasAssociatedInstanceOfExpr() { exists(this.getAssociatedInstanceOfExpr()) }
/** Gets the initializer expression of this local variable declaration expression, if any. */
/**
* Gets the initializer expression of this local variable declaration expression, if any.
*
* Note this applies specifically to a syntactic initialization like `T varname = init`;
* to include also `e instanceof T varname` and `switch(e) ... case T varname`, which both
* have the effect of initializing `varname` to a known local expression without using
* that syntax, use `getInitOrPatternSource`.
*/
Expr getInit() { result.isNthChildOf(this, 0) }
/**
* Gets the local expression that initializes this variable declaration, if any.
*
* Note this includes explicit `T varname = init;`, as well as `e instanceof T varname`
* and `switch(e) ... case T varname`. To get only explicit initializers, use `getInit`.
*
* Note that record pattern variables like `e instance of T Record(T varname)` do not have
* either an explicit initializer or a pattern source.
*/
Expr getInitOrPatternSource() {
result = this.getInit()
or
exists(SwitchStmt switch |
result = switch.getExpr() and
this = switch.getAPatternCase().getPattern().asBindingPattern()
)
or
exists(SwitchExpr switch |
result = switch.getExpr() and
this = switch.getAPatternCase().getPattern().asBindingPattern()
)
or
exists(InstanceOfExpr ioe |
result = ioe.getExpr() and
this = ioe.getPattern().asBindingPattern()
)
}
/** Holds if this variable declaration implicitly initializes the variable. */
predicate hasImplicitInit() {
exists(CatchClause cc | cc.getVariable() = this) or
exists(EnhancedForStmt efs | efs.getVariable() = this) or
this.hasAssociatedSwitch() or
this.hasAssociatedInstanceOfExpr()
exists(CatchClause cc | cc.getVariable() = this)
or
exists(EnhancedForStmt efs | efs.getVariable() = this)
or
this.getParent() instanceof RecordPatternExpr
}
/** Gets a printable representation of this expression. */
@@ -1699,6 +1735,13 @@ class LocalVariableDeclExpr extends Expr, @localvariabledeclexpr {
override string getAPrimaryQlClass() { result = "LocalVariableDeclExpr" }
}
/** A local variable declaration that occurs within a record pattern. */
class RecordBindingVariableExpr extends LocalVariableDeclExpr {
RecordBindingVariableExpr() {
this.getParent() instanceof RecordPatternExpr
}
}
/** An update of a variable or an initialization of the variable. */
class VariableUpdate extends Expr {
VariableUpdate() {
@@ -1727,12 +1770,12 @@ class VariableAssign extends VariableUpdate {
/**
* Gets the source (right-hand side) of this assignment, if any.
*
* An initialization in a `CatchClause` or `EnhancedForStmt` is implicit and
* does not have a source.
* An initialization in a `CatchClause`, `EnhancedForStmt` or `RecordPatternExpr`
* is implicit and does not have a source.
*/
Expr getSource() {
result = this.(AssignExpr).getSource() or
result = this.(LocalVariableDeclExpr).getInit()
result = this.(LocalVariableDeclExpr).getInitOrPatternSource()
}
}

View File

@@ -116,22 +116,6 @@ private predicate step(TypeFlowNode n1, TypeFlowNode n2) {
n2.asSsa().(BaseSsaUpdate).getDefiningExpr().(VariableAssign).getSource() = n1.asExpr()
or
n2.asSsa().(BaseSsaImplicitInit).captures(n1.asSsa())
or
exists(PatternCase pc, LocalVariableDeclExpr patternVar |
patternVar = pc.getPattern().asBindingPattern() and
n2.asSsa().(BaseSsaUpdate).getDefiningExpr() = patternVar and
(
pc.getSwitch().getExpr() = n1.asExpr()
or
pc.getSwitchExpr().getExpr() = n1.asExpr()
)
)
or
exists(InstanceOfExpr ioe, LocalVariableDeclExpr patternVar |
patternVar = ioe.getPattern().asBindingPattern() and
n2.asSsa().(BaseSsaUpdate).getDefiningExpr() = patternVar and
ioe.getExpr() = n1.asExpr()
)
}
/**

View File

@@ -191,11 +191,14 @@ predicate simpleAstFlowStep(Expr e1, Expr e2) {
or
e2.(WhenExpr).getBranch(_).getAResult() = e1
or
exists(SwitchExpr se | e1 = se.getExpr() and e2 = se.getACase().(PatternCase).getPattern())
// In the following three cases only record patterns need this flow edge, leading from the bound instanceof
// or switch tested expression to a record pattern that will read its fields. Simple binding patterns are
// handled via VariableAssign.getSource instead.
exists(SwitchExpr se | e1 = se.getExpr() and e2 = se.getACase().(PatternCase).getPattern().asRecordPattern())
or
exists(SwitchStmt ss | e1 = ss.getExpr() and e2 = ss.getACase().(PatternCase).getPattern())
exists(SwitchStmt ss | e1 = ss.getExpr() and e2 = ss.getACase().(PatternCase).getPattern().asRecordPattern())
or
exists(InstanceOfExpr ioe | e1 = ioe.getExpr() and e2 = ioe.getPattern())
exists(InstanceOfExpr ioe | e1 = ioe.getExpr() and e2 = ioe.getPattern().asRecordPattern())
}
private predicate simpleLocalFlowStep0(Node node1, Node node2) {
@@ -204,7 +207,7 @@ private predicate simpleLocalFlowStep0(Node node1, Node node2) {
exists(SsaExplicitUpdate upd |
upd.getDefiningExpr().(VariableAssign).getSource() = node1.asExpr() or
upd.getDefiningExpr().(AssignOp) = node1.asExpr() or
upd.getDefiningExpr().(PatternExpr).asBindingPattern() = node1.asExpr()
upd.getDefiningExpr().(RecordBindingVariableExpr) = node1.asExpr()
|
node2.asExpr() = upd.getAFirstUse() and
not capturedVariableRead(node2)

View File

@@ -167,20 +167,6 @@ private module TypeTrackingSteps {
def.(BaseSsaUpdate).getDefiningExpr().(VariableAssign).getSource() = n1.asExpr()
or
def.(BaseSsaImplicitInit).isParameterDefinition(n1.asParameter())
or
exists(PatternCase pc |
pc.getPattern().asBindingPattern() = def.(BaseSsaUpdate).getDefiningExpr() and
(
pc.getSwitch().getExpr() = n1.asExpr()
or
pc.getSwitchExpr().getExpr() = n1.asExpr()
)
)
or
exists(InstanceOfExpr ioe |
ioe.getPattern().asBindingPattern() = def.(BaseSsaUpdate).getDefiningExpr() and
ioe.getExpr() = n1.asExpr()
)
|
v.getAnUltimateDefinition() = def and
v.getAUse() = n2.asExpr()

View File

@@ -80,20 +80,6 @@ private predicate step(Node n1, Node n2) {
for.getVariable() = def.(BaseSsaUpdate).getDefiningExpr() and
for.getExpr() = n1.asExpr()
)
or
exists(PatternCase pc |
pc.getPattern().asBindingPattern() = def.(BaseSsaUpdate).getDefiningExpr() and
(
pc.getSwitch().getExpr() = n1.asExpr()
or
pc.getSwitchExpr().getExpr() = n1.asExpr()
)
)
or
exists(InstanceOfExpr ioe |
ioe.getPattern().asBindingPattern() = def.(BaseSsaUpdate).getDefiningExpr() and
ioe.getExpr() = n1.asExpr()
)
|
v.getAnUltimateDefinition() = def and
v.getAUse() = n2.asExpr()