[clang] 3b9f8f0 - [analyzer][NFC] Merge `BlockInvocationContext` class into `StackFrameContext` (#194857)

via cfe-commits cfe-commits at lists.llvm.org
Mon May 4 04:56:49 PDT 2026


Author: tigbr
Date: 2026-05-04T13:56:43+02:00
New Revision: 3b9f8f03a0ba3962a58b803bd0d2a9f65ab765e4

URL: https://github.com/llvm/llvm-project/commit/3b9f8f03a0ba3962a58b803bd0d2a9f65ab765e4
DIFF: https://github.com/llvm/llvm-project/commit/3b9f8f03a0ba3962a58b803bd0d2a9f65ab765e4.diff

LOG: [analyzer][NFC] Merge `BlockInvocationContext` class into `StackFrameContext` (#194857)

At the moment, the execution stack in the analyzer is represented with
the `LocationContext` base class and its two sub-classes
`StackFrameContext` and `BlockInvocationContext`. This hierarchy,
however, is more complicated than necessary and, in issue #190973, a
roadmap was created to reduce this hierarchy down to just a single
`StackFrame` class.

This patch implements the first five steps of that roadmap.
Specifically, the functionality of `BlockInvocationContext` was merged
into the `StackFrameContext` class and the `BlockInvocationContext`
class was removed together with its usages.

Added: 
    

Modified: 
    clang/include/clang/Analysis/AnalysisDeclContext.h
    clang/lib/Analysis/AnalysisDeclContext.cpp
    clang/lib/StaticAnalyzer/Core/CallEvent.cpp
    clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
    clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
    clang/lib/StaticAnalyzer/Core/MemRegion.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Analysis/AnalysisDeclContext.h b/clang/include/clang/Analysis/AnalysisDeclContext.h
index 00785d6d1db51..fb9ed61229277 100644
--- a/clang/include/clang/Analysis/AnalysisDeclContext.h
+++ b/clang/include/clang/Analysis/AnalysisDeclContext.h
@@ -36,7 +36,6 @@ namespace clang {
 class AnalysisDeclContextManager;
 class ASTContext;
 class BlockDecl;
-class BlockInvocationContext;
 class CFGReverseBlockReachabilityAnalysis;
 class ImplicitParamDecl;
 class LocationContext;
@@ -179,14 +178,10 @@ class AnalysisDeclContext {
 
   /// \copydoc LocationContextManager::getStackFrame()
   const StackFrameContext *getStackFrame(LocationContext const *ParentLC,
-                                         const Expr *E, const CFGBlock *Blk,
+                                         const void *Data, const Expr *E,
+                                         const CFGBlock *Blk,
                                          unsigned BlockCount, unsigned Index);
 
-  /// \copydoc LocationContextManager::getBlockInvocationContext()
-  const BlockInvocationContext *
-  getBlockInvocationContext(const LocationContext *ParentLC,
-                            const BlockDecl *BD, const void *Data);
-
   /// \returns The specified analysis object, lazily running the analysis if
   /// necessary or nullptr if the analysis could not run.
   template <typename T> T *getAnalysis() {
@@ -208,13 +203,9 @@ class AnalysisDeclContext {
   LocationContextManager &getLocationContextManager();
 };
 
-/// It wraps the AnalysisDeclContext to represent both the call stack with
-/// the help of StackFrameContext and inside the function calls the
-/// BlockInvocationContext. It is needed for context sensitive analysis to
-/// model entering, leaving or inlining function calls.
 class LocationContext : public llvm::FoldingSetNode {
 public:
-  enum ContextKind { StackFrame, Block };
+  enum ContextKind { StackFrame };
 
 private:
   ContextKind Kind;
@@ -299,6 +290,9 @@ class LocationContext : public llvm::FoldingSetNode {
 class StackFrameContext : public LocationContext {
   friend class LocationContextManager;
 
+  // Extra data for BlockInvocations
+  const void *Data;
+
   // The call site where this stack frame is established.
   const Expr *CallSite;
 
@@ -314,14 +308,16 @@ class StackFrameContext : public LocationContext {
   const unsigned Index;
 
   StackFrameContext(AnalysisDeclContext *ADC, const LocationContext *ParentLC,
-                    const Expr *E, const CFGBlock *Block, unsigned BlockCount,
-                    unsigned Index, int64_t ID)
-      : LocationContext(StackFrame, ADC, ParentLC, ID), CallSite(E),
+                    const void *Data, const Expr *E, const CFGBlock *Block,
+                    unsigned BlockCount, unsigned Index, int64_t ID)
+      : LocationContext(StackFrame, ADC, ParentLC, ID), Data(Data), CallSite(E),
         Block(Block), BlockCount(BlockCount), Index(Index) {}
 
 public:
   ~StackFrameContext() override = default;
 
+  const void *getData() const { return Data; }
+
   const Expr *getCallSite() const { return CallSite; }
 
   const CFGBlock *getCallSiteBlock() const { return Block; }
@@ -335,10 +331,11 @@ class StackFrameContext : public LocationContext {
   void Profile(llvm::FoldingSetNodeID &ID) override;
 
   static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ADC,
-                      const LocationContext *ParentLC, const Expr *E,
-                      const CFGBlock *Block, unsigned BlockCount,
+                      const LocationContext *ParentLC, const void *Data,
+                      const Expr *E, const CFGBlock *Block, unsigned BlockCount,
                       unsigned Index) {
     ProfileCommon(ID, StackFrame, ADC, ParentLC, E);
+    ID.AddPointer(Data);
     ID.AddPointer(Block);
     ID.AddInteger(BlockCount);
     ID.AddInteger(Index);
@@ -349,41 +346,6 @@ class StackFrameContext : public LocationContext {
   }
 };
 
-/// It represents a block invocation (based on BlockCall).
-class BlockInvocationContext : public LocationContext {
-  friend class LocationContextManager;
-
-  const BlockDecl *BD;
-
-  // FIXME: Come up with a more type-safe way to model context-sensitivity.
-  const void *Data;
-
-  BlockInvocationContext(AnalysisDeclContext *ADC,
-                         const LocationContext *ParentLC, const BlockDecl *BD,
-                         const void *Data, int64_t ID)
-      : LocationContext(Block, ADC, ParentLC, ID), BD(BD), Data(Data) {}
-
-public:
-  ~BlockInvocationContext() override = default;
-
-  const BlockDecl *getBlockDecl() const { return BD; }
-
-  const void *getData() const { return Data; }
-
-  void Profile(llvm::FoldingSetNodeID &ID) override;
-
-  static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ADC,
-                      const LocationContext *ParentLC, const BlockDecl *BD,
-                      const void *Data) {
-    ProfileCommon(ID, Block, ADC, ParentLC, BD);
-    ID.AddPointer(Data);
-  }
-
-  static bool classof(const LocationContext *LC) {
-    return LC->getKind() == Block;
-  }
-};
-
 class LocationContextManager {
   llvm::FoldingSet<LocationContext> Contexts;
 
@@ -396,7 +358,10 @@ class LocationContextManager {
   /// Obtain a context of the call stack using its parent context.
   ///
   /// \param ADC        The AnalysisDeclContext.
-  /// \param ParentLC   The parent context of this newly created context.
+  /// \param ParentLC   The parent context of this newly created
+  ///                   context.
+  /// \param Data       Extra data in case this StackFrameContext is
+  ///                   created for a BlockInvocation.
   /// \param E          The call expression.
   /// \param Block      The basic block.
   /// \param BlockCount The current count of entering into \p Block.
@@ -405,20 +370,10 @@ class LocationContextManager {
   /// \returns The stack frame context corresponding to the call.
   const StackFrameContext *getStackFrame(AnalysisDeclContext *ADC,
                                          const LocationContext *ParentLC,
-                                         const Expr *E, const CFGBlock *Block,
+                                         const void *Data, const Expr *E,
+                                         const CFGBlock *Block,
                                          unsigned BlockCount, unsigned StmtIdx);
 
-  /// Obtain a context of the block invocation using its parent context.
-  ///
-  /// \param ADC      The AnalysisDeclContext.
-  /// \param ParentLC The parent context of this newly created context.
-  /// \param BD       The BlockDecl.
-  /// \param Data     The raw data to store as part of the context.
-  const BlockInvocationContext *
-  getBlockInvocationContext(AnalysisDeclContext *ADC,
-                            const LocationContext *ParentLC,
-                            const BlockDecl *BD, const void *Data);
-
   /// Discard all previously created LocationContext objects.
   void clear();
 };
@@ -469,8 +424,8 @@ class AnalysisDeclContextManager {
   ///
   /// \returns The top level stack frame for \p D.
   const StackFrameContext *getStackFrame(const Decl *D) {
-    return LocCtxMgr.getStackFrame(getContext(D), nullptr, nullptr, nullptr, 0,
-                                   0);
+    return LocCtxMgr.getStackFrame(getContext(D), nullptr, nullptr, nullptr,
+                                   nullptr, 0, 0);
   }
 
   BodyFarm &getBodyFarm();

diff  --git a/clang/lib/Analysis/AnalysisDeclContext.cpp b/clang/lib/Analysis/AnalysisDeclContext.cpp
index 266d20632e3cc..132b824857651 100644
--- a/clang/lib/Analysis/AnalysisDeclContext.cpp
+++ b/clang/lib/Analysis/AnalysisDeclContext.cpp
@@ -310,20 +310,13 @@ AnalysisDeclContext *AnalysisDeclContextManager::getContext(const Decl *D) {
 
 BodyFarm &AnalysisDeclContextManager::getBodyFarm() { return FunctionBodyFarm; }
 
-const StackFrameContext *
-AnalysisDeclContext::getStackFrame(const LocationContext *ParentLC,
-                                   const Expr *E, const CFGBlock *Blk,
-                                   unsigned BlockCount, unsigned Index) {
-  return getLocationContextManager().getStackFrame(this, ParentLC, E, Blk,
+const StackFrameContext *AnalysisDeclContext::getStackFrame(
+    const LocationContext *ParentLC, const void *Data, const Expr *E,
+    const CFGBlock *Blk, unsigned BlockCount, unsigned Index) {
+  return getLocationContextManager().getStackFrame(this, ParentLC, Data, E, Blk,
                                                    BlockCount, Index);
 }
 
-const BlockInvocationContext *AnalysisDeclContext::getBlockInvocationContext(
-    const LocationContext *ParentLC, const BlockDecl *BD, const void *Data) {
-  return getLocationContextManager().getBlockInvocationContext(this, ParentLC,
-                                                               BD, Data);
-}
-
 bool AnalysisDeclContext::isInStdNamespace(const Decl *D) {
   const DeclContext *DC = D->getDeclContext()->getEnclosingNamespaceContext();
   const auto *ND = dyn_cast<NamespaceDecl>(DC);
@@ -415,50 +408,31 @@ void LocationContext::ProfileCommon(llvm::FoldingSetNodeID &ID,
 }
 
 void StackFrameContext::Profile(llvm::FoldingSetNodeID &ID) {
-  Profile(ID, getAnalysisDeclContext(), getParent(), CallSite, Block,
+  Profile(ID, getAnalysisDeclContext(), getParent(), Data, CallSite, Block,
           BlockCount, Index);
 }
 
-void BlockInvocationContext::Profile(llvm::FoldingSetNodeID &ID) {
-  Profile(ID, getAnalysisDeclContext(), getParent(), BD, Data);
-}
-
 //===----------------------------------------------------------------------===//
 // LocationContext creation.
 //===----------------------------------------------------------------------===//
 
 const StackFrameContext *LocationContextManager::getStackFrame(
-    AnalysisDeclContext *Ctx, const LocationContext *Parent, const Expr *E,
-    const CFGBlock *Blk, unsigned BlockCount, unsigned StmtIdx) {
+    AnalysisDeclContext *Ctx, const LocationContext *Parent, const void *Data,
+    const Expr *E, const CFGBlock *Blk, unsigned BlockCount, unsigned StmtIdx) {
   llvm::FoldingSetNodeID ID;
-  StackFrameContext::Profile(ID, Ctx, Parent, E, Blk, BlockCount, StmtIdx);
+  StackFrameContext::Profile(ID, Ctx, Parent, Data, E, Blk, BlockCount,
+                             StmtIdx);
   void *InsertPos;
   auto *L =
    cast_or_null<StackFrameContext>(Contexts.FindNodeOrInsertPos(ID, InsertPos));
   if (!L) {
-    L = new StackFrameContext(Ctx, Parent, E, Blk, BlockCount, StmtIdx,
+    L = new StackFrameContext(Ctx, Parent, Data, E, Blk, BlockCount, StmtIdx,
                               ++NewID);
     Contexts.InsertNode(L, InsertPos);
   }
   return L;
 }
 
-const BlockInvocationContext *LocationContextManager::getBlockInvocationContext(
-    AnalysisDeclContext *ADC, const LocationContext *ParentLC,
-    const BlockDecl *BD, const void *Data) {
-  llvm::FoldingSetNodeID ID;
-  BlockInvocationContext::Profile(ID, ADC, ParentLC, BD, Data);
-  void *InsertPos;
-  auto *L =
-    cast_or_null<BlockInvocationContext>(Contexts.FindNodeOrInsertPos(ID,
-                                                                    InsertPos));
-  if (!L) {
-    L = new BlockInvocationContext(ADC, ParentLC, BD, Data, ++NewID);
-    Contexts.InsertNode(L, InsertPos);
-  }
-  return L;
-}
-
 //===----------------------------------------------------------------------===//
 // LocationContext methods.
 //===----------------------------------------------------------------------===//
@@ -520,13 +494,6 @@ void LocationContext::dumpStack(raw_ostream &Out) const {
         printLocation(Out, SM, E->getBeginLoc());
       }
       break;
-    case Block:
-      Out << "Invoking block";
-      if (const Decl *D = cast<BlockInvocationContext>(LCtx)->getDecl()) {
-        Out << " defined at line ";
-        printLocation(Out, SM, D->getBeginLoc());
-      }
-      break;
     }
     Out << '\n';
   }
@@ -565,14 +532,6 @@ void LocationContext::printJson(raw_ostream &Out, const char *NL,
 
       Out << ", \"items\": ";
       break;
-    case Block:
-      Out << "Invoking block\" ";
-      if (const Decl *D = cast<BlockInvocationContext>(LCtx)->getDecl()) {
-        Out << ", \"location\": ";
-        printSourceLocationAsJson(Out, D->getBeginLoc(), SM);
-        Out << ' ';
-      }
-      break;
     }
 
     printMoreInfoPerContext(LCtx);

diff  --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
index eb32b9e581291..911ffdf1d4eab 100644
--- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -186,7 +186,7 @@ CallEvent::getCalleeStackFrame(unsigned BlockCount) const {
         break;
   assert(Idx < Sz);
 
-  return ADC->getStackFrame(LCtx, E, B, BlockCount, Idx);
+  return ADC->getStackFrame(LCtx, nullptr, E, B, BlockCount, Idx);
 }
 
 const ParamVarRegion

diff  --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 5807b4db61fef..72394817da326 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -222,12 +222,6 @@ SVal ExprEngine::computeObjectUnderConstruction(
           // able to find construction context at all.
           break;
         }
-        if (isa<BlockInvocationContext>(CallerLCtx)) {
-          // Unwrap block invocation contexts. They're mostly part of
-          // the current stack frame.
-          CallerLCtx = CallerLCtx->getParent();
-          assert(!isa<BlockInvocationContext>(CallerLCtx));
-        }
 
         unsigned NVCaller = getNumVisited(CallerLCtx, SFC->getCallSiteBlock());
         return computeObjectUnderConstruction(
@@ -447,12 +441,6 @@ ProgramStateRef ExprEngine::updateObjectsUnderConstruction(
       auto RTC = (*SFC->getCallSiteBlock())[SFC->getIndex()]
                      .getAs<CFGCXXRecordTypedCall>();
       assert(RTC && "Could not have had a target region without it");
-      if (isa<BlockInvocationContext>(CallerLCtx)) {
-        // Unwrap block invocation contexts. They're mostly part of
-        // the current stack frame.
-        CallerLCtx = CallerLCtx->getParent();
-        assert(!isa<BlockInvocationContext>(CallerLCtx));
-      }
 
       return updateObjectsUnderConstruction(
           V, SFC->getCallSite(), State, CallerLCtx,

diff  --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index eceb29b4f12b8..1c5e7972d7fb9 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -534,15 +534,12 @@ void ExprEngine::inlineCall(WorkList *WList, const CallEvent &Call,
 
   const LocationContext *CurLC = Pred->getLocationContext();
   const StackFrameContext *CallerSFC = CurLC->getStackFrame();
-  const LocationContext *ParentOfCallee = CallerSFC;
+  const BlockDataRegion *BlockInvocationData = nullptr;
   if (Call.getKind() == CE_Block &&
       !cast<BlockCall>(Call).isConversionFromLambda()) {
-    const BlockDataRegion *BR = cast<BlockCall>(Call).getBlockRegion();
-    assert(BR && "If we have the block definition we should have its region");
-    AnalysisDeclContext *BlockCtx = AMgr.getAnalysisDeclContext(D);
-    ParentOfCallee = BlockCtx->getBlockInvocationContext(CallerSFC,
-                                                         cast<BlockDecl>(D),
-                                                         BR);
+    BlockInvocationData = cast<BlockCall>(Call).getBlockRegion();
+    assert(BlockInvocationData &&
+           "If we have the block definition we should have its region");
   }
 
   // This may be NULL, but that's fine.
@@ -550,9 +547,9 @@ 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, getCurrBlock(),
-                               getNumVisitedCurrent(), currStmtIdx);
+  const StackFrameContext *CalleeSFC = CalleeADC->getStackFrame(
+      CallerSFC, BlockInvocationData, CallE, getCurrBlock(),
+      getNumVisitedCurrent(), currStmtIdx);
 
   CallEnter Loc(CallE, CalleeSFC, CurLC);
 

diff  --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
index 941cb2fa2a103..ac4c16bcddf00 100644
--- a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -1004,15 +1004,15 @@ getStackOrCaptureRegionForDeclContext(const LocationContext *LC,
     if (const auto *SFC = dyn_cast<StackFrameContext>(LC)) {
       if (cast<DeclContext>(SFC->getDecl()) == DC)
         return SFC;
-    }
-    if (const auto *BC = dyn_cast<BlockInvocationContext>(LC)) {
-      const auto *BR = static_cast<const BlockDataRegion *>(BC->getData());
-      // FIXME: This can be made more efficient.
-      for (auto Var : BR->referenced_vars()) {
-        const TypedValueRegion *OrigR = Var.getOriginalRegion();
-        if (const auto *VR = dyn_cast<VarRegion>(OrigR)) {
-          if (VR->getDecl() == VD)
-            return cast<VarRegion>(Var.getCapturedRegion());
+      if (SFC->getData()) {
+        // FIXME: This can be made more efficient.
+        for (auto Var : static_cast<const BlockDataRegion *>(SFC->getData())
+                            ->referenced_vars()) {
+          const TypedValueRegion *OrigR = Var.getOriginalRegion();
+          if (const auto *VR = dyn_cast<VarRegion>(OrigR)) {
+            if (VR->getDecl() == VD)
+              return cast<VarRegion>(Var.getCapturedRegion());
+          }
         }
       }
     }


        


More information about the cfe-commits mailing list