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?=
 <[email protected]>
Date: Thu, 23 Jul 2026 17:17:28 +0200
Subject: [PATCH 01/22] 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?=
 <[email protected]>
Date: Fri, 24 Jul 2026 10:16:06 +0200
Subject: [PATCH 02/22] 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?=
 <[email protected]>
Date: Fri, 24 Jul 2026 14:20:41 +0200
Subject: [PATCH 03/22] 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?=
 <[email protected]>
Date: Fri, 24 Jul 2026 14:28:04 +0200
Subject: [PATCH 04/22] 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?=
 <[email protected]>
Date: Fri, 24 Jul 2026 15:35:00 +0200
Subject: [PATCH 05/22] 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?=
 <[email protected]>
Date: Fri, 24 Jul 2026 15:50:10 +0200
Subject: [PATCH 06/22] 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?=
 <[email protected]>
Date: Fri, 24 Jul 2026 17:33:57 +0200
Subject: [PATCH 07/22] 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?=
 <[email protected]>
Date: Fri, 24 Jul 2026 17:49:18 +0200
Subject: [PATCH 08/22] 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?=
 <[email protected]>
Date: Fri, 24 Jul 2026 17:58:08 +0200
Subject: [PATCH 09/22] 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?=
 <[email protected]>
Date: Fri, 24 Jul 2026 18:17:56 +0200
Subject: [PATCH 10/22] 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?=
 <[email protected]>
Date: Fri, 24 Jul 2026 18:22:12 +0200
Subject: [PATCH 11/22] 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?=
 <[email protected]>
Date: Fri, 24 Jul 2026 18:28:39 +0200
Subject: [PATCH 12/22] 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?=
 <[email protected]>
Date: Fri, 24 Jul 2026 18:32:46 +0200
Subject: [PATCH 13/22] 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?=
 <[email protected]>
Date: Fri, 24 Jul 2026 18:40:31 +0200
Subject: [PATCH 14/22] 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?=
 <[email protected]>
Date: Fri, 24 Jul 2026 18:58:38 +0200
Subject: [PATCH 15/22] 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?=
 <[email protected]>
Date: Sat, 25 Jul 2026 11:10:47 +0200
Subject: [PATCH 16/22] 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?=
 <[email protected]>
Date: Sat, 25 Jul 2026 11:52:40 +0200
Subject: [PATCH 17/22] 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?=
 <[email protected]>
Date: Sat, 25 Jul 2026 12:06:51 +0200
Subject: [PATCH 18/22] 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?=
 <[email protected]>
Date: Sat, 25 Jul 2026 17:22:17 +0200
Subject: [PATCH 19/22] 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?=
 <[email protected]>
Date: Mon, 27 Jul 2026 09:21:32 +0200
Subject: [PATCH 20/22] 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?=
 <[email protected]>
Date: Mon, 27 Jul 2026 14:11:21 +0200
Subject: [PATCH 21/22] 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?=
 <[email protected]>
Date: Mon, 27 Jul 2026 14:23:32 +0200
Subject: [PATCH 22/22] 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::

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to