[clang] [NFC][analyzer] Eliminate NodeBuilder from ExprEngine visit methods and from their utility methods (PR #212186)
Gábor Tóthvári via cfe-commits
cfe-commits at lists.llvm.org
Sat Aug 1 04:57:17 PDT 2026
https://github.com/tigbr updated https://github.com/llvm/llvm-project/pull/212186
>From 89967a66b4a656feaf71921dbb2c841f8aef31d1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?=
<gabor.tothvari at ericsson.com>
Date: Thu, 23 Jul 2026 17:17:28 +0200
Subject: [PATCH 01/29] Remove `NodeBuilder` from
`ExprEngine::VisitCompoundLiteralExpr`.
---
clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 3e7973769f091..8e142334103b7 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -545,8 +545,6 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
void ExprEngine::VisitCompoundLiteralExpr(const CompoundLiteralExpr *CL,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- NodeBuilder B(Pred, Dst, *currBldrCtx);
-
ProgramStateRef State = Pred->getState();
const StackFrame *SF = Pred->getStackFrame();
@@ -564,7 +562,7 @@ void ExprEngine::VisitCompoundLiteralExpr(const CompoundLiteralExpr *CL,
V = CLLoc;
}
- B.generateNode(CL, Pred, State->BindExpr(CL, SF, V));
+ Dst.insert(Engine.makeNodeWithBinding(Pred, CL, V, State));
}
void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
>From 2ec7d9a1f249759ab50f6808ed619e9e15f0f72e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?=
<gabor.tothvari at ericsson.com>
Date: Fri, 24 Jul 2026 10:16:06 +0200
Subject: [PATCH 02/29] Remove `NodeBuilder` from
`ExprEngine::VisitUnaryExprOrTypeTraitExpr`.
---
clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp | 11 ++++-------
1 file changed, 4 insertions(+), 7 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 8e142334103b7..2b73a6e69132c 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -846,8 +846,6 @@ VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex,
getCheckerManager().runCheckersForPreStmt(CheckedSet, Pred, Ex, *this);
ExplodedNodeSet EvalSet;
- NodeBuilder Bldr(CheckedSet, EvalSet, *currBldrCtx);
-
QualType T = Ex->getTypeOfArgument();
for (ExplodedNode *N : CheckedSet) {
@@ -858,11 +856,13 @@ VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex,
// FIXME: Add support for VLA type arguments and VLA expressions.
// When that happens, we should probably refactor VLASizeChecker's code.
+ EvalSet.insert(N);
continue;
} else if (T->getAs<ObjCObjectType>()) {
// Some code tries to take the sizeof an ObjCObjectType, relying that
// the compiler has laid out its representation. Just report Unknown
// for these.
+ EvalSet.insert(N);
continue;
}
}
@@ -870,11 +870,8 @@ VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex,
APSInt Value = Ex->EvaluateKnownConstInt(getContext());
CharUnits amt = CharUnits::fromQuantity(Value.getZExtValue());
- ProgramStateRef state = N->getState();
- state = state->BindExpr(
- Ex, N->getStackFrame(),
- svalBuilder.makeIntVal(amt.getQuantity(), Ex->getType()));
- Bldr.generateNode(Ex, N, state);
+ SVal V = svalBuilder.makeIntVal(amt.getQuantity(), Ex->getType());
+ EvalSet.insert(Engine.makeNodeWithBinding(N, Ex, V));
}
getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, Ex, *this);
>From 1d53110853ef1e1ae431ec79f38cb075af7e539f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?=
<gabor.tothvari at ericsson.com>
Date: Fri, 24 Jul 2026 14:20:41 +0200
Subject: [PATCH 03/29] Remove `NodeBuilder` from
`ExprEngine::VisitGuardedExpr`.
---
clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 2b73a6e69132c..104a5074b6a22 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -762,7 +762,6 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex,
ExplodedNodeSet &Dst) {
assert(L && R);
- NodeBuilder B(Pred, Dst, *currBldrCtx);
ProgramStateRef state = Pred->getState();
const StackFrame *SF = Pred->getStackFrame();
const CFGBlock *SrcBlock = nullptr;
@@ -816,7 +815,7 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex,
getNumVisitedCurrent());
// Generate a new node with the binding from the appropriate path.
- B.generateNode(Ex, Pred, state->BindExpr(Ex, SF, V, true));
+ Dst.insert(Engine.makeNodeWithBinding(Pred, Ex, V));
}
void ExprEngine::
>From 67a9961ef9c48454fa8bc44fb8bc9dc8e4efc9ef Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?=
<gabor.tothvari at ericsson.com>
Date: Fri, 24 Jul 2026 14:28:04 +0200
Subject: [PATCH 04/29] Remove `NodeBuilder` from
`ExprEngine::VisitOffsetOfExpr`.
---
clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp | 10 +++-------
1 file changed, 3 insertions(+), 7 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 104a5074b6a22..752abdc1943ed 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -818,10 +818,8 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex,
Dst.insert(Engine.makeNodeWithBinding(Pred, Ex, V));
}
-void ExprEngine::
-VisitOffsetOfExpr(const OffsetOfExpr *OOE,
- ExplodedNode *Pred, ExplodedNodeSet &Dst) {
- NodeBuilder B(Pred, Dst, *currBldrCtx);
+void ExprEngine::VisitOffsetOfExpr(const OffsetOfExpr *OOE, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
Expr::EvalResult Result;
if (OOE->EvaluateAsInt(Result, getContext())) {
APSInt IV = Result.Val.getInt();
@@ -829,13 +827,11 @@ VisitOffsetOfExpr(const OffsetOfExpr *OOE,
assert(OOE->getType()->castAs<BuiltinType>()->isInteger());
assert(IV.isSigned() == OOE->getType()->isSignedIntegerType());
SVal X = svalBuilder.makeIntVal(IV);
- B.generateNode(OOE, Pred,
- Pred->getState()->BindExpr(OOE, Pred->getStackFrame(), X));
+ Dst.insert(Engine.makeNodeWithBinding(Pred, OOE, X));
}
// FIXME: Handle the case where __builtin_offsetof is not a constant.
}
-
void ExprEngine::
VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex,
ExplodedNode *Pred,
>From a4d10a4b90e5c5c8a84ddc73eaa9bf2bddf8666c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?=
<gabor.tothvari at ericsson.com>
Date: Fri, 24 Jul 2026 15:35:00 +0200
Subject: [PATCH 05/29] Remove `NodeBuilder` from `ExprEngine::evalLocation`.
---
clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 24 ++++++++++----------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 7669b65818272..b52a295c69536 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -3661,23 +3661,20 @@ void ExprEngine::evalLoad(ExplodedNodeSet &Dst,
}
}
-void ExprEngine::evalLocation(ExplodedNodeSet &Dst,
- const Stmt *NodeEx,
- const Stmt *BoundEx,
- ExplodedNode *Pred,
- ProgramStateRef state,
- SVal location,
+void ExprEngine::evalLocation(ExplodedNodeSet &Dst, const Stmt *NodeEx,
+ const Stmt *BoundEx, ExplodedNode *Pred,
+ ProgramStateRef state, SVal location,
bool isLoad) {
- NodeBuilder BldrTop(Pred, Dst, *currBldrCtx);
// Early checks for performance reason.
if (location.isUnknown()) {
+ Dst.insert(Pred);
return;
}
ExplodedNodeSet Src;
- BldrTop.takeNodes(Pred);
- NodeBuilder Bldr(Pred, Src, *currBldrCtx);
- if (Pred->getState() != state) {
+ if (Pred->getState() == state) {
+ Src.insert(Pred);
+ } else {
// Associate this new state with an ExplodedNode.
// FIXME: If I pass null tag, the graph is incorrect, e.g for
// int *p;
@@ -3688,12 +3685,15 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst,
// "Variable 'p' initialized to a null pointer value"
static SimpleProgramPointTag tag(TagProviderName, "Location");
- Bldr.generateNode(NodeEx, Pred, state, &tag);
+ const ProgramPoint &L = ProgramPoint::getProgramPoint(
+ NodeEx, ProgramPoint::PostStmtKind, Pred->getStackFrame(), &tag);
+ Src.insert(Engine.makeNode(L, state, Pred));
}
+
ExplodedNodeSet Tmp;
getCheckerManager().runCheckersForLocation(Tmp, Src, location, isLoad,
NodeEx, BoundEx, *this);
- BldrTop.addNodes(Tmp);
+ Dst.insert(Tmp);
}
std::pair<const ProgramPointTag *, const ProgramPointTag *>
>From 7442b7c54ac4bfa656d98f05dcbe2bce6c5f9342 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?=
<gabor.tothvari at ericsson.com>
Date: Fri, 24 Jul 2026 15:50:10 +0200
Subject: [PATCH 06/29] Remove `NodeBuilder` from
`ExprEngine::VisitLogicalExpr`.
---
clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 752abdc1943ed..d10677b02be52 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -683,7 +683,6 @@ void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred,
assert(B->getOpcode() == BO_LAnd ||
B->getOpcode() == BO_LOr);
- NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
ProgramStateRef state = Pred->getState();
if (B->getType()->isVectorType()) {
@@ -692,7 +691,7 @@ void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred,
// logical operators on vectors are not short-circuit. Currently they are
// modeled as short-circuit in Clang CFG but this is incorrect.
// Do not set the value for the expression. It'd be UnknownVal by default.
- Bldr.generateNode(B, Pred, state);
+ Dst.insert(Engine.makePostStmtNode(B, state, Pred));
return;
}
@@ -704,7 +703,7 @@ void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred,
(void) P;
if (N->pred_size() != 1) {
// We failed to track back where we came from.
- Bldr.generateNode(B, Pred, state);
+ Dst.insert(Engine.makePostStmtNode(B, state, Pred));
return;
}
N = *N->pred_begin();
@@ -712,7 +711,7 @@ void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred,
if (N->pred_size() != 1) {
// We failed to track back where we came from.
- Bldr.generateNode(B, Pred, state);
+ Dst.insert(Engine.makePostStmtNode(B, state, Pred));
return;
}
@@ -752,7 +751,7 @@ void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred,
svalBuilder.makeZeroVal(RHS->getType()), B->getType());
}
}
- Bldr.generateNode(B, Pred, state->BindExpr(B, Pred->getStackFrame(), X));
+ Dst.insert(Engine.makeNodeWithBinding(Pred, B, X));
}
void ExprEngine::VisitGuardedExpr(const Expr *Ex,
>From 14b4954873a3e1bb6da6cfcaccd604104f06f318 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?=
<gabor.tothvari at ericsson.com>
Date: Fri, 24 Jul 2026 17:33:57 +0200
Subject: [PATCH 07/29] Remove `NodeBuilder` from `ExprEngine::VisitCast`.
---
.../Core/PathSensitive/ExprEngine.h | 2 +-
clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp | 51 ++++++++-----------
2 files changed, 21 insertions(+), 32 deletions(-)
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index b725db1d6256f..f3b4f6f3cecb1 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -679,7 +679,7 @@ class ExprEngine {
ProgramStateRef handleLValueBitCast(ProgramStateRef state, const Expr *Ex,
const StackFrame *SF, QualType T,
QualType ExTy, const CastExpr *CastE,
- NodeBuilder &Bldr, ExplodedNode *Pred);
+ ExplodedNodeSet &Dst, ExplodedNode *Pred);
public:
SVal evalBinOp(ProgramStateRef ST, BinaryOperator::Opcode Op,
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index d10677b02be52..fcce70f7ffde2 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -226,7 +226,7 @@ void ExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred,
ProgramStateRef
ExprEngine::handleLValueBitCast(ProgramStateRef state, const Expr *Ex,
const StackFrame *SF, QualType T, QualType ExTy,
- const CastExpr *CastE, NodeBuilder &Bldr,
+ const CastExpr *CastE, ExplodedNodeSet &Dst,
ExplodedNode *Pred) {
if (T->isLValueReferenceType()) {
assert(!CastE->getType()->isLValueReferenceType());
@@ -247,7 +247,7 @@ ExprEngine::handleLValueBitCast(ProgramStateRef state, const Expr *Ex,
if (V.isUnknown() && !OrigV.isUnknown()) {
state = escapeValues(state, OrigV, PSK_EscapeOther);
}
- Bldr.generateNode(CastE, Pred, state);
+ Dst.insert(Engine.makePostStmtNode(CastE, state, Pred));
return state;
}
@@ -279,7 +279,6 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
}
// Simulate the operation that actually casts the original value to a new
// value of the destination type :
- NodeBuilder Bldr(DstEvalLoc, Dst, *currBldrCtx);
for (ExplodedNode *Node : DstEvalLoc) {
ProgramStateRef State = Node->getState();
@@ -294,8 +293,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
CastedV = svalBuilder.evalCast(svalBuilder.simplifySVal(State, OrigV),
CastE->getType(), Ex->getType());
}
- State = State->BindExpr(CastE, SF, CastedV);
- Bldr.generateNode(CastE, Node, State);
+ Dst.insert(Engine.makeNodeWithBinding(Node, CastE, CastedV));
}
return;
}
@@ -307,7 +305,6 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
if (const ExplicitCastExpr *ExCast=dyn_cast_or_null<ExplicitCastExpr>(CastE))
T = ExCast->getTypeAsWritten();
- NodeBuilder Bldr(DstPreStmt, Dst, *currBldrCtx);
for (ExplodedNode *Pred : DstPreStmt) {
ProgramStateRef state = Pred->getState();
const StackFrame *SF = Pred->getStackFrame();
@@ -317,6 +314,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
case CK_LValueToRValueBitCast:
llvm_unreachable("LValueToRValue casts handled earlier.");
case CK_ToVoid:
+ Dst.insert(Pred);
continue;
// The analyzer doesn't do anything special with these casts,
// since it understands retain/release semantics already.
@@ -341,8 +339,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
ProgramStateRef state = Pred->getState();
const StackFrame *SF = Pred->getStackFrame();
SVal V = state->getSVal(Ex, SF);
- state = state->BindExpr(CastE, SF, V);
- Bldr.generateNode(CastE, Pred, state);
+ Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, V));
continue;
}
case CK_MemberPointerToBoolean:
@@ -352,12 +349,11 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
if (PTMSV)
V = svalBuilder.makeTruthVal(!PTMSV->isNullMemberPointer(), ExTy);
if (V.isUndef() || PTMSV) {
- state = state->BindExpr(CastE, SF, V);
- Bldr.generateNode(CastE, Pred, state);
+ Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, V));
continue;
}
// Explicitly proceed with default handler for this case cascade.
- state = handleLValueBitCast(state, Ex, SF, T, ExTy, CastE, Bldr, Pred);
+ state = handleLValueBitCast(state, Ex, SF, T, ExTy, CastE, Dst, Pred);
continue;
}
case CK_Dependent:
@@ -369,12 +365,11 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
case CK_PointerToIntegral: {
SVal V = state->getSVal(Ex, SF);
if (isa<nonloc::PointerToMember>(V)) {
- state = state->BindExpr(CastE, SF, UnknownVal());
- Bldr.generateNode(CastE, Pred, state);
+ Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, V));
continue;
}
// Explicitly proceed with default handler for this case cascade.
- state = handleLValueBitCast(state, Ex, SF, T, ExTy, CastE, Bldr, Pred);
+ state = handleLValueBitCast(state, Ex, SF, T, ExTy, CastE, Dst, Pred);
continue;
}
case CK_IntegralToBoolean:
@@ -405,7 +400,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
case CK_FixedPointToBoolean:
case CK_FixedPointToIntegral:
case CK_IntegralToFixedPoint: {
- state = handleLValueBitCast(state, Ex, SF, T, ExTy, CastE, Bldr, Pred);
+ state = handleLValueBitCast(state, Ex, SF, T, ExTy, CastE, Dst, Pred);
continue;
}
case CK_IntegralCast: {
@@ -415,8 +410,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
V = svalBuilder.evalCast(V, T, ExTy);
else
V = svalBuilder.evalIntegralCast(state, V, T, ExTy);
- state = state->BindExpr(CastE, SF, V);
- Bldr.generateNode(CastE, Pred, state);
+ Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, V));
continue;
}
case CK_DerivedToBase:
@@ -424,8 +418,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
// For DerivedToBase cast, delegate to the store manager.
SVal val = state->getSVal(Ex, SF);
val = getStoreManager().evalDerivedToBase(val, CastE);
- state = state->BindExpr(CastE, SF, val);
- Bldr.generateNode(CastE, Pred, state);
+ Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, val));
continue;
}
// Handle C++ dyn_cast.
@@ -451,7 +444,8 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
if (T->isReferenceType()) {
// A bad_cast exception is thrown if input value is a reference.
// Currently, we model this, by generating a sink.
- Bldr.generateSink(CastE, Pred, state);
+ Dst.insert(Engine.makePostStmtNode(CastE, state, Pred,
+ /* MarkAsSink */ true));
continue;
} else {
// If the cast fails on a pointer, bind to 0.
@@ -469,7 +463,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
// Else, bind to the derived region value.
state = state->BindExpr(CastE, SF, val);
}
- Bldr.generateNode(CastE, Pred, state);
+ Dst.insert(Engine.makePostStmtNode(CastE, state, Pred));
continue;
}
case CK_BaseToDerived: {
@@ -489,20 +483,17 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
/*symbolTag=*/nullptr, getCFGElementRef(), SF, resultType,
getNumVisitedCurrent());
}
- state = state->BindExpr(CastE, SF, val);
- Bldr.generateNode(CastE, Pred, state);
+ Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, val));
continue;
}
case CK_NullToPointer: {
SVal V = svalBuilder.makeNullWithType(CastE->getType());
- state = state->BindExpr(CastE, SF, V);
- Bldr.generateNode(CastE, Pred, state);
+ Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, V));
continue;
}
case CK_NullToMemberPointer: {
SVal V = svalBuilder.getMemberPointer(nullptr);
- state = state->BindExpr(CastE, SF, V);
- Bldr.generateNode(CastE, Pred, state);
+ Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, V));
continue;
}
case CK_DerivedToBaseMemberPointer:
@@ -513,8 +504,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
SVal CastedPTMSV =
svalBuilder.makePointerToMember(getBasicVals().accumCXXBase(
CastE->path(), *PTMSV, CastE->getCastKind()));
- state = state->BindExpr(CastE, SF, CastedPTMSV);
- Bldr.generateNode(CastE, Pred, state);
+ Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, CastedPTMSV));
continue;
}
// Explicitly proceed with default handler for this case cascade.
@@ -534,8 +524,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
SVal result = svalBuilder.conjureSymbolVal(
/*symbolTag=*/nullptr, getCFGElementRef(), SF, resultType,
getNumVisitedCurrent());
- state = state->BindExpr(CastE, SF, result);
- Bldr.generateNode(CastE, Pred, state);
+ Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, result));
continue;
}
}
>From dc876aaf46d65273103139661435e7f9b0d74161 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?=
<gabor.tothvari at ericsson.com>
Date: Fri, 24 Jul 2026 17:49:18 +0200
Subject: [PATCH 08/29] Remove `NodeBuilder` from `ExprEngine::VisitDeclStmt`.
---
clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp | 13 ++++---------
1 file changed, 4 insertions(+), 9 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index fcce70f7ffde2..07ad6a42dfbef 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -603,7 +603,6 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, DS, *this);
ExplodedNodeSet dstEvaluated;
- NodeBuilder B(dstPreVisit, dstEvaluated, *currBldrCtx);
for (ExplodedNodeSet::iterator I = dstPreVisit.begin(), E = dstPreVisit.end();
I!=E; ++I) {
ExplodedNode *N = *I;
@@ -622,7 +621,7 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
state = finishObjectConstruction(state, DS, SF);
// We constructed the object directly in the variable.
// No need to bind anything.
- B.generateNode(DS, UpdatedN, state);
+ dstEvaluated.insert(Engine.makePostStmtNode(DS, state, UpdatedN));
} else {
// Recover some path-sensitivity if a scalar value evaluated to
// UnknownVal.
@@ -637,19 +636,15 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
getNumVisitedCurrent());
}
-
- B.takeNodes(UpdatedN);
- ExplodedNodeSet Dst2;
- evalBind(Dst2, DS, UpdatedN, state->getLValue(VD, SF), InitVal, true);
- B.addNodes(Dst2);
+ evalBind(dstEvaluated, DS, UpdatedN, state->getLValue(VD, SF), InitVal, true);
}
}
else {
- B.generateNode(DS, N, state);
+ dstEvaluated.insert(Engine.makePostStmtNode(DS, state, N));
}
}
- getCheckerManager().runCheckersForPostStmt(Dst, B.getResults(), DS, *this);
+ getCheckerManager().runCheckersForPostStmt(Dst, dstEvaluated, DS, *this);
}
void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred,
>From 0c076fd66c2248331242c2d82fe16b23a3b15702 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?=
<gabor.tothvari at ericsson.com>
Date: Fri, 24 Jul 2026 17:58:08 +0200
Subject: [PATCH 09/29] Remove `NodeBuilder` from
`ExprEngine::VisitIncrementDecrementOperator`.
---
clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp | 12 ++----------
1 file changed, 2 insertions(+), 10 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 07ad6a42dfbef..95577073d7065 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -1007,7 +1007,6 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U,
evalLoad(Tmp, U, Ex, Pred, state, loc);
ExplodedNodeSet Dst2;
- NodeBuilder Bldr(Tmp, Dst2, *currBldrCtx);
for (ExplodedNode *N : Tmp) {
state = N->getState();
assert(SF == N->getStackFrame());
@@ -1018,11 +1017,7 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U,
state = state->BindExpr(U, SF, V2_untested);
// Perform the store, so that the uninitialized value detection happens.
- Bldr.takeNodes(N);
- ExplodedNodeSet Dst3;
- evalStore(Dst3, U, Ex, N, state, loc, V2_untested);
- Bldr.addNodes(Dst3);
-
+ evalStore(Dst2, U, Ex, N, state, loc, V2_untested);
continue;
}
DefinedSVal V2 = V2_untested.castAs<DefinedSVal>();
@@ -1086,10 +1081,7 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U,
state = state->BindExpr(U, SF, U->isPostfix() ? V2 : Result);
// Perform the store.
- Bldr.takeNodes(N);
- ExplodedNodeSet Dst3;
- evalStore(Dst3, U, Ex, N, state, loc, Result);
- Bldr.addNodes(Dst3);
+ evalStore(Dst2, U, Ex, N, state, loc, Result);
}
Dst.insert(Dst2);
}
>From 91d848a98f7b7eec7817a2cef35a2963e0cc08ac Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?=
<gabor.tothvari at ericsson.com>
Date: Fri, 24 Jul 2026 18:17:56 +0200
Subject: [PATCH 10/29] Remove `NodeBuilder` from `ExprEngine::evalLoad`.
---
clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index b52a295c69536..9cb2dc2e25198 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -3640,9 +3640,10 @@ void ExprEngine::evalLoad(ExplodedNodeSet &Dst,
if (Tmp.empty())
return;
- NodeBuilder Bldr(Tmp, Dst, *currBldrCtx);
- if (location.isUndef())
+ if (location.isUndef()) {
+ Dst.insert(Tmp);
return;
+ }
// Proceed with the load.
for (const auto I : Tmp) {
@@ -3655,9 +3656,10 @@ void ExprEngine::evalLoad(ExplodedNodeSet &Dst,
V = state->getSVal(location.castAs<Loc>(), LoadTy);
}
- Bldr.generateNode(NodeEx, I,
- state->BindExpr(BoundEx, I->getStackFrame(), V), tag,
- ProgramPoint::PostLoadKind);
+ const auto *SF = I->getStackFrame();
+ const auto &Loc = ProgramPoint::getProgramPoint(
+ NodeEx, ProgramPoint::PostLoadKind, SF, tag);
+ Dst.insert(Engine.makeNode(Loc, state->BindExpr(BoundEx, SF, V), I));
}
}
>From 4a5f929757a2c8a2435ec08e33007e2c270b089f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?=
<gabor.tothvari at ericsson.com>
Date: Fri, 24 Jul 2026 18:22:12 +0200
Subject: [PATCH 11/29] Pass EvalSet to `evalLoad` directly since it no longer
uses `NodeBuilder`.
---
clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 9cb2dc2e25198..4572aa43a6355 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -3351,7 +3351,6 @@ void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred,
for (const auto I : CheckedSet)
VisitCommonDeclRefExpr(M, Member, I, EvalSet);
} else {
- ExplodedNodeSet Tmp;
for (const auto I : CheckedSet) {
ProgramStateRef state = I->getState();
@@ -3412,10 +3411,7 @@ void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred,
EvalSet.insert(Engine.makeNodeWithBinding(
I, M, L, state, ProgramPoint::PostLValueKind));
} else {
- // FIXME: When evalLoad no longer uses NodeBuilders, eliminate Tmp and
- // pass EvalSet as the first argument of evalLoad.
- evalLoad(Tmp, M, M, I, state, L);
- EvalSet.insert(Tmp);
+ evalLoad(EvalSet, M, M, I, state, L);
}
}
}
>From cb3d806f7bedade23978d400015e8f8be8d2a7de Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?=
<gabor.tothvari at ericsson.com>
Date: Fri, 24 Jul 2026 18:28:39 +0200
Subject: [PATCH 12/29] Remove `NodeBuilder` from
`ExprEngine::CreateCXXTemporaryObject`.
---
clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 9c10bcbdc4c0d..38df71120a7f9 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -33,13 +33,12 @@ using namespace ento;
void ExprEngine::CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
const Expr *tempExpr = ME->getSubExpr()->IgnoreParens();
ProgramStateRef state = Pred->getState();
const StackFrame *SF = Pred->getStackFrame();
state = createTemporaryRegionIfNeeded(state, SF, tempExpr, ME);
- Bldr.generateNode(ME, Pred, state);
+ Dst.insert(Engine.makePostStmtNode(ME, state, Pred));
}
void ExprEngine::performTrivialCopy(ExplodedNodeSet &Dst, ExplodedNode *Pred,
>From e06a2208ab6bd5d43101517699f99eee0827de70 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?=
<gabor.tothvari at ericsson.com>
Date: Fri, 24 Jul 2026 18:32:46 +0200
Subject: [PATCH 13/29] Remove `NodeBuilder` from
`ExprEngine::VisitCXXCatchStmt`.
---
clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 38df71120a7f9..69938d26a613b 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -1114,8 +1114,7 @@ void ExprEngine::VisitCXXCatchStmt(const CXXCatchStmt *CS, ExplodedNode *Pred,
ProgramStateRef state = Pred->getState();
state = state->bindLoc(state->getLValue(VD, SF), V, SF);
- NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
- Bldr.generateNode(CS, Pred, state);
+ Dst.insert(Engine.makePostStmtNode(CS, state, Pred));
}
void ExprEngine::VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred,
>From cd29809eeb04c8a3b6b3612ce858ef3c19066239 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?=
<gabor.tothvari at ericsson.com>
Date: Fri, 24 Jul 2026 18:40:31 +0200
Subject: [PATCH 14/29] Remove `NodeBuilder` from
`ExprEngine::VisitCXXThisExpr`.
---
clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 69938d26a613b..ad3e7e826564a 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -1119,8 +1119,6 @@ void ExprEngine::VisitCXXCatchStmt(const CXXCatchStmt *CS, ExplodedNode *Pred,
void ExprEngine::VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
-
// Get the this object region from StoreManager.
const StackFrame *SF = Pred->getStackFrame();
const MemRegion *R = svalBuilder.getRegionManager().getCXXThisRegion(
@@ -1128,7 +1126,7 @@ void ExprEngine::VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred,
ProgramStateRef state = Pred->getState();
SVal V = state->getSVal(loc::MemRegionVal(R));
- Bldr.generateNode(TE, Pred, state->BindExpr(TE, SF, V));
+ Dst.insert(Engine.makeNodeWithBinding(Pred, TE, V));
}
void ExprEngine::VisitLambdaExpr(const LambdaExpr *LE, ExplodedNode *Pred,
>From 5bcf78e3879e2ca9c42ab2d2484f1317a74ee7e5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?=
<gabor.tothvari at ericsson.com>
Date: Fri, 24 Jul 2026 18:58:38 +0200
Subject: [PATCH 15/29] Remove `NodeBuilder` from
`ExprEngine::VisitLambdaExpr`.
---
clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index ad3e7e826564a..df801e10a974e 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -1191,14 +1191,12 @@ void ExprEngine::VisitLambdaExpr(const LambdaExpr *LE, ExplodedNode *Pred,
// to be an RValue.
SVal LambdaRVal = State->getSVal(R);
- ExplodedNodeSet Tmp;
- NodeBuilder Bldr(Pred, Tmp, *currBldrCtx);
// FIXME: is this the right program point kind?
- Bldr.generateNode(LE, Pred, State->BindExpr(LE, SF, LambdaRVal), nullptr,
- ProgramPoint::PostLValueKind);
+ ExplodedNode *N = Engine.makeNodeWithBinding(Pred, LE, LambdaRVal, State,
+ ProgramPoint::PostLValueKind);
// FIXME: Move all post/pre visits to ::Visit().
- getCheckerManager().runCheckersForPostStmt(Dst, Tmp, LE, *this);
+ getCheckerManager().runCheckersForPostStmt(Dst, N, LE, *this);
}
void ExprEngine::VisitAttributedStmt(const AttributedStmt *A,
>From a423c005d9935d782c45d741a6e2e7216fe61625 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?=
<gabor.tothvari at ericsson.com>
Date: Sat, 25 Jul 2026 11:10:47 +0200
Subject: [PATCH 16/29] Remove `NodeBuilder` from
`ExprEngine::VisitCXXDestructor`.
---
clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index df801e10a974e..f88df584f654c 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -820,8 +820,7 @@ void ExprEngine::VisitCXXDestructor(QualType ObjectType,
// FIXME: PostImplicitCall with a null decl may crash elsewhere anyway.
PostImplicitCall PP(/*Decl=*/nullptr, S->getEndLoc(), SF,
getCFGElementRef(), &T);
- NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
- Bldr.generateNode(PP, Pred->getState(), Pred);
+ Dst.insert(Engine.makeNode(PP, Pred->getState(), Pred));
return;
}
@@ -836,9 +835,9 @@ void ExprEngine::VisitCXXDestructor(QualType ObjectType,
Dest = MRMgr.getCXXTempObjectRegion(E, Pred->getStackFrame());
} else {
static SimpleProgramPointTag T("ExprEngine", "SkipInvalidDestructor");
- NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
- Bldr.generateSink(Pred->getLocation().withTag(&T),
- Pred->getState(), Pred);
+ Dst.insert(Engine.makeNode(Pred->getLocation().withTag(&T),
+ Pred->getState(), Pred,
+ /* MarkAsSink */ true));
return;
}
}
>From 670143668f9c7465ff7992cee300b10a1a88c7a4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?=
<gabor.tothvari at ericsson.com>
Date: Sat, 25 Jul 2026 11:52:40 +0200
Subject: [PATCH 17/29] Remove `NodeBuilder` from
`ExprEngine::handleConstructor`.
---
.../lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 26 +++++++++----------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index f88df584f654c..14e3170e76b0a 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -541,11 +541,10 @@ void ExprEngine::handleConstructor(const Expr *E,
// it in fact constructs into the correct target. This constructor can
// therefore be skipped.
Target = *ElidedTarget;
- NodeBuilder Bldr(Pred, destNodes, *currBldrCtx);
State = finishObjectConstruction(State, CE, SF);
if (auto L = Target.getAs<Loc>())
State = State->BindExpr(CE, SF, State->getSVal(*L, CE->getType()));
- Bldr.generateNode(CE, Pred, State);
+ destNodes.insert(Engine.makePostStmtNode(CE, State, Pred));
return;
}
}
@@ -582,10 +581,11 @@ void ExprEngine::handleConstructor(const Expr *E,
// No element construction will happen in a 0 size array.
if (isZeroSizeArray()) {
- NodeBuilder Bldr(Pred, destNodes, *currBldrCtx);
static SimpleProgramPointTag T{"ExprEngine",
"Skipping 0 size array construction"};
- Bldr.generateNode(CE, Pred, State, &T);
+ const ProgramPoint &P = ProgramPoint::getProgramPoint(
+ CE, ProgramPoint::PostStmtKind, Pred->getStackFrame(), &T);
+ destNodes.insert(Engine.makeNode(P, State, Pred));
return;
}
@@ -663,10 +663,9 @@ void ExprEngine::handleConstructor(const Expr *E,
if (State != Pred->getState()) {
static SimpleProgramPointTag T("ExprEngine",
"Prepare for object construction");
- ExplodedNodeSet DstPrepare;
- NodeBuilder BldrPrepare(Pred, DstPrepare, *currBldrCtx);
- Pred =
- BldrPrepare.generateNode(E, Pred, State, &T, ProgramPoint::PreStmtKind);
+ const ProgramPoint &P = ProgramPoint::getProgramPoint(
+ E, ProgramPoint::PreStmtKind, Pred->getStackFrame(), &T);
+ Pred = Engine.makeNode(P, State, Pred);
if (!Pred)
return;
}
@@ -685,7 +684,6 @@ void ExprEngine::handleConstructor(const Expr *E,
ExplodedNodeSet PreInitialized;
if (CE) {
// FIXME: Is it possible and/or useful to do this before PreStmt?
- NodeBuilder Bldr(DstPreVisit, PreInitialized, *currBldrCtx);
for (ExplodedNode *N : DstPreVisit) {
ProgramStateRef State = N->getState();
if (CE->requiresZeroInitialization()) {
@@ -708,8 +706,9 @@ void ExprEngine::handleConstructor(const Expr *E,
State = State->bindDefaultZero(Target, SF);
}
- Bldr.generateNode(CE, N, State, /*tag=*/nullptr,
- ProgramPoint::PreStmtKind);
+ const ProgramPoint &P = ProgramPoint::getProgramPoint(
+ CE, ProgramPoint::PreStmtKind, N->getStackFrame(), /*tag=*/nullptr);
+ PreInitialized.insert(Engine.makeNode(P, State, N));
}
} else {
PreInitialized = DstPreVisit;
@@ -742,7 +741,6 @@ void ExprEngine::handleConstructor(const Expr *E,
// later (for life-time extended temporaries) -- but avoids infeasible
// paths when no-return temporary destructors are used for assertions.
ExplodedNodeSet DstEvaluatedPostProcessed;
- NodeBuilder Bldr(DstEvaluated, DstEvaluatedPostProcessed, *currBldrCtx);
const AnalysisDeclContext *ADC = SF->getAnalysisDeclContext();
if (!ADC->getCFGBuildOptions().AddTemporaryDtors) {
if (llvm::isa_and_nonnull<CXXTempObjectRegion,
@@ -762,7 +760,8 @@ void ExprEngine::handleConstructor(const Expr *E,
"We should not have inlined this constructor!");
for (ExplodedNode *N : DstEvaluated) {
- Bldr.generateSink(E, N, N->getState());
+ DstEvaluatedPostProcessed.insert(Engine.makePostStmtNode(
+ E, N->getState(), N, /* MarkAsSink */ true));
}
// There is no need to run the PostCall and PostStmt checker
@@ -772,6 +771,7 @@ void ExprEngine::handleConstructor(const Expr *E,
}
}
+ DstEvaluatedPostProcessed.insert(DstEvaluated);
ExplodedNodeSet DstPostArgumentCleanup;
for (ExplodedNode *I : DstEvaluatedPostProcessed)
finishArgumentConstruction(DstPostArgumentCleanup, I, *Call);
>From c3cc1b1a97b8a0d412ae80ed42c338902d79ff06 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?=
<gabor.tothvari at ericsson.com>
Date: Sat, 25 Jul 2026 12:06:51 +0200
Subject: [PATCH 18/29] Remove `NodeBuilder` from
`ExprEngine::VisitCXXNewAllocatorCall`.
---
clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 14e3170e76b0a..54ec3ad37d293 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -895,7 +895,6 @@ void ExprEngine::VisitCXXNewAllocatorCall(const CXXNewExpr *CNE,
// Store return value of operator new() for future use, until the actual
// CXXNewExpr gets processed.
ExplodedNodeSet DstPostValue;
- NodeBuilder ValueBldr(DstPostCall, DstPostValue, *currBldrCtx);
for (ExplodedNode *I : DstPostCall) {
// FIXME: Because CNE serves as the "call site" for the allocator (due to
// lack of a better expression in the AST), the conjured return value symbol
@@ -928,8 +927,8 @@ void ExprEngine::VisitCXXNewAllocatorCall(const CXXNewExpr *CNE,
State = State->assume(RetVal.castAs<DefinedOrUnknownSVal>(), true);
}
- ValueBldr.generateNode(CNE, I,
- addObjectUnderConstruction(State, CNE, SF, RetVal));
+ DstPostValue.insert(Engine.makePostStmtNode(
+ CNE, addObjectUnderConstruction(State, CNE, SF, RetVal), I));
}
ExplodedNodeSet DstPostPostCallCallback;
>From 190299e77e7fbddd04d482ffc178e2bc84ee691f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?=
<gabor.tothvari at ericsson.com>
Date: Sat, 25 Jul 2026 17:22:17 +0200
Subject: [PATCH 19/29] Remove `NodeBuilder` from
`ExprEngine::VisitCXXNewExpr`.
---
.../lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 20 ++++++++-----------
1 file changed, 8 insertions(+), 12 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 54ec3ad37d293..1d7479680d599 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -1000,8 +1000,6 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
State = State->assume(*dSymVal, true);
}
- NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
-
SVal Result = symVal;
if (CNE->isArray()) {
@@ -1024,23 +1022,21 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
// If the array is list initialized, we bind the initializer list to the
// memory region here, otherwise we would lose it.
if (isInitList) {
- Bldr.takeNodes(Pred);
- Pred = Bldr.generateNode(CNE, Pred, State);
+ Pred = Engine.makePostStmtNode(CNE, State, Pred);
SVal V = State->getSVal(Init, SF);
ExplodedNodeSet evaluated;
evalBind(evaluated, CNE, Pred, Result, V, true);
- Bldr.takeNodes(Pred);
- Bldr.addNodes(evaluated);
+ Dst.insert(evaluated);
Pred = *evaluated.begin();
State = Pred->getState();
}
}
- State = State->BindExpr(CNE, Pred->getStackFrame(), Result);
- Bldr.generateNode(CNE, Pred, State);
+ Dst.erase(Pred);
+ Dst.insert(Engine.makeNodeWithBinding(Pred, CNE, Result, State));
return;
}
@@ -1056,8 +1052,8 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
}
// Bind the address of the object, then check to see if we cached out.
- State = State->BindExpr(CNE, SF, Result);
- ExplodedNode *NewN = Bldr.generateNode(CNE, Pred, State);
+ ExplodedNode *NewN = Engine.makeNodeWithBinding(Pred, CNE, Result, State);
+ Dst.insert(NewN);
if (!NewN)
return;
@@ -1065,8 +1061,8 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
// initializer. Copy the value over.
if (const Expr *Init = CNE->getInitializer()) {
if (!isa<CXXConstructExpr>(Init)) {
- assert(Bldr.getResults().size() == 1);
- Bldr.takeNodes(NewN);
+ assert(Dst.size() == 1);
+ Dst.erase(NewN);
evalBind(Dst, CNE, NewN, Result, State->getSVal(Init, SF),
/*FirstInit=*/IsStandardGlobalOpNewFunction);
}
>From e2c3199d02ebafa4e7bb3734c0d53f1770d4378f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?=
<gabor.tothvari at ericsson.com>
Date: Mon, 27 Jul 2026 09:21:32 +0200
Subject: [PATCH 20/29] Formatting.
---
clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp | 7 ++++---
clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 2 +-
2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 95577073d7065..bf48a8955197f 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -621,7 +621,7 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
state = finishObjectConstruction(state, DS, SF);
// We constructed the object directly in the variable.
// No need to bind anything.
- dstEvaluated.insert(Engine.makePostStmtNode(DS, state, UpdatedN));
+ dstEvaluated.insert(Engine.makePostStmtNode(DS, state, UpdatedN));
} else {
// Recover some path-sensitivity if a scalar value evaluated to
// UnknownVal.
@@ -636,11 +636,12 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
getNumVisitedCurrent());
}
- evalBind(dstEvaluated, DS, UpdatedN, state->getLValue(VD, SF), InitVal, true);
+ evalBind(dstEvaluated, DS, UpdatedN, state->getLValue(VD, SF), InitVal,
+ true);
}
}
else {
- dstEvaluated.insert(Engine.makePostStmtNode(DS, state, N));
+ dstEvaluated.insert(Engine.makePostStmtNode(DS, state, N));
}
}
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 1d7479680d599..0f90a7195032a 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -1112,7 +1112,7 @@ void ExprEngine::VisitCXXCatchStmt(const CXXCatchStmt *CS, ExplodedNode *Pred,
}
void ExprEngine::VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {
+ ExplodedNodeSet &Dst) {
// Get the this object region from StoreManager.
const StackFrame *SF = Pred->getStackFrame();
const MemRegion *R = svalBuilder.getRegionManager().getCXXThisRegion(
>From 316711adf34cd43f14e6a339a98ec0b5344ae152 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?=
<gabor.tothvari at ericsson.com>
Date: Mon, 27 Jul 2026 14:11:21 +0200
Subject: [PATCH 21/29] Fix accidental change of bind value back to
`UnknownVal()`.
---
clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index bf48a8955197f..d22117544f17e 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -365,7 +365,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
case CK_PointerToIntegral: {
SVal V = state->getSVal(Ex, SF);
if (isa<nonloc::PointerToMember>(V)) {
- Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, V));
+ Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, UnknownVal()));
continue;
}
// Explicitly proceed with default handler for this case cascade.
>From b43428d14a0decdec22a1a7b4bac3b9f86909e29 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?=
<gabor.tothvari at ericsson.com>
Date: Mon, 27 Jul 2026 14:23:32 +0200
Subject: [PATCH 22/29] Fix missing insert into destination set in
`ExprEngine::VisitOffsetOfExpr`
---
clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index d22117544f17e..b815587675379 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -812,8 +812,10 @@ void ExprEngine::VisitOffsetOfExpr(const OffsetOfExpr *OOE, ExplodedNode *Pred,
assert(IV.isSigned() == OOE->getType()->isSignedIntegerType());
SVal X = svalBuilder.makeIntVal(IV);
Dst.insert(Engine.makeNodeWithBinding(Pred, OOE, X));
+ } else {
+ // FIXME: Handle the case where __builtin_offsetof is not a constant.
+ Dst.insert(Pred);
}
- // FIXME: Handle the case where __builtin_offsetof is not a constant.
}
void ExprEngine::
>From f0dce6816a8c742f69f80154019db52089bf9dff Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?=
<gabor.tothvari at ericsson.com>
Date: Mon, 27 Jul 2026 15:44:48 +0200
Subject: [PATCH 23/29] Add test for the scenario when __builtin_offsetof is
non-constant.
---
clang/test/Analysis/misc-ps.m | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/clang/test/Analysis/misc-ps.m b/clang/test/Analysis/misc-ps.m
index c22e0dbb6137d..e6f665d68a8d6 100644
--- a/clang/test/Analysis/misc-ps.m
+++ b/clang/test/Analysis/misc-ps.m
@@ -622,6 +622,15 @@ void test_offsetof_4(void) {
*p = 0xDEADBEEF; // expected-warning{{Dereference of null pointer}}
}
+// Test when __builtin_offsetof is not constant-foldable.
+struct test_offsetof_5_struct { int a; int arr[10]; };
+int test_offsetof_5(int i) {
+ int *p = 0;
+ unsigned long off = __builtin_offsetof(struct test_offsetof_5_struct, arr[i]);
+ (void)off;
+ return *p; // expected-warning{{Dereference of null pointer}}
+}
+
// "nil receiver" false positive: make tracking of the MemRegion for 'self'
// path-sensitive
@interface RDar6829164 : NSObject {
>From 81025850693f330a5c976416a09d6b8c3ec0728d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?=
<gabor.tothvari at ericsson.com>
Date: Tue, 28 Jul 2026 16:30:28 +0200
Subject: [PATCH 24/29] Simplify `getProgramPoint` calls.
---
clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 8 +++-----
clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 12 ++++--------
2 files changed, 7 insertions(+), 13 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 4572aa43a6355..72c9e93c3f0fc 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -3653,8 +3653,7 @@ void ExprEngine::evalLoad(ExplodedNodeSet &Dst,
}
const auto *SF = I->getStackFrame();
- const auto &Loc = ProgramPoint::getProgramPoint(
- NodeEx, ProgramPoint::PostLoadKind, SF, tag);
+ PostLoad Loc(NodeEx, SF, tag);
Dst.insert(Engine.makeNode(Loc, state->BindExpr(BoundEx, SF, V), I));
}
}
@@ -3683,9 +3682,8 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst, const Stmt *NodeEx,
// "Variable 'p' initialized to a null pointer value"
static SimpleProgramPointTag tag(TagProviderName, "Location");
- const ProgramPoint &L = ProgramPoint::getProgramPoint(
- NodeEx, ProgramPoint::PostStmtKind, Pred->getStackFrame(), &tag);
- Src.insert(Engine.makeNode(L, state, Pred));
+ PostStmt Loc(NodeEx, Pred->getStackFrame(), &tag);
+ Src.insert(Engine.makeNode(Loc, state, Pred));
}
ExplodedNodeSet Tmp;
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 0f90a7195032a..5248843635155 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -583,9 +583,8 @@ void ExprEngine::handleConstructor(const Expr *E,
if (isZeroSizeArray()) {
static SimpleProgramPointTag T{"ExprEngine",
"Skipping 0 size array construction"};
- const ProgramPoint &P = ProgramPoint::getProgramPoint(
- CE, ProgramPoint::PostStmtKind, Pred->getStackFrame(), &T);
- destNodes.insert(Engine.makeNode(P, State, Pred));
+ PostStmt Loc(CE, Pred->getStackFrame(), &T);
+ destNodes.insert(Engine.makeNode(Loc, State, Pred));
return;
}
@@ -663,9 +662,7 @@ void ExprEngine::handleConstructor(const Expr *E,
if (State != Pred->getState()) {
static SimpleProgramPointTag T("ExprEngine",
"Prepare for object construction");
- const ProgramPoint &P = ProgramPoint::getProgramPoint(
- E, ProgramPoint::PreStmtKind, Pred->getStackFrame(), &T);
- Pred = Engine.makeNode(P, State, Pred);
+ Pred = Engine.makeNode(PreStmt(E, SF, &T), State, Pred);
if (!Pred)
return;
}
@@ -706,8 +703,7 @@ void ExprEngine::handleConstructor(const Expr *E,
State = State->bindDefaultZero(Target, SF);
}
- const ProgramPoint &P = ProgramPoint::getProgramPoint(
- CE, ProgramPoint::PreStmtKind, N->getStackFrame(), /*tag=*/nullptr);
+ PreStmt P(CE, N->getStackFrame(), /*tag=*/nullptr);
PreInitialized.insert(Engine.makeNode(P, State, N));
}
} else {
>From 45506d87db62a9508c8a4f185a01e49378f7830d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?=
<gabor.tothvari at ericsson.com>
Date: Tue, 28 Jul 2026 16:45:17 +0200
Subject: [PATCH 25/29] Remove insertions of sink nodes into
`ExplodedNodeSet`s.
---
clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp | 3 +--
clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 8 +++-----
2 files changed, 4 insertions(+), 7 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index b815587675379..db496c4e9b129 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -444,8 +444,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
if (T->isReferenceType()) {
// A bad_cast exception is thrown if input value is a reference.
// Currently, we model this, by generating a sink.
- Dst.insert(Engine.makePostStmtNode(CastE, state, Pred,
- /* MarkAsSink */ true));
+ Engine.makePostStmtNode(CastE, state, Pred, /*MarkAsSink=*/ true);
continue;
} else {
// If the cast fails on a pointer, bind to 0.
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 5248843635155..114b8a1e1f8d0 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -756,8 +756,7 @@ void ExprEngine::handleConstructor(const Expr *E,
"We should not have inlined this constructor!");
for (ExplodedNode *N : DstEvaluated) {
- DstEvaluatedPostProcessed.insert(Engine.makePostStmtNode(
- E, N->getState(), N, /* MarkAsSink */ true));
+ Engine.makePostStmtNode(E, N->getState(), N, /*MarkAsSink=*/ true);
}
// There is no need to run the PostCall and PostStmt checker
@@ -831,9 +830,8 @@ void ExprEngine::VisitCXXDestructor(QualType ObjectType,
Dest = MRMgr.getCXXTempObjectRegion(E, Pred->getStackFrame());
} else {
static SimpleProgramPointTag T("ExprEngine", "SkipInvalidDestructor");
- Dst.insert(Engine.makeNode(Pred->getLocation().withTag(&T),
- Pred->getState(), Pred,
- /* MarkAsSink */ true));
+ Engine.makeNode(Pred->getLocation().withTag(&T), Pred->getState(), Pred,
+ /*MarkAsSink=*/ true);
return;
}
}
>From b3d2cb03a4c296f4e9f5a53d9f70c4ca01f5e892 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?=
<gabor.tothvari at ericsson.com>
Date: Tue, 28 Jul 2026 16:50:42 +0200
Subject: [PATCH 26/29] Rename `destNodes` to `Dst` in
`ExprEngine::handleConstructor`.
---
clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 114b8a1e1f8d0..3822df26748fa 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -524,7 +524,7 @@ bindRequiredArrayElementToEnvironment(ProgramStateRef State,
void ExprEngine::handleConstructor(const Expr *E,
ExplodedNode *Pred,
- ExplodedNodeSet &destNodes) {
+ ExplodedNodeSet &Dst) {
const auto *CE = dyn_cast<CXXConstructExpr>(E);
const auto *CIE = dyn_cast<CXXInheritedCtorInitExpr>(E);
assert(CE || CIE);
@@ -544,7 +544,7 @@ void ExprEngine::handleConstructor(const Expr *E,
State = finishObjectConstruction(State, CE, SF);
if (auto L = Target.getAs<Loc>())
State = State->BindExpr(CE, SF, State->getSVal(*L, CE->getType()));
- destNodes.insert(Engine.makePostStmtNode(CE, State, Pred));
+ Dst.insert(Engine.makePostStmtNode(CE, State, Pred));
return;
}
}
@@ -584,7 +584,7 @@ void ExprEngine::handleConstructor(const Expr *E,
static SimpleProgramPointTag T{"ExprEngine",
"Skipping 0 size array construction"};
PostStmt Loc(CE, Pred->getStackFrame(), &T);
- destNodes.insert(Engine.makeNode(Loc, State, Pred));
+ Dst.insert(Engine.makeNode(Loc, State, Pred));
return;
}
@@ -777,7 +777,7 @@ void ExprEngine::handleConstructor(const Expr *E,
getCheckerManager().runCheckersForPostCall(DstPostCall,
DstPostArgumentCleanup,
*Call, *this);
- getCheckerManager().runCheckersForPostStmt(destNodes, DstPostCall, E, *this);
+ getCheckerManager().runCheckersForPostStmt(Dst, DstPostCall, E, *this);
}
void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
>From 03b432cd522e0001da17dfaa6fb051372c2c7705 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?=
<gabor.tothvari at ericsson.com>
Date: Wed, 29 Jul 2026 11:19:11 +0200
Subject: [PATCH 27/29] Simplify `ExplodedNodeSet` insert then erase pair.
---
clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 3 ---
1 file changed, 3 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 3822df26748fa..5c21addb39802 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -1022,14 +1022,11 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
ExplodedNodeSet evaluated;
evalBind(evaluated, CNE, Pred, Result, V, true);
- Dst.insert(evaluated);
-
Pred = *evaluated.begin();
State = Pred->getState();
}
}
- Dst.erase(Pred);
Dst.insert(Engine.makeNodeWithBinding(Pred, CNE, Result, State));
return;
}
>From 5d2c8ed75df4ffd1848cca4574a006c60d3aa8ca Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?=
<gabor.tothvari at ericsson.com>
Date: Wed, 29 Jul 2026 20:13:23 +0200
Subject: [PATCH 28/29] Formatting.
---
clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp | 2 +-
clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 7 +++----
2 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index db496c4e9b129..070601cecf916 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -444,7 +444,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
if (T->isReferenceType()) {
// A bad_cast exception is thrown if input value is a reference.
// Currently, we model this, by generating a sink.
- Engine.makePostStmtNode(CastE, state, Pred, /*MarkAsSink=*/ true);
+ Engine.makePostStmtNode(CastE, state, Pred, /*MarkAsSink=*/true);
continue;
} else {
// If the cast fails on a pointer, bind to 0.
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 5c21addb39802..9a7bfb6aa6cf0 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -522,8 +522,7 @@ bindRequiredArrayElementToEnvironment(ProgramStateRef State,
return State->BindExpr(Ctor->getArg(0), SF, loc::MemRegionVal(ElementRegion));
}
-void ExprEngine::handleConstructor(const Expr *E,
- ExplodedNode *Pred,
+void ExprEngine::handleConstructor(const Expr *E, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
const auto *CE = dyn_cast<CXXConstructExpr>(E);
const auto *CIE = dyn_cast<CXXInheritedCtorInitExpr>(E);
@@ -756,7 +755,7 @@ void ExprEngine::handleConstructor(const Expr *E,
"We should not have inlined this constructor!");
for (ExplodedNode *N : DstEvaluated) {
- Engine.makePostStmtNode(E, N->getState(), N, /*MarkAsSink=*/ true);
+ Engine.makePostStmtNode(E, N->getState(), N, /*MarkAsSink=*/true);
}
// There is no need to run the PostCall and PostStmt checker
@@ -831,7 +830,7 @@ void ExprEngine::VisitCXXDestructor(QualType ObjectType,
} else {
static SimpleProgramPointTag T("ExprEngine", "SkipInvalidDestructor");
Engine.makeNode(Pred->getLocation().withTag(&T), Pred->getState(), Pred,
- /*MarkAsSink=*/ true);
+ /*MarkAsSink=*/true);
return;
}
}
>From eeb26b430010c95c6b28a67015e84e00661f70c6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?=
<gabor.tothvari at ericsson.com>
Date: Sat, 1 Aug 2026 13:52:04 +0200
Subject: [PATCH 29/29] Document assumption with an `assert` in
ExprEngineCXX.cpp.
---
clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 1 +
1 file changed, 1 insertion(+)
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 9a7bfb6aa6cf0..c9ef6df71abc5 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -1021,6 +1021,7 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
ExplodedNodeSet evaluated;
evalBind(evaluated, CNE, Pred, Result, V, true);
+ assert(evaluated.size() == 1);
Pred = *evaluated.begin();
State = Pred->getState();
}
More information about the cfe-commits
mailing list