Merge pull request #19883 from aschackmull/java/fix-assert-cfg

Java: Fix assert CFG by properly tagging the false successor.
This commit is contained in:
Anders Schack-Mulligen
2025-06-26 11:43:27 +02:00
committed by GitHub
5 changed files with 44 additions and 15 deletions

View File

@@ -100,7 +100,8 @@ module ControlFlow {
private newtype TNode =
TExprNode(Expr e) { hasControlFlow(e) } or
TStmtNode(Stmt s) or
TExitNode(Callable c) { exists(c.getBody()) }
TExitNode(Callable c) { exists(c.getBody()) } or
TAssertThrowNode(AssertStmt s)
/** A node in the expression-level control-flow graph. */
class Node extends TNode {
@@ -204,6 +205,25 @@ module ControlFlow {
/** Gets the source location for this element. */
override Location getLocation() { result = c.getLocation() }
}
/** A control flow node indicating a failing assertion. */
class AssertThrowNode extends Node, TAssertThrowNode {
AssertStmt s;
AssertThrowNode() { this = TAssertThrowNode(s) }
override Stmt getEnclosingStmt() { result = s }
override Callable getEnclosingCallable() { result = s.getEnclosingCallable() }
override ExprParent getAstNode() { result = s }
/** Gets a textual representation of this element. */
override string toString() { result = "Assert Throw" }
/** Gets the source location for this element. */
override Location getLocation() { result = s.getLocation() }
}
}
class ControlFlowNode = ControlFlow::Node;
@@ -327,7 +347,17 @@ private module ControlFlowGraphImpl {
)
}
private ThrowableType assertionError() { result.hasQualifiedName("java.lang", "AssertionError") }
private ThrowableType actualAssertionError() {
result.hasQualifiedName("java.lang", "AssertionError")
}
private ThrowableType assertionError() {
result = actualAssertionError()
or
// In case `AssertionError` is not extracted, we use `Error` as a fallback.
not exists(actualAssertionError()) and
result.hasQualifiedName("java.lang", "Error")
}
/**
* Gets an exception type that may be thrown during execution of the
@@ -1123,12 +1153,7 @@ private module ControlFlowGraphImpl {
or
// `assert` statements may throw
completion = ThrowCompletion(assertionError()) and
(
last(assertstmt.getMessage(), last, NormalCompletion())
or
not exists(assertstmt.getMessage()) and
last(assertstmt.getExpr(), last, BooleanCompletion(false, _))
)
last.(AssertThrowNode).getAstNode() = assertstmt
)
or
// `throw` statements or throwing calls give rise to `Throw` completion
@@ -1547,7 +1572,15 @@ private module ControlFlowGraphImpl {
or
last(assertstmt.getExpr(), n, completion) and
completion = BooleanCompletion(false, _) and
result = first(assertstmt.getMessage())
(
result = first(assertstmt.getMessage())
or
not exists(assertstmt.getMessage()) and
result.(AssertThrowNode).getAstNode() = assertstmt
)
or
last(assertstmt.getMessage(), n, NormalCompletion()) and
result.(AssertThrowNode).getAstNode() = assertstmt
)
or
// When expressions: