Skip to content
Open
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
category: deprecated
---
* `ControlFlow::ConditionGuardNode` is now deprecated. Use the API from `semmle.go.controlflow.Guards` instead.
4 changes: 4 additions & 0 deletions go/ql/lib/change-notes/2026-08-17-shared-guards.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
category: feature
---
* The Go language library now instantiates the shared library `semmle.go.controlflow.Guards`, including the `Guard` and `GuardValue` classes and the `guardEnsures`, `guardEnsuresEq`, `guardEnsuresNeq`, and `guardEnsuresLeq` predicates.
7 changes: 7 additions & 0 deletions go/ql/lib/semmle/go/Expr.qll
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ overlay[local]
module;

import go
private import semmle.go.controlflow.ControlFlowGraphImpl

/**
* An expression.
Expand All @@ -17,6 +18,12 @@ import go
* ```
*/
class Expr extends @expr, ExprParent {
/** Gets the control-flow node associated with this expression. */
CfgImpl::Cfg::ControlFlowNode getControlFlowNode() { result.injects(this) }

/** Gets the basic block containing this expression. */
CfgImpl::Cfg::BasicBlock getBasicBlock() { result = this.getControlFlowNode().getBasicBlock() }

/**
* Gets the kind of this expression, which is an integer value representing the expression's
* node type.
Expand Down
56 changes: 42 additions & 14 deletions go/ql/lib/semmle/go/controlflow/ControlFlowGraph.qll
Original file line number Diff line number Diff line change
Expand Up @@ -258,10 +258,12 @@
}

/**
* DEPRECATED: Use `Guard` from `semmle.go.controlflow.Guards` instead.
*
* A control-flow node recording the fact that a certain expression has a known
* Boolean value at this point in the program.
*/
class ConditionGuardNode extends IR::Instruction {
deprecated class ConditionGuardNode extends IR::Instruction {
Expr cond;
boolean outcome;

Expand All @@ -280,7 +282,7 @@
)
}

private predicate ensuresAux(Expr expr, boolean b) {

Check warning

Code scanning / CodeQL

Candidate predicate not marked as `nomagic` Warning

Candidate predicate to
ensures
is not marked as nomagic.
expr = cond and b = outcome
or
expr = any(NotExpr ne | this.ensuresAux(ne, b.booleanNot())).getOperand()
Expand All @@ -292,43 +294,69 @@
b = false
}

/** Holds if this guard ensures that the result of `nd` is `b`. */
predicate ensures(DataFlow::Node nd, boolean b) {
/**
* DEPRECATED: Use `Guard.controls` from `semmle.go.controlflow.Guards`
* instead.
*
* Holds if this guard ensures that the result of `nd` is `b`.
*/
deprecated predicate ensures(DataFlow::Node nd, boolean b) {
this.ensuresAux(any(Expr e | nd = DataFlow::exprNode(e)), b)
}

/** Holds if this guard ensures that `lesser <= greater + bias` holds. */
predicate ensuresLeq(DataFlow::Node lesser, DataFlow::Node greater, int bias) {
/**
* DEPRECATED: Use `guardEnsuresLeq` from `semmle.go.controlflow.Guards`
* instead.
*
* Holds if this guard ensures that `lesser <= greater + bias` holds.
*/
deprecated predicate ensuresLeq(DataFlow::Node lesser, DataFlow::Node greater, int bias) {
exists(DataFlow::RelationalComparisonNode rel, boolean b |
this.ensures(rel, b) and
this.ensuresAux(rel.asExpr(), b) and
rel.leq(b, lesser, greater, bias)
)
or
this.ensuresEq(lesser, greater) and
exists(DataFlow::EqualityTestNode eq, boolean b |
this.ensuresAux(eq.asExpr(), b) and
eq.eq(b, lesser, greater)
) and
bias = 0
}

/** Holds if this guard ensures that `i = j` holds. */
predicate ensuresEq(DataFlow::Node i, DataFlow::Node j) {
/**
* DEPRECATED: Use `guardEnsuresEq` from `semmle.go.controlflow.Guards`
* instead.
*
* Holds if this guard ensures that `i = j` holds.
*/
deprecated predicate ensuresEq(DataFlow::Node i, DataFlow::Node j) {
exists(DataFlow::EqualityTestNode eq, boolean b |
this.ensures(eq, b) and
this.ensuresAux(eq.asExpr(), b) and
eq.eq(b, i, j)
)
}

/** Holds if this guard ensures that `i != j` holds. */
predicate ensuresNeq(DataFlow::Node i, DataFlow::Node j) {
/**
* DEPRECATED: Use `guardEnsuresNeq` from `semmle.go.controlflow.Guards`
* instead.
*
* Holds if this guard ensures that `i != j` holds.
*/
deprecated predicate ensuresNeq(DataFlow::Node i, DataFlow::Node j) {
exists(DataFlow::EqualityTestNode eq, boolean b |
this.ensures(eq, b.booleanNot()) and
this.ensuresAux(eq.asExpr(), b.booleanNot()) and
eq.eq(b, i, j)
)
}

/**
* DEPRECATED: Use `Guard.controls` from `semmle.go.controlflow.Guards`
* instead.
*
* Holds if this guard dominates basic block `bb`, that is, the guard
* is known to hold at `bb`.
*/
predicate dominates(ReachableBasicBlock bb) {
deprecated predicate dominates(ReachableBasicBlock bb) {
this = bb.getANode() or
this.dominates(bb.getImmediateDominator())
}
Expand Down
Loading
Loading