Merge pull request #21466 from owen-mc/go/add-nil-helper-predicate

Go: Add and use `exprRefersToNil` predicate
This commit is contained in:
Owen Mansel-Chan
2026-03-12 14:36:03 +00:00
committed by GitHub
6 changed files with 13 additions and 10 deletions

View File

@@ -2035,6 +2035,9 @@ class ConstantName extends ValueName {
override string getAPrimaryQlClass() { result = "ConstantName" }
}
/** Holds if `e` is an expression that refers to the `nil` constant. */
predicate exprRefersToNil(Expr e) { e.(ConstantName).getTarget() = Builtin::nil() }
/**
* A name referring to a variable.
*
@@ -2175,7 +2178,7 @@ private predicate isTypeExprTopDown(Expr e) {
or
e = any(TypeSwitchStmt s).getACase().getExpr(_) and
// special case: `nil` is allowed in a type case but isn't a type
not e = Builtin::nil().getAReference()
not exprRefersToNil(e)
or
e = any(SelectorExpr sel | isTypeExprTopDown(sel)).getBase()
or

View File

@@ -22,7 +22,7 @@ class Property extends TProperty {
isTrue = eq.getPolarity().booleanXor(e.getBoolValue().booleanXor(outcome))
or
this = IsNil(isTrue) and
e = Builtin::nil().getAReference() and
exprRefersToNil(e) and
isTrue = eq.getPolarity().booleanXor(outcome).booleanNot()
)
or

View File

@@ -560,7 +560,7 @@ private predicate onlyPossibleReturnOfBool(FuncDecl fd, FunctionOutput res, Node
*/
predicate possiblyReturnsNonNil(FuncDecl fd, FunctionOutput res, Node ret) {
ret = res.getEntryNode(fd) and
not ret.asExpr() = Builtin::nil().getAReference()
not exprRefersToNil(ret.asExpr())
}
/**
@@ -570,7 +570,7 @@ predicate possiblyReturnsNonNil(FuncDecl fd, FunctionOutput res, Node ret) {
private predicate onlyPossibleReturnOfNonNil(FuncDecl fd, FunctionOutput res, Node ret) {
possiblyReturnsNonNil(fd, res, ret) and
forall(Node otherRet | otherRet = res.getEntryNode(fd) and otherRet != ret |
otherRet.asExpr() = Builtin::nil().getAReference()
exprRefersToNil(otherRet.asExpr())
)
}
@@ -609,7 +609,7 @@ private predicate isCertainlyNotNil(DataFlow::Node node) {
*/
private predicate onlyPossibleReturnOfNil(FuncDecl fd, FunctionOutput res, DataFlow::Node ret) {
ret = res.getEntryNode(fd) and
ret.asExpr() = Builtin::nil().getAReference() and
exprRefersToNil(ret.asExpr()) and
forall(DataFlow::Node otherRet | otherRet = res.getEntryNode(fd) and otherRet != ret |
isCertainlyNotNil(otherRet)
)

View File

@@ -418,7 +418,7 @@ predicate functionEnsuresInputIsConstant(
forex(DataFlow::Node ret, IR::ReturnInstruction ri |
ret = outp.getEntryNode(fd) and
ri.getReturnStmt().getAnExpr() = ret.asExpr() and
ret.asExpr() = Builtin::nil().getAReference()
exprRefersToNil(ret.asExpr())
|
DataFlow::localFlow(inp.getExitNode(fd), _) and
mustPassConstantCaseTestToReach(ri, inp.getExitNode(fd))

View File

@@ -26,7 +26,7 @@ ControlFlow::Node nonGuardPredecessor(ControlFlow::Node nd) {
* Matches if `retval` is a constant or a struct composed wholly of constants.
*/
predicate isAllowedReturnValue(Expr retval) {
retval = Builtin::nil().getAReference()
exprRefersToNil(retval)
or
retval = Builtin::true_().getAReference()
or

View File

@@ -36,7 +36,7 @@ private class SensitiveStringCompareSink extends Sink {
not op1 = nonSensitiveOperand and
not (
// Comparisons with `nil` should be excluded.
nonSensitiveOperand = Builtin::nil().getAReference()
exprRefersToNil(nonSensitiveOperand)
or
// Comparisons with empty string should also be excluded.
nonSensitiveOperand.getStringValue().length() = 0
@@ -60,7 +60,7 @@ private class SensitiveCompareSink extends Sink {
not op1 = op2 and
not (
// Comparisons with `nil` should be excluded.
op2 = Builtin::nil().getAReference()
exprRefersToNil(op2)
or
// Comparisons with empty string should also be excluded.
op2.getStringValue().length() = 0
@@ -85,7 +85,7 @@ private class SensitiveStringSink extends Sink {
not op1 = op2 and
not (
// Comparisons with `nil` should be excluded.
op2 = Builtin::nil().getAReference()
exprRefersToNil(op2)
or
// Comparisons with empty string should also be excluded.
op2.getStringValue().length() = 0