Author: DonĂ¡t Nagy
Date: 2026-03-11T15:08:25+01:00
New Revision: 1c424bfb03d6dd4b994a0d549e1f3e23852f1e16

URL: 
https://github.com/llvm/llvm-project/commit/1c424bfb03d6dd4b994a0d549e1f3e23852f1e16
DIFF: 
https://github.com/llvm/llvm-project/commit/1c424bfb03d6dd4b994a0d549e1f3e23852f1e16.diff

LOG: [NFC][analyzer] Clarify current LocationContext and CFGBlock (#185107)

The analyzer often uses the current `LocationContext` and `CFGBlock`,
for example to assign unique identifiers to conjured symbols.

This information is currently handled in a haphazard way:
- Logic that determines this is often duplicated in several redundant
locations.
- It is stored in `NodeBuilderContext` objects, despite the fact that it
is not actually used for building (exploded) nodes.
- Many methods pass it around in arguments, while many others use it
through the field `NodeBuilderContext *currBldrCtx` of `ExprEngine`.
- This `currBldrCtx` points to local variables in random stack frames,
e.g. there is an early return in `ExprEngine::processBranch` where it
becomes stale (but AFAIK it is never dereferenced after that point).

This commit starts a transition to a more principled system, where there
is a single canonical source for accessing this information (methods of
`ExprEngine`), which is populated once per `dispatchWorkItem` call, as
close to the beginning of `dispatchWorkItem` as possible.

As the transition is not yet complete, this commit keeps `currBldrCtx`
to retain compatiblity with the old way of working -- but builds a nice
interface around it that will be able to switch to a different, more
natural data representation in the future.

I intend to follow this up with additional commits that performs
analogous transitions in the remaining parts of the codebase.

Added: 
    

Modified: 
    clang/include/clang/StaticAnalyzer/Core/CheckerManager.h
    clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
    clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
    clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
    clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
    clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
    clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
    clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
    clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
    clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h 
b/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h
index bf33ce616d954..348c7eff09161 100644
--- a/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h
+++ b/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h
@@ -360,11 +360,8 @@ class CheckerManager {
                                    ExprEngine &Eng);
 
   /// Run checkers on end of function.
-  void runCheckersForEndFunction(NodeBuilderContext &BC,
-                                 ExplodedNodeSet &Dst,
-                                 ExplodedNode *Pred,
-                                 ExprEngine &Eng,
-                                 const ReturnStmt *RS);
+  void runCheckersForEndFunction(ExplodedNodeSet &Dst, ExplodedNode *Pred,
+                                 ExprEngine &Eng, const ReturnStmt *RS);
 
   /// Run checkers for branch condition.
   void runCheckersForBranchCondition(const Stmt *condition,

diff  --git 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
index 21749b0f42b2b..6b70fda42819c 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
@@ -339,8 +339,9 @@ class IndirectGotoNodeBuilder : public NodeBuilder {
   const Expr *Target;
 
 public:
-  IndirectGotoNodeBuilder(ExplodedNodeSet &DstSet, NodeBuilderContext &Ctx,
-                          const Expr *Tgt, const CFGBlock *Dispatch)
+  IndirectGotoNodeBuilder(ExplodedNodeSet &DstSet,
+                          const NodeBuilderContext &Ctx, const Expr *Tgt,
+                          const CFGBlock *Dispatch)
       : NodeBuilder(DstSet, Ctx), DispatchBlock(*Dispatch), Target(Tgt) {}
 
   using iterator = CFGBlock::const_succ_iterator;

diff  --git 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index 2ca03174fbdc9..2023a7a5b1ac8 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -159,7 +159,29 @@ class ExprEngine {
   SValBuilder &svalBuilder;
 
   unsigned int currStmtIdx = 0;
+
+  /// Pointer to a (so-called, somewhat misnamed) NodeBuilderContext object
+  /// which has three independent roles:
+  /// - It holds a pointer to the CFGBlock that is currently under analysis.
+  ///   (This is the primary way to get the current block.)
+  /// - It holds a pointer to the current LocationContext. (This is rarely
+  ///   used, the location context is usually queried from a recent
+  ///   ExplodedNode. Unfortunately it seems that these two sources of truth
+  ///   are not always consistent.)
+  /// - It can be used for constructing `NodeBuilder`s. Practically all
+  ///   `NodeBuilder` objects are useless complications in the code, so I
+  ///   intend to replace them with direct use of `CoreEngine::makeNode`.
+  /// TODO: Eventually `currBldrCtx` should be replaced by two separate fields:
+  /// `const CFGBlock *CurrBlock` & `const LocationContext 
*CurrLocationContext`
+  /// that are kept up-to-date and are almost always non-null during the
+  /// analysis. I will switch to this more natural representation when
+  /// `NodeBuilder`s are eliminated from the code.
   const NodeBuilderContext *currBldrCtx = nullptr;
+  /// Historically `currBldrCtx` pointed to a local variable in some stack
+  /// frame. This field is introduced as a temporary measure to allow a gradual
+  /// transition. Only use this in {re,}setLocationContextAndBlock!
+  /// TODO: Remove this temporary hack.
+  std::optional<NodeBuilderContext> OwnedCurrBldrCtx;
 
   /// Helper object to determine if an Objective-C message expression
   /// implicitly never returns.
@@ -216,7 +238,28 @@ class ExprEngine {
     return &CTU;
   }
 
-  const NodeBuilderContext &getBuilderContext() {
+  // FIXME: Ideally the body of this method should look like
+  //   CurrLocationContext = LC;
+  //   CurrBlock = B;
+  // where CurrLocationContext and CurrBlock are new member variables that
+  // fulfill the roles of `currBldrCtx` in a more natural way.
+  // This implementation is a temporary measure to allow a gradual transition.
+  void setCurrLocationContextAndBlock(const LocationContext *LC,
+                                      const CFGBlock *B) {
+    // Note that there is a call to resetCurrLocationContextAndBlock at the
+    // beginning of dispatchWorkItem.
+    assert(!currBldrCtx && !OwnedCurrBldrCtx &&
+           "This should be called at most once per call to dispatchWorkItem");
+    OwnedCurrBldrCtx.emplace(Engine, B, LC);
+    currBldrCtx = &*OwnedCurrBldrCtx;
+  }
+
+  void resetCurrLocationContextAndBlock() {
+    currBldrCtx = nullptr;
+    OwnedCurrBldrCtx = std::nullopt;
+  }
+
+  const NodeBuilderContext &getBuilderContext() const {
     assert(currBldrCtx);
     return *currBldrCtx;
   }
@@ -226,9 +269,35 @@ class ExprEngine {
     return G.getRoot()->getLocation().getLocationContext();
   }
 
+  /// Get the 'current' location context corresponding to the current work item
+  /// (elementary analysis step handled by `dispatchWorkItem`).
+  /// FIXME: This sometimes (e.g. in some `BeginFunction` callbacks) 
diff ers
+  /// from the `LocationContext` that can be obtained from 
diff erent sources
+  /// (e.g. a recent `ExplodedNode`). Traditionally this location context is
+  /// only used for block count calculations (`getNumVisited`); it is probably
+  /// wise to follow this tradition until the discrepancies are resolved.
+  const LocationContext *getCurrLocationContext() const {
+    return currBldrCtx ? currBldrCtx->getLocationContext() : nullptr;
+  }
+
+  /// Get the 'current' CFGBlock corresponding to the current work item
+  /// (elementary analysis step handled by `dispatchWorkItem`).
+  const CFGBlock *getCurrBlock() const {
+    return currBldrCtx ? currBldrCtx->getBlock() : nullptr;
+  }
+
   ConstCFGElementRef getCFGElementRef() const {
-    const CFGBlock *blockPtr = currBldrCtx ? currBldrCtx->getBlock() : nullptr;
-    return {blockPtr, currStmtIdx};
+    return {getCurrBlock(), currStmtIdx};
+  }
+
+  unsigned getNumVisited(const LocationContext *LC,
+                         const CFGBlock *Block) const {
+    return Engine.WList->getBlockCounter().getNumVisited(LC->getStackFrame(),
+                                                         Block->getBlockID());
+  }
+
+  unsigned getNumVisitedCurrent() const {
+    return getNumVisited(getCurrLocationContext(), getCurrBlock());
   }
 
   /// Dump graph to the specified filename.
@@ -293,7 +362,7 @@ class ExprEngine {
   /// processCFGElement - Called by CoreEngine. Used to generate new successor
   ///  nodes by processing the 'effects' of a CFG element.
   void processCFGElement(const CFGElement E, ExplodedNode *Pred,
-                         unsigned StmtIdx, NodeBuilderContext *Ctx);
+                         unsigned StmtIdx);
 
   void ProcessStmt(const Stmt *S, ExplodedNode *Pred);
 
@@ -320,35 +389,30 @@ class ExprEngine {
   void processCFGBlockEntrance(const BlockEdge &L, const BlockEntrance &BE,
                                NodeBuilder &Builder, ExplodedNode *Pred);
 
-  void runCheckersForBlockEntrance(const NodeBuilderContext &BldCtx,
-                                   const BlockEntrance &Entrance,
+  void runCheckersForBlockEntrance(const BlockEntrance &Entrance,
                                    ExplodedNode *Pred, ExplodedNodeSet &Dst);
 
   /// ProcessBranch - Called by CoreEngine. Used to generate successor nodes by
   /// processing the 'effects' of a branch condition. If the branch condition
   /// is a loop condition, IterationsCompletedInLoop is the number of completed
   /// iterations (otherwise it's std::nullopt).
-  void processBranch(const Stmt *Condition, NodeBuilderContext &BuilderCtx,
-                     ExplodedNode *Pred, ExplodedNodeSet &Dst,
-                     const CFGBlock *DstT, const CFGBlock *DstF,
+  void processBranch(const Stmt *Condition, ExplodedNode *Pred,
+                     ExplodedNodeSet &Dst, const CFGBlock *DstT,
+                     const CFGBlock *DstF,
                      std::optional<unsigned> IterationsCompletedInLoop);
 
   /// Called by CoreEngine.
   /// Used to generate successor nodes for temporary destructors depending
   /// on whether the corresponding constructor was visited.
   void processCleanupTemporaryBranch(const CXXBindTemporaryExpr *BTE,
-                                     NodeBuilderContext &BldCtx,
                                      ExplodedNode *Pred, ExplodedNodeSet &Dst,
                                      const CFGBlock *DstT,
                                      const CFGBlock *DstF);
 
   /// Called by CoreEngine.  Used to processing branching behavior
   /// at static initializers.
-  void processStaticInitializer(const DeclStmt *DS,
-                                NodeBuilderContext& BuilderCtx,
-                                ExplodedNode *Pred,
-                                ExplodedNodeSet &Dst,
-                                const CFGBlock *DstT,
+  void processStaticInitializer(const DeclStmt *DS, ExplodedNode *Pred,
+                                ExplodedNodeSet &Dst, const CFGBlock *DstT,
                                 const CFGBlock *DstF);
 
   /// processIndirectGoto - Called by CoreEngine.  Used to generate successor
@@ -358,29 +422,23 @@ class ExprEngine {
 
   /// ProcessSwitch - Called by CoreEngine.  Used to generate successor
   ///  nodes by processing the 'effects' of a switch statement.
-  void processSwitch(NodeBuilderContext &BC, const SwitchStmt *Switch,
-                     ExplodedNode *Pred, ExplodedNodeSet &Dst);
+  void processSwitch(const SwitchStmt *Switch, ExplodedNode *Pred,
+                     ExplodedNodeSet &Dst);
 
   /// Called by CoreEngine.  Used to notify checkers that processing a
   /// function has begun. Called for both inlined and top-level functions.
-  void processBeginOfFunction(NodeBuilderContext &BC,
-                              ExplodedNode *Pred, ExplodedNodeSet &Dst,
+  void processBeginOfFunction(ExplodedNode *Pred, ExplodedNodeSet &Dst,
                               const BlockEdge &L);
 
   /// Called by CoreEngine.  Used to notify checkers that processing a
   /// function has ended. Called for both inlined and top-level functions.
-  void processEndOfFunction(NodeBuilderContext& BC,
-                            ExplodedNode *Pred,
-                            const ReturnStmt *RS = nullptr);
+  void processEndOfFunction(ExplodedNode *Pred, const ReturnStmt *RS = 
nullptr);
 
   /// Remove dead bindings/symbols before exiting a function.
-  void removeDeadOnEndOfFunction(NodeBuilderContext& BC,
-                                 ExplodedNode *Pred,
-                                 ExplodedNodeSet &Dst);
+  void removeDeadOnEndOfFunction(ExplodedNode *Pred, ExplodedNodeSet &Dst);
 
   /// Generate the entry node of the callee.
-  void processCallEnter(NodeBuilderContext& BC, CallEnter CE,
-                        ExplodedNode *Pred);
+  void processCallEnter(CallEnter CE, ExplodedNode *Pred);
 
   /// Generate the sequence of nodes that simulate the call exit and the post
   /// visit for CallExpr.
@@ -706,9 +764,7 @@ class ExprEngine {
 
   /// Return the CFG element corresponding to the worklist element
   /// that is currently being processed by ExprEngine.
-  CFGElement getCurrentCFGElement() {
-    return (*currBldrCtx->getBlock())[currStmtIdx];
-  }
+  CFGElement getCurrentCFGElement() { return (*getCurrBlock())[currStmtIdx]; }
 
   /// Create a new state in which the call return value is binded to the
   /// call origin expression.

diff  --git a/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp 
b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
index 8ee4832643b91..20a906dde38b1 100644
--- a/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -505,15 +505,14 @@ void 
CheckerManager::runCheckersForBeginFunction(ExplodedNodeSet &Dst,
 /// Run checkers for end of path.
 // Note, We do not chain the checker output (like in expandGraphWithCheckers)
 // for this callback since end of path nodes are expected to be final.
-void CheckerManager::runCheckersForEndFunction(NodeBuilderContext &BC,
-                                               ExplodedNodeSet &Dst,
+void CheckerManager::runCheckersForEndFunction(ExplodedNodeSet &Dst,
                                                ExplodedNode *Pred,
                                                ExprEngine &Eng,
                                                const ReturnStmt *RS) {
   // We define the builder outside of the loop because if at least one checker
   // creates a successor for Pred, we do not need to generate an
   // autotransition for it.
-  NodeBuilder Bldr(Pred, Dst, BC);
+  NodeBuilder Bldr(Pred, Dst, Eng.getBuilderContext());
   for (const auto &checkFn : EndFunctionCheckers) {
     const ProgramPoint &L =
         FunctionExitPoint(RS, Pred->getLocationContext(), checkFn.Checker);

diff  --git a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp 
b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
index d32db1669e1fe..3dc9c53bd30d7 100644
--- a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
@@ -119,9 +119,10 @@ bool CoreEngine::ExecuteWorkList(const LocationContext *L, 
unsigned MaxSteps,
     assert(IsNew);
     G.designateAsRoot(Node);
 
-    NodeBuilderContext BuilderCtx(*this, StartLoc.getDst(), Node);
+    ExprEng.setCurrLocationContextAndBlock(Node->getLocationContext(), Succ);
+
     ExplodedNodeSet DstBegin;
-    ExprEng.processBeginOfFunction(BuilderCtx, Node, DstBegin, StartLoc);
+    ExprEng.processBeginOfFunction(Node, DstBegin, StartLoc);
 
     enqueue(DstBegin);
   }
@@ -216,6 +217,14 @@ void CoreEngine::dispatchWorkItem(ExplodedNode *Pred, 
ProgramPoint Loc,
                              return timeTraceMetadata(Pred, Loc);
                            }};
   PrettyStackTraceLocationContext CrashInfo(Pred->getLocationContext());
+
+  // This work item is not necessarily related to the previous one, so
+  // the old current LocationContext and Block is no longer relevant.
+  // The new current LocationContext and Block should be set soon, but this
+  // guarantees that buggy access before that will trigger loud crashes instead
+  // of silently using stale data.
+  ExprEng.resetCurrLocationContextAndBlock();
+
   // Dispatch on the location type.
   switch (Loc.getKind()) {
     case ProgramPoint::BlockEdgeKind:
@@ -259,7 +268,7 @@ void CoreEngine::dispatchWorkItem(ExplodedNode *Pred, 
ProgramPoint Loc,
 
 void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) {
   const CFGBlock *Blk = L.getDst();
-  NodeBuilderContext BuilderCtx(*this, Blk, Pred);
+  ExprEng.setCurrLocationContextAndBlock(Pred->getLocationContext(), Blk);
 
   // Mark this block as visited.
   const LocationContext *LC = Pred->getLocationContext();
@@ -280,17 +289,15 @@ void CoreEngine::HandleBlockEdge(const BlockEdge &L, 
ExplodedNode *Pred) {
         },
         /*IsPrunable=*/true));
     // Perform the transition.
-    ExplodedNodeSet Dst;
-    NodeBuilder Bldr(Pred, Dst, BuilderCtx);
-    Pred = Bldr.generateNode(P, Pred->getState(), Pred);
+    Pred = makeNode(P, Pred->getState(), Pred);
     if (!Pred)
       return;
   }
 
   // Check if we are entering the EXIT block.
-  if (Blk == &(L.getLocationContext()->getCFG()->getExit())) {
-    assert(L.getLocationContext()->getCFG()->getExit().empty() &&
-           "EXIT block cannot contain Stmts.");
+  const CFGBlock &ExitBlk = L.getLocationContext()->getCFG()->getExit();
+  if (Blk == &ExitBlk) {
+    assert(ExitBlk.empty() && "EXIT block cannot contain Stmts.");
 
     // Get return statement..
     const ReturnStmt *RS = nullptr;
@@ -306,11 +313,11 @@ void CoreEngine::HandleBlockEdge(const BlockEdge &L, 
ExplodedNode *Pred) {
 
     ExplodedNodeSet CheckerNodes;
     BlockEntrance BE(L.getSrc(), L.getDst(), Pred->getLocationContext());
-    ExprEng.runCheckersForBlockEntrance(BuilderCtx, BE, Pred, CheckerNodes);
+    ExprEng.runCheckersForBlockEntrance(BE, Pred, CheckerNodes);
 
     // Process the final state transition.
     for (ExplodedNode *P : CheckerNodes) {
-      ExprEng.processEndOfFunction(BuilderCtx, P, RS);
+      ExprEng.processEndOfFunction(P, RS);
     }
 
     // This path is done. Don't enqueue any more nodes.
@@ -320,7 +327,7 @@ void CoreEngine::HandleBlockEdge(const BlockEdge &L, 
ExplodedNode *Pred) {
   // Call into the ExprEngine to process entering the CFGBlock.
   BlockEntrance BE(L.getSrc(), L.getDst(), Pred->getLocationContext());
   ExplodedNodeSet DstNodes;
-  NodeBuilder Builder(Pred, DstNodes, BuilderCtx);
+  NodeBuilder Builder(Pred, DstNodes, ExprEng.getBuilderContext());
   ExprEng.processCFGBlockEntrance(L, BE, Builder, Pred);
 
   // Auto-generate a node.
@@ -330,7 +337,7 @@ void CoreEngine::HandleBlockEdge(const BlockEdge &L, 
ExplodedNode *Pred) {
 
   ExplodedNodeSet CheckerNodes;
   for (auto *N : DstNodes) {
-    ExprEng.runCheckersForBlockEntrance(BuilderCtx, BE, N, CheckerNodes);
+    ExprEng.runCheckersForBlockEntrance(BE, N, CheckerNodes);
   }
 
   // Enqueue nodes onto the worklist.
@@ -349,14 +356,17 @@ void CoreEngine::HandleBlockEntrance(const BlockEntrance 
&L,
 
   // Process the entrance of the block.
   if (std::optional<CFGElement> E = L.getFirstElement()) {
-    NodeBuilderContext Ctx(*this, L.getBlock(), Pred);
-    ExprEng.processCFGElement(*E, Pred, 0, &Ctx);
+    ExprEng.setCurrLocationContextAndBlock(Pred->getLocationContext(),
+                                           L.getBlock());
+    ExprEng.processCFGElement(*E, Pred, 0);
   } else
     HandleBlockExit(L.getBlock(), Pred);
 }
 
 void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode *Pred) {
   if (const Stmt *Term = B->getTerminatorStmt()) {
+    ExprEng.setCurrLocationContextAndBlock(Pred->getLocationContext(), B);
+
     switch (Term->getStmtClass()) {
       default:
         llvm_unreachable("Analysis for this terminator not implemented.");
@@ -425,11 +435,10 @@ void CoreEngine::HandleBlockExit(const CFGBlock * B, 
ExplodedNode *Pred) {
       case Stmt::IndirectGotoStmtClass: {
         // Only 1 successor: the indirect goto dispatch block.
         assert(B->succ_size() == 1);
-        NodeBuilderContext Ctx(*this, B, Pred);
         ExplodedNodeSet Dst;
         IndirectGotoNodeBuilder Builder(
-            Dst, Ctx, cast<IndirectGotoStmt>(Term)->getTarget(),
-            *(B->succ_begin()));
+            Dst, ExprEng.getBuilderContext(),
+            cast<IndirectGotoStmt>(Term)->getTarget(), *(B->succ_begin()));
 
         ExprEng.processIndirectGoto(Builder, Pred);
         // Enqueue the new frontier onto the worklist.
@@ -452,9 +461,8 @@ void CoreEngine::HandleBlockExit(const CFGBlock * B, 
ExplodedNode *Pred) {
         return;
 
       case Stmt::SwitchStmtClass: {
-        NodeBuilderContext Ctx(*this, B, Pred);
         ExplodedNodeSet Dst;
-        ExprEng.processSwitch(Ctx, cast<SwitchStmt>(Term), Pred, Dst);
+        ExprEng.processSwitch(cast<SwitchStmt>(Term), Pred, Dst);
         // Enqueue the new frontier onto the worklist.
         enqueue(Dst);
         return;
@@ -485,16 +493,16 @@ void CoreEngine::HandleBlockExit(const CFGBlock * B, 
ExplodedNode *Pred) {
 }
 
 void CoreEngine::HandleCallEnter(const CallEnter &CE, ExplodedNode *Pred) {
-  NodeBuilderContext BuilderCtx(*this, CE.getEntry(), Pred);
-  ExprEng.processCallEnter(BuilderCtx, CE, Pred);
+  ExprEng.setCurrLocationContextAndBlock(Pred->getLocationContext(),
+                                         CE.getEntry());
+  ExprEng.processCallEnter(CE, Pred);
 }
 
 void CoreEngine::HandleBranch(const Stmt *Cond, const Stmt *Term,
                                 const CFGBlock * B, ExplodedNode *Pred) {
   assert(B->succ_size() == 2);
-  NodeBuilderContext Ctx(*this, B, Pred);
   ExplodedNodeSet Dst;
-  ExprEng.processBranch(Cond, Ctx, Pred, Dst, *(B->succ_begin()),
+  ExprEng.processBranch(Cond, Pred, Dst, *(B->succ_begin()),
                         *(B->succ_begin() + 1),
                         getCompletedIterationCount(B, Pred));
   // Enqueue the new frontier onto the worklist.
@@ -505,10 +513,9 @@ void CoreEngine::HandleCleanupTemporaryBranch(const 
CXXBindTemporaryExpr *BTE,
                                               const CFGBlock *B,
                                               ExplodedNode *Pred) {
   assert(B->succ_size() == 2);
-  NodeBuilderContext Ctx(*this, B, Pred);
   ExplodedNodeSet Dst;
-  ExprEng.processCleanupTemporaryBranch(BTE, Ctx, Pred, Dst, 
*(B->succ_begin()),
-                                       *(B->succ_begin() + 1));
+  ExprEng.processCleanupTemporaryBranch(BTE, Pred, Dst, *(B->succ_begin()),
+                                        *(B->succ_begin() + 1));
   // Enqueue the new frontier onto the worklist.
   enqueue(Dst);
 }
@@ -516,10 +523,9 @@ void CoreEngine::HandleCleanupTemporaryBranch(const 
CXXBindTemporaryExpr *BTE,
 void CoreEngine::HandleStaticInit(const DeclStmt *DS, const CFGBlock *B,
                                   ExplodedNode *Pred) {
   assert(B->succ_size() == 2);
-  NodeBuilderContext Ctx(*this, B, Pred);
   ExplodedNodeSet Dst;
-  ExprEng.processStaticInitializer(DS, Ctx, Pred, Dst,
-                                  *(B->succ_begin()), *(B->succ_begin()+1));
+  ExprEng.processStaticInitializer(DS, Pred, Dst, *(B->succ_begin()),
+                                   *(B->succ_begin() + 1));
   // Enqueue the new frontier onto the worklist.
   enqueue(Dst);
 }
@@ -538,8 +544,8 @@ void CoreEngine::HandlePostStmt(const CFGBlock *B, unsigned 
StmtIdx,
   if (StmtIdx == B->size())
     HandleBlockExit(B, Pred);
   else {
-    NodeBuilderContext Ctx(*this, B, Pred);
-    ExprEng.processCFGElement((*B)[StmtIdx], Pred, StmtIdx, &Ctx);
+    ExprEng.setCurrLocationContextAndBlock(Pred->getLocationContext(), B);
+    ExprEng.processCFGElement((*B)[StmtIdx], Pred, StmtIdx);
   }
 }
 

diff  --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp 
b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index bc8e9040444c9..ad419bbca50e6 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -422,7 +422,7 @@ ProgramStateRef ExprEngine::createTemporaryRegionIfNeeded(
     case SubobjectAdjustment::MemberPointerAdjustment:
       // FIXME: Unimplemented.
       State = State->invalidateRegions(Reg, getCFGElementRef(),
-                                       currBldrCtx->blockCount(), LC, true,
+                                       getNumVisitedCurrent(), LC, true,
                                        nullptr, nullptr, nullptr);
       return State;
     }
@@ -439,7 +439,7 @@ ProgramStateRef ExprEngine::createTemporaryRegionIfNeeded(
   SVal InitVal = State->getSVal(Init, LC);
   if (InitVal.isUnknown()) {
     InitVal = getSValBuilder().conjureSymbolVal(
-        getCFGElementRef(), LC, Init->getType(), currBldrCtx->blockCount());
+        getCFGElementRef(), LC, Init->getType(), getNumVisitedCurrent());
     State = State->bindLoc(BaseReg.castAs<Loc>(), InitVal, LC, false);
 
     // Then we'd need to take the value that certainly exists and bind it
@@ -449,7 +449,7 @@ ProgramStateRef ExprEngine::createTemporaryRegionIfNeeded(
       // compute the value.
       InitValWithAdjustments = getSValBuilder().conjureSymbolVal(
           getCFGElementRef(), LC, InitWithAdjustments->getType(),
-          currBldrCtx->blockCount());
+          getNumVisitedCurrent());
     }
     State =
         State->bindLoc(Reg.castAs<Loc>(), InitValWithAdjustments, LC, false);
@@ -966,9 +966,8 @@ void ExprEngine::processEndWorklist() {
 }
 
 void ExprEngine::processCFGElement(const CFGElement E, ExplodedNode *Pred,
-                                   unsigned StmtIdx, NodeBuilderContext *Ctx) {
+                                   unsigned StmtIdx) {
   currStmtIdx = StmtIdx;
-  currBldrCtx = Ctx;
 
   switch (E.getKind()) {
     case CFGElement::Statement:
@@ -1144,7 +1143,7 @@ void ExprEngine::ProcessStmt(const Stmt *currStmt, 
ExplodedNode *Pred) {
   }
 
   // Enqueue the new nodes onto the work list.
-  Engine.enqueueStmtNodes(Dst, currBldrCtx->getBlock(), currStmtIdx);
+  Engine.enqueueStmtNodes(Dst, getCurrBlock(), currStmtIdx);
 }
 
 void ExprEngine::ProcessLoopExit(const Stmt* S, ExplodedNode *Pred) {
@@ -1159,7 +1158,7 @@ void ExprEngine::ProcessLoopExit(const Stmt* S, 
ExplodedNode *Pred) {
   LoopExit PP(S, Pred->getLocationContext());
   ExplodedNode *N = Engine.makeNode(PP, NewState, Pred);
   if (N && !N->isSink())
-    Engine.enqueueStmtNode(N, currBldrCtx->getBlock(), currStmtIdx);
+    Engine.enqueueStmtNode(N, getCurrBlock(), currStmtIdx);
 }
 
 void ExprEngine::ProcessInitializer(const CFGInitializer CFGInit,
@@ -1217,7 +1216,7 @@ void ExprEngine::ProcessInitializer(const CFGInitializer 
CFGInit,
           SValBuilder &SVB = getSValBuilder();
           InitVal =
               SVB.conjureSymbolVal(getCFGElementRef(), stackFrame,
-                                   Field->getType(), 
currBldrCtx->blockCount());
+                                   Field->getType(), getNumVisitedCurrent());
         }
       } else {
         InitVal = State->getSVal(BMI->getInit(), stackFrame);
@@ -1248,7 +1247,7 @@ void ExprEngine::ProcessInitializer(const CFGInitializer 
CFGInit,
   for (ExplodedNode *Pred : Tmp)
     Dst.Add(Engine.makeNode(PP, Pred->getState(), Pred));
   // Enqueue the new nodes onto the work list.
-  Engine.enqueueStmtNodes(Dst, currBldrCtx->getBlock(), currStmtIdx);
+  Engine.enqueueStmtNodes(Dst, getCurrBlock(), currStmtIdx);
 }
 
 std::pair<ProgramStateRef, uint64_t>
@@ -1312,7 +1311,7 @@ void ExprEngine::ProcessImplicitDtor(const 
CFGImplicitDtor D,
   }
 
   // Enqueue the new nodes onto the work list.
-  Engine.enqueueStmtNodes(Dst, currBldrCtx->getBlock(), currStmtIdx);
+  Engine.enqueueStmtNodes(Dst, getCurrBlock(), currStmtIdx);
 }
 
 void ExprEngine::ProcessNewAllocator(const CXXNewExpr *NE,
@@ -1331,7 +1330,7 @@ void ExprEngine::ProcessNewAllocator(const CXXNewExpr *NE,
                         getCFGElementRef());
     Dst.Add(Engine.makeNode(PP, Pred->getState(), Pred));
   }
-  Engine.enqueueStmtNodes(Dst, currBldrCtx->getBlock(), currStmtIdx);
+  Engine.enqueueStmtNodes(Dst, getCurrBlock(), currStmtIdx);
 }
 
 void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor Dtor,
@@ -1638,12 +1637,11 @@ void ExprEngine::ProcessTemporaryDtor(const 
CFGTemporaryDtor D,
 }
 
 void ExprEngine::processCleanupTemporaryBranch(const CXXBindTemporaryExpr *BTE,
-                                               NodeBuilderContext &BldCtx,
                                                ExplodedNode *Pred,
                                                ExplodedNodeSet &Dst,
                                                const CFGBlock *DstT,
                                                const CFGBlock *DstF) {
-  BranchNodeBuilder TempDtorBuilder(Dst, BldCtx, DstT, DstF);
+  BranchNodeBuilder TempDtorBuilder(Dst, *currBldrCtx, DstT, DstF);
   ProgramStateRef State = Pred->getState();
   const LocationContext *LC = Pred->getLocationContext();
   if (getObjectUnderConstruction(State, BTE, LC)) {
@@ -1844,7 +1842,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
     case Stmt::OMPMetaDirectiveClass:
     case Stmt::HLSLOutArgExprClass: {
       const ExplodedNode *node = Bldr.generateSink(S, Pred, Pred->getState());
-      Engine.addAbortedBlock(node, currBldrCtx->getBlock());
+      Engine.addAbortedBlock(node, getCurrBlock());
       break;
     }
 
@@ -2052,7 +2050,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
         const LocationContext *LCtx = N->getLocationContext();
         SVal result = svalBuilder.conjureSymbolVal(
             /*symbolTag=*/nullptr, getCFGElementRef(), LCtx, resultType,
-            currBldrCtx->blockCount());
+            getNumVisitedCurrent());
         ProgramStateRef State = N->getState()->BindExpr(Ex, LCtx, result);
 
         // Escape pointers passed into the list, unless it's an ObjC boxed
@@ -2120,7 +2118,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
         Bldr.addNodes(Dst);
       } else {
         const ExplodedNode *node = Bldr.generateSink(S, Pred, 
Pred->getState());
-        Engine.addAbortedBlock(node, currBldrCtx->getBlock());
+        Engine.addAbortedBlock(node, getCurrBlock());
       }
       break;
 
@@ -2640,17 +2638,14 @@ void ExprEngine::processCFGBlockEntrance(const 
BlockEdge &L,
   }
 }
 
-void ExprEngine::runCheckersForBlockEntrance(const NodeBuilderContext &BldCtx,
-                                             const BlockEntrance &Entrance,
+void ExprEngine::runCheckersForBlockEntrance(const BlockEntrance &Entrance,
                                              ExplodedNode *Pred,
                                              ExplodedNodeSet &Dst) {
   llvm::PrettyStackTraceFormat CrashInfo(
       "Processing block entrance B%d -> B%d",
       Entrance.getPreviousBlock()->getBlockID(),
       Entrance.getBlock()->getBlockID());
-  currBldrCtx = &BldCtx;
   getCheckerManager().runCheckersForBlockEntrance(Dst, Pred, Entrance, *this);
-  currBldrCtx = nullptr;
 }
 
 
//===----------------------------------------------------------------------===//
@@ -2835,16 +2830,15 @@ assumeCondition(const Stmt *Condition, ExplodedNode *N) 
{
 }
 
 void ExprEngine::processBranch(
-    const Stmt *Condition, NodeBuilderContext &BldCtx, ExplodedNode *Pred,
-    ExplodedNodeSet &Dst, const CFGBlock *DstT, const CFGBlock *DstF,
+    const Stmt *Condition, ExplodedNode *Pred, ExplodedNodeSet &Dst,
+    const CFGBlock *DstT, const CFGBlock *DstF,
     std::optional<unsigned> IterationsCompletedInLoop) {
   assert((!Condition || !isa<CXXBindTemporaryExpr>(Condition)) &&
          "CXXBindTemporaryExprs are handled by processBindTemporary.");
-  currBldrCtx = &BldCtx;
 
   // Check for NULL conditions; e.g. "for(;;)"
   if (!Condition) {
-    BranchNodeBuilder NullCondBldr(Dst, BldCtx, DstT, DstF);
+    BranchNodeBuilder NullCondBldr(Dst, *currBldrCtx, DstT, DstF);
     NullCondBldr.generateNode(Pred->getState(), true, Pred);
     return;
   }
@@ -2852,7 +2846,7 @@ void ExprEngine::processBranch(
   if (const auto *Ex = dyn_cast<Expr>(Condition))
     Condition = Ex->IgnoreParens();
 
-  Condition = ResolveCondition(Condition, BldCtx.getBlock());
+  Condition = ResolveCondition(Condition, getCurrBlock());
   PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
                                 Condition->getBeginLoc(),
                                 "Error evaluating branch");
@@ -2864,7 +2858,7 @@ void ExprEngine::processBranch(
   if (CheckersOutSet.empty())
     return;
 
-  BranchNodeBuilder Builder(Dst, BldCtx, DstT, DstF);
+  BranchNodeBuilder Builder(Dst, *currBldrCtx, DstT, DstF);
   for (ExplodedNode *PredN : CheckersOutSet) {
     ProgramStateRef PrevState = PredN->getState();
 
@@ -2954,7 +2948,6 @@ void ExprEngine::processBranch(
         Builder.generateNode(StFalse, false, PredN);
     }
   }
-  currBldrCtx = nullptr;
 }
 
 /// The GDM component containing the set of global variables which have been
@@ -2962,23 +2955,21 @@ void ExprEngine::processBranch(
 REGISTER_TRAIT_WITH_PROGRAMSTATE(InitializedGlobalsSet,
                                  llvm::ImmutableSet<const VarDecl *>)
 
-void ExprEngine::processStaticInitializer(
-    const DeclStmt *DS, NodeBuilderContext &BuilderCtx, ExplodedNode *Pred,
-    ExplodedNodeSet &Dst, const CFGBlock *DstT, const CFGBlock *DstF) {
-  currBldrCtx = &BuilderCtx;
-
+void ExprEngine::processStaticInitializer(const DeclStmt *DS,
+                                          ExplodedNode *Pred,
+                                          ExplodedNodeSet &Dst,
+                                          const CFGBlock *DstT,
+                                          const CFGBlock *DstF) {
   const auto *VD = cast<VarDecl>(DS->getSingleDecl());
   ProgramStateRef state = Pred->getState();
   bool initHasRun = state->contains<InitializedGlobalsSet>(VD);
-  BranchNodeBuilder Builder(Dst, BuilderCtx, DstT, DstF);
+  BranchNodeBuilder Builder(Dst, *currBldrCtx, DstT, DstF);
 
   if (!initHasRun) {
     state = state->add<InitializedGlobalsSet>(VD);
   }
 
   Builder.generateNode(state, initHasRun, Pred);
-
-  currBldrCtx = nullptr;
 }
 
 /// processIndirectGoto - Called by CoreEngine.  Used to generate successor
@@ -3014,18 +3005,15 @@ void 
ExprEngine::processIndirectGoto(IndirectGotoNodeBuilder &Builder,
     Builder.generateNode(Succ, State, Pred);
 }
 
-void ExprEngine::processBeginOfFunction(NodeBuilderContext &BC,
-                                        ExplodedNode *Pred,
+void ExprEngine::processBeginOfFunction(ExplodedNode *Pred,
                                         ExplodedNodeSet &Dst,
                                         const BlockEdge &L) {
-  SaveAndRestore<const NodeBuilderContext *> NodeContextRAII(currBldrCtx, &BC);
   getCheckerManager().runCheckersForBeginFunction(Dst, L, Pred, *this);
 }
 
 /// ProcessEndPath - Called by CoreEngine.  Used to generate end-of-path
 ///  nodes when the control reaches the end of a function.
-void ExprEngine::processEndOfFunction(NodeBuilderContext& BC,
-                                      ExplodedNode *Pred,
+void ExprEngine::processEndOfFunction(ExplodedNode *Pred,
                                       const ReturnStmt *RS) {
   ProgramStateRef State = Pred->getState();
 
@@ -3064,9 +3052,7 @@ void ExprEngine::processEndOfFunction(NodeBuilderContext& 
BC,
 
   // Perform the transition with cleanups.
   if (State != Pred->getState()) {
-    ExplodedNodeSet PostCleanup;
-    NodeBuilder Bldr(Pred, PostCleanup, BC);
-    Pred = Bldr.generateNode(Pred->getLocation(), State, Pred);
+    Pred = Engine.makeNode(Pred->getLocation(), State, Pred);
     if (!Pred) {
       // The node with clean temporaries already exists. We might have reached
       // it on a path on which we initialize 
diff erent temporaries.
@@ -3081,13 +3067,13 @@ void 
ExprEngine::processEndOfFunction(NodeBuilderContext& BC,
   if (Pred->getLocationContext()->inTopFrame()) {
     // Remove dead symbols.
     ExplodedNodeSet AfterRemovedDead;
-    removeDeadOnEndOfFunction(BC, Pred, AfterRemovedDead);
+    removeDeadOnEndOfFunction(Pred, AfterRemovedDead);
 
     // Notify checkers.
     for (const auto I : AfterRemovedDead)
-      getCheckerManager().runCheckersForEndFunction(BC, Dst, I, *this, RS);
+      getCheckerManager().runCheckersForEndFunction(Dst, I, *this, RS);
   } else {
-    getCheckerManager().runCheckersForEndFunction(BC, Dst, Pred, *this, RS);
+    getCheckerManager().runCheckersForEndFunction(Dst, Pred, *this, RS);
   }
 
   Engine.enqueueEndOfFunction(Dst, RS);
@@ -3095,12 +3081,11 @@ void 
ExprEngine::processEndOfFunction(NodeBuilderContext& BC,
 
 /// ProcessSwitch - Called by CoreEngine.  Used to generate successor
 ///  nodes by processing the 'effects' of a switch statement.
-void ExprEngine::processSwitch(NodeBuilderContext &BC, const SwitchStmt 
*Switch,
-                               ExplodedNode *Pred, ExplodedNodeSet &Dst) {
-  currBldrCtx = &BC;
+void ExprEngine::processSwitch(const SwitchStmt *Switch, ExplodedNode *Pred,
+                               ExplodedNodeSet &Dst) {
   const Expr *Condition = Switch->getCond();
 
-  SwitchNodeBuilder Builder(Dst, BC);
+  SwitchNodeBuilder Builder(Dst, *currBldrCtx);
   ExplodedNodeSet CheckersOutSet;
 
   getCheckerManager().runCheckersForBranchCondition(
@@ -3172,8 +3157,6 @@ void ExprEngine::processSwitch(NodeBuilderContext &BC, 
const SwitchStmt *Switch,
 
     Builder.generateDefaultCaseNode(State, Node);
   }
-
-  currBldrCtx = nullptr;
 }
 
 
//===----------------------------------------------------------------------===//
@@ -3601,7 +3584,7 @@ void ExprEngine::VisitAtomicExpr(const AtomicExpr *AE, 
ExplodedNode *Pred,
     }
 
     State = State->invalidateRegions(ValuesToInvalidate, getCFGElementRef(),
-                                     currBldrCtx->blockCount(), LCtx,
+                                     getNumVisitedCurrent(), LCtx,
                                      /*CausedByPointerEscape*/ true,
                                      /*Symbols=*/nullptr);
 
@@ -3950,7 +3933,7 @@ void ExprEngine::VisitGCCAsmStmt(const GCCAsmStmt *A, 
ExplodedNode *Pred,
 
     if (std::optional<Loc> LV = X.getAs<Loc>())
       state = state->invalidateRegions(*LV, getCFGElementRef(),
-                                       currBldrCtx->blockCount(),
+                                       getNumVisitedCurrent(),
                                        Pred->getLocationContext(),
                                        /*CausedByPointerEscape=*/true);
   }
@@ -3961,7 +3944,7 @@ void ExprEngine::VisitGCCAsmStmt(const GCCAsmStmt *A, 
ExplodedNode *Pred,
 
     if (std::optional<Loc> LV = X.getAs<Loc>())
       state = state->invalidateRegions(*LV, getCFGElementRef(),
-                                       currBldrCtx->blockCount(),
+                                       getNumVisitedCurrent(),
                                        Pred->getLocationContext(),
                                        /*CausedByPointerEscape=*/true);
   }

diff  --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp 
b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index b7fac30500d26..67beed5dbb6fb 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -65,7 +65,7 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
       // EXPERIMENTAL: "Conjured" symbols.
       // FIXME: Handle structs.
       if (RightV.isUnknown()) {
-        unsigned Count = currBldrCtx->blockCount();
+        unsigned Count = getNumVisitedCurrent();
         RightV = svalBuilder.conjureSymbolVal(nullptr, getCFGElementRef(), 
LCtx,
                                               Count);
       }
@@ -83,7 +83,7 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
       if (B->isAdditiveOp()) {
         // TODO: This can be removed after we enable history tracking with
         // SymSymExpr.
-        unsigned Count = currBldrCtx->blockCount();
+        unsigned Count = getNumVisitedCurrent();
         RightV = conjureOffsetSymbolOnLocation(
             RightV, LeftV, getCFGElementRef(), RHS->getType(), svalBuilder,
             Count, LCtx);
@@ -170,7 +170,7 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* 
B,
         // LValue on the LHS will bind to.
         LHSVal = svalBuilder.conjureSymbolVal(/*symbolTag=*/nullptr,
                                               getCFGElementRef(), LCtx, LTy,
-                                              currBldrCtx->blockCount());
+                                              getNumVisitedCurrent());
         // However, we need to convert the symbol to the computation type.
         Result = svalBuilder.evalCast(LHSVal, CTy, LTy);
       } else {
@@ -201,9 +201,8 @@ void ExprEngine::VisitBlockExpr(const BlockExpr *BE, 
ExplodedNode *Pred,
 
   const BlockDecl *BD = BE->getBlockDecl();
   // Get the value of the block itself.
-  SVal V = svalBuilder.getBlockPointer(BD, T,
-                                       Pred->getLocationContext(),
-                                       currBldrCtx->blockCount());
+  SVal V = svalBuilder.getBlockPointer(BD, T, Pred->getLocationContext(),
+                                       getNumVisitedCurrent());
 
   ProgramStateRef State = Pred->getState();
 
@@ -498,7 +497,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const 
Expr *Ex,
           if (val.isUnknown()) {
             DefinedOrUnknownSVal NewSym = svalBuilder.conjureSymbolVal(
                 /*symbolTag=*/nullptr, getCFGElementRef(), LCtx, resultType,
-                currBldrCtx->blockCount());
+                getNumVisitedCurrent());
             state = state->BindExpr(CastE, LCtx, NewSym);
           } else
             // Else, bind to the derived region value.
@@ -522,7 +521,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const 
Expr *Ex,
         if (val.isUnknown()) {
           val = svalBuilder.conjureSymbolVal(
               /*symbolTag=*/nullptr, getCFGElementRef(), LCtx, resultType,
-              currBldrCtx->blockCount());
+              getNumVisitedCurrent());
         }
         state = state->BindExpr(CastE, LCtx, val);
         Bldr.generateNode(CastE, Pred, state);
@@ -568,7 +567,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const 
Expr *Ex,
           resultType = getContext().getPointerType(resultType);
         SVal result = svalBuilder.conjureSymbolVal(
             /*symbolTag=*/nullptr, getCFGElementRef(), LCtx, resultType,
-            currBldrCtx->blockCount());
+            getNumVisitedCurrent());
         state = state->BindExpr(CastE, LCtx, result);
         Bldr.generateNode(CastE, Pred, state);
         continue;
@@ -661,7 +660,7 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, 
ExplodedNode *Pred,
 
           InitVal = svalBuilder.conjureSymbolVal(
               /*symbolTag=*/nullptr, getCFGElementRef(), LC, Ty,
-              currBldrCtx->blockCount());
+              getNumVisitedCurrent());
         }
 
 
@@ -831,7 +830,7 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex,
 
   if (!hasValue)
     V = svalBuilder.conjureSymbolVal(nullptr, getCFGElementRef(), LCtx,
-                                     currBldrCtx->blockCount());
+                                     getNumVisitedCurrent());
 
   // Generate a new node with the binding from the appropriate path.
   B.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V, true));
@@ -1115,7 +1114,7 @@ void ExprEngine::VisitIncrementDecrementOperator(const 
UnaryOperator* U,
     if (Result.isUnknown()){
       DefinedOrUnknownSVal SymVal = svalBuilder.conjureSymbolVal(
           /*symbolTag=*/nullptr, getCFGElementRef(), LCtx,
-          currBldrCtx->blockCount());
+          getNumVisitedCurrent());
       Result = SymVal;
 
       // If the value is a location, ++/-- should always preserve

diff  --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp 
b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 07852984e4ee3..0866dda766667 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -254,7 +254,7 @@ SVal ExprEngine::computeObjectUnderConstruction(
         QualType ReturnTy = RetE->getType();
         QualType RegionTy = ACtx.getPointerType(ReturnTy);
         return SVB.conjureSymbolVal(&TopLevelSymRegionTag, getCFGElementRef(),
-                                    SFC, RegionTy, currBldrCtx->blockCount());
+                                    SFC, RegionTy, getNumVisitedCurrent());
       }
       llvm_unreachable("Unhandled return value construction context!");
     }
@@ -975,7 +975,7 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, 
ExplodedNode *Pred,
   // really part of the CXXNewExpr because they happen BEFORE the
   // CXXConstructExpr subexpression. See PR12014 for some discussion.
 
-  unsigned blockCount = currBldrCtx->blockCount();
+  unsigned blockCount = getNumVisitedCurrent();
   const LocationContext *LCtx = Pred->getLocationContext();
   SVal symVal = UnknownVal();
   FunctionDecl *FD = CNE->getOperatorNew();
@@ -1138,7 +1138,7 @@ void ExprEngine::VisitCXXCatchStmt(const CXXCatchStmt 
*CS, ExplodedNode *Pred,
 
   const LocationContext *LCtx = Pred->getLocationContext();
   SVal V = svalBuilder.conjureSymbolVal(getCFGElementRef(), LCtx, 
VD->getType(),
-                                        currBldrCtx->blockCount());
+                                        getNumVisitedCurrent());
   ProgramStateRef state = Pred->getState();
   state = state->bindLoc(state->getLValue(VD, LCtx), V, LCtx);
 

diff  --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp 
b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index a407a923d7d0f..a4a22ce10952c 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -39,8 +39,7 @@ STAT_COUNTER(NumInlinedCalls, "The # of times we inlined a 
call");
 STAT_COUNTER(NumReachedInlineCountMax,
              "The # of times we reached inline count maximum");
 
-void ExprEngine::processCallEnter(NodeBuilderContext& BC, CallEnter CE,
-                                  ExplodedNode *Pred) {
+void ExprEngine::processCallEnter(CallEnter CE, ExplodedNode *Pred) {
   // Get the entry block in the CFG of the callee.
   const CFGBlock *Entry = CE.getEntry();
 
@@ -62,8 +61,13 @@ void ExprEngine::processCallEnter(NodeBuilderContext& BC, 
CallEnter CE,
   ExplodedNode *Node = G.getNode(Loc, state, false, &isNew);
   Node->addPredecessor(Pred, G);
   if (isNew) {
+    // FIXME: In the `processBeginOfFunction` callback
+    // `ExprEngine::getCurrLocationContext()` can be 
diff erent from the
+    // `LocationContext` queried from e.g. the `ExplodedNode`s. I'm not
+    // touching this now because this commit is NFC; but in the future it would
+    // be nice to avoid this inconsistency.
     ExplodedNodeSet DstBegin;
-    processBeginOfFunction(BC, Node, DstBegin, Loc);
+    processBeginOfFunction(Node, DstBegin, Loc);
     Engine.enqueue(DstBegin);
   }
 }
@@ -158,8 +162,7 @@ static SVal adjustReturnValue(SVal V, QualType ExpectedTy, 
QualType ActualTy,
   return UnknownVal();
 }
 
-void ExprEngine::removeDeadOnEndOfFunction(NodeBuilderContext& BC,
-                                           ExplodedNode *Pred,
+void ExprEngine::removeDeadOnEndOfFunction(ExplodedNode *Pred,
                                            ExplodedNodeSet &Dst) {
   // Find the last statement in the function and the corresponding basic block.
   const Stmt *LastSt = nullptr;
@@ -175,7 +178,6 @@ void 
ExprEngine::removeDeadOnEndOfFunction(NodeBuilderContext& BC,
   // point will be associated. However, we only want to use LastStmt as a
   // reference for what to clean up if it's a ReturnStmt; otherwise, everything
   // is dead.
-  SaveAndRestore<const NodeBuilderContext *> NodeContextRAII(currBldrCtx, &BC);
   const LocationContext *LCtx = Pred->getLocationContext();
   removeDead(Pred, Dst, dyn_cast<ReturnStmt>(LastSt), LCtx,
              LCtx->getAnalysisDeclContext()->getBody(),
@@ -551,8 +553,8 @@ void ExprEngine::inlineCall(WorkList *WList, const 
CallEvent &Call,
   // Construct a new stack frame for the callee.
   AnalysisDeclContext *CalleeADC = AMgr.getAnalysisDeclContext(D);
   const StackFrameContext *CalleeSFC =
-      CalleeADC->getStackFrame(ParentOfCallee, CallE, currBldrCtx->getBlock(),
-                               currBldrCtx->blockCount(), currStmtIdx);
+      CalleeADC->getStackFrame(ParentOfCallee, CallE, getCurrBlock(),
+                               getNumVisitedCurrent(), currStmtIdx);
 
   CallEnter Loc(CallE, CalleeSFC, CurLC);
 
@@ -768,7 +770,7 @@ ProgramStateRef ExprEngine::bindReturnValue(const CallEvent 
&Call,
 
   SVal R;
   QualType ResultTy = Call.getResultType();
-  unsigned Count = currBldrCtx->blockCount();
+  unsigned Count = getNumVisitedCurrent();
   if (auto RTC = getCurrentCFGElement().getAs<CFGCXXRecordTypedCall>()) {
     // Conjure a temporary if the function returns an object by value.
     SVal Target;
@@ -833,7 +835,7 @@ ProgramStateRef ExprEngine::bindReturnValue(const CallEvent 
&Call,
 // a conjured return value.
 void ExprEngine::conservativeEvalCall(const CallEvent &Call, NodeBuilder &Bldr,
                                       ExplodedNode *Pred, ProgramStateRef 
State) {
-  State = Call.invalidateRegions(currBldrCtx->blockCount(), State);
+  State = Call.invalidateRegions(getNumVisitedCurrent(), State);
   State = bindReturnValue(Call, Pred->getLocationContext(), State);
 
   // And make the result node.

diff  --git a/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp 
b/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
index bb0fd6ded2def..07703bdf38239 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
@@ -48,7 +48,7 @@ static void populateObjCForDestinationSet(ExplodedNodeSet 
&dstLocation,
                                           const ObjCForCollectionStmt *S,
                                           ConstCFGElementRef elem,
                                           SVal elementV, SymbolManager &SymMgr,
-                                          const NodeBuilderContext 
*currBldrCtx,
+                                          unsigned NumVisitedCurrent,
                                           NodeBuilder &Bldr, bool hasElements) 
{
 
   for (ExplodedNode *Pred : dstLocation) {
@@ -69,7 +69,7 @@ static void populateObjCForDestinationSet(ExplodedNodeSet 
&dstLocation,
         SVal V;
         if (hasElements) {
           SymbolRef Sym =
-              SymMgr.conjureSymbol(elem, LCtx, T, currBldrCtx->blockCount());
+              SymMgr.conjureSymbol(elem, LCtx, T, NumVisitedCurrent);
           V = svalBuilder.makeLoc(Sym);
         } else {
           V = svalBuilder.makeIntVal(0, T);
@@ -136,12 +136,13 @@ void ExprEngine::VisitObjCForCollectionStmt(const 
ObjCForCollectionStmt *S,
 
     if (!isContainerNull)
       populateObjCForDestinationSet(DstLocationSingleton, svalBuilder, S,
-                                    elemRef, elementV, SymMgr, currBldrCtx,
-                                    Bldr,
+                                    elemRef, elementV, SymMgr,
+                                    getNumVisitedCurrent(), Bldr,
                                     /*hasElements=*/true);
 
     populateObjCForDestinationSet(DstLocationSingleton, svalBuilder, S, 
elemRef,
-                                  elementV, SymMgr, currBldrCtx, Bldr,
+                                  elementV, SymMgr, getNumVisitedCurrent(),
+                                  Bldr,
                                   /*hasElements=*/false);
 
     // Finally, run any custom checkers.


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

Reply via email to