Java: Update the CFG for assert statements to make them proper guards.

This commit is contained in:
Anders Schack-Mulligen
2025-06-11 15:38:29 +02:00
parent 31770edc26
commit b3bb71f2e2

View File

@@ -327,12 +327,18 @@ private module ControlFlowGraphImpl {
)
}
private ThrowableType assertionError() { result.hasQualifiedName("java.lang", "AssertionError") }
/**
* Gets an exception type that may be thrown during execution of the
* body or the resources (if any) of `try`.
*/
private ThrowableType thrownInBody(TryStmt try) {
exists(AstNode n | mayThrow(n, result) |
exists(AstNode n |
mayThrow(n, result)
or
n instanceof AssertStmt and result = assertionError()
|
n.getEnclosingStmt().getEnclosingStmt+() = try.getBlock() or
n.(Expr).getParent*() = try.getAResource()
)
@@ -394,10 +400,7 @@ private module ControlFlowGraphImpl {
exists(LogicExpr logexpr |
logexpr.(BinaryExpr).getLeftOperand() = b
or
// Cannot use LogicExpr.getAnOperand or BinaryExpr.getAnOperand as they remove parentheses.
logexpr.(BinaryExpr).getRightOperand() = b and inBooleanContext(logexpr)
or
logexpr.(UnaryExpr).getExpr() = b and inBooleanContext(logexpr)
logexpr.getAnOperand() = b and inBooleanContext(logexpr)
)
or
exists(ConditionalExpr condexpr |
@@ -407,6 +410,8 @@ private module ControlFlowGraphImpl {
inBooleanContext(condexpr)
)
or
exists(AssertStmt assertstmt | assertstmt.getExpr() = b)
or
exists(SwitchExpr switch |
inBooleanContext(switch) and
switch.getAResult() = b
@@ -672,8 +677,6 @@ private module ControlFlowGraphImpl {
this instanceof EmptyStmt
or
this instanceof LocalTypeDeclStmt
or
this instanceof AssertStmt
}
/** Gets child nodes in their order of execution. Indexing starts at either -1 or 0. */
@@ -744,8 +747,6 @@ private module ControlFlowGraphImpl {
or
index = 0 and result = this.(ThrowStmt).getExpr()
or
index = 0 and result = this.(AssertStmt).getExpr()
or
result = this.(RecordPatternExpr).getSubPattern(index)
}
@@ -807,9 +808,12 @@ private module ControlFlowGraphImpl {
or
result = first(n.(SynchronizedStmt).getExpr())
or
result = first(n.(AssertStmt).getExpr())
or
result.asStmt() = n and
not n instanceof PostOrderNode and
not n instanceof SynchronizedStmt
not n instanceof SynchronizedStmt and
not n instanceof AssertStmt
or
result.asExpr() = n and n instanceof SwitchExpr
}
@@ -1112,7 +1116,19 @@ private module ControlFlowGraphImpl {
// `return` statements give rise to a `Return` completion
last.asStmt() = n.(ReturnStmt) and completion = ReturnCompletion()
or
// `throw` statements or throwing calls give rise to ` Throw` completion
exists(AssertStmt assertstmt | assertstmt = n |
// `assert` statements may complete normally - we use the `AssertStmt` itself
// to represent this outcome
last.asStmt() = assertstmt and completion = NormalCompletion()
or
// `assert` statements may throw
completion = ThrowCompletion(assertionError()) and
if exists(assertstmt.getMessage())
then last(assertstmt.getMessage(), last, NormalCompletion())
else last(assertstmt.getExpr(), last, BooleanCompletion(false, _))
)
or
// `throw` statements or throwing calls give rise to `Throw` completion
exists(ThrowableType tt | mayThrow(n, tt) |
last = n.getCfgNode() and completion = ThrowCompletion(tt)
)
@@ -1520,6 +1536,17 @@ private module ControlFlowGraphImpl {
exists(int i | last(s.getVariable(i), n, completion) and result = first(s.getVariable(i + 1)))
)
or
// Assert statements:
exists(AssertStmt assertstmt |
last(assertstmt.getExpr(), n, completion) and
completion = BooleanCompletion(true, _) and
result.asStmt() = assertstmt
or
last(assertstmt.getExpr(), n, completion) and
completion = BooleanCompletion(false, _) and
result = first(assertstmt.getMessage())
)
or
// When expressions:
exists(WhenExpr whenexpr |
n.asExpr() = whenexpr and