[clang] [nfc][analyzer] Add MemSpace trait to program state (PR #123003)

Balazs Benics via cfe-commits cfe-commits at lists.llvm.org
Sun Feb 2 11:29:38 PST 2025


https://github.com/steakhal updated https://github.com/llvm/llvm-project/pull/123003

>From 7e0758d2ead53bd4288989b8b2eda218cd6dc34a Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Mon, 13 Jan 2025 12:34:50 -0600
Subject: [PATCH 01/55] [analyzer] Add MemSpace trait to program state

This trait associates MemSpaceRegions with MemRegions to allow refining or
changing information known about memory regions after they are created, since
they are immutable. This commit is an intermediate step towards moving
MemSpaceRegion out of the MemRegion class hierarchy and moving all notion of
MemSpaceRegion to the trait. The intermediate step is that for now, only
MemRegions with UnknownSpaceRegion are mapped in the trait and checked in
checkers/core.
---
 .../Core/PathSensitive/MemSpaces.h            | 47 ++++++++++++++
 .../Checkers/ArrayBoundCheckerV2.cpp          |  1 +
 .../Checkers/MacOSXAPIChecker.cpp             | 10 +--
 .../StaticAnalyzer/Checkers/MallocChecker.cpp | 32 +++++++---
 .../StaticAnalyzer/Checkers/MoveChecker.cpp   | 41 ++++++------
 .../Checkers/PutenvStackArrayChecker.cpp      | 10 ++-
 .../RetainCountDiagnostics.cpp                | 12 +++-
 .../Checkers/StackAddrEscapeChecker.cpp       | 26 +++++---
 .../Checkers/UnixAPIChecker.cpp               |  3 +-
 .../Core/BugReporterVisitors.cpp              | 12 +++-
 clang/lib/StaticAnalyzer/Core/CMakeLists.txt  |  1 +
 clang/lib/StaticAnalyzer/Core/ExprEngine.cpp  | 10 +++
 clang/lib/StaticAnalyzer/Core/MemSpaces.cpp   | 62 +++++++++++++++++++
 13 files changed, 221 insertions(+), 46 deletions(-)
 create mode 100644 clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
 create mode 100644 clang/lib/StaticAnalyzer/Core/MemSpaces.cpp

diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
new file mode 100644
index 000000000000000..178a6b60c1cb1a5
--- /dev/null
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
@@ -0,0 +1,47 @@
+//===-- MemSpaces.h -----------------------------------------------*- C++ -*--//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// TODO
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CHECKERS_MEMSPACES_H
+#define LLVM_CLANG_STATICANALYZER_CHECKERS_MEMSPACES_H
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
+
+namespace clang {
+namespace ento {
+
+class MemRegion;
+class MemSpaceRegion;
+
+namespace memspace {
+
+[[nodiscard]] ProgramStateRef setMemSpaceTrait(ProgramStateRef State,
+                                               const MemRegion *MR,
+                                               const MemSpaceRegion *MS);
+
+[[nodiscard]] const MemSpaceRegion *getMemSpaceTrait(ProgramStateRef State,
+                                                     const MemRegion *MR);
+
+[[nodiscard]] bool hasMemSpaceTrait(ProgramStateRef State, const MemRegion *MR);
+
+template <typename FirstT, typename... RestT>
+[[nodiscard]] bool isMemSpaceOrTrait(ProgramStateRef State,
+                                     const MemRegion *MR) {
+  return isa<FirstT, RestT...>(MR->getMemorySpace()) ||
+         isa_and_nonnull<FirstT, RestT...>(getMemSpaceTrait(State, MR));
+}
+
+} // namespace memspace
+} // namespace ento
+} // namespace clang
+
+#endif // LLVM_CLANG_STATICANALYZER_CHECKERS_MEMSPACES_H
diff --git a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
index 6422933c8828a91..e97be53fee4c7fe 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
@@ -22,6 +22,7 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
 #include "llvm/ADT/APSInt.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/Support/FormatVariadic.h"
diff --git a/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
index 754b167642961cb..858b6a37551f5d5 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
@@ -22,6 +22,7 @@
 #include "clang/StaticAnalyzer/Core/Checker.h"
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringSwitch.h"
@@ -75,10 +76,11 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
   if (!R)
     return;
 
+  ProgramStateRef State = C.getState();
+
   // Global variables are fine.
   const MemRegion *RB = R->getBaseRegion();
-  const MemSpaceRegion *RS = RB->getMemorySpace();
-  if (isa<GlobalsSpaceRegion>(RS))
+  if (memspace::isMemSpaceOrTrait<GlobalsSpaceRegion>(State, RB))
     return;
 
   // Handle _dispatch_once.  In some versions of the OS X SDK we have the case
@@ -117,9 +119,9 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
     if (IVR != R)
       os << " memory within";
     os << " the instance variable '" << IVR->getDecl()->getName() << '\'';
-  } else if (isa<HeapSpaceRegion>(RS)) {
+  } else if (memspace::isMemSpaceOrTrait<HeapSpaceRegion>(State, RB)) {
     os << " heap-allocated memory";
-  } else if (isa<UnknownSpaceRegion>(RS)) {
+  } else if (isa<UnknownSpaceRegion>(RB->getMemorySpace())) {
     // Presence of an IVar superregion has priority over this branch, because
     // ObjC objects are on the heap even if the core doesn't realize this.
     // Presence of a block variable base region has priority over this branch,
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 4166cf14391e2d0..76fee2f1322e17a 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -72,6 +72,7 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
@@ -784,7 +785,8 @@ class MallocChecker
                                              bool IsALeakCheck = false) const;
   ///@}
   static bool SummarizeValue(raw_ostream &os, SVal V);
-  static bool SummarizeRegion(raw_ostream &os, const MemRegion *MR);
+  static bool SummarizeRegion(ProgramStateRef State, raw_ostream &os,
+                              const MemRegion *MR);
 
   void HandleNonHeapDealloc(CheckerContext &C, SVal ArgVal, SourceRange Range,
                             const Expr *DeallocExpr,
@@ -2206,13 +2208,21 @@ MallocChecker::FreeMemAux(CheckerContext &C, const Expr *ArgExpr,
 
   // Parameters, locals, statics, globals, and memory returned by
   // __builtin_alloca() shouldn't be freed.
-  if (!isa<UnknownSpaceRegion, HeapSpaceRegion>(MS)) {
+  // Should skip this check if:
+  // - The region is in the heap
+  // - The region has unknown memspace and no trait for further clarification
+  //   (i.e., just unknown)
+  // - The region has unknown memspace and a heap memspace trait
+  const MemSpaceRegion *MSTrait = memspace::getMemSpaceTrait(State, R);
+  bool HasHeapOrUnknownTrait = !MSTrait || isa<HeapSpaceRegion>(MSTrait);
+  if (!(isa<HeapSpaceRegion>(MS) ||
+        (isa<UnknownSpaceRegion>(MS) && HasHeapOrUnknownTrait))) {
     // Regions returned by malloc() are represented by SymbolicRegion objects
     // within HeapSpaceRegion. Of course, free() can work on memory allocated
     // outside the current function, so UnknownSpaceRegion is also a
     // possibility here.
 
-    if (isa<AllocaRegion>(R))
+    if (isa<AllocaRegion>(R) || isa_and_nonnull<AllocaRegion>(MSTrait))
       HandleFreeAlloca(C, ArgVal, ArgExpr->getSourceRange());
     else
       HandleNonHeapDealloc(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,
@@ -2384,7 +2394,7 @@ bool MallocChecker::SummarizeValue(raw_ostream &os, SVal V) {
   return true;
 }
 
-bool MallocChecker::SummarizeRegion(raw_ostream &os,
+bool MallocChecker::SummarizeRegion(ProgramStateRef State, raw_ostream &os,
                                     const MemRegion *MR) {
   switch (MR->getKind()) {
   case MemRegion::FunctionCodeRegionKind: {
@@ -2404,8 +2414,10 @@ bool MallocChecker::SummarizeRegion(raw_ostream &os,
     return true;
   default: {
     const MemSpaceRegion *MS = MR->getMemorySpace();
+    const MemSpaceRegion *MSTrait = memspace::getMemSpaceTrait(State, MR);
 
-    if (isa<StackLocalsSpaceRegion>(MS)) {
+    if (isa<StackLocalsSpaceRegion>(MS) ||
+        isa_and_nonnull<StackLocalsSpaceRegion>(MSTrait)) {
       const VarRegion *VR = dyn_cast<VarRegion>(MR);
       const VarDecl *VD;
       if (VR)
@@ -2420,7 +2432,8 @@ bool MallocChecker::SummarizeRegion(raw_ostream &os,
       return true;
     }
 
-    if (isa<StackArgumentsSpaceRegion>(MS)) {
+    if (isa<StackArgumentsSpaceRegion>(MS) ||
+        isa_and_nonnull<StackArgumentsSpaceRegion>(MSTrait)) {
       const VarRegion *VR = dyn_cast<VarRegion>(MR);
       const VarDecl *VD;
       if (VR)
@@ -2435,7 +2448,8 @@ bool MallocChecker::SummarizeRegion(raw_ostream &os,
       return true;
     }
 
-    if (isa<GlobalsSpaceRegion>(MS)) {
+    if (isa<GlobalsSpaceRegion>(MS) ||
+        isa_and_nonnull<GlobalsSpaceRegion>(MSTrait)) {
       const VarRegion *VR = dyn_cast<VarRegion>(MR);
       const VarDecl *VD;
       if (VR)
@@ -2489,8 +2503,8 @@ void MallocChecker::HandleNonHeapDealloc(CheckerContext &C, SVal ArgVal,
       os << "deallocator";
 
     os << " is ";
-    bool Summarized = MR ? SummarizeRegion(os, MR)
-                         : SummarizeValue(os, ArgVal);
+    bool Summarized =
+        MR ? SummarizeRegion(C.getState(), os, MR) : SummarizeValue(os, ArgVal);
     if (Summarized)
       os << ", which is not memory allocated by ";
     else
diff --git a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
index 52416e213991474..d4ff8186ea69c95 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
@@ -22,6 +22,7 @@
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
 #include "llvm/ADT/StringSet.h"
 
 using namespace clang;
@@ -145,12 +146,14 @@ class MoveChecker
 
   // Obtains ObjectKind of an object. Because class declaration cannot always
   // be easily obtained from the memory region, it is supplied separately.
-  ObjectKind classifyObject(const MemRegion *MR, const CXXRecordDecl *RD) const;
+  ObjectKind classifyObject(ProgramStateRef State, const MemRegion *MR,
+                            const CXXRecordDecl *RD) const;
 
   // Classifies the object and dumps a user-friendly description string to
   // the stream.
-  void explainObject(llvm::raw_ostream &OS, const MemRegion *MR,
-                     const CXXRecordDecl *RD, MisuseKind MK) const;
+  void explainObject(ProgramStateRef State, llvm::raw_ostream &OS,
+                     const MemRegion *MR, const CXXRecordDecl *RD,
+                     MisuseKind MK) const;
 
   bool belongsTo(const CXXRecordDecl *RD, const llvm::StringSet<> &Set) const;
 
@@ -299,12 +302,12 @@ MoveChecker::MovedBugVisitor::VisitNode(const ExplodedNode *N,
   SmallString<128> Str;
   llvm::raw_svector_ostream OS(Str);
 
-  ObjectKind OK = Chk.classifyObject(Region, RD);
+  ObjectKind OK = Chk.classifyObject(State, Region, RD);
   switch (OK.StdKind) {
     case SK_SmartPtr:
       if (MK == MK_Dereference) {
         OS << "Smart pointer";
-        Chk.explainObject(OS, Region, RD, MK);
+        Chk.explainObject(State, OS, Region, RD, MK);
         OS << " is reset to null when moved from";
         break;
       }
@@ -315,12 +318,12 @@ MoveChecker::MovedBugVisitor::VisitNode(const ExplodedNode *N,
     case SK_NonStd:
     case SK_Safe:
       OS << "Object";
-      Chk.explainObject(OS, Region, RD, MK);
+      Chk.explainObject(State, OS, Region, RD, MK);
       OS << " is moved";
       break;
     case SK_Unsafe:
       OS << "Object";
-      Chk.explainObject(OS, Region, RD, MK);
+      Chk.explainObject(State, OS, Region, RD, MK);
       OS << " is left in a valid but unspecified state after move";
       break;
   }
@@ -353,7 +356,7 @@ void MoveChecker::modelUse(ProgramStateRef State, const MemRegion *Region,
                            CheckerContext &C) const {
   assert(!C.isDifferent() && "No transitions should have been made by now");
   const RegionState *RS = State->get<TrackedRegionMap>(Region);
-  ObjectKind OK = classifyObject(Region, RD);
+  ObjectKind OK = classifyObject(State, Region, RD);
 
   // Just in case: if it's not a smart pointer but it does have operator *,
   // we shouldn't call the bug a dereference.
@@ -406,24 +409,25 @@ ExplodedNode *MoveChecker::tryToReportBug(const MemRegion *Region,
     // Creating the error message.
     llvm::SmallString<128> Str;
     llvm::raw_svector_ostream OS(Str);
+    ProgramStateRef ErrorNodeState = N->getState();
     switch(MK) {
       case MK_FunCall:
         OS << "Method called on moved-from object";
-        explainObject(OS, Region, RD, MK);
+        explainObject(ErrorNodeState, OS, Region, RD, MK);
         break;
       case MK_Copy:
         OS << "Moved-from object";
-        explainObject(OS, Region, RD, MK);
+        explainObject(ErrorNodeState, OS, Region, RD, MK);
         OS << " is copied";
         break;
       case MK_Move:
         OS << "Moved-from object";
-        explainObject(OS, Region, RD, MK);
+        explainObject(ErrorNodeState, OS, Region, RD, MK);
         OS << " is moved";
         break;
       case MK_Dereference:
         OS << "Dereference of null smart pointer";
-        explainObject(OS, Region, RD, MK);
+        explainObject(ErrorNodeState, OS, Region, RD, MK);
         break;
     }
 
@@ -482,7 +486,7 @@ void MoveChecker::checkPostCall(const CallEvent &Call,
     return;
 
   const CXXRecordDecl *RD = MethodDecl->getParent();
-  ObjectKind OK = classifyObject(ArgRegion, RD);
+  ObjectKind OK = classifyObject(State, ArgRegion, RD);
   if (shouldBeTracked(OK)) {
     // Mark object as moved-from.
     State = State->set<TrackedRegionMap>(ArgRegion, RegionState::getMoved());
@@ -549,7 +553,7 @@ bool MoveChecker::belongsTo(const CXXRecordDecl *RD,
 }
 
 MoveChecker::ObjectKind
-MoveChecker::classifyObject(const MemRegion *MR,
+MoveChecker::classifyObject(ProgramStateRef State, const MemRegion *MR,
                             const CXXRecordDecl *RD) const {
   // Local variables and local rvalue references are classified as "Local".
   // For the purposes of this checker, we classify move-safe STL types
@@ -557,7 +561,7 @@ MoveChecker::classifyObject(const MemRegion *MR,
   MR = unwrapRValueReferenceIndirection(MR);
   bool IsLocal =
       isa_and_nonnull<VarRegion, CXXLifetimeExtendedObjectRegion>(MR) &&
-      isa<StackSpaceRegion>(MR->getMemorySpace());
+      memspace::isMemSpaceOrTrait<StackSpaceRegion>(State, MR);
 
   if (!RD || !RD->getDeclContext()->isStdNamespace())
     return { IsLocal, SK_NonStd };
@@ -571,8 +575,9 @@ MoveChecker::classifyObject(const MemRegion *MR,
   return { IsLocal, SK_Unsafe };
 }
 
-void MoveChecker::explainObject(llvm::raw_ostream &OS, const MemRegion *MR,
-                                const CXXRecordDecl *RD, MisuseKind MK) const {
+void MoveChecker::explainObject(ProgramStateRef State, llvm::raw_ostream &OS,
+                                const MemRegion *MR, const CXXRecordDecl *RD,
+                                MisuseKind MK) const {
   // We may need a leading space every time we actually explain anything,
   // and we never know if we are to explain anything until we try.
   if (const auto DR =
@@ -581,7 +586,7 @@ void MoveChecker::explainObject(llvm::raw_ostream &OS, const MemRegion *MR,
     OS << " '" << RegionDecl->getDeclName() << "'";
   }
 
-  ObjectKind OK = classifyObject(MR, RD);
+  ObjectKind OK = classifyObject(State, MR, RD);
   switch (OK.StdKind) {
     case SK_NonStd:
     case SK_Safe:
diff --git a/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
index bf81d57bf82fd34..4449cb4ae68eb9a 100644
--- a/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
@@ -21,6 +21,7 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
 
 using namespace clang;
 using namespace ento;
@@ -45,10 +46,15 @@ void PutenvStackArrayChecker::checkPostCall(const CallEvent &Call,
   SVal ArgV = Call.getArgSVal(0);
   const Expr *ArgExpr = Call.getArgExpr(0);
 
-  const auto *SSR =
-      dyn_cast<StackSpaceRegion>(ArgV.getAsRegion()->getMemorySpace());
+  const MemRegion *MR = ArgV.getAsRegion();
+
+  const auto *SSR = dyn_cast<StackSpaceRegion>(MR->getMemorySpace());
+  if (!SSR)
+    SSR = dyn_cast_if_present<StackSpaceRegion>(
+        memspace::getMemSpaceTrait(C.getState(), MR));
   if (!SSR)
     return;
+
   const auto *StackFrameFuncD =
       dyn_cast_or_null<FunctionDecl>(SSR->getStackFrame()->getDecl());
   if (StackFrameFuncD && StackFrameFuncD->isMain())
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
index 456132ef0a0a228..ecc7563ceb4bba5 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
@@ -13,6 +13,7 @@
 
 #include "RetainCountDiagnostics.h"
 #include "RetainCountChecker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallVector.h"
 #include <optional>
@@ -690,9 +691,14 @@ static AllocationInfo GetAllocationSite(ProgramStateManager &StateMgr,
       const MemRegion *R = FB.getRegion();
       // Do not show local variables belonging to a function other than
       // where the error is reported.
-      if (auto MR = dyn_cast<StackSpaceRegion>(R->getMemorySpace()))
-        if (MR->getStackFrame() == LeakContext->getStackFrame())
-          FirstBinding = R;
+      const StackSpaceRegion *MR =
+          dyn_cast<StackSpaceRegion>(R->getMemorySpace());
+      if (!MR)
+        MR = dyn_cast_if_present<StackSpaceRegion>(
+            memspace::getMemSpaceTrait(St, R));
+
+      if (MR && MR->getStackFrame() == LeakContext->getStackFrame())
+        FirstBinding = R;
     }
 
     // AllocationNode is the last node in which the symbol was tracked.
diff --git a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index f4de3b500499c48..4d8c8eea14ea633 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -19,6 +19,7 @@
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/Support/raw_ostream.h"
@@ -61,7 +62,7 @@ class StackAddrEscapeChecker
                              ASTContext &Ctx);
   static SmallVector<const MemRegion *, 4>
   getCapturedStackRegions(const BlockDataRegion &B, CheckerContext &C);
-  static bool isNotInCurrentFrame(const MemRegion *R, CheckerContext &C);
+  static bool isNotInCurrentFrame(const MemSpaceRegion *MS, CheckerContext &C);
 };
 } // namespace
 
@@ -117,9 +118,9 @@ SourceRange StackAddrEscapeChecker::genName(raw_ostream &os, const MemRegion *R,
   return range;
 }
 
-bool StackAddrEscapeChecker::isNotInCurrentFrame(const MemRegion *R,
+bool StackAddrEscapeChecker::isNotInCurrentFrame(const MemSpaceRegion *MS,
                                                  CheckerContext &C) {
-  const StackSpaceRegion *S = cast<StackSpaceRegion>(R->getMemorySpace());
+  const StackSpaceRegion *S = cast<StackSpaceRegion>(MS);
   return S->getStackFrame() != C.getStackFrame();
 }
 
@@ -138,10 +139,11 @@ SmallVector<const MemRegion *, 4>
 StackAddrEscapeChecker::getCapturedStackRegions(const BlockDataRegion &B,
                                                 CheckerContext &C) {
   SmallVector<const MemRegion *, 4> Regions;
+  ProgramStateRef State = C.getState();
   for (auto Var : B.referenced_vars()) {
-    SVal Val = C.getState()->getSVal(Var.getCapturedRegion());
+    SVal Val = State->getSVal(Var.getCapturedRegion());
     const MemRegion *Region = Val.getAsRegion();
-    if (Region && isa<StackSpaceRegion>(Region->getMemorySpace()))
+    if (Region && memspace::isMemSpaceOrTrait<StackSpaceRegion>(State, Region))
       Regions.push_back(Region);
   }
   return Regions;
@@ -212,7 +214,7 @@ void StackAddrEscapeChecker::checkAsyncExecutedBlockCaptures(
 void StackAddrEscapeChecker::checkReturnedBlockCaptures(
     const BlockDataRegion &B, CheckerContext &C) const {
   for (const MemRegion *Region : getCapturedStackRegions(B, C)) {
-    if (isNotInCurrentFrame(Region, C))
+    if (isNotInCurrentFrame(Region->getMemorySpace(), C))
       continue;
     ExplodedNode *N = C.generateNonFatalErrorNode();
     if (!N)
@@ -265,7 +267,14 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
   if (const BlockDataRegion *B = dyn_cast<BlockDataRegion>(R))
     checkReturnedBlockCaptures(*B, C);
 
-  if (!isa<StackSpaceRegion>(R->getMemorySpace()) || isNotInCurrentFrame(R, C))
+  if (isa<UnknownSpaceRegion>(R)) {
+    const MemSpaceRegion *MS = memspace::getMemSpaceTrait(C.getState(), R);
+    if (!isa_and_nonnull<StackSpaceRegion>(MS) || isNotInCurrentFrame(MS, C))
+      return;
+  }
+
+  const MemSpaceRegion *MS = R->getMemorySpace();
+  if (!isa<StackSpaceRegion>(MS) || isNotInCurrentFrame(MS, C))
     return;
 
   // Returning a record by value is fine. (In this case, the returned
@@ -468,7 +477,8 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,
       if (!isa_and_nonnull<GlobalsSpaceRegion>(
               getStackOrGlobalSpaceRegion(Region)))
         return true;
-      if (VR && VR->hasStackStorage() && !isNotInCurrentFrame(VR, Ctx))
+      if (VR && VR->hasStackStorage() &&
+          !isNotInCurrentFrame(VR->getMemorySpace(), Ctx))
         V.emplace_back(Region, VR);
       return true;
     }
diff --git a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
index da2d16ca9b5dd74..1c6c5fa14bceeca 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
@@ -21,6 +21,7 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringExtras.h"
@@ -411,7 +412,7 @@ void UnixAPIMisuseChecker::CheckPthreadOnce(CheckerContext &C,
   // because that's likely to be bad news.
   ProgramStateRef state = C.getState();
   const MemRegion *R = Call.getArgSVal(0).getAsRegion();
-  if (!R || !isa<StackSpaceRegion>(R->getMemorySpace()))
+  if (!R || !memspace::isMemSpaceOrTrait<StackSpaceRegion>(state, R))
     return;
 
   ExplodedNode *N = C.generateErrorNode(state);
diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index a9b4dbb39b5bd62..e708bd8ec2f72d9 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -40,6 +40,7 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h"
@@ -1193,7 +1194,16 @@ static bool isInitializationOfVar(const ExplodedNode *N, const VarRegion *VR) {
     return false;
 
   const MemSpaceRegion *VarSpace = VR->getMemorySpace();
-  const auto *FrameSpace = dyn_cast<StackSpaceRegion>(VarSpace);
+  const StackSpaceRegion *FrameSpace;
+
+  if (isa<UnknownSpaceRegion>(VarSpace)) {
+    ProgramStateRef State = N->getState();
+    const MemSpaceRegion *MemSpace = memspace::getMemSpaceTrait(State, VR);
+    FrameSpace = dyn_cast_if_present<StackSpaceRegion>(MemSpace);
+  } else {
+    FrameSpace = dyn_cast<StackSpaceRegion>(VarSpace);
+  }
+
   if (!FrameSpace) {
     // If we ever directly evaluate global DeclStmts, this assertion will be
     // invalid, but this still seems preferable to silently accepting an
diff --git a/clang/lib/StaticAnalyzer/Core/CMakeLists.txt b/clang/lib/StaticAnalyzer/Core/CMakeLists.txt
index fb9394a519eb71b..993d37bb052e9b7 100644
--- a/clang/lib/StaticAnalyzer/Core/CMakeLists.txt
+++ b/clang/lib/StaticAnalyzer/Core/CMakeLists.txt
@@ -36,6 +36,7 @@ add_clang_library(clangStaticAnalyzerCore
   LoopUnrolling.cpp
   LoopWidening.cpp
   MemRegion.cpp
+  MemSpaces.cpp
   PlistDiagnostics.cpp
   ProgramState.cpp
   RangeConstraintManager.cpp
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 70e95c2c644c091..f22d4e7bf9dbd0c 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -53,6 +53,7 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
@@ -3516,6 +3517,15 @@ ProgramStateRef ExprEngine::processPointerEscapedOnBind(
       continue;
     }
 
+    // Case (2) continued.
+    if (isa<UnknownSpaceRegion>(MR)) {
+      const MemSpaceRegion *MS = memspace::getMemSpaceTrait(State, MR);
+      if (!isa<StackSpaceRegion, StaticGlobalSpaceRegion>(MS)) {
+        Escaped.push_back(LocAndVal.second);
+        continue;
+      }
+    }
+
     // Case (3).
     if (const auto *VR = dyn_cast<VarRegion>(MR->getBaseRegion()))
       if (VR->hasStackParametersStorage() && VR->getStackFrame()->inTopFrame())
diff --git a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
new file mode 100644
index 000000000000000..909d11d64567586
--- /dev/null
+++ b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
@@ -0,0 +1,62 @@
+//===-- MemSpaces.cpp ---------------------------------------------*- C++ -*--//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// TODO
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
+#include <cassert>
+
+REGISTER_MAP_WITH_PROGRAMSTATE(MemSpacesMap, const clang::ento::MemRegion *,
+                               const clang::ento::MemSpaceRegion *)
+
+namespace clang {
+namespace ento {
+namespace memspace {
+
+ProgramStateRef setMemSpaceTrait(ProgramStateRef State, const MemRegion *MR,
+                                 const MemSpaceRegion *MS) {
+  // for now, this should only be called to update the trait for mem regions
+  // that have an unknown mem spaces since we assume everywhere else that the
+  // memspace trait is set only for unknown mem spaces (setting this info
+  // otherwise would go unused).
+  assert(isa<UnknownSpaceRegion>(MR->getMemorySpace()));
+
+  // Shouldn't use the memspace trait to associate UnknownSpaceRegion with an
+  // already UnknownSpaceRegion
+  assert(!isa<UnknownSpaceRegion>(MS));
+
+  ProgramStateRef NewState = State->set<MemSpacesMap>(MR, MS);
+  return NewState;
+}
+
+bool hasMemSpaceTrait(ProgramStateRef State, const MemRegion *MR) {
+  if (!isa<UnknownSpaceRegion>(MR->getMemorySpace()))
+    return false;
+
+  const MemSpaceRegion *const *Result = State->get<MemSpacesMap>(MR);
+  return Result;
+}
+
+const MemSpaceRegion *getMemSpaceTrait(ProgramStateRef State,
+                                       const MemRegion *MR) {
+  if (!isa<UnknownSpaceRegion>(MR->getMemorySpace()))
+    return nullptr;
+
+  const MemSpaceRegion *const *Result = State->get<MemSpacesMap>(MR);
+  if (!Result)
+    return nullptr;
+  return *Result;
+}
+
+} // namespace memspace
+} // namespace ento
+} // namespace clang

>From 94c0e4da693faeacb108e3dc239ed56d99242b3c Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Wed, 15 Jan 2025 09:13:10 -0600
Subject: [PATCH 02/55] Uppercase start and s/mem/memory/ in long comment

---
 clang/lib/StaticAnalyzer/Core/MemSpaces.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
index 909d11d64567586..886359fdbfab3dc 100644
--- a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
+++ b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
@@ -24,13 +24,13 @@ namespace memspace {
 
 ProgramStateRef setMemSpaceTrait(ProgramStateRef State, const MemRegion *MR,
                                  const MemSpaceRegion *MS) {
-  // for now, this should only be called to update the trait for mem regions
-  // that have an unknown mem spaces since we assume everywhere else that the
-  // memspace trait is set only for unknown mem spaces (setting this info
+  // For now, this should only be called to update the trait for memory regions
+  // that have an unknown memory spaces since we assume everywhere else that the
+  // memory space trait is set only for unknown memory spaces (setting this info
   // otherwise would go unused).
   assert(isa<UnknownSpaceRegion>(MR->getMemorySpace()));
 
-  // Shouldn't use the memspace trait to associate UnknownSpaceRegion with an
+  // Shouldn't use the memory space trait to associate UnknownSpaceRegion with an
   // already UnknownSpaceRegion
   assert(!isa<UnknownSpaceRegion>(MS));
 

>From 79a7c900303b84164aa8b473f0e241e44a80062b Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Wed, 15 Jan 2025 09:22:54 -0600
Subject: [PATCH 03/55] Fill in TODO file headers description and format
 comments

---
 .../clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h   | 7 ++++++-
 clang/lib/StaticAnalyzer/Core/MemSpaces.cpp               | 8 +++++---
 2 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
index 178a6b60c1cb1a5..4f03738254b9368 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
@@ -6,7 +6,12 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// TODO
+// This file declares getters and setters for the memory space trait which
+// associates memory regions with memory spaces in the program state. We are
+// still transitioning to having all memory space information stored in the
+// trait, so currently memory regions still have memory spaces as a class field.
+// Because of this, these getters still consider memory spaces set as class
+// fields in memory region types.
 //
 //===----------------------------------------------------------------------===//
 
diff --git a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
index 886359fdbfab3dc..47ad03c04b2ece2 100644
--- a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
+++ b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
@@ -6,7 +6,9 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// TODO
+// This file defines getters and setters for the memory space trait which
+// associates memory regions with memory spaces in the program state. It also
+// defines the MemSpacesMap which maps memory regions to memory spaces.
 //
 //===----------------------------------------------------------------------===//
 
@@ -30,8 +32,8 @@ ProgramStateRef setMemSpaceTrait(ProgramStateRef State, const MemRegion *MR,
   // otherwise would go unused).
   assert(isa<UnknownSpaceRegion>(MR->getMemorySpace()));
 
-  // Shouldn't use the memory space trait to associate UnknownSpaceRegion with an
-  // already UnknownSpaceRegion
+  // Shouldn't use the memory space trait to associate UnknownSpaceRegion with
+  // an already UnknownSpaceRegion
   assert(!isa<UnknownSpaceRegion>(MS));
 
   ProgramStateRef NewState = State->set<MemSpacesMap>(MR, MS);

>From bcc2f937bcc22d98ee06ebea9e3944fc16089997 Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Wed, 15 Jan 2025 11:33:52 -0600
Subject: [PATCH 04/55] getMemSpaceTrait->getMemSpace

---
 .../StaticAnalyzer/Core/PathSensitive/MemSpaces.h    |  4 ++--
 clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp  |  4 ++--
 .../Checkers/PutenvStackArrayChecker.cpp             |  2 +-
 .../RetainCountChecker/RetainCountDiagnostics.cpp    |  2 +-
 .../Checkers/StackAddrEscapeChecker.cpp              |  2 +-
 .../lib/StaticAnalyzer/Core/BugReporterVisitors.cpp  |  2 +-
 clang/lib/StaticAnalyzer/Core/ExprEngine.cpp         |  2 +-
 clang/lib/StaticAnalyzer/Core/MemSpaces.cpp          | 12 +++++-------
 8 files changed, 14 insertions(+), 16 deletions(-)

diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
index 4f03738254b9368..b6ca1f9e4ab78eb 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
@@ -33,7 +33,7 @@ namespace memspace {
                                                const MemRegion *MR,
                                                const MemSpaceRegion *MS);
 
-[[nodiscard]] const MemSpaceRegion *getMemSpaceTrait(ProgramStateRef State,
+[[nodiscard]] const MemSpaceRegion *getMemSpace(ProgramStateRef State,
                                                      const MemRegion *MR);
 
 [[nodiscard]] bool hasMemSpaceTrait(ProgramStateRef State, const MemRegion *MR);
@@ -42,7 +42,7 @@ template <typename FirstT, typename... RestT>
 [[nodiscard]] bool isMemSpaceOrTrait(ProgramStateRef State,
                                      const MemRegion *MR) {
   return isa<FirstT, RestT...>(MR->getMemorySpace()) ||
-         isa_and_nonnull<FirstT, RestT...>(getMemSpaceTrait(State, MR));
+         isa_and_nonnull<FirstT, RestT...>(getMemSpace(State, MR));
 }
 
 } // namespace memspace
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 76fee2f1322e17a..7d13e82472d7bd3 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -2213,7 +2213,7 @@ MallocChecker::FreeMemAux(CheckerContext &C, const Expr *ArgExpr,
   // - The region has unknown memspace and no trait for further clarification
   //   (i.e., just unknown)
   // - The region has unknown memspace and a heap memspace trait
-  const MemSpaceRegion *MSTrait = memspace::getMemSpaceTrait(State, R);
+  const MemSpaceRegion *MSTrait = memspace::getMemSpace(State, R);
   bool HasHeapOrUnknownTrait = !MSTrait || isa<HeapSpaceRegion>(MSTrait);
   if (!(isa<HeapSpaceRegion>(MS) ||
         (isa<UnknownSpaceRegion>(MS) && HasHeapOrUnknownTrait))) {
@@ -2414,7 +2414,7 @@ bool MallocChecker::SummarizeRegion(ProgramStateRef State, raw_ostream &os,
     return true;
   default: {
     const MemSpaceRegion *MS = MR->getMemorySpace();
-    const MemSpaceRegion *MSTrait = memspace::getMemSpaceTrait(State, MR);
+    const MemSpaceRegion *MSTrait = memspace::getMemSpace(State, MR);
 
     if (isa<StackLocalsSpaceRegion>(MS) ||
         isa_and_nonnull<StackLocalsSpaceRegion>(MSTrait)) {
diff --git a/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
index 4449cb4ae68eb9a..fddef2ee0ac1616 100644
--- a/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
@@ -51,7 +51,7 @@ void PutenvStackArrayChecker::checkPostCall(const CallEvent &Call,
   const auto *SSR = dyn_cast<StackSpaceRegion>(MR->getMemorySpace());
   if (!SSR)
     SSR = dyn_cast_if_present<StackSpaceRegion>(
-        memspace::getMemSpaceTrait(C.getState(), MR));
+        memspace::getMemSpace(C.getState(), MR));
   if (!SSR)
     return;
 
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
index ecc7563ceb4bba5..80fa8d3e3f921e0 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
@@ -695,7 +695,7 @@ static AllocationInfo GetAllocationSite(ProgramStateManager &StateMgr,
           dyn_cast<StackSpaceRegion>(R->getMemorySpace());
       if (!MR)
         MR = dyn_cast_if_present<StackSpaceRegion>(
-            memspace::getMemSpaceTrait(St, R));
+            memspace::getMemSpace(St, R));
 
       if (MR && MR->getStackFrame() == LeakContext->getStackFrame())
         FirstBinding = R;
diff --git a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index 4d8c8eea14ea633..43a444e3b8ee84e 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -268,7 +268,7 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
     checkReturnedBlockCaptures(*B, C);
 
   if (isa<UnknownSpaceRegion>(R)) {
-    const MemSpaceRegion *MS = memspace::getMemSpaceTrait(C.getState(), R);
+    const MemSpaceRegion *MS = memspace::getMemSpace(C.getState(), R);
     if (!isa_and_nonnull<StackSpaceRegion>(MS) || isNotInCurrentFrame(MS, C))
       return;
   }
diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index e708bd8ec2f72d9..ad2429d61de9271 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -1198,7 +1198,7 @@ static bool isInitializationOfVar(const ExplodedNode *N, const VarRegion *VR) {
 
   if (isa<UnknownSpaceRegion>(VarSpace)) {
     ProgramStateRef State = N->getState();
-    const MemSpaceRegion *MemSpace = memspace::getMemSpaceTrait(State, VR);
+    const MemSpaceRegion *MemSpace = memspace::getMemSpace(State, VR);
     FrameSpace = dyn_cast_if_present<StackSpaceRegion>(MemSpace);
   } else {
     FrameSpace = dyn_cast<StackSpaceRegion>(VarSpace);
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index f22d4e7bf9dbd0c..82274f3327f16d5 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -3519,7 +3519,7 @@ ProgramStateRef ExprEngine::processPointerEscapedOnBind(
 
     // Case (2) continued.
     if (isa<UnknownSpaceRegion>(MR)) {
-      const MemSpaceRegion *MS = memspace::getMemSpaceTrait(State, MR);
+      const MemSpaceRegion *MS = memspace::getMemSpace(State, MR);
       if (!isa<StackSpaceRegion, StaticGlobalSpaceRegion>(MS)) {
         Escaped.push_back(LocAndVal.second);
         continue;
diff --git a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
index 47ad03c04b2ece2..1dd6568cfa80d20 100644
--- a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
+++ b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
@@ -48,15 +48,13 @@ bool hasMemSpaceTrait(ProgramStateRef State, const MemRegion *MR) {
   return Result;
 }
 
-const MemSpaceRegion *getMemSpaceTrait(ProgramStateRef State,
+const MemSpaceRegion *getMemSpace(ProgramStateRef State,
                                        const MemRegion *MR) {
-  if (!isa<UnknownSpaceRegion>(MR->getMemorySpace()))
-    return nullptr;
-
   const MemSpaceRegion *const *Result = State->get<MemSpacesMap>(MR);
-  if (!Result)
-    return nullptr;
-  return *Result;
+  if (Result)
+    return *Result;
+
+  return MR->getMemorySpace();
 }
 
 } // namespace memspace

>From 28bc5a3009236f3d50a9db9f7580ffd295a2e31c Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Wed, 15 Jan 2025 11:49:27 -0600
Subject: [PATCH 05/55] add comment about invariant

---
 .../Core/PathSensitive/MemSpaces.h            |  2 +-
 clang/lib/StaticAnalyzer/Core/MemSpaces.cpp   | 22 ++++++++++++++++++-
 2 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
index b6ca1f9e4ab78eb..0f8f72fd6993fb5 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
@@ -34,7 +34,7 @@ namespace memspace {
                                                const MemSpaceRegion *MS);
 
 [[nodiscard]] const MemSpaceRegion *getMemSpace(ProgramStateRef State,
-                                                     const MemRegion *MR);
+                                                const MemRegion *MR);
 
 [[nodiscard]] bool hasMemSpaceTrait(ProgramStateRef State, const MemRegion *MR);
 
diff --git a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
index 1dd6568cfa80d20..287493649825459 100644
--- a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
+++ b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
@@ -9,6 +9,14 @@
 // This file defines getters and setters for the memory space trait which
 // associates memory regions with memory spaces in the program state. It also
 // defines the MemSpacesMap which maps memory regions to memory spaces.
+// 
+// These functions keep the following invariants over the MemSpacesMap:
+// 1. (Temporary as an intermediate step) Memory space traits are only
+//    mapped for memory regions that have an unknown memory space
+// 2. Only base memory regions are mapped in the trait
+// 3. Memory regions which have no mapping in the trait are assumed to be
+//    unknown; no memory region is allowed to be mapped to an unknown memory
+//    space in the trait;
 //
 //===----------------------------------------------------------------------===//
 
@@ -24,8 +32,16 @@ namespace clang {
 namespace ento {
 namespace memspace {
 
+// Canonicalize to base, in case of subregions, we don't want base regions and subregions
+// to have different memory spaces
+[[nodiscard]] static const MemRegion *canonicalizeMemRegion(const MemRegion *MR) {
+  return MR->getBaseRegion();
+}
+
 ProgramStateRef setMemSpaceTrait(ProgramStateRef State, const MemRegion *MR,
                                  const MemSpaceRegion *MS) {
+  MR = canonicalizeMemRegion(MR);
+
   // For now, this should only be called to update the trait for memory regions
   // that have an unknown memory spaces since we assume everywhere else that the
   // memory space trait is set only for unknown memory spaces (setting this info
@@ -41,6 +57,8 @@ ProgramStateRef setMemSpaceTrait(ProgramStateRef State, const MemRegion *MR,
 }
 
 bool hasMemSpaceTrait(ProgramStateRef State, const MemRegion *MR) {
+  MR = canonicalizeMemRegion(MR);
+
   if (!isa<UnknownSpaceRegion>(MR->getMemorySpace()))
     return false;
 
@@ -49,7 +67,9 @@ bool hasMemSpaceTrait(ProgramStateRef State, const MemRegion *MR) {
 }
 
 const MemSpaceRegion *getMemSpace(ProgramStateRef State,
-                                       const MemRegion *MR) {
+                                  const MemRegion *MR) {
+  MR = canonicalizeMemRegion(MR);
+
   const MemSpaceRegion *const *Result = State->get<MemSpacesMap>(MR);
   if (Result)
     return *Result;

>From c6482c4327fd21de71e3e9591137b49e6f055eb0 Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Wed, 15 Jan 2025 12:00:06 -0600
Subject: [PATCH 06/55] isMemSpaceOrTrait->isMemSpace

---
 .../clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h       | 4 ++--
 clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp        | 4 ++--
 clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp             | 2 +-
 clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp  | 2 +-
 clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp          | 2 +-
 5 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
index 0f8f72fd6993fb5..132261391c27165 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
@@ -39,8 +39,8 @@ namespace memspace {
 [[nodiscard]] bool hasMemSpaceTrait(ProgramStateRef State, const MemRegion *MR);
 
 template <typename FirstT, typename... RestT>
-[[nodiscard]] bool isMemSpaceOrTrait(ProgramStateRef State,
-                                     const MemRegion *MR) {
+[[nodiscard]] bool isMemSpace(ProgramStateRef State,
+                              const MemRegion *MR) {
   return isa<FirstT, RestT...>(MR->getMemorySpace()) ||
          isa_and_nonnull<FirstT, RestT...>(getMemSpace(State, MR));
 }
diff --git a/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
index 858b6a37551f5d5..c81f1bfa7eaf32c 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
@@ -80,7 +80,7 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
 
   // Global variables are fine.
   const MemRegion *RB = R->getBaseRegion();
-  if (memspace::isMemSpaceOrTrait<GlobalsSpaceRegion>(State, RB))
+  if (memspace::isMemSpace<GlobalsSpaceRegion>(State, RB))
     return;
 
   // Handle _dispatch_once.  In some versions of the OS X SDK we have the case
@@ -119,7 +119,7 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
     if (IVR != R)
       os << " memory within";
     os << " the instance variable '" << IVR->getDecl()->getName() << '\'';
-  } else if (memspace::isMemSpaceOrTrait<HeapSpaceRegion>(State, RB)) {
+  } else if (memspace::isMemSpace<HeapSpaceRegion>(State, RB)) {
     os << " heap-allocated memory";
   } else if (isa<UnknownSpaceRegion>(RB->getMemorySpace())) {
     // Presence of an IVar superregion has priority over this branch, because
diff --git a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
index d4ff8186ea69c95..042c4e0c1ab2e69 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
@@ -561,7 +561,7 @@ MoveChecker::classifyObject(ProgramStateRef State, const MemRegion *MR,
   MR = unwrapRValueReferenceIndirection(MR);
   bool IsLocal =
       isa_and_nonnull<VarRegion, CXXLifetimeExtendedObjectRegion>(MR) &&
-      memspace::isMemSpaceOrTrait<StackSpaceRegion>(State, MR);
+      memspace::isMemSpace<StackSpaceRegion>(State, MR);
 
   if (!RD || !RD->getDeclContext()->isStdNamespace())
     return { IsLocal, SK_NonStd };
diff --git a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index 43a444e3b8ee84e..9f126cd8d3d23c6 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -143,7 +143,7 @@ StackAddrEscapeChecker::getCapturedStackRegions(const BlockDataRegion &B,
   for (auto Var : B.referenced_vars()) {
     SVal Val = State->getSVal(Var.getCapturedRegion());
     const MemRegion *Region = Val.getAsRegion();
-    if (Region && memspace::isMemSpaceOrTrait<StackSpaceRegion>(State, Region))
+    if (Region && memspace::isMemSpace<StackSpaceRegion>(State, Region))
       Regions.push_back(Region);
   }
   return Regions;
diff --git a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
index 1c6c5fa14bceeca..0da562a9fe51db8 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
@@ -412,7 +412,7 @@ void UnixAPIMisuseChecker::CheckPthreadOnce(CheckerContext &C,
   // because that's likely to be bad news.
   ProgramStateRef state = C.getState();
   const MemRegion *R = Call.getArgSVal(0).getAsRegion();
-  if (!R || !memspace::isMemSpaceOrTrait<StackSpaceRegion>(state, R))
+  if (!R || !memspace::isMemSpace<StackSpaceRegion>(state, R))
     return;
 
   ExplodedNode *N = C.generateErrorNode(state);

>From 4dd1432f15428fb05f46f8fc56c2c9d583c80809 Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Wed, 15 Jan 2025 12:59:00 -0600
Subject: [PATCH 07/55] change MacOSXApiChecker and MallocChecker

---
 .../Core/PathSensitive/MemSpaces.h            |  5 +----
 .../Checkers/MacOSXAPIChecker.cpp             |  2 +-
 .../StaticAnalyzer/Checkers/MallocChecker.cpp | 21 +++++--------------
 clang/lib/StaticAnalyzer/Core/MemSpaces.cpp   | 10 ---------
 4 files changed, 7 insertions(+), 31 deletions(-)

diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
index 132261391c27165..419d24ac58ef6db 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
@@ -36,13 +36,10 @@ namespace memspace {
 [[nodiscard]] const MemSpaceRegion *getMemSpace(ProgramStateRef State,
                                                 const MemRegion *MR);
 
-[[nodiscard]] bool hasMemSpaceTrait(ProgramStateRef State, const MemRegion *MR);
-
 template <typename FirstT, typename... RestT>
 [[nodiscard]] bool isMemSpace(ProgramStateRef State,
                               const MemRegion *MR) {
-  return isa<FirstT, RestT...>(MR->getMemorySpace()) ||
-         isa_and_nonnull<FirstT, RestT...>(getMemSpace(State, MR));
+  return isa_and_nonnull<FirstT, RestT...>(getMemSpace(State, MR));
 }
 
 } // namespace memspace
diff --git a/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
index c81f1bfa7eaf32c..e8d68e27fdaff3e 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
@@ -121,7 +121,7 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
     os << " the instance variable '" << IVR->getDecl()->getName() << '\'';
   } else if (memspace::isMemSpace<HeapSpaceRegion>(State, RB)) {
     os << " heap-allocated memory";
-  } else if (isa<UnknownSpaceRegion>(RB->getMemorySpace())) {
+  } else if (memspace::isMemSpace<UnknownSpaceRegion>(State, RB)) {
     // Presence of an IVar superregion has priority over this branch, because
     // ObjC objects are on the heap even if the core doesn't realize this.
     // Presence of a block variable base region has priority over this branch,
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 7d13e82472d7bd3..7d127facd1a36ac 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -2204,8 +2204,6 @@ MallocChecker::FreeMemAux(CheckerContext &C, const Expr *ArgExpr,
     return nullptr;
   }
 
-  const MemSpaceRegion *MS = R->getMemorySpace();
-
   // Parameters, locals, statics, globals, and memory returned by
   // __builtin_alloca() shouldn't be freed.
   // Should skip this check if:
@@ -2213,16 +2211,13 @@ MallocChecker::FreeMemAux(CheckerContext &C, const Expr *ArgExpr,
   // - The region has unknown memspace and no trait for further clarification
   //   (i.e., just unknown)
   // - The region has unknown memspace and a heap memspace trait
-  const MemSpaceRegion *MSTrait = memspace::getMemSpace(State, R);
-  bool HasHeapOrUnknownTrait = !MSTrait || isa<HeapSpaceRegion>(MSTrait);
-  if (!(isa<HeapSpaceRegion>(MS) ||
-        (isa<UnknownSpaceRegion>(MS) && HasHeapOrUnknownTrait))) {
+  if (!memspace::isMemSpace<HeapSpaceRegion, UnknownSpaceRegion>(State, R)) {
     // Regions returned by malloc() are represented by SymbolicRegion objects
     // within HeapSpaceRegion. Of course, free() can work on memory allocated
     // outside the current function, so UnknownSpaceRegion is also a
     // possibility here.
 
-    if (isa<AllocaRegion>(R) || isa_and_nonnull<AllocaRegion>(MSTrait))
+    if (isa<AllocaRegion>(R))
       HandleFreeAlloca(C, ArgVal, ArgExpr->getSourceRange());
     else
       HandleNonHeapDealloc(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,
@@ -2413,11 +2408,7 @@ bool MallocChecker::SummarizeRegion(ProgramStateRef State, raw_ostream &os,
     os << "a block";
     return true;
   default: {
-    const MemSpaceRegion *MS = MR->getMemorySpace();
-    const MemSpaceRegion *MSTrait = memspace::getMemSpace(State, MR);
-
-    if (isa<StackLocalsSpaceRegion>(MS) ||
-        isa_and_nonnull<StackLocalsSpaceRegion>(MSTrait)) {
+    if (memspace::isMemSpace<StackLocalsSpaceRegion>(State, MR)) {
       const VarRegion *VR = dyn_cast<VarRegion>(MR);
       const VarDecl *VD;
       if (VR)
@@ -2432,8 +2423,7 @@ bool MallocChecker::SummarizeRegion(ProgramStateRef State, raw_ostream &os,
       return true;
     }
 
-    if (isa<StackArgumentsSpaceRegion>(MS) ||
-        isa_and_nonnull<StackArgumentsSpaceRegion>(MSTrait)) {
+    if (memspace::isMemSpace<StackArgumentsSpaceRegion>(State, MR)) {
       const VarRegion *VR = dyn_cast<VarRegion>(MR);
       const VarDecl *VD;
       if (VR)
@@ -2448,8 +2438,7 @@ bool MallocChecker::SummarizeRegion(ProgramStateRef State, raw_ostream &os,
       return true;
     }
 
-    if (isa<GlobalsSpaceRegion>(MS) ||
-        isa_and_nonnull<GlobalsSpaceRegion>(MSTrait)) {
+    if (memspace::isMemSpace<GlobalsSpaceRegion>(State, MR)) {
       const VarRegion *VR = dyn_cast<VarRegion>(MR);
       const VarDecl *VD;
       if (VR)
diff --git a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
index 287493649825459..e20c1d15e4c518d 100644
--- a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
+++ b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
@@ -56,16 +56,6 @@ ProgramStateRef setMemSpaceTrait(ProgramStateRef State, const MemRegion *MR,
   return NewState;
 }
 
-bool hasMemSpaceTrait(ProgramStateRef State, const MemRegion *MR) {
-  MR = canonicalizeMemRegion(MR);
-
-  if (!isa<UnknownSpaceRegion>(MR->getMemorySpace()))
-    return false;
-
-  const MemSpaceRegion *const *Result = State->get<MemSpacesMap>(MR);
-  return Result;
-}
-
 const MemSpaceRegion *getMemSpace(ProgramStateRef State,
                                   const MemRegion *MR) {
   MR = canonicalizeMemRegion(MR);

>From 2f2730b0d6c634c732358e9fa081f86c3c5d36ef Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Wed, 15 Jan 2025 13:21:31 -0600
Subject: [PATCH 08/55] PutenvStackArrayChecker converted

---
 .../lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp  | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
index fddef2ee0ac1616..455cb6cc37a1fee 100644
--- a/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
@@ -48,10 +48,7 @@ void PutenvStackArrayChecker::checkPostCall(const CallEvent &Call,
 
   const MemRegion *MR = ArgV.getAsRegion();
 
-  const auto *SSR = dyn_cast<StackSpaceRegion>(MR->getMemorySpace());
-  if (!SSR)
-    SSR = dyn_cast_if_present<StackSpaceRegion>(
-        memspace::getMemSpace(C.getState(), MR));
+  const StackSpaceRegion *SSR = dyn_cast_if_present<StackSpaceRegion>(memspace::getMemSpace(C.getState(), MR));
   if (!SSR)
     return;
 

>From 7f7c274078a90d67299c7144257c32928b2d96da Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Wed, 15 Jan 2025 13:21:45 -0600
Subject: [PATCH 09/55] ExprEngine

---
 clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 82274f3327f16d5..1a056d8fc5970c4 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -3518,12 +3518,9 @@ ProgramStateRef ExprEngine::processPointerEscapedOnBind(
     }
 
     // Case (2) continued.
-    if (isa<UnknownSpaceRegion>(MR)) {
-      const MemSpaceRegion *MS = memspace::getMemSpace(State, MR);
-      if (!isa<StackSpaceRegion, StaticGlobalSpaceRegion>(MS)) {
-        Escaped.push_back(LocAndVal.second);
-        continue;
-      }
+    if (memspace::isMemSpace<StackSpaceRegion, StaticGlobalSpaceRegion>(State, MR)) {
+      Escaped.push_back(LocAndVal.second);
+      continue;
     }
 
     // Case (3).

>From 8fb29b7644c0ed25d6b5ce92bcee21e92fe6c34f Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Wed, 15 Jan 2025 13:21:58 -0600
Subject: [PATCH 10/55] BugReporterVisitors

---
 .../lib/StaticAnalyzer/Core/BugReporterVisitors.cpp  | 12 ++----------
 1 file changed, 2 insertions(+), 10 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index ad2429d61de9271..458d3e545ccd2f4 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -1194,16 +1194,8 @@ static bool isInitializationOfVar(const ExplodedNode *N, const VarRegion *VR) {
     return false;
 
   const MemSpaceRegion *VarSpace = VR->getMemorySpace();
-  const StackSpaceRegion *FrameSpace;
-
-  if (isa<UnknownSpaceRegion>(VarSpace)) {
-    ProgramStateRef State = N->getState();
-    const MemSpaceRegion *MemSpace = memspace::getMemSpace(State, VR);
-    FrameSpace = dyn_cast_if_present<StackSpaceRegion>(MemSpace);
-  } else {
-    FrameSpace = dyn_cast<StackSpaceRegion>(VarSpace);
-  }
-
+  const StackSpaceRegion *FrameSpace = dyn_cast_if_present<StackSpaceRegion>(memspace::getMemSpace(N->getState(), VR));
+  
   if (!FrameSpace) {
     // If we ever directly evaluate global DeclStmts, this assertion will be
     // invalid, but this still seems preferable to silently accepting an

>From 5503e7ad396a94a64e11f371d88fb7caedfd9230 Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Wed, 15 Jan 2025 13:22:12 -0600
Subject: [PATCH 11/55] StackAddrEscapeChecker

---
 .../StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp    | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index 9f126cd8d3d23c6..25323b6bea3d4d5 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -267,13 +267,7 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
   if (const BlockDataRegion *B = dyn_cast<BlockDataRegion>(R))
     checkReturnedBlockCaptures(*B, C);
 
-  if (isa<UnknownSpaceRegion>(R)) {
-    const MemSpaceRegion *MS = memspace::getMemSpace(C.getState(), R);
-    if (!isa_and_nonnull<StackSpaceRegion>(MS) || isNotInCurrentFrame(MS, C))
-      return;
-  }
-
-  const MemSpaceRegion *MS = R->getMemorySpace();
+  const MemSpaceRegion *MS = memspace::getMemSpace(C.getState(), R);
   if (!isa<StackSpaceRegion>(MS) || isNotInCurrentFrame(MS, C))
     return;
 

>From a51d7576945d539483c8b17feefba3d8c34fa767 Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Wed, 15 Jan 2025 13:22:26 -0600
Subject: [PATCH 12/55] RetainCountDiagnostics

---
 .../RetainCountChecker/RetainCountDiagnostics.cpp         | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
index 80fa8d3e3f921e0..0d4a102538a6d1b 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
@@ -691,13 +691,9 @@ static AllocationInfo GetAllocationSite(ProgramStateManager &StateMgr,
       const MemRegion *R = FB.getRegion();
       // Do not show local variables belonging to a function other than
       // where the error is reported.
-      const StackSpaceRegion *MR =
-          dyn_cast<StackSpaceRegion>(R->getMemorySpace());
-      if (!MR)
-        MR = dyn_cast_if_present<StackSpaceRegion>(
-            memspace::getMemSpace(St, R));
+      const StackSpaceRegion *SSR = dyn_cast_if_present<StackSpaceRegion>(memspace::getMemSpace(St, R));
 
-      if (MR && MR->getStackFrame() == LeakContext->getStackFrame())
+      if (SSR && SSR->getStackFrame() == LeakContext->getStackFrame())
         FirstBinding = R;
     }
 

>From c67671e27d593147691fa9f7ffdd71f131b19a32 Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Wed, 15 Jan 2025 13:52:02 -0600
Subject: [PATCH 13/55] ExprEngine remove redundant added case, invert
 condition bugfix

---
 clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 1a056d8fc5970c4..7a9177b3bcc7707 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -3512,13 +3512,7 @@ ProgramStateRef ExprEngine::processPointerEscapedOnBind(
     // Cases (1) and (2).
     const MemRegion *MR = LocAndVal.first.getAsRegion();
     if (!MR ||
-        !isa<StackSpaceRegion, StaticGlobalSpaceRegion>(MR->getMemorySpace())) {
-      Escaped.push_back(LocAndVal.second);
-      continue;
-    }
-
-    // Case (2) continued.
-    if (memspace::isMemSpace<StackSpaceRegion, StaticGlobalSpaceRegion>(State, MR)) {
+        !memspace::isMemSpace<StackSpaceRegion, StaticGlobalSpaceRegion>(State, MR)) {
       Escaped.push_back(LocAndVal.second);
       continue;
     }

>From 80b9b62e068aed8f53214086432e2e45b92981e0 Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Wed, 15 Jan 2025 14:02:55 -0600
Subject: [PATCH 14/55] formatting

---
 .../StaticAnalyzer/Core/PathSensitive/MemSpaces.h    |  3 +--
 .../Checkers/PutenvStackArrayChecker.cpp             |  3 ++-
 .../RetainCountChecker/RetainCountDiagnostics.cpp    |  3 ++-
 .../lib/StaticAnalyzer/Core/BugReporterVisitors.cpp  |  5 +++--
 clang/lib/StaticAnalyzer/Core/ExprEngine.cpp         |  4 ++--
 clang/lib/StaticAnalyzer/Core/MemSpaces.cpp          | 12 ++++++------
 6 files changed, 16 insertions(+), 14 deletions(-)

diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
index 419d24ac58ef6db..8d6679545a82661 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
@@ -37,8 +37,7 @@ namespace memspace {
                                                 const MemRegion *MR);
 
 template <typename FirstT, typename... RestT>
-[[nodiscard]] bool isMemSpace(ProgramStateRef State,
-                              const MemRegion *MR) {
+[[nodiscard]] bool isMemSpace(ProgramStateRef State, const MemRegion *MR) {
   return isa_and_nonnull<FirstT, RestT...>(getMemSpace(State, MR));
 }
 
diff --git a/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
index 455cb6cc37a1fee..a200f54a97b8c63 100644
--- a/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
@@ -48,7 +48,8 @@ void PutenvStackArrayChecker::checkPostCall(const CallEvent &Call,
 
   const MemRegion *MR = ArgV.getAsRegion();
 
-  const StackSpaceRegion *SSR = dyn_cast_if_present<StackSpaceRegion>(memspace::getMemSpace(C.getState(), MR));
+  const StackSpaceRegion *SSR = dyn_cast_if_present<StackSpaceRegion>(
+      memspace::getMemSpace(C.getState(), MR));
   if (!SSR)
     return;
 
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
index 0d4a102538a6d1b..b3a3aeac3a99e8d 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
@@ -691,7 +691,8 @@ static AllocationInfo GetAllocationSite(ProgramStateManager &StateMgr,
       const MemRegion *R = FB.getRegion();
       // Do not show local variables belonging to a function other than
       // where the error is reported.
-      const StackSpaceRegion *SSR = dyn_cast_if_present<StackSpaceRegion>(memspace::getMemSpace(St, R));
+      const StackSpaceRegion *SSR =
+          dyn_cast_if_present<StackSpaceRegion>(memspace::getMemSpace(St, R));
 
       if (SSR && SSR->getStackFrame() == LeakContext->getStackFrame())
         FirstBinding = R;
diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index 458d3e545ccd2f4..83befeb99b5f284 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -1194,8 +1194,9 @@ static bool isInitializationOfVar(const ExplodedNode *N, const VarRegion *VR) {
     return false;
 
   const MemSpaceRegion *VarSpace = VR->getMemorySpace();
-  const StackSpaceRegion *FrameSpace = dyn_cast_if_present<StackSpaceRegion>(memspace::getMemSpace(N->getState(), VR));
-  
+  const StackSpaceRegion *FrameSpace = dyn_cast_if_present<StackSpaceRegion>(
+      memspace::getMemSpace(N->getState(), VR));
+
   if (!FrameSpace) {
     // If we ever directly evaluate global DeclStmts, this assertion will be
     // invalid, but this still seems preferable to silently accepting an
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 7a9177b3bcc7707..eabadfddedebbb6 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -3511,8 +3511,8 @@ ProgramStateRef ExprEngine::processPointerEscapedOnBind(
   for (const std::pair<SVal, SVal> &LocAndVal : LocAndVals) {
     // Cases (1) and (2).
     const MemRegion *MR = LocAndVal.first.getAsRegion();
-    if (!MR ||
-        !memspace::isMemSpace<StackSpaceRegion, StaticGlobalSpaceRegion>(State, MR)) {
+    if (!MR || !memspace::isMemSpace<StackSpaceRegion, StaticGlobalSpaceRegion>(
+                   State, MR)) {
       Escaped.push_back(LocAndVal.second);
       continue;
     }
diff --git a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
index e20c1d15e4c518d..25846527264ab6b 100644
--- a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
+++ b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
@@ -9,7 +9,7 @@
 // This file defines getters and setters for the memory space trait which
 // associates memory regions with memory spaces in the program state. It also
 // defines the MemSpacesMap which maps memory regions to memory spaces.
-// 
+//
 // These functions keep the following invariants over the MemSpacesMap:
 // 1. (Temporary as an intermediate step) Memory space traits are only
 //    mapped for memory regions that have an unknown memory space
@@ -32,9 +32,10 @@ namespace clang {
 namespace ento {
 namespace memspace {
 
-// Canonicalize to base, in case of subregions, we don't want base regions and subregions
-// to have different memory spaces
-[[nodiscard]] static const MemRegion *canonicalizeMemRegion(const MemRegion *MR) {
+// Canonicalize to base, in case of subregions, we don't want base regions and
+// subregions to have different memory spaces
+[[nodiscard]] static const MemRegion *
+canonicalizeMemRegion(const MemRegion *MR) {
   return MR->getBaseRegion();
 }
 
@@ -56,8 +57,7 @@ ProgramStateRef setMemSpaceTrait(ProgramStateRef State, const MemRegion *MR,
   return NewState;
 }
 
-const MemSpaceRegion *getMemSpace(ProgramStateRef State,
-                                  const MemRegion *MR) {
+const MemSpaceRegion *getMemSpace(ProgramStateRef State, const MemRegion *MR) {
   MR = canonicalizeMemRegion(MR);
 
   const MemSpaceRegion *const *Result = State->get<MemSpacesMap>(MR);

>From 287bbd46862cfe2a5d1a3331e4f2b72ab70d32e8 Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Tue, 21 Jan 2025 20:01:12 -0600
Subject: [PATCH 15/55] wip

---
 clang/lib/StaticAnalyzer/Core/MemSpaces.cpp     | 9 +++++----
 clang/lib/StaticAnalyzer/Core/SymbolManager.cpp | 2 +-
 2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
index 25846527264ab6b..662771623d3e239 100644
--- a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
+++ b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
@@ -60,11 +60,12 @@ ProgramStateRef setMemSpaceTrait(ProgramStateRef State, const MemRegion *MR,
 const MemSpaceRegion *getMemSpace(ProgramStateRef State, const MemRegion *MR) {
   MR = canonicalizeMemRegion(MR);
 
+  const MemSpaceRegion *MS = MR->getMemorySpace();
+  if (!isa<UnknownSpaceRegion>(MS))
+    return MS;
+    
   const MemSpaceRegion *const *Result = State->get<MemSpacesMap>(MR);
-  if (Result)
-    return *Result;
-
-  return MR->getMemorySpace();
+  return Result ? *Result : MS;
 }
 
 } // namespace memspace
diff --git a/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp b/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp
index 738b6a175ce6deb..5126edac6a8508b 100644
--- a/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp
@@ -437,7 +437,7 @@ bool SymbolReaper::isLiveRegion(const MemRegion *MR) {
   // tell if anything still refers to this region. Unlike SymbolicRegions,
   // AllocaRegions don't have associated symbols, though, so we don't actually
   // have a way to track their liveness.
-  return isa<AllocaRegion, CXXThisRegion, MemSpaceRegion, CodeTextRegion>(MR);
+  return isa<AllocaRegion, CXXThisRegion, CodeTextRegion>(MR);
 }
 
 bool SymbolReaper::isLazilyCopiedRegion(const MemRegion *MR) const {

>From 82f450603bb9f4db180b561dc824d4a98d314730 Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Mon, 27 Jan 2025 12:25:41 -0600
Subject: [PATCH 16/55] Move memspace::* to MemRegion::* instance methods

---
 .../StaticAnalyzer/Checkers/SValExplainer.h   |  2 +-
 .../Core/PathSensitive/MemRegion.h            | 22 +++++++-
 .../Core/PathSensitive/MemSpaces.h            | 12 -----
 .../Checkers/ArrayBoundCheckerV2.cpp          |  4 +-
 .../StaticAnalyzer/Checkers/ErrnoChecker.cpp  |  2 +-
 .../Checkers/MacOSXAPIChecker.cpp             |  6 +--
 .../StaticAnalyzer/Checkers/MallocChecker.cpp |  8 +--
 .../StaticAnalyzer/Checkers/MoveChecker.cpp   |  2 +-
 .../Checkers/NSErrorChecker.cpp               |  2 +-
 .../Checkers/PutenvStackArrayChecker.cpp      |  2 +-
 .../RetainCountChecker/RetainCountChecker.cpp |  2 +-
 .../RetainCountDiagnostics.cpp                |  2 +-
 .../Checkers/StackAddrEscapeChecker.cpp       | 14 ++---
 .../Checkers/UnixAPIChecker.cpp               |  4 +-
 .../Core/BugReporterVisitors.cpp              |  3 +-
 clang/lib/StaticAnalyzer/Core/ExprEngine.cpp  |  3 +-
 clang/lib/StaticAnalyzer/Core/MemRegion.cpp   | 53 +++++++++++++++----
 clang/lib/StaticAnalyzer/Core/MemSpaces.cpp   | 35 ------------
 clang/lib/StaticAnalyzer/Core/RegionStore.cpp |  8 +--
 .../StaticAnalyzer/Core/SimpleSValBuilder.cpp |  4 +-
 .../lib/StaticAnalyzer/Core/SymbolManager.cpp |  2 +-
 21 files changed, 98 insertions(+), 94 deletions(-)

diff --git a/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h b/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
index 43a70f596a4da28..f07e69621404c44 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
+++ b/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
@@ -166,7 +166,7 @@ class SValExplainer : public FullSValVisitor<SValExplainer, std::string> {
             .getCanonicalType()->getAs<ObjCObjectPointerType>())
       return "object at " + Visit(R->getSymbol());
     // Other heap-based symbolic regions are also special.
-    if (isa<HeapSpaceRegion>(R->getMemorySpace()))
+    if (isa<HeapSpaceRegion>(R->getRawMemorySpace()))
       return "heap segment that starts at " + Visit(R->getSymbol());
     return "pointee of " + Visit(R->getSymbol());
   }
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index f88bf70d72398c2..f414737b6cd3136 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -26,6 +26,7 @@
 #include "clang/Analysis/AnalysisDeclContext.h"
 #include "clang/Basic/LLVM.h"
 #include "clang/Basic/SourceLocation.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
 #include "llvm/ADT/DenseMap.h"
@@ -119,7 +120,21 @@ class MemRegion : public llvm::FoldingSetNode {
 
   virtual MemRegionManager &getMemRegionManager() const = 0;
 
-  LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion *getMemorySpace() const;
+  /// Deprecated. Gets the 'raw' memory space of a memory region's base region. Deprecated
+  /// in favor of the memory space trait which maps memory regions to memory spaces, allowing
+  /// dynamic updating of a memory region's memory space. 
+  /// @deprecated Use getMemorySpace(ProgramStateRef) instead.
+  LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion *getRawMemorySpace() const;
+
+  /// Returns the most specific memory space for this memory region in the given ProgramStateRef.
+  [[nodiscard]] LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion *getMemorySpace(ProgramStateRef State) const;
+
+  template <typename FirstT, typename... RestT>
+  [[nodiscard]] bool isMemorySpace(ProgramStateRef State) const {
+    return isa_and_nonnull<FirstT, RestT...>(getMemorySpace(State));
+  }
+
+  [[nodiscard]] ProgramStateRef setMemSpaceTrait(ProgramStateRef State, const MemSpaceRegion *MS) const;
 
   LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion *getBaseRegion() const;
 
@@ -140,7 +155,10 @@ class MemRegion : public llvm::FoldingSetNode {
   /// It might return null.
   const SymbolicRegion *getSymbolicBase() const;
 
-  bool hasStackStorage() const;
+  /// @deprecated Use hasStackStorage(ProgramStateRef) instead.
+  bool hasRawStackStorage() const;
+
+  [[nodiscard]] bool hasStackStorage(ProgramStateRef State) const;
 
   bool hasStackNonParametersStorage() const;
 
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
index 8d6679545a82661..c44f57da067da19 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
@@ -29,18 +29,6 @@ class MemSpaceRegion;
 
 namespace memspace {
 
-[[nodiscard]] ProgramStateRef setMemSpaceTrait(ProgramStateRef State,
-                                               const MemRegion *MR,
-                                               const MemSpaceRegion *MS);
-
-[[nodiscard]] const MemSpaceRegion *getMemSpace(ProgramStateRef State,
-                                                const MemRegion *MR);
-
-template <typename FirstT, typename... RestT>
-[[nodiscard]] bool isMemSpace(ProgramStateRef State, const MemRegion *MR) {
-  return isa_and_nonnull<FirstT, RestT...>(getMemSpace(State, MR));
-}
-
 } // namespace memspace
 } // namespace ento
 } // namespace clang
diff --git a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
index e97be53fee4c7fe..84d27000f059b5a 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
@@ -353,7 +353,7 @@ static std::string getRegionName(const SubRegion *Region) {
     return "the memory returned by 'alloca'";
 
   if (isa<SymbolicRegion>(Region) &&
-      isa<HeapSpaceRegion>(Region->getMemorySpace()))
+      isa<HeapSpaceRegion>(Region->getRawMemorySpace()))
     return "the heap area";
 
   if (isa<StringRegion>(Region))
@@ -575,7 +575,7 @@ void ArrayBoundCheckerV2::performCheck(const Expr *E, CheckerContext &C) const {
   StateUpdateReporter SUR(Reg, ByteOffset, E, C);
 
   // CHECK LOWER BOUND
-  const MemSpaceRegion *Space = Reg->getMemorySpace();
+  const MemSpaceRegion *Space = Reg->getRawMemorySpace();
   if (!(isa<SymbolicRegion>(Reg) && isa<UnknownSpaceRegion>(Space))) {
     // A symbolic region in unknown space represents an unknown pointer that
     // may point into the middle of an array, so we don't look for underflows.
diff --git a/clang/lib/StaticAnalyzer/Checkers/ErrnoChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ErrnoChecker.cpp
index beb3c8574b5fd4d..c2444aaf125a1b1 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ErrnoChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ErrnoChecker.cpp
@@ -231,7 +231,7 @@ ProgramStateRef ErrnoChecker::checkRegionChanges(
 
   // Always reset errno state when the system memory space is invalidated.
   // The ErrnoRegion is not always found in the list in this case.
-  if (llvm::is_contained(Regions, ErrnoRegion->getMemorySpace()))
+  if (llvm::is_contained(Regions, ErrnoRegion->getRawMemorySpace()))
     return clearErrnoState(State);
 
   return State;
diff --git a/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
index e8d68e27fdaff3e..14aeff31f8c80b8 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
@@ -80,7 +80,7 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
 
   // Global variables are fine.
   const MemRegion *RB = R->getBaseRegion();
-  if (memspace::isMemSpace<GlobalsSpaceRegion>(State, RB))
+  if (RB->isMemorySpace<GlobalsSpaceRegion>(State))
     return;
 
   // Handle _dispatch_once.  In some versions of the OS X SDK we have the case
@@ -119,9 +119,9 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
     if (IVR != R)
       os << " memory within";
     os << " the instance variable '" << IVR->getDecl()->getName() << '\'';
-  } else if (memspace::isMemSpace<HeapSpaceRegion>(State, RB)) {
+  } else if (RB->isMemorySpace<HeapSpaceRegion>(State)) {
     os << " heap-allocated memory";
-  } else if (memspace::isMemSpace<UnknownSpaceRegion>(State, RB)) {
+  } else if (RB->isMemorySpace<UnknownSpaceRegion>(State)) {
     // Presence of an IVar superregion has priority over this branch, because
     // ObjC objects are on the heap even if the core doesn't realize this.
     // Presence of a block variable base region has priority over this branch,
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 7d127facd1a36ac..7e1f869877edd70 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -2211,7 +2211,7 @@ MallocChecker::FreeMemAux(CheckerContext &C, const Expr *ArgExpr,
   // - The region has unknown memspace and no trait for further clarification
   //   (i.e., just unknown)
   // - The region has unknown memspace and a heap memspace trait
-  if (!memspace::isMemSpace<HeapSpaceRegion, UnknownSpaceRegion>(State, R)) {
+  if (!R->isMemorySpace<HeapSpaceRegion, UnknownSpaceRegion>(State)) {
     // Regions returned by malloc() are represented by SymbolicRegion objects
     // within HeapSpaceRegion. Of course, free() can work on memory allocated
     // outside the current function, so UnknownSpaceRegion is also a
@@ -2408,7 +2408,7 @@ bool MallocChecker::SummarizeRegion(ProgramStateRef State, raw_ostream &os,
     os << "a block";
     return true;
   default: {
-    if (memspace::isMemSpace<StackLocalsSpaceRegion>(State, MR)) {
+    if (MR->isMemorySpace<StackLocalsSpaceRegion>(State)) {
       const VarRegion *VR = dyn_cast<VarRegion>(MR);
       const VarDecl *VD;
       if (VR)
@@ -2423,7 +2423,7 @@ bool MallocChecker::SummarizeRegion(ProgramStateRef State, raw_ostream &os,
       return true;
     }
 
-    if (memspace::isMemSpace<StackArgumentsSpaceRegion>(State, MR)) {
+    if (MR->isMemorySpace<StackArgumentsSpaceRegion>(State)) {
       const VarRegion *VR = dyn_cast<VarRegion>(MR);
       const VarDecl *VD;
       if (VR)
@@ -2438,7 +2438,7 @@ bool MallocChecker::SummarizeRegion(ProgramStateRef State, raw_ostream &os,
       return true;
     }
 
-    if (memspace::isMemSpace<GlobalsSpaceRegion>(State, MR)) {
+    if (MR->isMemorySpace<GlobalsSpaceRegion>(State)) {
       const VarRegion *VR = dyn_cast<VarRegion>(MR);
       const VarDecl *VD;
       if (VR)
diff --git a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
index 042c4e0c1ab2e69..090c63c69af4fd7 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
@@ -561,7 +561,7 @@ MoveChecker::classifyObject(ProgramStateRef State, const MemRegion *MR,
   MR = unwrapRValueReferenceIndirection(MR);
   bool IsLocal =
       isa_and_nonnull<VarRegion, CXXLifetimeExtendedObjectRegion>(MR) &&
-      memspace::isMemSpace<StackSpaceRegion>(State, MR);
+      MR->isMemorySpace<StackSpaceRegion>(State);
 
   if (!RD || !RD->getDeclContext()->isStdNamespace())
     return { IsLocal, SK_NonStd };
diff --git a/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
index 54870bcb4bb22be..151f6312f5d232a 100644
--- a/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
@@ -202,7 +202,7 @@ static QualType parameterTypeFromSVal(SVal val, CheckerContext &C) {
     const MemRegion* R = X->getRegion();
     if (const VarRegion *VR = R->getAs<VarRegion>())
       if (const StackArgumentsSpaceRegion *
-          stackReg = dyn_cast<StackArgumentsSpaceRegion>(VR->getMemorySpace()))
+          stackReg = dyn_cast<StackArgumentsSpaceRegion>(VR->getRawMemorySpace()))
         if (stackReg->getStackFrame() == SFC)
           return VR->getValueType();
   }
diff --git a/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
index a200f54a97b8c63..f71259ee2e1c6bb 100644
--- a/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
@@ -49,7 +49,7 @@ void PutenvStackArrayChecker::checkPostCall(const CallEvent &Call,
   const MemRegion *MR = ArgV.getAsRegion();
 
   const StackSpaceRegion *SSR = dyn_cast_if_present<StackSpaceRegion>(
-      memspace::getMemSpace(C.getState(), MR));
+      MR->getMemorySpace(C.getState()));
   if (!SSR)
     return;
 
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
index 7e74b418b335361..3887e752a43cec5 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
@@ -507,7 +507,7 @@ static bool shouldEscapeRegion(const MemRegion *R) {
 
   const auto *VR = dyn_cast<VarRegion>(R);
 
-  if (!R->hasStackStorage() || !VR)
+  if (!R->hasRawStackStorage() || !VR)
     return true;
 
   const VarDecl *VD = VR->getDecl();
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
index b3a3aeac3a99e8d..ef430254b8d8531 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
@@ -692,7 +692,7 @@ static AllocationInfo GetAllocationSite(ProgramStateManager &StateMgr,
       // Do not show local variables belonging to a function other than
       // where the error is reported.
       const StackSpaceRegion *SSR =
-          dyn_cast_if_present<StackSpaceRegion>(memspace::getMemSpace(St, R));
+          dyn_cast_if_present<StackSpaceRegion>(R->getMemSpace(St));
 
       if (SSR && SSR->getStackFrame() == LeakContext->getStackFrame())
         FirstBinding = R;
diff --git a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index 25323b6bea3d4d5..903ed1d1cfa12c9 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -143,7 +143,7 @@ StackAddrEscapeChecker::getCapturedStackRegions(const BlockDataRegion &B,
   for (auto Var : B.referenced_vars()) {
     SVal Val = State->getSVal(Var.getCapturedRegion());
     const MemRegion *Region = Val.getAsRegion();
-    if (Region && memspace::isMemSpace<StackSpaceRegion>(State, Region))
+    if (Region && Region->isMemorySpace<StackSpaceRegion>(State))
       Regions.push_back(Region);
   }
   return Regions;
@@ -214,7 +214,7 @@ void StackAddrEscapeChecker::checkAsyncExecutedBlockCaptures(
 void StackAddrEscapeChecker::checkReturnedBlockCaptures(
     const BlockDataRegion &B, CheckerContext &C) const {
   for (const MemRegion *Region : getCapturedStackRegions(B, C)) {
-    if (isNotInCurrentFrame(Region->getMemorySpace(), C))
+    if (isNotInCurrentFrame(Region->getRawMemorySpace(), C))
       continue;
     ExplodedNode *N = C.generateNonFatalErrorNode();
     if (!N)
@@ -267,7 +267,7 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
   if (const BlockDataRegion *B = dyn_cast<BlockDataRegion>(R))
     checkReturnedBlockCaptures(*B, C);
 
-  const MemSpaceRegion *MS = memspace::getMemSpace(C.getState(), R);
+  const MemSpaceRegion *MS = R->getMemSpace(C.getState());
   if (!isa<StackSpaceRegion>(MS) || isNotInCurrentFrame(MS, C))
     return;
 
@@ -293,7 +293,7 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
 
 static const MemSpaceRegion *getStackOrGlobalSpaceRegion(const MemRegion *R) {
   assert(R);
-  if (const auto *MemSpace = R->getMemorySpace()) {
+  if (const auto *MemSpace = R->getRawMemorySpace()) {
     if (const auto *SSR = MemSpace->getAs<StackSpaceRegion>())
       return SSR;
     if (const auto *GSR = MemSpace->getAs<GlobalsSpaceRegion>())
@@ -406,7 +406,7 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,
                                        const MemRegion *Referred) {
       const auto *ReferrerMemSpace = getStackOrGlobalSpaceRegion(Referrer);
       const auto *ReferredMemSpace =
-          Referred->getMemorySpace()->getAs<StackSpaceRegion>();
+          Referred->getRawMemorySpace()->getAs<StackSpaceRegion>();
 
       if (!ReferrerMemSpace || !ReferredMemSpace)
         return false;
@@ -471,8 +471,8 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,
       if (!isa_and_nonnull<GlobalsSpaceRegion>(
               getStackOrGlobalSpaceRegion(Region)))
         return true;
-      if (VR && VR->hasStackStorage() &&
-          !isNotInCurrentFrame(VR->getMemorySpace(), Ctx))
+      if (VR && VR->hasRawStackStorage() &&
+          !isNotInCurrentFrame(VR->getRawMemorySpace(), Ctx))
         V.emplace_back(Region, VR);
       return true;
     }
diff --git a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
index 0da562a9fe51db8..715098ecbf05d20 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
@@ -412,7 +412,7 @@ void UnixAPIMisuseChecker::CheckPthreadOnce(CheckerContext &C,
   // because that's likely to be bad news.
   ProgramStateRef state = C.getState();
   const MemRegion *R = Call.getArgSVal(0).getAsRegion();
-  if (!R || !memspace::isMemSpace<StackSpaceRegion>(state, R))
+  if (!R || !R->isMemorySpace<StackSpaceRegion>(state))
     return;
 
   ExplodedNode *N = C.generateErrorNode(state);
@@ -428,7 +428,7 @@ void UnixAPIMisuseChecker::CheckPthreadOnce(CheckerContext &C,
     os << " stack allocated memory";
   os << " for the \"control\" value.  Using such transient memory for "
   "the control value is potentially dangerous.";
-  if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace()))
+  if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getRawMemorySpace()))
     os << "  Perhaps you intended to declare the variable as 'static'?";
 
   auto report =
diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index 83befeb99b5f284..0df56c49ab5742d 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -1193,9 +1193,8 @@ static bool isInitializationOfVar(const ExplodedNode *N, const VarRegion *VR) {
   if (DS->getSingleDecl() != VR->getDecl())
     return false;
 
-  const MemSpaceRegion *VarSpace = VR->getMemorySpace();
   const StackSpaceRegion *FrameSpace = dyn_cast_if_present<StackSpaceRegion>(
-      memspace::getMemSpace(N->getState(), VR));
+      VR->getMemorySpace(N->getState()));
 
   if (!FrameSpace) {
     // If we ever directly evaluate global DeclStmts, this assertion will be
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index eabadfddedebbb6..23219ae291fb30a 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -3511,8 +3511,7 @@ ProgramStateRef ExprEngine::processPointerEscapedOnBind(
   for (const std::pair<SVal, SVal> &LocAndVal : LocAndVals) {
     // Cases (1) and (2).
     const MemRegion *MR = LocAndVal.first.getAsRegion();
-    if (!MR || !memspace::isMemSpace<StackSpaceRegion, StaticGlobalSpaceRegion>(
-                   State, MR)) {
+    if (!MR || !MR->isMemorySpace<StackSpaceRegion, StaticGlobalSpaceRegion>(State)) {
       Escaped.push_back(LocAndVal.second);
       continue;
     }
diff --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
index 559c80634c12e57..67b5117f19dc6a2 100644
--- a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -61,6 +61,9 @@ using namespace ento;
 
 #define DEBUG_TYPE "MemRegion"
 
+REGISTER_MAP_WITH_PROGRAMSTATE(MemSpacesMap, const clang::ento::MemRegion *,
+                               const clang::ento::MemSpaceRegion *)
+
 //===----------------------------------------------------------------------===//
 // MemRegion Construction.
 //===----------------------------------------------------------------------===//
@@ -163,20 +166,20 @@ MemRegionManager &SubRegion::getMemRegionManager() const {
 }
 
 const StackFrameContext *VarRegion::getStackFrame() const {
-  const auto *SSR = dyn_cast<StackSpaceRegion>(getMemorySpace());
+  const auto *SSR = dyn_cast<StackSpaceRegion>(getRawMemorySpace());
   return SSR ? SSR->getStackFrame() : nullptr;
 }
 
 const StackFrameContext *
 CXXLifetimeExtendedObjectRegion::getStackFrame() const {
-  const auto *SSR = dyn_cast<StackSpaceRegion>(getMemorySpace());
+  const auto *SSR = dyn_cast<StackSpaceRegion>(getRawMemorySpace());
   return SSR ? SSR->getStackFrame() : nullptr;
 }
 
 const StackFrameContext *CXXTempObjectRegion::getStackFrame() const {
-  assert(isa<StackSpaceRegion>(getMemorySpace()) &&
+  assert(isa<StackSpaceRegion>(getRawMemorySpace()) &&
          "A temporary object can only be allocated on the stack");
-  return cast<StackSpaceRegion>(getMemorySpace())->getStackFrame();
+  return cast<StackSpaceRegion>(getRawMemorySpace())->getStackFrame();
 }
 
 ObjCIvarRegion::ObjCIvarRegion(const ObjCIvarDecl *ivd, const SubRegion *sReg)
@@ -1348,7 +1351,7 @@ MemRegionManager::getAllocaRegion(const Expr *E, unsigned cnt,
   return getSubRegion<AllocaRegion>(E, cnt, getStackLocalsRegion(STC));
 }
 
-const MemSpaceRegion *MemRegion::getMemorySpace() const {
+const MemSpaceRegion *MemRegion::getRawMemorySpace() const {
   const MemRegion *R = this;
   const auto *SR = dyn_cast<SubRegion>(this);
 
@@ -1360,16 +1363,48 @@ const MemSpaceRegion *MemRegion::getMemorySpace() const {
   return cast<MemSpaceRegion>(R);
 }
 
-bool MemRegion::hasStackStorage() const {
-  return isa<StackSpaceRegion>(getMemorySpace());
+const MemSpaceRegion *MemRegion::getMemorySpace(ProgramStateRef State) const {
+  const MemRegion *MR = getBaseRegion();
+
+  const MemSpaceRegion *MS = MR->getRawMemorySpace();
+  if (!isa<UnknownSpaceRegion>(MS))
+    return MS;
+    
+  const MemSpaceRegion *const *Result = State->get<MemSpacesMap>(MR);
+  return Result ? *Result : MS;
+}
+
+ProgramStateRef MemRegion::setMemSpaceTrait(ProgramStateRef State, const MemSpaceRegion *MS) const {
+  const MemRegion *MR = getBaseRegion();
+
+  // For now, this should only be called to update the trait for memory regions
+  // that have an unknown memory spaces since we assume everywhere else that the
+  // memory space trait is set only for unknown memory spaces (setting this info
+  // otherwise would go unused).
+  assert(isa<UnknownSpaceRegion>(MR->getRawMemorySpace()));
+
+  // Shouldn't use the memory space trait to associate UnknownSpaceRegion with
+  // an already UnknownSpaceRegion
+  assert(!isa<UnknownSpaceRegion>(MS));
+
+  ProgramStateRef NewState = State->set<MemSpacesMap>(MR, MS);
+  return NewState;
+}
+
+bool MemRegion::hasRawStackStorage() const {
+  return isa<StackSpaceRegion>(getRawMemorySpace());
+}
+
+bool MemRegion::hasStackStorage(ProgramStateRef State) const { 
+  return isMemorySpace<StackSpaceRegion>(State); 
 }
 
 bool MemRegion::hasStackNonParametersStorage() const {
-  return isa<StackLocalsSpaceRegion>(getMemorySpace());
+  return isa<StackLocalsSpaceRegion>(getRawMemorySpace());
 }
 
 bool MemRegion::hasStackParametersStorage() const {
-  return isa<StackArgumentsSpaceRegion>(getMemorySpace());
+  return isa<StackArgumentsSpaceRegion>(getRawMemorySpace());
 }
 
 // Strips away all elements and fields.
diff --git a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
index 662771623d3e239..7201ec816bc8a20 100644
--- a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
+++ b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
@@ -32,41 +32,6 @@ namespace clang {
 namespace ento {
 namespace memspace {
 
-// Canonicalize to base, in case of subregions, we don't want base regions and
-// subregions to have different memory spaces
-[[nodiscard]] static const MemRegion *
-canonicalizeMemRegion(const MemRegion *MR) {
-  return MR->getBaseRegion();
-}
-
-ProgramStateRef setMemSpaceTrait(ProgramStateRef State, const MemRegion *MR,
-                                 const MemSpaceRegion *MS) {
-  MR = canonicalizeMemRegion(MR);
-
-  // For now, this should only be called to update the trait for memory regions
-  // that have an unknown memory spaces since we assume everywhere else that the
-  // memory space trait is set only for unknown memory spaces (setting this info
-  // otherwise would go unused).
-  assert(isa<UnknownSpaceRegion>(MR->getMemorySpace()));
-
-  // Shouldn't use the memory space trait to associate UnknownSpaceRegion with
-  // an already UnknownSpaceRegion
-  assert(!isa<UnknownSpaceRegion>(MS));
-
-  ProgramStateRef NewState = State->set<MemSpacesMap>(MR, MS);
-  return NewState;
-}
-
-const MemSpaceRegion *getMemSpace(ProgramStateRef State, const MemRegion *MR) {
-  MR = canonicalizeMemRegion(MR);
-
-  const MemSpaceRegion *MS = MR->getMemorySpace();
-  if (!isa<UnknownSpaceRegion>(MS))
-    return MS;
-    
-  const MemSpaceRegion *const *Result = State->get<MemSpacesMap>(MR);
-  return Result ? *Result : MS;
-}
 
 } // namespace memspace
 } // namespace ento
diff --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
index ad45ab5757a5ac4..b44001f049044b2 100644
--- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -1292,9 +1292,9 @@ bool InvalidateRegionsWorker::isInitiallyIncludedGlobalRegion(
   case GFK_None:
     return false;
   case GFK_SystemOnly:
-    return isa<GlobalSystemSpaceRegion>(R->getMemorySpace());
+    return isa<GlobalSystemSpaceRegion>(R->getRawMemorySpace());
   case GFK_All:
-    return isa<NonStaticGlobalSpaceRegion>(R->getMemorySpace());
+    return isa<NonStaticGlobalSpaceRegion>(R->getRawMemorySpace());
   }
 
   llvm_unreachable("unknown globals filter");
@@ -1304,7 +1304,7 @@ bool InvalidateRegionsWorker::includeEntireMemorySpace(const MemRegion *Base) {
   if (isInitiallyIncludedGlobalRegion(Base))
     return true;
 
-  const MemSpaceRegion *MemSpace = Base->getMemorySpace();
+  const MemSpaceRegion *MemSpace = Base->getRawMemorySpace();
   return ITraits.hasTrait(MemSpace,
                           RegionAndSymbolInvalidationTraits::TK_EntireMemSpace);
 }
@@ -2239,7 +2239,7 @@ SVal RegionStoreManager::getBindingForVar(RegionBindingsConstRef B,
 
   // Lazily derive a value for the VarRegion.
   const VarDecl *VD = R->getDecl();
-  const MemSpaceRegion *MS = R->getMemorySpace();
+  const MemSpaceRegion *MS = R->getRawMemorySpace();
 
   // Arguments are always symbolic.
   if (isa<StackArgumentsSpaceRegion>(MS))
diff --git a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
index 455621739f69358..ab5b21c68f6e7f4 100644
--- a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
@@ -948,8 +948,8 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state,
 
     const MemRegion *LeftBase = LeftMR->getBaseRegion();
     const MemRegion *RightBase = RightMR->getBaseRegion();
-    const MemSpaceRegion *LeftMS = LeftBase->getMemorySpace();
-    const MemSpaceRegion *RightMS = RightBase->getMemorySpace();
+    const MemSpaceRegion *LeftMS = LeftBase->getRawMemorySpace();
+    const MemSpaceRegion *RightMS = RightBase->getRawMemorySpace();
     const MemSpaceRegion *UnknownMS = MemMgr.getUnknownRegion();
 
     // If the two regions are from different known memory spaces they cannot be
diff --git a/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp b/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp
index 5126edac6a8508b..738b6a175ce6deb 100644
--- a/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp
@@ -437,7 +437,7 @@ bool SymbolReaper::isLiveRegion(const MemRegion *MR) {
   // tell if anything still refers to this region. Unlike SymbolicRegions,
   // AllocaRegions don't have associated symbols, though, so we don't actually
   // have a way to track their liveness.
-  return isa<AllocaRegion, CXXThisRegion, CodeTextRegion>(MR);
+  return isa<AllocaRegion, CXXThisRegion, MemSpaceRegion, CodeTextRegion>(MR);
 }
 
 bool SymbolReaper::isLazilyCopiedRegion(const MemRegion *MR) const {

>From 1c69818ee9c0647c2c952b0d92e4af42f807db59 Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Mon, 27 Jan 2025 12:36:55 -0600
Subject: [PATCH 17/55] change some more MemRegion::* instace methods to raw
 and non-raw

---
 .../StaticAnalyzer/Core/PathSensitive/MemRegion.h    |  8 ++++++--
 clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp     |  2 +-
 clang/lib/StaticAnalyzer/Core/ExprEngine.cpp         |  2 +-
 clang/lib/StaticAnalyzer/Core/MemRegion.cpp          | 12 ++++++++++--
 clang/lib/StaticAnalyzer/Core/RegionStore.cpp        |  4 ++--
 5 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index f414737b6cd3136..c889a9ab0604728 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -160,9 +160,13 @@ class MemRegion : public llvm::FoldingSetNode {
 
   [[nodiscard]] bool hasStackStorage(ProgramStateRef State) const;
 
-  bool hasStackNonParametersStorage() const;
+  bool hasRawStackNonParametersStorage() const;
 
-  bool hasStackParametersStorage() const;
+  [[nodiscard]] bool hasStackNonParametersStorage(ProgramStateRef State) const;
+
+  bool hasRawStackParametersStorage() const;
+
+  [[nodiscard]] bool hasStackParametersStorage(ProgramStateRef State) const;
 
   /// Compute the offset within the top level memory object.
   RegionOffset getAsOffset() const;
diff --git a/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp
index 9757a00f1fb2f61..470801f90adb0f0 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp
@@ -134,7 +134,7 @@ static const ParmVarDecl *getOriginParam(SVal V, CheckerContext &C,
   // routine arguments in the heap.
   while (const MemRegion *MR = Sym->getOriginRegion()) {
     const auto *VR = dyn_cast<VarRegion>(MR);
-    if (VR && VR->hasStackParametersStorage() &&
+    if (VR && VR->hasRawStackParametersStorage() &&
            VR->getStackFrame()->inTopFrame())
       return cast<ParmVarDecl>(VR->getDecl());
 
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 23219ae291fb30a..0d245395665cec0 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -3518,7 +3518,7 @@ ProgramStateRef ExprEngine::processPointerEscapedOnBind(
 
     // Case (3).
     if (const auto *VR = dyn_cast<VarRegion>(MR->getBaseRegion()))
-      if (VR->hasStackParametersStorage() && VR->getStackFrame()->inTopFrame())
+      if (VR->hasRawStackParametersStorage() && VR->getStackFrame()->inTopFrame())
         if (const auto *RD = VR->getValueType()->getAsCXXRecordDecl())
           if (!RD->hasTrivialDestructor()) {
             Escaped.push_back(LocAndVal.second);
diff --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
index 67b5117f19dc6a2..4b621e5cb4f9758 100644
--- a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -1399,14 +1399,22 @@ bool MemRegion::hasStackStorage(ProgramStateRef State) const {
   return isMemorySpace<StackSpaceRegion>(State); 
 }
 
-bool MemRegion::hasStackNonParametersStorage() const {
+bool MemRegion::hasRawStackNonParametersStorage() const {
   return isa<StackLocalsSpaceRegion>(getRawMemorySpace());
 }
 
-bool MemRegion::hasStackParametersStorage() const {
+bool MemRegion::hasStackNonParametersStorage(ProgramStateRef State) const {
+  return isMemorySpace<StackLocalsSpaceRegion>(State);
+}
+
+bool MemRegion::hasRawStackParametersStorage() const {
   return isa<StackArgumentsSpaceRegion>(getRawMemorySpace());
 }
 
+bool MemRegion::hasStackParametersStorage(ProgramStateRef State) const {
+  return isMemorySpace<StackArgumentsSpaceRegion>(State);
+}
+
 // Strips away all elements and fields.
 // Returns the base region of them.
 const MemRegion *MemRegion::getBaseRegion() const {
diff --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
index b44001f049044b2..927c8094e81aa04 100644
--- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -1544,7 +1544,7 @@ SVal RegionStoreManager::getBinding(RegionBindingsConstRef B, Loc L, QualType T)
   // The location does not have a bound value.  This means that it has
   // the value it had upon its creation and/or entry to the analyzed
   // function/method.  These are either symbolic values or 'undefined'.
-  if (R->hasStackNonParametersStorage()) {
+  if (R->hasRawStackNonParametersStorage()) {
     // All stack variables are considered to have undefined values
     // upon creation.  All heap allocated blocks are considered to
     // have undefined values as well unless they are explicitly bound
@@ -2175,7 +2175,7 @@ RegionStoreManager::getBindingForFieldOrElementCommon(RegionBindingsConstRef B,
     SR = dyn_cast<SubRegion>(Base);
   }
 
-  if (R->hasStackNonParametersStorage()) {
+  if (R->hasRawStackNonParametersStorage()) {
     if (isa<ElementRegion>(R)) {
       // Currently we don't reason specially about Clang-style vectors.  Check
       // if superR is a vector and if so return Unknown.

>From 5f2053267ffef1e4fd955f19b8152d3bc57dfbce Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Mon, 27 Jan 2025 12:43:47 -0600
Subject: [PATCH 18/55] remove old MemSpaces.h includes

---
 .../Core/PathSensitive/MemSpaces.h            |   36 -
 .../Checkers/ArrayBoundCheckerV2.cpp          |    1 -
 .../Checkers/MacOSXAPIChecker.cpp             |    1 -
 .../StaticAnalyzer/Checkers/MallocChecker.cpp |    1 -
 .../StaticAnalyzer/Checkers/MoveChecker.cpp   |    1 -
 .../Checkers/PutenvStackArrayChecker.cpp      |    1 -
 .../RetainCountDiagnostics.cpp                |    1 -
 .../Checkers/StackAddrEscapeChecker.cpp       |    1 -
 .../Checkers/UnixAPIChecker.cpp               |    1 -
 .../Core/BugReporterVisitors.cpp              |    1 -
 clang/lib/StaticAnalyzer/Core/ExprEngine.cpp  |    1 -
 clang/lib/StaticAnalyzer/Core/MemRegion.cpp   | 1881 -----------------
 12 files changed, 1927 deletions(-)
 delete mode 100644 clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
 delete mode 100644 clang/lib/StaticAnalyzer/Core/MemRegion.cpp

diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
deleted file mode 100644
index c44f57da067da19..000000000000000
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h
+++ /dev/null
@@ -1,36 +0,0 @@
-//===-- MemSpaces.h -----------------------------------------------*- C++ -*--//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file declares getters and setters for the memory space trait which
-// associates memory regions with memory spaces in the program state. We are
-// still transitioning to having all memory space information stored in the
-// trait, so currently memory regions still have memory spaces as a class field.
-// Because of this, these getters still consider memory spaces set as class
-// fields in memory region types.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_STATICANALYZER_CHECKERS_MEMSPACES_H
-#define LLVM_CLANG_STATICANALYZER_CHECKERS_MEMSPACES_H
-
-#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
-
-namespace clang {
-namespace ento {
-
-class MemRegion;
-class MemSpaceRegion;
-
-namespace memspace {
-
-} // namespace memspace
-} // namespace ento
-} // namespace clang
-
-#endif // LLVM_CLANG_STATICANALYZER_CHECKERS_MEMSPACES_H
diff --git a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
index 84d27000f059b5a..3ac31cce4e46d62 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
@@ -22,7 +22,6 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
 #include "llvm/ADT/APSInt.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/Support/FormatVariadic.h"
diff --git a/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
index 14aeff31f8c80b8..874cc511eecb935 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
@@ -22,7 +22,6 @@
 #include "clang/StaticAnalyzer/Core/Checker.h"
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringSwitch.h"
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 7e1f869877edd70..1b1bd7be15aff63 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -72,7 +72,6 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
diff --git a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
index 090c63c69af4fd7..288cbd03656abef 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
@@ -22,7 +22,6 @@
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
 #include "llvm/ADT/StringSet.h"
 
 using namespace clang;
diff --git a/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
index f71259ee2e1c6bb..96be9bf07e01c03 100644
--- a/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
@@ -21,7 +21,6 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
 
 using namespace clang;
 using namespace ento;
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
index ef430254b8d8531..1fbfa8cf0eaddf8 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
@@ -13,7 +13,6 @@
 
 #include "RetainCountDiagnostics.h"
 #include "RetainCountChecker.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallVector.h"
 #include <optional>
diff --git a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index 903ed1d1cfa12c9..57f889af1e94321 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -19,7 +19,6 @@
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/Support/raw_ostream.h"
diff --git a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
index 715098ecbf05d20..f62ac080c729c12 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
@@ -21,7 +21,6 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringExtras.h"
diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index 0df56c49ab5742d..48d5be04adab521 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -40,7 +40,6 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h"
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 0d245395665cec0..53f9998a5810a51 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -53,7 +53,6 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
diff --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
deleted file mode 100644
index 4b621e5cb4f9758..000000000000000
--- a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ /dev/null
@@ -1,1881 +0,0 @@
-//===- MemRegion.cpp - Abstract memory regions for static analysis --------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-//  This file defines MemRegion and its subclasses.  MemRegion defines a
-//  partially-typed abstraction of memory useful for path-sensitive dataflow
-//  analyses.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/Attr.h"
-#include "clang/AST/CharUnits.h"
-#include "clang/AST/Decl.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/PrettyPrinter.h"
-#include "clang/AST/RecordLayout.h"
-#include "clang/AST/Type.h"
-#include "clang/Analysis/AnalysisDeclContext.h"
-#include "clang/Analysis/Support/BumpVector.h"
-#include "clang/Basic/IdentifierTable.h"
-#include "clang/Basic/LLVM.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
-#include "llvm/ADT/APInt.h"
-#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/PointerUnion.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/Twine.h"
-#include "llvm/ADT/iterator_range.h"
-#include "llvm/Support/Allocator.h"
-#include "llvm/Support/Casting.h"
-#include "llvm/Support/CheckedArithmetic.h"
-#include "llvm/Support/Compiler.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/raw_ostream.h"
-#include <cassert>
-#include <cstdint>
-#include <functional>
-#include <iterator>
-#include <optional>
-#include <string>
-#include <tuple>
-#include <utility>
-
-using namespace clang;
-using namespace ento;
-
-#define DEBUG_TYPE "MemRegion"
-
-REGISTER_MAP_WITH_PROGRAMSTATE(MemSpacesMap, const clang::ento::MemRegion *,
-                               const clang::ento::MemSpaceRegion *)
-
-//===----------------------------------------------------------------------===//
-// MemRegion Construction.
-//===----------------------------------------------------------------------===//
-
-[[maybe_unused]] static bool isAReferenceTypedValueRegion(const MemRegion *R) {
-  const auto *TyReg = llvm::dyn_cast<TypedValueRegion>(R);
-  return TyReg && TyReg->getValueType()->isReferenceType();
-}
-
-template <typename RegionTy, typename SuperTy, typename Arg1Ty>
-RegionTy* MemRegionManager::getSubRegion(const Arg1Ty arg1,
-                                         const SuperTy *superRegion) {
-  llvm::FoldingSetNodeID ID;
-  RegionTy::ProfileRegion(ID, arg1, superRegion);
-  void *InsertPos;
-  auto *R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID, InsertPos));
-
-  if (!R) {
-    R = new (A) RegionTy(arg1, superRegion);
-    Regions.InsertNode(R, InsertPos);
-    assert(!isAReferenceTypedValueRegion(superRegion));
-  }
-
-  return R;
-}
-
-template <typename RegionTy, typename SuperTy, typename Arg1Ty, typename Arg2Ty>
-RegionTy* MemRegionManager::getSubRegion(const Arg1Ty arg1, const Arg2Ty arg2,
-                                         const SuperTy *superRegion) {
-  llvm::FoldingSetNodeID ID;
-  RegionTy::ProfileRegion(ID, arg1, arg2, superRegion);
-  void *InsertPos;
-  auto *R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID, InsertPos));
-
-  if (!R) {
-    R = new (A) RegionTy(arg1, arg2, superRegion);
-    Regions.InsertNode(R, InsertPos);
-    assert(!isAReferenceTypedValueRegion(superRegion));
-  }
-
-  return R;
-}
-
-template <typename RegionTy, typename SuperTy,
-          typename Arg1Ty, typename Arg2Ty, typename Arg3Ty>
-RegionTy* MemRegionManager::getSubRegion(const Arg1Ty arg1, const Arg2Ty arg2,
-                                         const Arg3Ty arg3,
-                                         const SuperTy *superRegion) {
-  llvm::FoldingSetNodeID ID;
-  RegionTy::ProfileRegion(ID, arg1, arg2, arg3, superRegion);
-  void *InsertPos;
-  auto *R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID, InsertPos));
-
-  if (!R) {
-    R = new (A) RegionTy(arg1, arg2, arg3, superRegion);
-    Regions.InsertNode(R, InsertPos);
-    assert(!isAReferenceTypedValueRegion(superRegion));
-  }
-
-  return R;
-}
-
-//===----------------------------------------------------------------------===//
-// Object destruction.
-//===----------------------------------------------------------------------===//
-
-MemRegion::~MemRegion() = default;
-
-// All regions and their data are BumpPtrAllocated.  No need to call their
-// destructors.
-MemRegionManager::~MemRegionManager() = default;
-
-//===----------------------------------------------------------------------===//
-// Basic methods.
-//===----------------------------------------------------------------------===//
-
-bool SubRegion::isSubRegionOf(const MemRegion* R) const {
-  const MemRegion* r = this;
-  do {
-    if (r == R)
-      return true;
-    if (const auto *sr = dyn_cast<SubRegion>(r))
-      r = sr->getSuperRegion();
-    else
-      break;
-  } while (r != nullptr);
-  return false;
-}
-
-MemRegionManager &SubRegion::getMemRegionManager() const {
-  const SubRegion* r = this;
-  do {
-    const MemRegion *superRegion = r->getSuperRegion();
-    if (const auto *sr = dyn_cast<SubRegion>(superRegion)) {
-      r = sr;
-      continue;
-    }
-    return superRegion->getMemRegionManager();
-  } while (true);
-}
-
-const StackFrameContext *VarRegion::getStackFrame() const {
-  const auto *SSR = dyn_cast<StackSpaceRegion>(getRawMemorySpace());
-  return SSR ? SSR->getStackFrame() : nullptr;
-}
-
-const StackFrameContext *
-CXXLifetimeExtendedObjectRegion::getStackFrame() const {
-  const auto *SSR = dyn_cast<StackSpaceRegion>(getRawMemorySpace());
-  return SSR ? SSR->getStackFrame() : nullptr;
-}
-
-const StackFrameContext *CXXTempObjectRegion::getStackFrame() const {
-  assert(isa<StackSpaceRegion>(getRawMemorySpace()) &&
-         "A temporary object can only be allocated on the stack");
-  return cast<StackSpaceRegion>(getRawMemorySpace())->getStackFrame();
-}
-
-ObjCIvarRegion::ObjCIvarRegion(const ObjCIvarDecl *ivd, const SubRegion *sReg)
-    : DeclRegion(sReg, ObjCIvarRegionKind), IVD(ivd) {
-  assert(IVD);
-}
-
-const ObjCIvarDecl *ObjCIvarRegion::getDecl() const { return IVD; }
-
-QualType ObjCIvarRegion::getValueType() const {
-  return getDecl()->getType();
-}
-
-QualType CXXBaseObjectRegion::getValueType() const {
-  return QualType(getDecl()->getTypeForDecl(), 0);
-}
-
-QualType CXXDerivedObjectRegion::getValueType() const {
-  return QualType(getDecl()->getTypeForDecl(), 0);
-}
-
-QualType ParamVarRegion::getValueType() const {
-  assert(getDecl() &&
-         "`ParamVarRegion` support functions without `Decl` not implemented"
-         " yet.");
-  return getDecl()->getType();
-}
-
-const ParmVarDecl *ParamVarRegion::getDecl() const {
-  const Decl *D = getStackFrame()->getDecl();
-
-  if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
-    assert(Index < FD->param_size());
-    return FD->parameters()[Index];
-  } else if (const auto *BD = dyn_cast<BlockDecl>(D)) {
-    assert(Index < BD->param_size());
-    return BD->parameters()[Index];
-  } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
-    assert(Index < MD->param_size());
-    return MD->parameters()[Index];
-  } else if (const auto *CD = dyn_cast<CXXConstructorDecl>(D)) {
-    assert(Index < CD->param_size());
-    return CD->parameters()[Index];
-  } else {
-    llvm_unreachable("Unexpected Decl kind!");
-  }
-}
-
-//===----------------------------------------------------------------------===//
-// FoldingSet profiling.
-//===----------------------------------------------------------------------===//
-
-void MemSpaceRegion::Profile(llvm::FoldingSetNodeID &ID) const {
-  ID.AddInteger(static_cast<unsigned>(getKind()));
-}
-
-void StackSpaceRegion::Profile(llvm::FoldingSetNodeID &ID) const {
-  ID.AddInteger(static_cast<unsigned>(getKind()));
-  ID.AddPointer(getStackFrame());
-}
-
-void StaticGlobalSpaceRegion::Profile(llvm::FoldingSetNodeID &ID) const {
-  ID.AddInteger(static_cast<unsigned>(getKind()));
-  ID.AddPointer(getCodeRegion());
-}
-
-void StringRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
-                                 const StringLiteral *Str,
-                                 const MemRegion *superRegion) {
-  ID.AddInteger(static_cast<unsigned>(StringRegionKind));
-  ID.AddPointer(Str);
-  ID.AddPointer(superRegion);
-}
-
-void ObjCStringRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
-                                     const ObjCStringLiteral *Str,
-                                     const MemRegion *superRegion) {
-  ID.AddInteger(static_cast<unsigned>(ObjCStringRegionKind));
-  ID.AddPointer(Str);
-  ID.AddPointer(superRegion);
-}
-
-void AllocaRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
-                                 const Expr *Ex, unsigned cnt,
-                                 const MemRegion *superRegion) {
-  ID.AddInteger(static_cast<unsigned>(AllocaRegionKind));
-  ID.AddPointer(Ex);
-  ID.AddInteger(cnt);
-  ID.AddPointer(superRegion);
-}
-
-void AllocaRegion::Profile(llvm::FoldingSetNodeID& ID) const {
-  ProfileRegion(ID, Ex, Cnt, superRegion);
-}
-
-void CompoundLiteralRegion::Profile(llvm::FoldingSetNodeID& ID) const {
-  CompoundLiteralRegion::ProfileRegion(ID, CL, superRegion);
-}
-
-void CompoundLiteralRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
-                                          const CompoundLiteralExpr *CL,
-                                          const MemRegion* superRegion) {
-  ID.AddInteger(static_cast<unsigned>(CompoundLiteralRegionKind));
-  ID.AddPointer(CL);
-  ID.AddPointer(superRegion);
-}
-
-void CXXThisRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
-                                  const PointerType *PT,
-                                  const MemRegion *sRegion) {
-  ID.AddInteger(static_cast<unsigned>(CXXThisRegionKind));
-  ID.AddPointer(PT);
-  ID.AddPointer(sRegion);
-}
-
-void CXXThisRegion::Profile(llvm::FoldingSetNodeID &ID) const {
-  CXXThisRegion::ProfileRegion(ID, ThisPointerTy, superRegion);
-}
-
-void FieldRegion::Profile(llvm::FoldingSetNodeID &ID) const {
-  ProfileRegion(ID, getDecl(), superRegion);
-}
-
-void ObjCIvarRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
-                                   const ObjCIvarDecl *ivd,
-                                   const MemRegion* superRegion) {
-  ID.AddInteger(static_cast<unsigned>(ObjCIvarRegionKind));
-  ID.AddPointer(ivd);
-  ID.AddPointer(superRegion);
-}
-
-void ObjCIvarRegion::Profile(llvm::FoldingSetNodeID &ID) const {
-  ProfileRegion(ID, getDecl(), superRegion);
-}
-
-void NonParamVarRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
-                                      const VarDecl *VD,
-                                      const MemRegion *superRegion) {
-  ID.AddInteger(static_cast<unsigned>(NonParamVarRegionKind));
-  ID.AddPointer(VD);
-  ID.AddPointer(superRegion);
-}
-
-void NonParamVarRegion::Profile(llvm::FoldingSetNodeID &ID) const {
-  ProfileRegion(ID, getDecl(), superRegion);
-}
-
-void ParamVarRegion::ProfileRegion(llvm::FoldingSetNodeID &ID, const Expr *OE,
-                                   unsigned Idx, const MemRegion *SReg) {
-  ID.AddInteger(static_cast<unsigned>(ParamVarRegionKind));
-  ID.AddPointer(OE);
-  ID.AddInteger(Idx);
-  ID.AddPointer(SReg);
-}
-
-void ParamVarRegion::Profile(llvm::FoldingSetNodeID &ID) const {
-  ProfileRegion(ID, getOriginExpr(), getIndex(), superRegion);
-}
-
-void SymbolicRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, SymbolRef sym,
-                                   const MemRegion *sreg) {
-  ID.AddInteger(static_cast<unsigned>(MemRegion::SymbolicRegionKind));
-  ID.Add(sym);
-  ID.AddPointer(sreg);
-}
-
-void SymbolicRegion::Profile(llvm::FoldingSetNodeID& ID) const {
-  SymbolicRegion::ProfileRegion(ID, sym, getSuperRegion());
-}
-
-void ElementRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
-                                  QualType ElementType, SVal Idx,
-                                  const MemRegion* superRegion) {
-  ID.AddInteger(MemRegion::ElementRegionKind);
-  ID.Add(ElementType);
-  ID.AddPointer(superRegion);
-  Idx.Profile(ID);
-}
-
-void ElementRegion::Profile(llvm::FoldingSetNodeID& ID) const {
-  ElementRegion::ProfileRegion(ID, ElementType, Index, superRegion);
-}
-
-void FunctionCodeRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
-                                       const NamedDecl *FD,
-                                       const MemRegion*) {
-  ID.AddInteger(MemRegion::FunctionCodeRegionKind);
-  ID.AddPointer(FD);
-}
-
-void FunctionCodeRegion::Profile(llvm::FoldingSetNodeID& ID) const {
-  FunctionCodeRegion::ProfileRegion(ID, FD, superRegion);
-}
-
-void BlockCodeRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
-                                    const BlockDecl *BD, CanQualType,
-                                    const AnalysisDeclContext *AC,
-                                    const MemRegion*) {
-  ID.AddInteger(MemRegion::BlockCodeRegionKind);
-  ID.AddPointer(BD);
-}
-
-void BlockCodeRegion::Profile(llvm::FoldingSetNodeID& ID) const {
-  BlockCodeRegion::ProfileRegion(ID, BD, locTy, AC, superRegion);
-}
-
-void BlockDataRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
-                                    const BlockCodeRegion *BC,
-                                    const LocationContext *LC,
-                                    unsigned BlkCount,
-                                    const MemRegion *sReg) {
-  ID.AddInteger(MemRegion::BlockDataRegionKind);
-  ID.AddPointer(BC);
-  ID.AddPointer(LC);
-  ID.AddInteger(BlkCount);
-  ID.AddPointer(sReg);
-}
-
-void BlockDataRegion::Profile(llvm::FoldingSetNodeID& ID) const {
-  BlockDataRegion::ProfileRegion(ID, BC, LC, BlockCount, getSuperRegion());
-}
-
-void CXXTempObjectRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
-                                        Expr const *Ex,
-                                        const MemRegion *sReg) {
-  ID.AddPointer(Ex);
-  ID.AddPointer(sReg);
-}
-
-void CXXTempObjectRegion::Profile(llvm::FoldingSetNodeID &ID) const {
-  ProfileRegion(ID, Ex, getSuperRegion());
-}
-
-void CXXLifetimeExtendedObjectRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
-                                                    const Expr *E,
-                                                    const ValueDecl *D,
-                                                    const MemRegion *sReg) {
-  ID.AddPointer(E);
-  ID.AddPointer(D);
-  ID.AddPointer(sReg);
-}
-
-void CXXLifetimeExtendedObjectRegion::Profile(
-    llvm::FoldingSetNodeID &ID) const {
-  ProfileRegion(ID, Ex, ExD, getSuperRegion());
-}
-
-void CXXBaseObjectRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
-                                        const CXXRecordDecl *RD,
-                                        bool IsVirtual,
-                                        const MemRegion *SReg) {
-  ID.AddPointer(RD);
-  ID.AddBoolean(IsVirtual);
-  ID.AddPointer(SReg);
-}
-
-void CXXBaseObjectRegion::Profile(llvm::FoldingSetNodeID &ID) const {
-  ProfileRegion(ID, getDecl(), isVirtual(), superRegion);
-}
-
-void CXXDerivedObjectRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
-                                           const CXXRecordDecl *RD,
-                                           const MemRegion *SReg) {
-  ID.AddPointer(RD);
-  ID.AddPointer(SReg);
-}
-
-void CXXDerivedObjectRegion::Profile(llvm::FoldingSetNodeID &ID) const {
-  ProfileRegion(ID, getDecl(), superRegion);
-}
-
-//===----------------------------------------------------------------------===//
-// Region anchors.
-//===----------------------------------------------------------------------===//
-
-void GlobalsSpaceRegion::anchor() {}
-
-void NonStaticGlobalSpaceRegion::anchor() {}
-
-void StackSpaceRegion::anchor() {}
-
-void TypedRegion::anchor() {}
-
-void TypedValueRegion::anchor() {}
-
-void CodeTextRegion::anchor() {}
-
-void SubRegion::anchor() {}
-
-//===----------------------------------------------------------------------===//
-// Region pretty-printing.
-//===----------------------------------------------------------------------===//
-
-LLVM_DUMP_METHOD void MemRegion::dump() const {
-  dumpToStream(llvm::errs());
-}
-
-std::string MemRegion::getString() const {
-  std::string s;
-  llvm::raw_string_ostream os(s);
-  dumpToStream(os);
-  return s;
-}
-
-void MemRegion::dumpToStream(raw_ostream &os) const {
-  os << "<Unknown Region>";
-}
-
-void AllocaRegion::dumpToStream(raw_ostream &os) const {
-  os << "alloca{S" << Ex->getID(getContext()) << ',' << Cnt << '}';
-}
-
-void FunctionCodeRegion::dumpToStream(raw_ostream &os) const {
-  os << "code{" << getDecl()->getDeclName().getAsString() << '}';
-}
-
-void BlockCodeRegion::dumpToStream(raw_ostream &os) const {
-  os << "block_code{" << static_cast<const void *>(this) << '}';
-}
-
-void BlockDataRegion::dumpToStream(raw_ostream &os) const {
-  os << "block_data{" << BC;
-  os << "; ";
-  for (auto Var : referenced_vars())
-    os << "(" << Var.getCapturedRegion() << "<-" << Var.getOriginalRegion()
-       << ") ";
-  os << '}';
-}
-
-void CompoundLiteralRegion::dumpToStream(raw_ostream &os) const {
-  // FIXME: More elaborate pretty-printing.
-  os << "{ S" << CL->getID(getContext()) <<  " }";
-}
-
-void CXXTempObjectRegion::dumpToStream(raw_ostream &os) const {
-  os << "temp_object{" << getValueType() << ", "
-     << "S" << Ex->getID(getContext()) << '}';
-}
-
-void CXXLifetimeExtendedObjectRegion::dumpToStream(raw_ostream &os) const {
-  os << "lifetime_extended_object{" << getValueType() << ", ";
-  if (const IdentifierInfo *ID = ExD->getIdentifier())
-    os << ID->getName();
-  else
-    os << "D" << ExD->getID();
-  os << ", "
-     << "S" << Ex->getID(getContext()) << '}';
-}
-
-void CXXBaseObjectRegion::dumpToStream(raw_ostream &os) const {
-  os << "Base{" << superRegion << ',' << getDecl()->getName() << '}';
-}
-
-void CXXDerivedObjectRegion::dumpToStream(raw_ostream &os) const {
-  os << "Derived{" << superRegion << ',' << getDecl()->getName() << '}';
-}
-
-void CXXThisRegion::dumpToStream(raw_ostream &os) const {
-  os << "this";
-}
-
-void ElementRegion::dumpToStream(raw_ostream &os) const {
-  os << "Element{" << superRegion << ',' << Index << ',' << getElementType()
-     << '}';
-}
-
-void FieldRegion::dumpToStream(raw_ostream &os) const {
-  os << superRegion << "." << *getDecl();
-}
-
-void ObjCIvarRegion::dumpToStream(raw_ostream &os) const {
-  os << "Ivar{" << superRegion << ',' << *getDecl() << '}';
-}
-
-void StringRegion::dumpToStream(raw_ostream &os) const {
-  assert(Str != nullptr && "Expecting non-null StringLiteral");
-  Str->printPretty(os, nullptr, PrintingPolicy(getContext().getLangOpts()));
-}
-
-void ObjCStringRegion::dumpToStream(raw_ostream &os) const {
-  assert(Str != nullptr && "Expecting non-null ObjCStringLiteral");
-  Str->printPretty(os, nullptr, PrintingPolicy(getContext().getLangOpts()));
-}
-
-void SymbolicRegion::dumpToStream(raw_ostream &os) const {
-  if (isa<HeapSpaceRegion>(getSuperRegion()))
-    os << "Heap";
-  os << "SymRegion{" << sym << '}';
-}
-
-void NonParamVarRegion::dumpToStream(raw_ostream &os) const {
-  if (const IdentifierInfo *ID = VD->getIdentifier())
-    os << ID->getName();
-  else
-    os << "NonParamVarRegion{D" << VD->getID() << '}';
-}
-
-LLVM_DUMP_METHOD void RegionRawOffset::dump() const {
-  dumpToStream(llvm::errs());
-}
-
-void RegionRawOffset::dumpToStream(raw_ostream &os) const {
-  os << "raw_offset{" << getRegion() << ',' << getOffset().getQuantity() << '}';
-}
-
-void CodeSpaceRegion::dumpToStream(raw_ostream &os) const {
-  os << "CodeSpaceRegion";
-}
-
-void StaticGlobalSpaceRegion::dumpToStream(raw_ostream &os) const {
-  os << "StaticGlobalsMemSpace{" << CR << '}';
-}
-
-void GlobalInternalSpaceRegion::dumpToStream(raw_ostream &os) const {
-  os << "GlobalInternalSpaceRegion";
-}
-
-void GlobalSystemSpaceRegion::dumpToStream(raw_ostream &os) const {
-  os << "GlobalSystemSpaceRegion";
-}
-
-void GlobalImmutableSpaceRegion::dumpToStream(raw_ostream &os) const {
-  os << "GlobalImmutableSpaceRegion";
-}
-
-void HeapSpaceRegion::dumpToStream(raw_ostream &os) const {
-  os << "HeapSpaceRegion";
-}
-
-void UnknownSpaceRegion::dumpToStream(raw_ostream &os) const {
-  os << "UnknownSpaceRegion";
-}
-
-void StackArgumentsSpaceRegion::dumpToStream(raw_ostream &os) const {
-  os << "StackArgumentsSpaceRegion";
-}
-
-void StackLocalsSpaceRegion::dumpToStream(raw_ostream &os) const {
-  os << "StackLocalsSpaceRegion";
-}
-
-void ParamVarRegion::dumpToStream(raw_ostream &os) const {
-  const ParmVarDecl *PVD = getDecl();
-  assert(PVD &&
-         "`ParamVarRegion` support functions without `Decl` not implemented"
-         " yet.");
-  if (const IdentifierInfo *ID = PVD->getIdentifier()) {
-    os << ID->getName();
-  } else {
-    os << "ParamVarRegion{P" << PVD->getID() << '}';
-  }
-}
-
-bool MemRegion::canPrintPretty() const {
-  return canPrintPrettyAsExpr();
-}
-
-bool MemRegion::canPrintPrettyAsExpr() const {
-  return false;
-}
-
-StringRef MemRegion::getKindStr() const {
-  switch (getKind()) {
-#define REGION(Id, Parent)                                                     \
-  case Id##Kind:                                                               \
-    return #Id;
-#include "clang/StaticAnalyzer/Core/PathSensitive/Regions.def"
-#undef REGION
-  }
-  llvm_unreachable("Unkown kind!");
-}
-
-void MemRegion::printPretty(raw_ostream &os) const {
-  assert(canPrintPretty() && "This region cannot be printed pretty.");
-  os << "'";
-  printPrettyAsExpr(os);
-  os << "'";
-}
-
-void MemRegion::printPrettyAsExpr(raw_ostream &) const {
-  llvm_unreachable("This region cannot be printed pretty.");
-}
-
-bool NonParamVarRegion::canPrintPrettyAsExpr() const { return true; }
-
-void NonParamVarRegion::printPrettyAsExpr(raw_ostream &os) const {
-  os << getDecl()->getName();
-}
-
-bool ParamVarRegion::canPrintPrettyAsExpr() const { return true; }
-
-void ParamVarRegion::printPrettyAsExpr(raw_ostream &os) const {
-  assert(getDecl() &&
-         "`ParamVarRegion` support functions without `Decl` not implemented"
-         " yet.");
-  os << getDecl()->getName();
-}
-
-bool ObjCIvarRegion::canPrintPrettyAsExpr() const {
-  return true;
-}
-
-void ObjCIvarRegion::printPrettyAsExpr(raw_ostream &os) const {
-  os << getDecl()->getName();
-}
-
-bool FieldRegion::canPrintPretty() const {
-  return true;
-}
-
-bool FieldRegion::canPrintPrettyAsExpr() const {
-  return superRegion->canPrintPrettyAsExpr();
-}
-
-void FieldRegion::printPrettyAsExpr(raw_ostream &os) const {
-  assert(canPrintPrettyAsExpr());
-  superRegion->printPrettyAsExpr(os);
-  os << "." << getDecl()->getName();
-}
-
-void FieldRegion::printPretty(raw_ostream &os) const {
-  if (canPrintPrettyAsExpr()) {
-    os << "\'";
-    printPrettyAsExpr(os);
-    os << "'";
-  } else {
-    os << "field " << "\'" << getDecl()->getName() << "'";
-  }
-}
-
-bool CXXBaseObjectRegion::canPrintPrettyAsExpr() const {
-  return superRegion->canPrintPrettyAsExpr();
-}
-
-void CXXBaseObjectRegion::printPrettyAsExpr(raw_ostream &os) const {
-  superRegion->printPrettyAsExpr(os);
-}
-
-bool CXXDerivedObjectRegion::canPrintPrettyAsExpr() const {
-  return superRegion->canPrintPrettyAsExpr();
-}
-
-void CXXDerivedObjectRegion::printPrettyAsExpr(raw_ostream &os) const {
-  superRegion->printPrettyAsExpr(os);
-}
-
-std::string MemRegion::getDescriptiveName(bool UseQuotes) const {
-  std::string VariableName;
-  std::string ArrayIndices;
-  const MemRegion *R = this;
-  SmallString<50> buf;
-  llvm::raw_svector_ostream os(buf);
-
-  // Enclose subject with single quotes if needed.
-  auto QuoteIfNeeded = [UseQuotes](const Twine &Subject) -> std::string {
-    if (UseQuotes)
-      return ("'" + Subject + "'").str();
-    return Subject.str();
-  };
-
-  // Obtain array indices to add them to the variable name.
-  const ElementRegion *ER = nullptr;
-  while ((ER = R->getAs<ElementRegion>())) {
-    // Index is a ConcreteInt.
-    if (auto CI = ER->getIndex().getAs<nonloc::ConcreteInt>()) {
-      llvm::SmallString<2> Idx;
-      CI->getValue()->toString(Idx);
-      ArrayIndices = (llvm::Twine("[") + Idx.str() + "]" + ArrayIndices).str();
-    }
-    // Index is symbolic, but may have a descriptive name.
-    else {
-      auto SI = ER->getIndex().getAs<nonloc::SymbolVal>();
-      if (!SI)
-        return "";
-
-      const MemRegion *OR = SI->getAsSymbol()->getOriginRegion();
-      if (!OR)
-        return "";
-
-      std::string Idx = OR->getDescriptiveName(false);
-      if (Idx.empty())
-        return "";
-
-      ArrayIndices = (llvm::Twine("[") + Idx + "]" + ArrayIndices).str();
-    }
-    R = ER->getSuperRegion();
-  }
-
-  // Get variable name.
-  if (R) {
-    // MemRegion can be pretty printed.
-    if (R->canPrintPrettyAsExpr()) {
-      R->printPrettyAsExpr(os);
-      return QuoteIfNeeded(llvm::Twine(os.str()) + ArrayIndices);
-    }
-
-    // FieldRegion may have ElementRegion as SuperRegion.
-    if (const auto *FR = R->getAs<FieldRegion>()) {
-      std::string Super = FR->getSuperRegion()->getDescriptiveName(false);
-      if (Super.empty())
-        return "";
-      return QuoteIfNeeded(Super + "." + FR->getDecl()->getName());
-    }
-  }
-
-  return VariableName;
-}
-
-SourceRange MemRegion::sourceRange() const {
-  // Check for more specific regions first.
-  if (auto *FR = dyn_cast<FieldRegion>(this)) {
-    return FR->getDecl()->getSourceRange();
-  }
-
-  if (auto *VR = dyn_cast<VarRegion>(this->getBaseRegion())) {
-    return VR->getDecl()->getSourceRange();
-  }
-
-  // Return invalid source range (can be checked by client).
-  return {};
-}
-
-//===----------------------------------------------------------------------===//
-// MemRegionManager methods.
-//===----------------------------------------------------------------------===//
-
-DefinedOrUnknownSVal MemRegionManager::getStaticSize(const MemRegion *MR,
-                                                     SValBuilder &SVB) const {
-  const auto *SR = cast<SubRegion>(MR);
-  SymbolManager &SymMgr = SVB.getSymbolManager();
-
-  switch (SR->getKind()) {
-  case MemRegion::AllocaRegionKind:
-  case MemRegion::SymbolicRegionKind:
-    return nonloc::SymbolVal(SymMgr.getExtentSymbol(SR));
-  case MemRegion::StringRegionKind:
-    return SVB.makeIntVal(
-        cast<StringRegion>(SR)->getStringLiteral()->getByteLength() + 1,
-        SVB.getArrayIndexType());
-  case MemRegion::CompoundLiteralRegionKind:
-  case MemRegion::CXXBaseObjectRegionKind:
-  case MemRegion::CXXDerivedObjectRegionKind:
-  case MemRegion::CXXTempObjectRegionKind:
-  case MemRegion::CXXLifetimeExtendedObjectRegionKind:
-  case MemRegion::CXXThisRegionKind:
-  case MemRegion::ObjCIvarRegionKind:
-  case MemRegion::NonParamVarRegionKind:
-  case MemRegion::ParamVarRegionKind:
-  case MemRegion::ElementRegionKind:
-  case MemRegion::ObjCStringRegionKind: {
-    QualType Ty = cast<TypedValueRegion>(SR)->getDesugaredValueType(Ctx);
-    if (isa<VariableArrayType>(Ty))
-      return nonloc::SymbolVal(SymMgr.getExtentSymbol(SR));
-
-    if (Ty->isIncompleteType())
-      return UnknownVal();
-
-    return getElementExtent(Ty, SVB);
-  }
-  case MemRegion::FieldRegionKind: {
-    // Force callers to deal with bitfields explicitly.
-    if (cast<FieldRegion>(SR)->getDecl()->isBitField())
-      return UnknownVal();
-
-    QualType Ty = cast<TypedValueRegion>(SR)->getDesugaredValueType(Ctx);
-    const DefinedOrUnknownSVal Size = getElementExtent(Ty, SVB);
-
-    // We currently don't model flexible array members (FAMs), which are:
-    //  - int array[]; of IncompleteArrayType
-    //  - int array[0]; of ConstantArrayType with size 0
-    //  - int array[1]; of ConstantArrayType with size 1
-    // https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
-    const auto isFlexibleArrayMemberCandidate =
-        [this](const ArrayType *AT) -> bool {
-      if (!AT)
-        return false;
-
-      auto IsIncompleteArray = [](const ArrayType *AT) {
-        return isa<IncompleteArrayType>(AT);
-      };
-      auto IsArrayOfZero = [](const ArrayType *AT) {
-        const auto *CAT = dyn_cast<ConstantArrayType>(AT);
-        return CAT && CAT->isZeroSize();
-      };
-      auto IsArrayOfOne = [](const ArrayType *AT) {
-        const auto *CAT = dyn_cast<ConstantArrayType>(AT);
-        return CAT && CAT->getSize() == 1;
-      };
-
-      using FAMKind = LangOptions::StrictFlexArraysLevelKind;
-      const FAMKind StrictFlexArraysLevel =
-          Ctx.getLangOpts().getStrictFlexArraysLevel();
-
-      // "Default": Any trailing array member is a FAM.
-      // Since we cannot tell at this point if this array is a trailing member
-      // or not, let's just do the same as for "OneZeroOrIncomplete".
-      if (StrictFlexArraysLevel == FAMKind::Default)
-        return IsArrayOfOne(AT) || IsArrayOfZero(AT) || IsIncompleteArray(AT);
-
-      if (StrictFlexArraysLevel == FAMKind::OneZeroOrIncomplete)
-        return IsArrayOfOne(AT) || IsArrayOfZero(AT) || IsIncompleteArray(AT);
-
-      if (StrictFlexArraysLevel == FAMKind::ZeroOrIncomplete)
-        return IsArrayOfZero(AT) || IsIncompleteArray(AT);
-
-      assert(StrictFlexArraysLevel == FAMKind::IncompleteOnly);
-      return IsIncompleteArray(AT);
-    };
-
-    if (isFlexibleArrayMemberCandidate(Ctx.getAsArrayType(Ty)))
-      return UnknownVal();
-
-    return Size;
-  }
-    // FIXME: The following are being used in 'SimpleSValBuilder' and in
-    // 'ArrayBoundChecker::checkLocation' because there is no symbol to
-    // represent the regions more appropriately.
-  case MemRegion::BlockDataRegionKind:
-  case MemRegion::BlockCodeRegionKind:
-  case MemRegion::FunctionCodeRegionKind:
-    return nonloc::SymbolVal(SymMgr.getExtentSymbol(SR));
-  default:
-    llvm_unreachable("Unhandled region");
-  }
-}
-
-template <typename REG>
-const REG *MemRegionManager::LazyAllocate(REG*& region) {
-  if (!region) {
-    region = new (A) REG(*this);
-  }
-
-  return region;
-}
-
-template <typename REG, typename ARG>
-const REG *MemRegionManager::LazyAllocate(REG*& region, ARG a) {
-  if (!region) {
-    region = new (A) REG(this, a);
-  }
-
-  return region;
-}
-
-const StackLocalsSpaceRegion*
-MemRegionManager::getStackLocalsRegion(const StackFrameContext *STC) {
-  assert(STC);
-  StackLocalsSpaceRegion *&R = StackLocalsSpaceRegions[STC];
-
-  if (R)
-    return R;
-
-  R = new (A) StackLocalsSpaceRegion(*this, STC);
-  return R;
-}
-
-const StackArgumentsSpaceRegion *
-MemRegionManager::getStackArgumentsRegion(const StackFrameContext *STC) {
-  assert(STC);
-  StackArgumentsSpaceRegion *&R = StackArgumentsSpaceRegions[STC];
-
-  if (R)
-    return R;
-
-  R = new (A) StackArgumentsSpaceRegion(*this, STC);
-  return R;
-}
-
-const GlobalsSpaceRegion
-*MemRegionManager::getGlobalsRegion(MemRegion::Kind K,
-                                    const CodeTextRegion *CR) {
-  if (!CR) {
-    if (K == MemRegion::GlobalSystemSpaceRegionKind)
-      return LazyAllocate(SystemGlobals);
-    if (K == MemRegion::GlobalImmutableSpaceRegionKind)
-      return LazyAllocate(ImmutableGlobals);
-    assert(K == MemRegion::GlobalInternalSpaceRegionKind);
-    return LazyAllocate(InternalGlobals);
-  }
-
-  assert(K == MemRegion::StaticGlobalSpaceRegionKind);
-  StaticGlobalSpaceRegion *&R = StaticsGlobalSpaceRegions[CR];
-  if (R)
-    return R;
-
-  R = new (A) StaticGlobalSpaceRegion(*this, CR);
-  return R;
-}
-
-const HeapSpaceRegion *MemRegionManager::getHeapRegion() {
-  return LazyAllocate(heap);
-}
-
-const UnknownSpaceRegion *MemRegionManager::getUnknownRegion() {
-  return LazyAllocate(unknown);
-}
-
-const CodeSpaceRegion *MemRegionManager::getCodeRegion() {
-  return LazyAllocate(code);
-}
-
-//===----------------------------------------------------------------------===//
-// Constructing regions.
-//===----------------------------------------------------------------------===//
-
-const StringRegion *MemRegionManager::getStringRegion(const StringLiteral *Str){
-  return getSubRegion<StringRegion>(
-      Str, cast<GlobalInternalSpaceRegion>(getGlobalsRegion()));
-}
-
-const ObjCStringRegion *
-MemRegionManager::getObjCStringRegion(const ObjCStringLiteral *Str){
-  return getSubRegion<ObjCStringRegion>(
-      Str, cast<GlobalInternalSpaceRegion>(getGlobalsRegion()));
-}
-
-/// Look through a chain of LocationContexts to either find the
-/// StackFrameContext that matches a DeclContext, or find a VarRegion
-/// for a variable captured by a block.
-static llvm::PointerUnion<const StackFrameContext *, const VarRegion *>
-getStackOrCaptureRegionForDeclContext(const LocationContext *LC,
-                                      const DeclContext *DC,
-                                      const VarDecl *VD) {
-  while (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());
-        }
-      }
-    }
-
-    LC = LC->getParent();
-  }
-  return (const StackFrameContext *)nullptr;
-}
-
-const VarRegion *MemRegionManager::getVarRegion(const VarDecl *D,
-                                                const LocationContext *LC) {
-  const auto *PVD = dyn_cast<ParmVarDecl>(D);
-  if (PVD) {
-    unsigned Index = PVD->getFunctionScopeIndex();
-    const StackFrameContext *SFC = LC->getStackFrame();
-    const Stmt *CallSite = SFC->getCallSite();
-    if (CallSite) {
-      const Decl *D = SFC->getDecl();
-      if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
-        if (Index < FD->param_size() && FD->parameters()[Index] == PVD)
-          return getSubRegion<ParamVarRegion>(cast<Expr>(CallSite), Index,
-                                              getStackArgumentsRegion(SFC));
-      } else if (const auto *BD = dyn_cast<BlockDecl>(D)) {
-        if (Index < BD->param_size() && BD->parameters()[Index] == PVD)
-          return getSubRegion<ParamVarRegion>(cast<Expr>(CallSite), Index,
-                                              getStackArgumentsRegion(SFC));
-      } else {
-        return getSubRegion<ParamVarRegion>(cast<Expr>(CallSite), Index,
-                                            getStackArgumentsRegion(SFC));
-      }
-    }
-  }
-
-  D = D->getCanonicalDecl();
-  const MemRegion *sReg = nullptr;
-
-  if (D->hasGlobalStorage() && !D->isStaticLocal()) {
-    QualType Ty = D->getType();
-    assert(!Ty.isNull());
-    if (Ty.isConstQualified()) {
-      sReg = getGlobalsRegion(MemRegion::GlobalImmutableSpaceRegionKind);
-    } else if (Ctx.getSourceManager().isInSystemHeader(D->getLocation())) {
-      sReg = getGlobalsRegion(MemRegion::GlobalSystemSpaceRegionKind);
-    } else {
-      sReg = getGlobalsRegion(MemRegion::GlobalInternalSpaceRegionKind);
-    }
-
-  // Finally handle static locals.
-  } else {
-    // FIXME: Once we implement scope handling, we will need to properly lookup
-    // 'D' to the proper LocationContext.
-    const DeclContext *DC = D->getDeclContext();
-    llvm::PointerUnion<const StackFrameContext *, const VarRegion *> V =
-      getStackOrCaptureRegionForDeclContext(LC, DC, D);
-
-    if (const auto *VR = dyn_cast_if_present<const VarRegion *>(V))
-      return VR;
-
-    const auto *STC = cast<const StackFrameContext *>(V);
-
-    if (!STC) {
-      // FIXME: Assign a more sensible memory space to static locals
-      // we see from within blocks that we analyze as top-level declarations.
-      sReg = getUnknownRegion();
-    } else {
-      if (D->hasLocalStorage()) {
-        sReg =
-            isa<ParmVarDecl, ImplicitParamDecl>(D)
-                ? static_cast<const MemRegion *>(getStackArgumentsRegion(STC))
-                : static_cast<const MemRegion *>(getStackLocalsRegion(STC));
-      }
-      else {
-        assert(D->isStaticLocal());
-        const Decl *STCD = STC->getDecl();
-        if (isa<FunctionDecl, ObjCMethodDecl>(STCD))
-          sReg = getGlobalsRegion(MemRegion::StaticGlobalSpaceRegionKind,
-                                  getFunctionCodeRegion(cast<NamedDecl>(STCD)));
-        else if (const auto *BD = dyn_cast<BlockDecl>(STCD)) {
-          // FIXME: The fallback type here is totally bogus -- though it should
-          // never be queried, it will prevent uniquing with the real
-          // BlockCodeRegion. Ideally we'd fix the AST so that we always had a
-          // signature.
-          QualType T;
-          if (const TypeSourceInfo *TSI = BD->getSignatureAsWritten())
-            T = TSI->getType();
-          if (T.isNull())
-            T = getContext().VoidTy;
-          if (!T->getAs<FunctionType>()) {
-            FunctionProtoType::ExtProtoInfo Ext;
-            T = getContext().getFunctionType(T, {}, Ext);
-          }
-          T = getContext().getBlockPointerType(T);
-
-          const BlockCodeRegion *BTR =
-            getBlockCodeRegion(BD, Ctx.getCanonicalType(T),
-                               STC->getAnalysisDeclContext());
-          sReg = getGlobalsRegion(MemRegion::StaticGlobalSpaceRegionKind,
-                                  BTR);
-        }
-        else {
-          sReg = getGlobalsRegion();
-        }
-      }
-    }
-  }
-
-  return getNonParamVarRegion(D, sReg);
-}
-
-const NonParamVarRegion *
-MemRegionManager::getNonParamVarRegion(const VarDecl *D,
-                                       const MemRegion *superR) {
-  // Prefer the definition over the canonical decl as the canonical form.
-  D = D->getCanonicalDecl();
-  if (const VarDecl *Def = D->getDefinition())
-    D = Def;
-  return getSubRegion<NonParamVarRegion>(D, superR);
-}
-
-const ParamVarRegion *
-MemRegionManager::getParamVarRegion(const Expr *OriginExpr, unsigned Index,
-                                    const LocationContext *LC) {
-  const StackFrameContext *SFC = LC->getStackFrame();
-  assert(SFC);
-  return getSubRegion<ParamVarRegion>(OriginExpr, Index,
-                                      getStackArgumentsRegion(SFC));
-}
-
-const BlockDataRegion *
-MemRegionManager::getBlockDataRegion(const BlockCodeRegion *BC,
-                                     const LocationContext *LC,
-                                     unsigned blockCount) {
-  const MemSpaceRegion *sReg = nullptr;
-  const BlockDecl *BD = BC->getDecl();
-  if (!BD->hasCaptures()) {
-    // This handles 'static' blocks.
-    sReg = getGlobalsRegion(MemRegion::GlobalImmutableSpaceRegionKind);
-  }
-  else {
-    bool IsArcManagedBlock = Ctx.getLangOpts().ObjCAutoRefCount;
-
-    // ARC managed blocks can be initialized on stack or directly in heap
-    // depending on the implementations.  So we initialize them with
-    // UnknownRegion.
-    if (!IsArcManagedBlock && LC) {
-      // FIXME: Once we implement scope handling, we want the parent region
-      // to be the scope.
-      const StackFrameContext *STC = LC->getStackFrame();
-      assert(STC);
-      sReg = getStackLocalsRegion(STC);
-    } else {
-      // We allow 'LC' to be NULL for cases where want BlockDataRegions
-      // without context-sensitivity.
-      sReg = getUnknownRegion();
-    }
-  }
-
-  return getSubRegion<BlockDataRegion>(BC, LC, blockCount, sReg);
-}
-
-const CompoundLiteralRegion*
-MemRegionManager::getCompoundLiteralRegion(const CompoundLiteralExpr *CL,
-                                           const LocationContext *LC) {
-  const MemSpaceRegion *sReg = nullptr;
-
-  if (CL->isFileScope())
-    sReg = getGlobalsRegion();
-  else {
-    const StackFrameContext *STC = LC->getStackFrame();
-    assert(STC);
-    sReg = getStackLocalsRegion(STC);
-  }
-
-  return getSubRegion<CompoundLiteralRegion>(CL, sReg);
-}
-
-const ElementRegion *
-MemRegionManager::getElementRegion(QualType elementType, NonLoc Idx,
-                                   const SubRegion *superRegion,
-                                   const ASTContext &Ctx) {
-  QualType T = Ctx.getCanonicalType(elementType).getUnqualifiedType();
-
-  llvm::FoldingSetNodeID ID;
-  ElementRegion::ProfileRegion(ID, T, Idx, superRegion);
-
-  void *InsertPos;
-  MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos);
-  auto *R = cast_or_null<ElementRegion>(data);
-
-  if (!R) {
-    R = new (A) ElementRegion(T, Idx, superRegion);
-    Regions.InsertNode(R, InsertPos);
-  }
-
-  return R;
-}
-
-const FunctionCodeRegion *
-MemRegionManager::getFunctionCodeRegion(const NamedDecl *FD) {
-  // To think: should we canonicalize the declaration here?
-  return getSubRegion<FunctionCodeRegion>(FD, getCodeRegion());
-}
-
-const BlockCodeRegion *
-MemRegionManager::getBlockCodeRegion(const BlockDecl *BD, CanQualType locTy,
-                                     AnalysisDeclContext *AC) {
-  return getSubRegion<BlockCodeRegion>(BD, locTy, AC, getCodeRegion());
-}
-
-const SymbolicRegion *
-MemRegionManager::getSymbolicRegion(SymbolRef sym,
-                                    const MemSpaceRegion *MemSpace) {
-  if (MemSpace == nullptr)
-    MemSpace = getUnknownRegion();
-  return getSubRegion<SymbolicRegion>(sym, MemSpace);
-}
-
-const SymbolicRegion *MemRegionManager::getSymbolicHeapRegion(SymbolRef Sym) {
-  return getSubRegion<SymbolicRegion>(Sym, getHeapRegion());
-}
-
-const FieldRegion*
-MemRegionManager::getFieldRegion(const FieldDecl *d,
-                                 const SubRegion* superRegion){
-  return getSubRegion<FieldRegion>(d, superRegion);
-}
-
-const ObjCIvarRegion*
-MemRegionManager::getObjCIvarRegion(const ObjCIvarDecl *d,
-                                    const SubRegion* superRegion) {
-  return getSubRegion<ObjCIvarRegion>(d, superRegion);
-}
-
-const CXXTempObjectRegion*
-MemRegionManager::getCXXTempObjectRegion(Expr const *E,
-                                         LocationContext const *LC) {
-  const StackFrameContext *SFC = LC->getStackFrame();
-  assert(SFC);
-  return getSubRegion<CXXTempObjectRegion>(E, getStackLocalsRegion(SFC));
-}
-
-const CXXLifetimeExtendedObjectRegion *
-MemRegionManager::getCXXLifetimeExtendedObjectRegion(
-    const Expr *Ex, const ValueDecl *VD, const LocationContext *LC) {
-  const StackFrameContext *SFC = LC->getStackFrame();
-  assert(SFC);
-  return getSubRegion<CXXLifetimeExtendedObjectRegion>(
-      Ex, VD, getStackLocalsRegion(SFC));
-}
-
-const CXXLifetimeExtendedObjectRegion *
-MemRegionManager::getCXXStaticLifetimeExtendedObjectRegion(
-    const Expr *Ex, const ValueDecl *VD) {
-  return getSubRegion<CXXLifetimeExtendedObjectRegion>(
-      Ex, VD,
-      getGlobalsRegion(MemRegion::GlobalInternalSpaceRegionKind, nullptr));
-}
-
-/// Checks whether \p BaseClass is a valid virtual or direct non-virtual base
-/// class of the type of \p Super.
-static bool isValidBaseClass(const CXXRecordDecl *BaseClass,
-                             const TypedValueRegion *Super,
-                             bool IsVirtual) {
-  BaseClass = BaseClass->getCanonicalDecl();
-
-  const CXXRecordDecl *Class = Super->getValueType()->getAsCXXRecordDecl();
-  if (!Class)
-    return true;
-
-  if (IsVirtual)
-    return Class->isVirtuallyDerivedFrom(BaseClass);
-
-  for (const auto &I : Class->bases()) {
-    if (I.getType()->getAsCXXRecordDecl()->getCanonicalDecl() == BaseClass)
-      return true;
-  }
-
-  return false;
-}
-
-const CXXBaseObjectRegion *
-MemRegionManager::getCXXBaseObjectRegion(const CXXRecordDecl *RD,
-                                         const SubRegion *Super,
-                                         bool IsVirtual) {
-  if (isa<TypedValueRegion>(Super)) {
-    assert(isValidBaseClass(RD, cast<TypedValueRegion>(Super), IsVirtual));
-    (void)&isValidBaseClass;
-
-    if (IsVirtual) {
-      // Virtual base regions should not be layered, since the layout rules
-      // are different.
-      while (const auto *Base = dyn_cast<CXXBaseObjectRegion>(Super))
-        Super = cast<SubRegion>(Base->getSuperRegion());
-      assert(Super && !isa<MemSpaceRegion>(Super));
-    }
-  }
-
-  return getSubRegion<CXXBaseObjectRegion>(RD, IsVirtual, Super);
-}
-
-const CXXDerivedObjectRegion *
-MemRegionManager::getCXXDerivedObjectRegion(const CXXRecordDecl *RD,
-                                            const SubRegion *Super) {
-  return getSubRegion<CXXDerivedObjectRegion>(RD, Super);
-}
-
-const CXXThisRegion*
-MemRegionManager::getCXXThisRegion(QualType thisPointerTy,
-                                   const LocationContext *LC) {
-  const auto *PT = thisPointerTy->getAs<PointerType>();
-  assert(PT);
-  // Inside the body of the operator() of a lambda a this expr might refer to an
-  // object in one of the parent location contexts.
-  const auto *D = dyn_cast<CXXMethodDecl>(LC->getDecl());
-  // FIXME: when operator() of lambda is analyzed as a top level function and
-  // 'this' refers to a this to the enclosing scope, there is no right region to
-  // return.
-  while (!LC->inTopFrame() && (!D || D->isStatic() ||
-                               PT != D->getThisType()->getAs<PointerType>())) {
-    LC = LC->getParent();
-    D = dyn_cast<CXXMethodDecl>(LC->getDecl());
-  }
-  const StackFrameContext *STC = LC->getStackFrame();
-  assert(STC);
-  return getSubRegion<CXXThisRegion>(PT, getStackArgumentsRegion(STC));
-}
-
-const AllocaRegion*
-MemRegionManager::getAllocaRegion(const Expr *E, unsigned cnt,
-                                  const LocationContext *LC) {
-  const StackFrameContext *STC = LC->getStackFrame();
-  assert(STC);
-  return getSubRegion<AllocaRegion>(E, cnt, getStackLocalsRegion(STC));
-}
-
-const MemSpaceRegion *MemRegion::getRawMemorySpace() const {
-  const MemRegion *R = this;
-  const auto *SR = dyn_cast<SubRegion>(this);
-
-  while (SR) {
-    R = SR->getSuperRegion();
-    SR = dyn_cast<SubRegion>(R);
-  }
-
-  return cast<MemSpaceRegion>(R);
-}
-
-const MemSpaceRegion *MemRegion::getMemorySpace(ProgramStateRef State) const {
-  const MemRegion *MR = getBaseRegion();
-
-  const MemSpaceRegion *MS = MR->getRawMemorySpace();
-  if (!isa<UnknownSpaceRegion>(MS))
-    return MS;
-    
-  const MemSpaceRegion *const *Result = State->get<MemSpacesMap>(MR);
-  return Result ? *Result : MS;
-}
-
-ProgramStateRef MemRegion::setMemSpaceTrait(ProgramStateRef State, const MemSpaceRegion *MS) const {
-  const MemRegion *MR = getBaseRegion();
-
-  // For now, this should only be called to update the trait for memory regions
-  // that have an unknown memory spaces since we assume everywhere else that the
-  // memory space trait is set only for unknown memory spaces (setting this info
-  // otherwise would go unused).
-  assert(isa<UnknownSpaceRegion>(MR->getRawMemorySpace()));
-
-  // Shouldn't use the memory space trait to associate UnknownSpaceRegion with
-  // an already UnknownSpaceRegion
-  assert(!isa<UnknownSpaceRegion>(MS));
-
-  ProgramStateRef NewState = State->set<MemSpacesMap>(MR, MS);
-  return NewState;
-}
-
-bool MemRegion::hasRawStackStorage() const {
-  return isa<StackSpaceRegion>(getRawMemorySpace());
-}
-
-bool MemRegion::hasStackStorage(ProgramStateRef State) const { 
-  return isMemorySpace<StackSpaceRegion>(State); 
-}
-
-bool MemRegion::hasRawStackNonParametersStorage() const {
-  return isa<StackLocalsSpaceRegion>(getRawMemorySpace());
-}
-
-bool MemRegion::hasStackNonParametersStorage(ProgramStateRef State) const {
-  return isMemorySpace<StackLocalsSpaceRegion>(State);
-}
-
-bool MemRegion::hasRawStackParametersStorage() const {
-  return isa<StackArgumentsSpaceRegion>(getRawMemorySpace());
-}
-
-bool MemRegion::hasStackParametersStorage(ProgramStateRef State) const {
-  return isMemorySpace<StackArgumentsSpaceRegion>(State);
-}
-
-// Strips away all elements and fields.
-// Returns the base region of them.
-const MemRegion *MemRegion::getBaseRegion() const {
-  const MemRegion *R = this;
-  while (true) {
-    switch (R->getKind()) {
-      case MemRegion::ElementRegionKind:
-      case MemRegion::FieldRegionKind:
-      case MemRegion::ObjCIvarRegionKind:
-      case MemRegion::CXXBaseObjectRegionKind:
-      case MemRegion::CXXDerivedObjectRegionKind:
-        R = cast<SubRegion>(R)->getSuperRegion();
-        continue;
-      default:
-        break;
-    }
-    break;
-  }
-  return R;
-}
-
-// Returns the region of the root class of a C++ class hierarchy.
-const MemRegion *MemRegion::getMostDerivedObjectRegion() const {
-  const MemRegion *R = this;
-  while (const auto *BR = dyn_cast<CXXBaseObjectRegion>(R))
-    R = BR->getSuperRegion();
-  return R;
-}
-
-bool MemRegion::isSubRegionOf(const MemRegion *) const {
-  return false;
-}
-
-//===----------------------------------------------------------------------===//
-// View handling.
-//===----------------------------------------------------------------------===//
-
-const MemRegion *MemRegion::StripCasts(bool StripBaseAndDerivedCasts) const {
-  const MemRegion *R = this;
-  while (true) {
-    switch (R->getKind()) {
-    case ElementRegionKind: {
-      const auto *ER = cast<ElementRegion>(R);
-      if (!ER->getIndex().isZeroConstant())
-        return R;
-      R = ER->getSuperRegion();
-      break;
-    }
-    case CXXBaseObjectRegionKind:
-    case CXXDerivedObjectRegionKind:
-      if (!StripBaseAndDerivedCasts)
-        return R;
-      R = cast<TypedValueRegion>(R)->getSuperRegion();
-      break;
-    default:
-      return R;
-    }
-  }
-}
-
-const SymbolicRegion *MemRegion::getSymbolicBase() const {
-  const auto *SubR = dyn_cast<SubRegion>(this);
-
-  while (SubR) {
-    if (const auto *SymR = dyn_cast<SymbolicRegion>(SubR))
-      return SymR;
-    SubR = dyn_cast<SubRegion>(SubR->getSuperRegion());
-  }
-  return nullptr;
-}
-
-RegionRawOffset ElementRegion::getAsArrayOffset() const {
-  int64_t offset = 0;
-  const ElementRegion *ER = this;
-  const MemRegion *superR = nullptr;
-  ASTContext &C = getContext();
-
-  // FIXME: Handle multi-dimensional arrays.
-
-  while (ER) {
-    superR = ER->getSuperRegion();
-
-    // FIXME: generalize to symbolic offsets.
-    SVal index = ER->getIndex();
-    if (auto CI = index.getAs<nonloc::ConcreteInt>()) {
-      // Update the offset.
-      if (int64_t i = CI->getValue()->getSExtValue(); i != 0) {
-        QualType elemType = ER->getElementType();
-
-        // If we are pointing to an incomplete type, go no further.
-        if (elemType->isIncompleteType()) {
-          superR = ER;
-          break;
-        }
-
-        int64_t size = C.getTypeSizeInChars(elemType).getQuantity();
-        if (auto NewOffset = llvm::checkedMulAdd(i, size, offset)) {
-          offset = *NewOffset;
-        } else {
-          LLVM_DEBUG(llvm::dbgs() << "MemRegion::getAsArrayOffset: "
-                                  << "offset overflowing, returning unknown\n");
-
-          return nullptr;
-        }
-      }
-
-      // Go to the next ElementRegion (if any).
-      ER = dyn_cast<ElementRegion>(superR);
-      continue;
-    }
-
-    return nullptr;
-  }
-
-  assert(superR && "super region cannot be NULL");
-  return RegionRawOffset(superR, CharUnits::fromQuantity(offset));
-}
-
-/// Returns true if \p Base is an immediate base class of \p Child
-static bool isImmediateBase(const CXXRecordDecl *Child,
-                            const CXXRecordDecl *Base) {
-  assert(Child && "Child must not be null");
-  // Note that we do NOT canonicalize the base class here, because
-  // ASTRecordLayout doesn't either. If that leads us down the wrong path,
-  // so be it; at least we won't crash.
-  for (const auto &I : Child->bases()) {
-    if (I.getType()->getAsCXXRecordDecl() == Base)
-      return true;
-  }
-
-  return false;
-}
-
-static RegionOffset calculateOffset(const MemRegion *R) {
-  const MemRegion *SymbolicOffsetBase = nullptr;
-  int64_t Offset = 0;
-
-  while (true) {
-    switch (R->getKind()) {
-    case MemRegion::CodeSpaceRegionKind:
-    case MemRegion::StackLocalsSpaceRegionKind:
-    case MemRegion::StackArgumentsSpaceRegionKind:
-    case MemRegion::HeapSpaceRegionKind:
-    case MemRegion::UnknownSpaceRegionKind:
-    case MemRegion::StaticGlobalSpaceRegionKind:
-    case MemRegion::GlobalInternalSpaceRegionKind:
-    case MemRegion::GlobalSystemSpaceRegionKind:
-    case MemRegion::GlobalImmutableSpaceRegionKind:
-      // Stores can bind directly to a region space to set a default value.
-      assert(Offset == 0 && !SymbolicOffsetBase);
-      goto Finish;
-
-    case MemRegion::FunctionCodeRegionKind:
-    case MemRegion::BlockCodeRegionKind:
-    case MemRegion::BlockDataRegionKind:
-      // These will never have bindings, but may end up having values requested
-      // if the user does some strange casting.
-      if (Offset != 0)
-        SymbolicOffsetBase = R;
-      goto Finish;
-
-    case MemRegion::SymbolicRegionKind:
-    case MemRegion::AllocaRegionKind:
-    case MemRegion::CompoundLiteralRegionKind:
-    case MemRegion::CXXThisRegionKind:
-    case MemRegion::StringRegionKind:
-    case MemRegion::ObjCStringRegionKind:
-    case MemRegion::NonParamVarRegionKind:
-    case MemRegion::ParamVarRegionKind:
-    case MemRegion::CXXTempObjectRegionKind:
-    case MemRegion::CXXLifetimeExtendedObjectRegionKind:
-      // Usual base regions.
-      goto Finish;
-
-    case MemRegion::ObjCIvarRegionKind:
-      // This is a little strange, but it's a compromise between
-      // ObjCIvarRegions having unknown compile-time offsets (when using the
-      // non-fragile runtime) and yet still being distinct, non-overlapping
-      // regions. Thus we treat them as "like" base regions for the purposes
-      // of computing offsets.
-      goto Finish;
-
-    case MemRegion::CXXBaseObjectRegionKind: {
-      const auto *BOR = cast<CXXBaseObjectRegion>(R);
-      R = BOR->getSuperRegion();
-
-      QualType Ty;
-      bool RootIsSymbolic = false;
-      if (const auto *TVR = dyn_cast<TypedValueRegion>(R)) {
-        Ty = TVR->getDesugaredValueType(R->getContext());
-      } else if (const auto *SR = dyn_cast<SymbolicRegion>(R)) {
-        // If our base region is symbolic, we don't know what type it really is.
-        // Pretend the type of the symbol is the true dynamic type.
-        // (This will at least be self-consistent for the life of the symbol.)
-        Ty = SR->getPointeeStaticType();
-        RootIsSymbolic = true;
-      }
-
-      const CXXRecordDecl *Child = Ty->getAsCXXRecordDecl();
-      if (!Child) {
-        // We cannot compute the offset of the base class.
-        SymbolicOffsetBase = R;
-      } else {
-        if (RootIsSymbolic) {
-          // Base layers on symbolic regions may not be type-correct.
-          // Double-check the inheritance here, and revert to a symbolic offset
-          // if it's invalid (e.g. due to a reinterpret_cast).
-          if (BOR->isVirtual()) {
-            if (!Child->isVirtuallyDerivedFrom(BOR->getDecl()))
-              SymbolicOffsetBase = R;
-          } else {
-            if (!isImmediateBase(Child, BOR->getDecl()))
-              SymbolicOffsetBase = R;
-          }
-        }
-      }
-
-      // Don't bother calculating precise offsets if we already have a
-      // symbolic offset somewhere in the chain.
-      if (SymbolicOffsetBase)
-        continue;
-
-      CharUnits BaseOffset;
-      const ASTRecordLayout &Layout = R->getContext().getASTRecordLayout(Child);
-      if (BOR->isVirtual())
-        BaseOffset = Layout.getVBaseClassOffset(BOR->getDecl());
-      else
-        BaseOffset = Layout.getBaseClassOffset(BOR->getDecl());
-
-      // The base offset is in chars, not in bits.
-      Offset += BaseOffset.getQuantity() * R->getContext().getCharWidth();
-      break;
-    }
-
-    case MemRegion::CXXDerivedObjectRegionKind: {
-      // TODO: Store the base type in the CXXDerivedObjectRegion and use it.
-      goto Finish;
-    }
-
-    case MemRegion::ElementRegionKind: {
-      const auto *ER = cast<ElementRegion>(R);
-      R = ER->getSuperRegion();
-
-      QualType EleTy = ER->getValueType();
-      if (EleTy->isIncompleteType()) {
-        // We cannot compute the offset of the base class.
-        SymbolicOffsetBase = R;
-        continue;
-      }
-
-      SVal Index = ER->getIndex();
-      if (std::optional<nonloc::ConcreteInt> CI =
-              Index.getAs<nonloc::ConcreteInt>()) {
-        // Don't bother calculating precise offsets if we already have a
-        // symbolic offset somewhere in the chain.
-        if (SymbolicOffsetBase)
-          continue;
-
-        int64_t i = CI->getValue()->getSExtValue();
-        // This type size is in bits.
-        Offset += i * R->getContext().getTypeSize(EleTy);
-      } else {
-        // We cannot compute offset for non-concrete index.
-        SymbolicOffsetBase = R;
-      }
-      break;
-    }
-    case MemRegion::FieldRegionKind: {
-      const auto *FR = cast<FieldRegion>(R);
-      R = FR->getSuperRegion();
-      assert(R);
-
-      const RecordDecl *RD = FR->getDecl()->getParent();
-      if (RD->isUnion() || !RD->isCompleteDefinition()) {
-        // We cannot compute offset for incomplete type.
-        // For unions, we could treat everything as offset 0, but we'd rather
-        // treat each field as a symbolic offset so they aren't stored on top
-        // of each other, since we depend on things in typed regions actually
-        // matching their types.
-        SymbolicOffsetBase = R;
-      }
-
-      // Don't bother calculating precise offsets if we already have a
-      // symbolic offset somewhere in the chain.
-      if (SymbolicOffsetBase)
-        continue;
-
-      // Get the field number.
-      unsigned idx = 0;
-      for (RecordDecl::field_iterator FI = RD->field_begin(),
-             FE = RD->field_end(); FI != FE; ++FI, ++idx) {
-        if (FR->getDecl() == *FI)
-          break;
-      }
-      const ASTRecordLayout &Layout = R->getContext().getASTRecordLayout(RD);
-      // This is offset in bits.
-      Offset += Layout.getFieldOffset(idx);
-      break;
-    }
-    }
-  }
-
- Finish:
-  if (SymbolicOffsetBase)
-    return RegionOffset(SymbolicOffsetBase, RegionOffset::Symbolic);
-  return RegionOffset(R, Offset);
-}
-
-RegionOffset MemRegion::getAsOffset() const {
-  if (!cachedOffset)
-    cachedOffset = calculateOffset(this);
-  return *cachedOffset;
-}
-
-//===----------------------------------------------------------------------===//
-// BlockDataRegion
-//===----------------------------------------------------------------------===//
-
-std::pair<const VarRegion *, const VarRegion *>
-BlockDataRegion::getCaptureRegions(const VarDecl *VD) {
-  MemRegionManager &MemMgr = getMemRegionManager();
-  const VarRegion *VR = nullptr;
-  const VarRegion *OriginalVR = nullptr;
-
-  if (!VD->hasAttr<BlocksAttr>() && VD->hasLocalStorage()) {
-    VR = MemMgr.getNonParamVarRegion(VD, this);
-    OriginalVR = MemMgr.getVarRegion(VD, LC);
-  }
-  else {
-    if (LC) {
-      VR = MemMgr.getVarRegion(VD, LC);
-      OriginalVR = VR;
-    }
-    else {
-      VR = MemMgr.getNonParamVarRegion(VD, MemMgr.getUnknownRegion());
-      OriginalVR = MemMgr.getVarRegion(VD, LC);
-    }
-  }
-  return std::make_pair(VR, OriginalVR);
-}
-
-void BlockDataRegion::LazyInitializeReferencedVars() {
-  if (ReferencedVars)
-    return;
-
-  AnalysisDeclContext *AC = getCodeRegion()->getAnalysisDeclContext();
-  const auto &ReferencedBlockVars = AC->getReferencedBlockVars(BC->getDecl());
-  auto NumBlockVars =
-      std::distance(ReferencedBlockVars.begin(), ReferencedBlockVars.end());
-
-  if (NumBlockVars == 0) {
-    ReferencedVars = (void*) 0x1;
-    return;
-  }
-
-  MemRegionManager &MemMgr = getMemRegionManager();
-  llvm::BumpPtrAllocator &A = MemMgr.getAllocator();
-  BumpVectorContext BC(A);
-
-  using VarVec = BumpVector<const MemRegion *>;
-
-  auto *BV = new (A) VarVec(BC, NumBlockVars);
-  auto *BVOriginal = new (A) VarVec(BC, NumBlockVars);
-
-  for (const auto *VD : ReferencedBlockVars) {
-    const VarRegion *VR = nullptr;
-    const VarRegion *OriginalVR = nullptr;
-    std::tie(VR, OriginalVR) = getCaptureRegions(VD);
-    assert(VR);
-    assert(OriginalVR);
-    BV->push_back(VR, BC);
-    BVOriginal->push_back(OriginalVR, BC);
-  }
-
-  ReferencedVars = BV;
-  OriginalVars = BVOriginal;
-}
-
-BlockDataRegion::referenced_vars_iterator
-BlockDataRegion::referenced_vars_begin() const {
-  const_cast<BlockDataRegion*>(this)->LazyInitializeReferencedVars();
-
-  auto *Vec = static_cast<BumpVector<const MemRegion *> *>(ReferencedVars);
-
-  if (Vec == (void*) 0x1)
-    return BlockDataRegion::referenced_vars_iterator(nullptr, nullptr);
-
-  auto *VecOriginal =
-      static_cast<BumpVector<const MemRegion *> *>(OriginalVars);
-
-  return BlockDataRegion::referenced_vars_iterator(Vec->begin(),
-                                                   VecOriginal->begin());
-}
-
-BlockDataRegion::referenced_vars_iterator
-BlockDataRegion::referenced_vars_end() const {
-  const_cast<BlockDataRegion*>(this)->LazyInitializeReferencedVars();
-
-  auto *Vec = static_cast<BumpVector<const MemRegion *> *>(ReferencedVars);
-
-  if (Vec == (void*) 0x1)
-    return BlockDataRegion::referenced_vars_iterator(nullptr, nullptr);
-
-  auto *VecOriginal =
-      static_cast<BumpVector<const MemRegion *> *>(OriginalVars);
-
-  return BlockDataRegion::referenced_vars_iterator(Vec->end(),
-                                                   VecOriginal->end());
-}
-
-llvm::iterator_range<BlockDataRegion::referenced_vars_iterator>
-BlockDataRegion::referenced_vars() const {
-  return llvm::make_range(referenced_vars_begin(), referenced_vars_end());
-}
-
-const VarRegion *BlockDataRegion::getOriginalRegion(const VarRegion *R) const {
-  for (const auto &I : referenced_vars()) {
-    if (I.getCapturedRegion() == R)
-      return I.getOriginalRegion();
-  }
-  return nullptr;
-}
-
-//===----------------------------------------------------------------------===//
-// RegionAndSymbolInvalidationTraits
-//===----------------------------------------------------------------------===//
-
-void RegionAndSymbolInvalidationTraits::setTrait(SymbolRef Sym,
-                                                 InvalidationKinds IK) {
-  SymTraitsMap[Sym] |= IK;
-}
-
-void RegionAndSymbolInvalidationTraits::setTrait(const MemRegion *MR,
-                                                 InvalidationKinds IK) {
-  assert(MR);
-  if (const auto *SR = dyn_cast<SymbolicRegion>(MR))
-    setTrait(SR->getSymbol(), IK);
-  else
-    MRTraitsMap[MR] |= IK;
-}
-
-bool RegionAndSymbolInvalidationTraits::hasTrait(SymbolRef Sym,
-                                                 InvalidationKinds IK) const {
-  const_symbol_iterator I = SymTraitsMap.find(Sym);
-  if (I != SymTraitsMap.end())
-    return I->second & IK;
-
-  return false;
-}
-
-bool RegionAndSymbolInvalidationTraits::hasTrait(const MemRegion *MR,
-                                                 InvalidationKinds IK) const {
-  if (!MR)
-    return false;
-
-  if (const auto *SR = dyn_cast<SymbolicRegion>(MR))
-    return hasTrait(SR->getSymbol(), IK);
-
-  const_region_iterator I = MRTraitsMap.find(MR);
-  if (I != MRTraitsMap.end())
-    return I->second & IK;
-
-  return false;
-}

>From 5524964964540519d2eea20ffb4e7315694a1bfc Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Mon, 27 Jan 2025 12:44:40 -0600
Subject: [PATCH 19/55] formatting

---
 .../Core/PathSensitive/MemRegion.h            | 19 ++++++++++++-------
 .../StaticAnalyzer/Checkers/MIGChecker.cpp    |  2 +-
 .../Checkers/NSErrorChecker.cpp               |  4 ++--
 .../Checkers/PutenvStackArrayChecker.cpp      |  4 ++--
 .../Core/BugReporterVisitors.cpp              |  4 ++--
 clang/lib/StaticAnalyzer/Core/ExprEngine.cpp  |  6 ++++--
 clang/lib/StaticAnalyzer/Core/MemSpaces.cpp   |  5 +----
 7 files changed, 24 insertions(+), 20 deletions(-)

diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index c889a9ab0604728..f81a438b4078974 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -120,21 +120,26 @@ class MemRegion : public llvm::FoldingSetNode {
 
   virtual MemRegionManager &getMemRegionManager() const = 0;
 
-  /// Deprecated. Gets the 'raw' memory space of a memory region's base region. Deprecated
-  /// in favor of the memory space trait which maps memory regions to memory spaces, allowing
-  /// dynamic updating of a memory region's memory space. 
+  /// Deprecated. Gets the 'raw' memory space of a memory region's base region.
+  /// Deprecated in favor of the memory space trait which maps memory regions to
+  /// memory spaces, allowing dynamic updating of a memory region's memory
+  /// space.
   /// @deprecated Use getMemorySpace(ProgramStateRef) instead.
-  LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion *getRawMemorySpace() const;
+  LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion *
+  getRawMemorySpace() const;
 
-  /// Returns the most specific memory space for this memory region in the given ProgramStateRef.
-  [[nodiscard]] LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion *getMemorySpace(ProgramStateRef State) const;
+  /// Returns the most specific memory space for this memory region in the given
+  /// ProgramStateRef.
+  [[nodiscard]] LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion *
+  getMemorySpace(ProgramStateRef State) const;
 
   template <typename FirstT, typename... RestT>
   [[nodiscard]] bool isMemorySpace(ProgramStateRef State) const {
     return isa_and_nonnull<FirstT, RestT...>(getMemorySpace(State));
   }
 
-  [[nodiscard]] ProgramStateRef setMemSpaceTrait(ProgramStateRef State, const MemSpaceRegion *MS) const;
+  [[nodiscard]] ProgramStateRef
+  setMemSpaceTrait(ProgramStateRef State, const MemSpaceRegion *MS) const;
 
   LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion *getBaseRegion() const;
 
diff --git a/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp
index 470801f90adb0f0..19f1d03ff4753a6 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp
@@ -135,7 +135,7 @@ static const ParmVarDecl *getOriginParam(SVal V, CheckerContext &C,
   while (const MemRegion *MR = Sym->getOriginRegion()) {
     const auto *VR = dyn_cast<VarRegion>(MR);
     if (VR && VR->hasRawStackParametersStorage() &&
-           VR->getStackFrame()->inTopFrame())
+        VR->getStackFrame()->inTopFrame())
       return cast<ParmVarDecl>(VR->getDecl());
 
     const SymbolicRegion *SR = MR->getSymbolicBase();
diff --git a/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
index 151f6312f5d232a..2a4a865b16f11ef 100644
--- a/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
@@ -201,8 +201,8 @@ static QualType parameterTypeFromSVal(SVal val, CheckerContext &C) {
   if (std::optional<loc::MemRegionVal> X = val.getAs<loc::MemRegionVal>()) {
     const MemRegion* R = X->getRegion();
     if (const VarRegion *VR = R->getAs<VarRegion>())
-      if (const StackArgumentsSpaceRegion *
-          stackReg = dyn_cast<StackArgumentsSpaceRegion>(VR->getRawMemorySpace()))
+      if (const StackArgumentsSpaceRegion *stackReg =
+              dyn_cast<StackArgumentsSpaceRegion>(VR->getRawMemorySpace()))
         if (stackReg->getStackFrame() == SFC)
           return VR->getValueType();
   }
diff --git a/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
index 96be9bf07e01c03..028f46fbd7273f0 100644
--- a/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
@@ -47,8 +47,8 @@ void PutenvStackArrayChecker::checkPostCall(const CallEvent &Call,
 
   const MemRegion *MR = ArgV.getAsRegion();
 
-  const StackSpaceRegion *SSR = dyn_cast_if_present<StackSpaceRegion>(
-      MR->getMemorySpace(C.getState()));
+  const StackSpaceRegion *SSR =
+      dyn_cast_if_present<StackSpaceRegion>(MR->getMemorySpace(C.getState()));
   if (!SSR)
     return;
 
diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index 48d5be04adab521..6ef333c2bcf1875 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -1192,8 +1192,8 @@ static bool isInitializationOfVar(const ExplodedNode *N, const VarRegion *VR) {
   if (DS->getSingleDecl() != VR->getDecl())
     return false;
 
-  const StackSpaceRegion *FrameSpace = dyn_cast_if_present<StackSpaceRegion>(
-      VR->getMemorySpace(N->getState()));
+  const StackSpaceRegion *FrameSpace =
+      dyn_cast_if_present<StackSpaceRegion>(VR->getMemorySpace(N->getState()));
 
   if (!FrameSpace) {
     // If we ever directly evaluate global DeclStmts, this assertion will be
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 53f9998a5810a51..5a4178b4e695ecf 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -3510,14 +3510,16 @@ ProgramStateRef ExprEngine::processPointerEscapedOnBind(
   for (const std::pair<SVal, SVal> &LocAndVal : LocAndVals) {
     // Cases (1) and (2).
     const MemRegion *MR = LocAndVal.first.getAsRegion();
-    if (!MR || !MR->isMemorySpace<StackSpaceRegion, StaticGlobalSpaceRegion>(State)) {
+    if (!MR ||
+        !MR->isMemorySpace<StackSpaceRegion, StaticGlobalSpaceRegion>(State)) {
       Escaped.push_back(LocAndVal.second);
       continue;
     }
 
     // Case (3).
     if (const auto *VR = dyn_cast<VarRegion>(MR->getBaseRegion()))
-      if (VR->hasRawStackParametersStorage() && VR->getStackFrame()->inTopFrame())
+      if (VR->hasRawStackParametersStorage() &&
+          VR->getStackFrame()->inTopFrame())
         if (const auto *RD = VR->getValueType()->getAsCXXRecordDecl())
           if (!RD->hasTrivialDestructor()) {
             Escaped.push_back(LocAndVal.second);
diff --git a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
index 7201ec816bc8a20..8221b79b0706c60 100644
--- a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
+++ b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
@@ -30,9 +30,6 @@ REGISTER_MAP_WITH_PROGRAMSTATE(MemSpacesMap, const clang::ento::MemRegion *,
 
 namespace clang {
 namespace ento {
-namespace memspace {
-
-
-} // namespace memspace
+namespace memspace {} // namespace memspace
 } // namespace ento
 } // namespace clang

>From 605cc80bc05acd094f44d2b7f918a9d13351168b Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Mon, 27 Jan 2025 13:13:05 -0600
Subject: [PATCH 20/55] fix wrong file removal, more renames and comments

---
 .../Core/PathSensitive/MemRegion.h            |    2 +
 .../RetainCountDiagnostics.cpp                |    2 +-
 .../Checkers/StackAddrEscapeChecker.cpp       |    2 +-
 clang/lib/StaticAnalyzer/Core/CMakeLists.txt  |    1 -
 clang/lib/StaticAnalyzer/Core/MemRegion.cpp   | 1881 +++++++++++++++++
 clang/lib/StaticAnalyzer/Core/MemSpaces.cpp   |   35 -
 6 files changed, 1885 insertions(+), 38 deletions(-)
 create mode 100644 clang/lib/StaticAnalyzer/Core/MemRegion.cpp
 delete mode 100644 clang/lib/StaticAnalyzer/Core/MemSpaces.cpp

diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index f81a438b4078974..9abd5882c245485 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -165,10 +165,12 @@ class MemRegion : public llvm::FoldingSetNode {
 
   [[nodiscard]] bool hasStackStorage(ProgramStateRef State) const;
 
+  /// @deprecated Use hasStackNonParametersStorage(ProgramStateRef) instead.
   bool hasRawStackNonParametersStorage() const;
 
   [[nodiscard]] bool hasStackNonParametersStorage(ProgramStateRef State) const;
 
+  /// @deprecated Use hasStackParametersStorage(ProgramStateRef) instead.
   bool hasRawStackParametersStorage() const;
 
   [[nodiscard]] bool hasStackParametersStorage(ProgramStateRef State) const;
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
index 1fbfa8cf0eaddf8..a5905c8d4ad4731 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
@@ -691,7 +691,7 @@ static AllocationInfo GetAllocationSite(ProgramStateManager &StateMgr,
       // Do not show local variables belonging to a function other than
       // where the error is reported.
       const StackSpaceRegion *SSR =
-          dyn_cast_if_present<StackSpaceRegion>(R->getMemSpace(St));
+          dyn_cast_if_present<StackSpaceRegion>(R->getMemorySpace(St));
 
       if (SSR && SSR->getStackFrame() == LeakContext->getStackFrame())
         FirstBinding = R;
diff --git a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index 57f889af1e94321..54655c9ea15df71 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -266,7 +266,7 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
   if (const BlockDataRegion *B = dyn_cast<BlockDataRegion>(R))
     checkReturnedBlockCaptures(*B, C);
 
-  const MemSpaceRegion *MS = R->getMemSpace(C.getState());
+  const MemSpaceRegion *MS = R->getMemorySpace(C.getState());
   if (!isa<StackSpaceRegion>(MS) || isNotInCurrentFrame(MS, C))
     return;
 
diff --git a/clang/lib/StaticAnalyzer/Core/CMakeLists.txt b/clang/lib/StaticAnalyzer/Core/CMakeLists.txt
index 993d37bb052e9b7..fb9394a519eb71b 100644
--- a/clang/lib/StaticAnalyzer/Core/CMakeLists.txt
+++ b/clang/lib/StaticAnalyzer/Core/CMakeLists.txt
@@ -36,7 +36,6 @@ add_clang_library(clangStaticAnalyzerCore
   LoopUnrolling.cpp
   LoopWidening.cpp
   MemRegion.cpp
-  MemSpaces.cpp
   PlistDiagnostics.cpp
   ProgramState.cpp
   RangeConstraintManager.cpp
diff --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
new file mode 100644
index 000000000000000..4b621e5cb4f9758
--- /dev/null
+++ b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -0,0 +1,1881 @@
+//===- MemRegion.cpp - Abstract memory regions for static analysis --------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file defines MemRegion and its subclasses.  MemRegion defines a
+//  partially-typed abstraction of memory useful for path-sensitive dataflow
+//  analyses.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/CharUnits.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/PrettyPrinter.h"
+#include "clang/AST/RecordLayout.h"
+#include "clang/AST/Type.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
+#include "clang/Analysis/Support/BumpVector.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/CheckedArithmetic.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <cstdint>
+#include <functional>
+#include <iterator>
+#include <optional>
+#include <string>
+#include <tuple>
+#include <utility>
+
+using namespace clang;
+using namespace ento;
+
+#define DEBUG_TYPE "MemRegion"
+
+REGISTER_MAP_WITH_PROGRAMSTATE(MemSpacesMap, const clang::ento::MemRegion *,
+                               const clang::ento::MemSpaceRegion *)
+
+//===----------------------------------------------------------------------===//
+// MemRegion Construction.
+//===----------------------------------------------------------------------===//
+
+[[maybe_unused]] static bool isAReferenceTypedValueRegion(const MemRegion *R) {
+  const auto *TyReg = llvm::dyn_cast<TypedValueRegion>(R);
+  return TyReg && TyReg->getValueType()->isReferenceType();
+}
+
+template <typename RegionTy, typename SuperTy, typename Arg1Ty>
+RegionTy* MemRegionManager::getSubRegion(const Arg1Ty arg1,
+                                         const SuperTy *superRegion) {
+  llvm::FoldingSetNodeID ID;
+  RegionTy::ProfileRegion(ID, arg1, superRegion);
+  void *InsertPos;
+  auto *R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID, InsertPos));
+
+  if (!R) {
+    R = new (A) RegionTy(arg1, superRegion);
+    Regions.InsertNode(R, InsertPos);
+    assert(!isAReferenceTypedValueRegion(superRegion));
+  }
+
+  return R;
+}
+
+template <typename RegionTy, typename SuperTy, typename Arg1Ty, typename Arg2Ty>
+RegionTy* MemRegionManager::getSubRegion(const Arg1Ty arg1, const Arg2Ty arg2,
+                                         const SuperTy *superRegion) {
+  llvm::FoldingSetNodeID ID;
+  RegionTy::ProfileRegion(ID, arg1, arg2, superRegion);
+  void *InsertPos;
+  auto *R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID, InsertPos));
+
+  if (!R) {
+    R = new (A) RegionTy(arg1, arg2, superRegion);
+    Regions.InsertNode(R, InsertPos);
+    assert(!isAReferenceTypedValueRegion(superRegion));
+  }
+
+  return R;
+}
+
+template <typename RegionTy, typename SuperTy,
+          typename Arg1Ty, typename Arg2Ty, typename Arg3Ty>
+RegionTy* MemRegionManager::getSubRegion(const Arg1Ty arg1, const Arg2Ty arg2,
+                                         const Arg3Ty arg3,
+                                         const SuperTy *superRegion) {
+  llvm::FoldingSetNodeID ID;
+  RegionTy::ProfileRegion(ID, arg1, arg2, arg3, superRegion);
+  void *InsertPos;
+  auto *R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID, InsertPos));
+
+  if (!R) {
+    R = new (A) RegionTy(arg1, arg2, arg3, superRegion);
+    Regions.InsertNode(R, InsertPos);
+    assert(!isAReferenceTypedValueRegion(superRegion));
+  }
+
+  return R;
+}
+
+//===----------------------------------------------------------------------===//
+// Object destruction.
+//===----------------------------------------------------------------------===//
+
+MemRegion::~MemRegion() = default;
+
+// All regions and their data are BumpPtrAllocated.  No need to call their
+// destructors.
+MemRegionManager::~MemRegionManager() = default;
+
+//===----------------------------------------------------------------------===//
+// Basic methods.
+//===----------------------------------------------------------------------===//
+
+bool SubRegion::isSubRegionOf(const MemRegion* R) const {
+  const MemRegion* r = this;
+  do {
+    if (r == R)
+      return true;
+    if (const auto *sr = dyn_cast<SubRegion>(r))
+      r = sr->getSuperRegion();
+    else
+      break;
+  } while (r != nullptr);
+  return false;
+}
+
+MemRegionManager &SubRegion::getMemRegionManager() const {
+  const SubRegion* r = this;
+  do {
+    const MemRegion *superRegion = r->getSuperRegion();
+    if (const auto *sr = dyn_cast<SubRegion>(superRegion)) {
+      r = sr;
+      continue;
+    }
+    return superRegion->getMemRegionManager();
+  } while (true);
+}
+
+const StackFrameContext *VarRegion::getStackFrame() const {
+  const auto *SSR = dyn_cast<StackSpaceRegion>(getRawMemorySpace());
+  return SSR ? SSR->getStackFrame() : nullptr;
+}
+
+const StackFrameContext *
+CXXLifetimeExtendedObjectRegion::getStackFrame() const {
+  const auto *SSR = dyn_cast<StackSpaceRegion>(getRawMemorySpace());
+  return SSR ? SSR->getStackFrame() : nullptr;
+}
+
+const StackFrameContext *CXXTempObjectRegion::getStackFrame() const {
+  assert(isa<StackSpaceRegion>(getRawMemorySpace()) &&
+         "A temporary object can only be allocated on the stack");
+  return cast<StackSpaceRegion>(getRawMemorySpace())->getStackFrame();
+}
+
+ObjCIvarRegion::ObjCIvarRegion(const ObjCIvarDecl *ivd, const SubRegion *sReg)
+    : DeclRegion(sReg, ObjCIvarRegionKind), IVD(ivd) {
+  assert(IVD);
+}
+
+const ObjCIvarDecl *ObjCIvarRegion::getDecl() const { return IVD; }
+
+QualType ObjCIvarRegion::getValueType() const {
+  return getDecl()->getType();
+}
+
+QualType CXXBaseObjectRegion::getValueType() const {
+  return QualType(getDecl()->getTypeForDecl(), 0);
+}
+
+QualType CXXDerivedObjectRegion::getValueType() const {
+  return QualType(getDecl()->getTypeForDecl(), 0);
+}
+
+QualType ParamVarRegion::getValueType() const {
+  assert(getDecl() &&
+         "`ParamVarRegion` support functions without `Decl` not implemented"
+         " yet.");
+  return getDecl()->getType();
+}
+
+const ParmVarDecl *ParamVarRegion::getDecl() const {
+  const Decl *D = getStackFrame()->getDecl();
+
+  if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
+    assert(Index < FD->param_size());
+    return FD->parameters()[Index];
+  } else if (const auto *BD = dyn_cast<BlockDecl>(D)) {
+    assert(Index < BD->param_size());
+    return BD->parameters()[Index];
+  } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
+    assert(Index < MD->param_size());
+    return MD->parameters()[Index];
+  } else if (const auto *CD = dyn_cast<CXXConstructorDecl>(D)) {
+    assert(Index < CD->param_size());
+    return CD->parameters()[Index];
+  } else {
+    llvm_unreachable("Unexpected Decl kind!");
+  }
+}
+
+//===----------------------------------------------------------------------===//
+// FoldingSet profiling.
+//===----------------------------------------------------------------------===//
+
+void MemSpaceRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+  ID.AddInteger(static_cast<unsigned>(getKind()));
+}
+
+void StackSpaceRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+  ID.AddInteger(static_cast<unsigned>(getKind()));
+  ID.AddPointer(getStackFrame());
+}
+
+void StaticGlobalSpaceRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+  ID.AddInteger(static_cast<unsigned>(getKind()));
+  ID.AddPointer(getCodeRegion());
+}
+
+void StringRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
+                                 const StringLiteral *Str,
+                                 const MemRegion *superRegion) {
+  ID.AddInteger(static_cast<unsigned>(StringRegionKind));
+  ID.AddPointer(Str);
+  ID.AddPointer(superRegion);
+}
+
+void ObjCStringRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
+                                     const ObjCStringLiteral *Str,
+                                     const MemRegion *superRegion) {
+  ID.AddInteger(static_cast<unsigned>(ObjCStringRegionKind));
+  ID.AddPointer(Str);
+  ID.AddPointer(superRegion);
+}
+
+void AllocaRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+                                 const Expr *Ex, unsigned cnt,
+                                 const MemRegion *superRegion) {
+  ID.AddInteger(static_cast<unsigned>(AllocaRegionKind));
+  ID.AddPointer(Ex);
+  ID.AddInteger(cnt);
+  ID.AddPointer(superRegion);
+}
+
+void AllocaRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+  ProfileRegion(ID, Ex, Cnt, superRegion);
+}
+
+void CompoundLiteralRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+  CompoundLiteralRegion::ProfileRegion(ID, CL, superRegion);
+}
+
+void CompoundLiteralRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+                                          const CompoundLiteralExpr *CL,
+                                          const MemRegion* superRegion) {
+  ID.AddInteger(static_cast<unsigned>(CompoundLiteralRegionKind));
+  ID.AddPointer(CL);
+  ID.AddPointer(superRegion);
+}
+
+void CXXThisRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
+                                  const PointerType *PT,
+                                  const MemRegion *sRegion) {
+  ID.AddInteger(static_cast<unsigned>(CXXThisRegionKind));
+  ID.AddPointer(PT);
+  ID.AddPointer(sRegion);
+}
+
+void CXXThisRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+  CXXThisRegion::ProfileRegion(ID, ThisPointerTy, superRegion);
+}
+
+void FieldRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+  ProfileRegion(ID, getDecl(), superRegion);
+}
+
+void ObjCIvarRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+                                   const ObjCIvarDecl *ivd,
+                                   const MemRegion* superRegion) {
+  ID.AddInteger(static_cast<unsigned>(ObjCIvarRegionKind));
+  ID.AddPointer(ivd);
+  ID.AddPointer(superRegion);
+}
+
+void ObjCIvarRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+  ProfileRegion(ID, getDecl(), superRegion);
+}
+
+void NonParamVarRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
+                                      const VarDecl *VD,
+                                      const MemRegion *superRegion) {
+  ID.AddInteger(static_cast<unsigned>(NonParamVarRegionKind));
+  ID.AddPointer(VD);
+  ID.AddPointer(superRegion);
+}
+
+void NonParamVarRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+  ProfileRegion(ID, getDecl(), superRegion);
+}
+
+void ParamVarRegion::ProfileRegion(llvm::FoldingSetNodeID &ID, const Expr *OE,
+                                   unsigned Idx, const MemRegion *SReg) {
+  ID.AddInteger(static_cast<unsigned>(ParamVarRegionKind));
+  ID.AddPointer(OE);
+  ID.AddInteger(Idx);
+  ID.AddPointer(SReg);
+}
+
+void ParamVarRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+  ProfileRegion(ID, getOriginExpr(), getIndex(), superRegion);
+}
+
+void SymbolicRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, SymbolRef sym,
+                                   const MemRegion *sreg) {
+  ID.AddInteger(static_cast<unsigned>(MemRegion::SymbolicRegionKind));
+  ID.Add(sym);
+  ID.AddPointer(sreg);
+}
+
+void SymbolicRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+  SymbolicRegion::ProfileRegion(ID, sym, getSuperRegion());
+}
+
+void ElementRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+                                  QualType ElementType, SVal Idx,
+                                  const MemRegion* superRegion) {
+  ID.AddInteger(MemRegion::ElementRegionKind);
+  ID.Add(ElementType);
+  ID.AddPointer(superRegion);
+  Idx.Profile(ID);
+}
+
+void ElementRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+  ElementRegion::ProfileRegion(ID, ElementType, Index, superRegion);
+}
+
+void FunctionCodeRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+                                       const NamedDecl *FD,
+                                       const MemRegion*) {
+  ID.AddInteger(MemRegion::FunctionCodeRegionKind);
+  ID.AddPointer(FD);
+}
+
+void FunctionCodeRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+  FunctionCodeRegion::ProfileRegion(ID, FD, superRegion);
+}
+
+void BlockCodeRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+                                    const BlockDecl *BD, CanQualType,
+                                    const AnalysisDeclContext *AC,
+                                    const MemRegion*) {
+  ID.AddInteger(MemRegion::BlockCodeRegionKind);
+  ID.AddPointer(BD);
+}
+
+void BlockCodeRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+  BlockCodeRegion::ProfileRegion(ID, BD, locTy, AC, superRegion);
+}
+
+void BlockDataRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+                                    const BlockCodeRegion *BC,
+                                    const LocationContext *LC,
+                                    unsigned BlkCount,
+                                    const MemRegion *sReg) {
+  ID.AddInteger(MemRegion::BlockDataRegionKind);
+  ID.AddPointer(BC);
+  ID.AddPointer(LC);
+  ID.AddInteger(BlkCount);
+  ID.AddPointer(sReg);
+}
+
+void BlockDataRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+  BlockDataRegion::ProfileRegion(ID, BC, LC, BlockCount, getSuperRegion());
+}
+
+void CXXTempObjectRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
+                                        Expr const *Ex,
+                                        const MemRegion *sReg) {
+  ID.AddPointer(Ex);
+  ID.AddPointer(sReg);
+}
+
+void CXXTempObjectRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+  ProfileRegion(ID, Ex, getSuperRegion());
+}
+
+void CXXLifetimeExtendedObjectRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
+                                                    const Expr *E,
+                                                    const ValueDecl *D,
+                                                    const MemRegion *sReg) {
+  ID.AddPointer(E);
+  ID.AddPointer(D);
+  ID.AddPointer(sReg);
+}
+
+void CXXLifetimeExtendedObjectRegion::Profile(
+    llvm::FoldingSetNodeID &ID) const {
+  ProfileRegion(ID, Ex, ExD, getSuperRegion());
+}
+
+void CXXBaseObjectRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
+                                        const CXXRecordDecl *RD,
+                                        bool IsVirtual,
+                                        const MemRegion *SReg) {
+  ID.AddPointer(RD);
+  ID.AddBoolean(IsVirtual);
+  ID.AddPointer(SReg);
+}
+
+void CXXBaseObjectRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+  ProfileRegion(ID, getDecl(), isVirtual(), superRegion);
+}
+
+void CXXDerivedObjectRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
+                                           const CXXRecordDecl *RD,
+                                           const MemRegion *SReg) {
+  ID.AddPointer(RD);
+  ID.AddPointer(SReg);
+}
+
+void CXXDerivedObjectRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+  ProfileRegion(ID, getDecl(), superRegion);
+}
+
+//===----------------------------------------------------------------------===//
+// Region anchors.
+//===----------------------------------------------------------------------===//
+
+void GlobalsSpaceRegion::anchor() {}
+
+void NonStaticGlobalSpaceRegion::anchor() {}
+
+void StackSpaceRegion::anchor() {}
+
+void TypedRegion::anchor() {}
+
+void TypedValueRegion::anchor() {}
+
+void CodeTextRegion::anchor() {}
+
+void SubRegion::anchor() {}
+
+//===----------------------------------------------------------------------===//
+// Region pretty-printing.
+//===----------------------------------------------------------------------===//
+
+LLVM_DUMP_METHOD void MemRegion::dump() const {
+  dumpToStream(llvm::errs());
+}
+
+std::string MemRegion::getString() const {
+  std::string s;
+  llvm::raw_string_ostream os(s);
+  dumpToStream(os);
+  return s;
+}
+
+void MemRegion::dumpToStream(raw_ostream &os) const {
+  os << "<Unknown Region>";
+}
+
+void AllocaRegion::dumpToStream(raw_ostream &os) const {
+  os << "alloca{S" << Ex->getID(getContext()) << ',' << Cnt << '}';
+}
+
+void FunctionCodeRegion::dumpToStream(raw_ostream &os) const {
+  os << "code{" << getDecl()->getDeclName().getAsString() << '}';
+}
+
+void BlockCodeRegion::dumpToStream(raw_ostream &os) const {
+  os << "block_code{" << static_cast<const void *>(this) << '}';
+}
+
+void BlockDataRegion::dumpToStream(raw_ostream &os) const {
+  os << "block_data{" << BC;
+  os << "; ";
+  for (auto Var : referenced_vars())
+    os << "(" << Var.getCapturedRegion() << "<-" << Var.getOriginalRegion()
+       << ") ";
+  os << '}';
+}
+
+void CompoundLiteralRegion::dumpToStream(raw_ostream &os) const {
+  // FIXME: More elaborate pretty-printing.
+  os << "{ S" << CL->getID(getContext()) <<  " }";
+}
+
+void CXXTempObjectRegion::dumpToStream(raw_ostream &os) const {
+  os << "temp_object{" << getValueType() << ", "
+     << "S" << Ex->getID(getContext()) << '}';
+}
+
+void CXXLifetimeExtendedObjectRegion::dumpToStream(raw_ostream &os) const {
+  os << "lifetime_extended_object{" << getValueType() << ", ";
+  if (const IdentifierInfo *ID = ExD->getIdentifier())
+    os << ID->getName();
+  else
+    os << "D" << ExD->getID();
+  os << ", "
+     << "S" << Ex->getID(getContext()) << '}';
+}
+
+void CXXBaseObjectRegion::dumpToStream(raw_ostream &os) const {
+  os << "Base{" << superRegion << ',' << getDecl()->getName() << '}';
+}
+
+void CXXDerivedObjectRegion::dumpToStream(raw_ostream &os) const {
+  os << "Derived{" << superRegion << ',' << getDecl()->getName() << '}';
+}
+
+void CXXThisRegion::dumpToStream(raw_ostream &os) const {
+  os << "this";
+}
+
+void ElementRegion::dumpToStream(raw_ostream &os) const {
+  os << "Element{" << superRegion << ',' << Index << ',' << getElementType()
+     << '}';
+}
+
+void FieldRegion::dumpToStream(raw_ostream &os) const {
+  os << superRegion << "." << *getDecl();
+}
+
+void ObjCIvarRegion::dumpToStream(raw_ostream &os) const {
+  os << "Ivar{" << superRegion << ',' << *getDecl() << '}';
+}
+
+void StringRegion::dumpToStream(raw_ostream &os) const {
+  assert(Str != nullptr && "Expecting non-null StringLiteral");
+  Str->printPretty(os, nullptr, PrintingPolicy(getContext().getLangOpts()));
+}
+
+void ObjCStringRegion::dumpToStream(raw_ostream &os) const {
+  assert(Str != nullptr && "Expecting non-null ObjCStringLiteral");
+  Str->printPretty(os, nullptr, PrintingPolicy(getContext().getLangOpts()));
+}
+
+void SymbolicRegion::dumpToStream(raw_ostream &os) const {
+  if (isa<HeapSpaceRegion>(getSuperRegion()))
+    os << "Heap";
+  os << "SymRegion{" << sym << '}';
+}
+
+void NonParamVarRegion::dumpToStream(raw_ostream &os) const {
+  if (const IdentifierInfo *ID = VD->getIdentifier())
+    os << ID->getName();
+  else
+    os << "NonParamVarRegion{D" << VD->getID() << '}';
+}
+
+LLVM_DUMP_METHOD void RegionRawOffset::dump() const {
+  dumpToStream(llvm::errs());
+}
+
+void RegionRawOffset::dumpToStream(raw_ostream &os) const {
+  os << "raw_offset{" << getRegion() << ',' << getOffset().getQuantity() << '}';
+}
+
+void CodeSpaceRegion::dumpToStream(raw_ostream &os) const {
+  os << "CodeSpaceRegion";
+}
+
+void StaticGlobalSpaceRegion::dumpToStream(raw_ostream &os) const {
+  os << "StaticGlobalsMemSpace{" << CR << '}';
+}
+
+void GlobalInternalSpaceRegion::dumpToStream(raw_ostream &os) const {
+  os << "GlobalInternalSpaceRegion";
+}
+
+void GlobalSystemSpaceRegion::dumpToStream(raw_ostream &os) const {
+  os << "GlobalSystemSpaceRegion";
+}
+
+void GlobalImmutableSpaceRegion::dumpToStream(raw_ostream &os) const {
+  os << "GlobalImmutableSpaceRegion";
+}
+
+void HeapSpaceRegion::dumpToStream(raw_ostream &os) const {
+  os << "HeapSpaceRegion";
+}
+
+void UnknownSpaceRegion::dumpToStream(raw_ostream &os) const {
+  os << "UnknownSpaceRegion";
+}
+
+void StackArgumentsSpaceRegion::dumpToStream(raw_ostream &os) const {
+  os << "StackArgumentsSpaceRegion";
+}
+
+void StackLocalsSpaceRegion::dumpToStream(raw_ostream &os) const {
+  os << "StackLocalsSpaceRegion";
+}
+
+void ParamVarRegion::dumpToStream(raw_ostream &os) const {
+  const ParmVarDecl *PVD = getDecl();
+  assert(PVD &&
+         "`ParamVarRegion` support functions without `Decl` not implemented"
+         " yet.");
+  if (const IdentifierInfo *ID = PVD->getIdentifier()) {
+    os << ID->getName();
+  } else {
+    os << "ParamVarRegion{P" << PVD->getID() << '}';
+  }
+}
+
+bool MemRegion::canPrintPretty() const {
+  return canPrintPrettyAsExpr();
+}
+
+bool MemRegion::canPrintPrettyAsExpr() const {
+  return false;
+}
+
+StringRef MemRegion::getKindStr() const {
+  switch (getKind()) {
+#define REGION(Id, Parent)                                                     \
+  case Id##Kind:                                                               \
+    return #Id;
+#include "clang/StaticAnalyzer/Core/PathSensitive/Regions.def"
+#undef REGION
+  }
+  llvm_unreachable("Unkown kind!");
+}
+
+void MemRegion::printPretty(raw_ostream &os) const {
+  assert(canPrintPretty() && "This region cannot be printed pretty.");
+  os << "'";
+  printPrettyAsExpr(os);
+  os << "'";
+}
+
+void MemRegion::printPrettyAsExpr(raw_ostream &) const {
+  llvm_unreachable("This region cannot be printed pretty.");
+}
+
+bool NonParamVarRegion::canPrintPrettyAsExpr() const { return true; }
+
+void NonParamVarRegion::printPrettyAsExpr(raw_ostream &os) const {
+  os << getDecl()->getName();
+}
+
+bool ParamVarRegion::canPrintPrettyAsExpr() const { return true; }
+
+void ParamVarRegion::printPrettyAsExpr(raw_ostream &os) const {
+  assert(getDecl() &&
+         "`ParamVarRegion` support functions without `Decl` not implemented"
+         " yet.");
+  os << getDecl()->getName();
+}
+
+bool ObjCIvarRegion::canPrintPrettyAsExpr() const {
+  return true;
+}
+
+void ObjCIvarRegion::printPrettyAsExpr(raw_ostream &os) const {
+  os << getDecl()->getName();
+}
+
+bool FieldRegion::canPrintPretty() const {
+  return true;
+}
+
+bool FieldRegion::canPrintPrettyAsExpr() const {
+  return superRegion->canPrintPrettyAsExpr();
+}
+
+void FieldRegion::printPrettyAsExpr(raw_ostream &os) const {
+  assert(canPrintPrettyAsExpr());
+  superRegion->printPrettyAsExpr(os);
+  os << "." << getDecl()->getName();
+}
+
+void FieldRegion::printPretty(raw_ostream &os) const {
+  if (canPrintPrettyAsExpr()) {
+    os << "\'";
+    printPrettyAsExpr(os);
+    os << "'";
+  } else {
+    os << "field " << "\'" << getDecl()->getName() << "'";
+  }
+}
+
+bool CXXBaseObjectRegion::canPrintPrettyAsExpr() const {
+  return superRegion->canPrintPrettyAsExpr();
+}
+
+void CXXBaseObjectRegion::printPrettyAsExpr(raw_ostream &os) const {
+  superRegion->printPrettyAsExpr(os);
+}
+
+bool CXXDerivedObjectRegion::canPrintPrettyAsExpr() const {
+  return superRegion->canPrintPrettyAsExpr();
+}
+
+void CXXDerivedObjectRegion::printPrettyAsExpr(raw_ostream &os) const {
+  superRegion->printPrettyAsExpr(os);
+}
+
+std::string MemRegion::getDescriptiveName(bool UseQuotes) const {
+  std::string VariableName;
+  std::string ArrayIndices;
+  const MemRegion *R = this;
+  SmallString<50> buf;
+  llvm::raw_svector_ostream os(buf);
+
+  // Enclose subject with single quotes if needed.
+  auto QuoteIfNeeded = [UseQuotes](const Twine &Subject) -> std::string {
+    if (UseQuotes)
+      return ("'" + Subject + "'").str();
+    return Subject.str();
+  };
+
+  // Obtain array indices to add them to the variable name.
+  const ElementRegion *ER = nullptr;
+  while ((ER = R->getAs<ElementRegion>())) {
+    // Index is a ConcreteInt.
+    if (auto CI = ER->getIndex().getAs<nonloc::ConcreteInt>()) {
+      llvm::SmallString<2> Idx;
+      CI->getValue()->toString(Idx);
+      ArrayIndices = (llvm::Twine("[") + Idx.str() + "]" + ArrayIndices).str();
+    }
+    // Index is symbolic, but may have a descriptive name.
+    else {
+      auto SI = ER->getIndex().getAs<nonloc::SymbolVal>();
+      if (!SI)
+        return "";
+
+      const MemRegion *OR = SI->getAsSymbol()->getOriginRegion();
+      if (!OR)
+        return "";
+
+      std::string Idx = OR->getDescriptiveName(false);
+      if (Idx.empty())
+        return "";
+
+      ArrayIndices = (llvm::Twine("[") + Idx + "]" + ArrayIndices).str();
+    }
+    R = ER->getSuperRegion();
+  }
+
+  // Get variable name.
+  if (R) {
+    // MemRegion can be pretty printed.
+    if (R->canPrintPrettyAsExpr()) {
+      R->printPrettyAsExpr(os);
+      return QuoteIfNeeded(llvm::Twine(os.str()) + ArrayIndices);
+    }
+
+    // FieldRegion may have ElementRegion as SuperRegion.
+    if (const auto *FR = R->getAs<FieldRegion>()) {
+      std::string Super = FR->getSuperRegion()->getDescriptiveName(false);
+      if (Super.empty())
+        return "";
+      return QuoteIfNeeded(Super + "." + FR->getDecl()->getName());
+    }
+  }
+
+  return VariableName;
+}
+
+SourceRange MemRegion::sourceRange() const {
+  // Check for more specific regions first.
+  if (auto *FR = dyn_cast<FieldRegion>(this)) {
+    return FR->getDecl()->getSourceRange();
+  }
+
+  if (auto *VR = dyn_cast<VarRegion>(this->getBaseRegion())) {
+    return VR->getDecl()->getSourceRange();
+  }
+
+  // Return invalid source range (can be checked by client).
+  return {};
+}
+
+//===----------------------------------------------------------------------===//
+// MemRegionManager methods.
+//===----------------------------------------------------------------------===//
+
+DefinedOrUnknownSVal MemRegionManager::getStaticSize(const MemRegion *MR,
+                                                     SValBuilder &SVB) const {
+  const auto *SR = cast<SubRegion>(MR);
+  SymbolManager &SymMgr = SVB.getSymbolManager();
+
+  switch (SR->getKind()) {
+  case MemRegion::AllocaRegionKind:
+  case MemRegion::SymbolicRegionKind:
+    return nonloc::SymbolVal(SymMgr.getExtentSymbol(SR));
+  case MemRegion::StringRegionKind:
+    return SVB.makeIntVal(
+        cast<StringRegion>(SR)->getStringLiteral()->getByteLength() + 1,
+        SVB.getArrayIndexType());
+  case MemRegion::CompoundLiteralRegionKind:
+  case MemRegion::CXXBaseObjectRegionKind:
+  case MemRegion::CXXDerivedObjectRegionKind:
+  case MemRegion::CXXTempObjectRegionKind:
+  case MemRegion::CXXLifetimeExtendedObjectRegionKind:
+  case MemRegion::CXXThisRegionKind:
+  case MemRegion::ObjCIvarRegionKind:
+  case MemRegion::NonParamVarRegionKind:
+  case MemRegion::ParamVarRegionKind:
+  case MemRegion::ElementRegionKind:
+  case MemRegion::ObjCStringRegionKind: {
+    QualType Ty = cast<TypedValueRegion>(SR)->getDesugaredValueType(Ctx);
+    if (isa<VariableArrayType>(Ty))
+      return nonloc::SymbolVal(SymMgr.getExtentSymbol(SR));
+
+    if (Ty->isIncompleteType())
+      return UnknownVal();
+
+    return getElementExtent(Ty, SVB);
+  }
+  case MemRegion::FieldRegionKind: {
+    // Force callers to deal with bitfields explicitly.
+    if (cast<FieldRegion>(SR)->getDecl()->isBitField())
+      return UnknownVal();
+
+    QualType Ty = cast<TypedValueRegion>(SR)->getDesugaredValueType(Ctx);
+    const DefinedOrUnknownSVal Size = getElementExtent(Ty, SVB);
+
+    // We currently don't model flexible array members (FAMs), which are:
+    //  - int array[]; of IncompleteArrayType
+    //  - int array[0]; of ConstantArrayType with size 0
+    //  - int array[1]; of ConstantArrayType with size 1
+    // https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
+    const auto isFlexibleArrayMemberCandidate =
+        [this](const ArrayType *AT) -> bool {
+      if (!AT)
+        return false;
+
+      auto IsIncompleteArray = [](const ArrayType *AT) {
+        return isa<IncompleteArrayType>(AT);
+      };
+      auto IsArrayOfZero = [](const ArrayType *AT) {
+        const auto *CAT = dyn_cast<ConstantArrayType>(AT);
+        return CAT && CAT->isZeroSize();
+      };
+      auto IsArrayOfOne = [](const ArrayType *AT) {
+        const auto *CAT = dyn_cast<ConstantArrayType>(AT);
+        return CAT && CAT->getSize() == 1;
+      };
+
+      using FAMKind = LangOptions::StrictFlexArraysLevelKind;
+      const FAMKind StrictFlexArraysLevel =
+          Ctx.getLangOpts().getStrictFlexArraysLevel();
+
+      // "Default": Any trailing array member is a FAM.
+      // Since we cannot tell at this point if this array is a trailing member
+      // or not, let's just do the same as for "OneZeroOrIncomplete".
+      if (StrictFlexArraysLevel == FAMKind::Default)
+        return IsArrayOfOne(AT) || IsArrayOfZero(AT) || IsIncompleteArray(AT);
+
+      if (StrictFlexArraysLevel == FAMKind::OneZeroOrIncomplete)
+        return IsArrayOfOne(AT) || IsArrayOfZero(AT) || IsIncompleteArray(AT);
+
+      if (StrictFlexArraysLevel == FAMKind::ZeroOrIncomplete)
+        return IsArrayOfZero(AT) || IsIncompleteArray(AT);
+
+      assert(StrictFlexArraysLevel == FAMKind::IncompleteOnly);
+      return IsIncompleteArray(AT);
+    };
+
+    if (isFlexibleArrayMemberCandidate(Ctx.getAsArrayType(Ty)))
+      return UnknownVal();
+
+    return Size;
+  }
+    // FIXME: The following are being used in 'SimpleSValBuilder' and in
+    // 'ArrayBoundChecker::checkLocation' because there is no symbol to
+    // represent the regions more appropriately.
+  case MemRegion::BlockDataRegionKind:
+  case MemRegion::BlockCodeRegionKind:
+  case MemRegion::FunctionCodeRegionKind:
+    return nonloc::SymbolVal(SymMgr.getExtentSymbol(SR));
+  default:
+    llvm_unreachable("Unhandled region");
+  }
+}
+
+template <typename REG>
+const REG *MemRegionManager::LazyAllocate(REG*& region) {
+  if (!region) {
+    region = new (A) REG(*this);
+  }
+
+  return region;
+}
+
+template <typename REG, typename ARG>
+const REG *MemRegionManager::LazyAllocate(REG*& region, ARG a) {
+  if (!region) {
+    region = new (A) REG(this, a);
+  }
+
+  return region;
+}
+
+const StackLocalsSpaceRegion*
+MemRegionManager::getStackLocalsRegion(const StackFrameContext *STC) {
+  assert(STC);
+  StackLocalsSpaceRegion *&R = StackLocalsSpaceRegions[STC];
+
+  if (R)
+    return R;
+
+  R = new (A) StackLocalsSpaceRegion(*this, STC);
+  return R;
+}
+
+const StackArgumentsSpaceRegion *
+MemRegionManager::getStackArgumentsRegion(const StackFrameContext *STC) {
+  assert(STC);
+  StackArgumentsSpaceRegion *&R = StackArgumentsSpaceRegions[STC];
+
+  if (R)
+    return R;
+
+  R = new (A) StackArgumentsSpaceRegion(*this, STC);
+  return R;
+}
+
+const GlobalsSpaceRegion
+*MemRegionManager::getGlobalsRegion(MemRegion::Kind K,
+                                    const CodeTextRegion *CR) {
+  if (!CR) {
+    if (K == MemRegion::GlobalSystemSpaceRegionKind)
+      return LazyAllocate(SystemGlobals);
+    if (K == MemRegion::GlobalImmutableSpaceRegionKind)
+      return LazyAllocate(ImmutableGlobals);
+    assert(K == MemRegion::GlobalInternalSpaceRegionKind);
+    return LazyAllocate(InternalGlobals);
+  }
+
+  assert(K == MemRegion::StaticGlobalSpaceRegionKind);
+  StaticGlobalSpaceRegion *&R = StaticsGlobalSpaceRegions[CR];
+  if (R)
+    return R;
+
+  R = new (A) StaticGlobalSpaceRegion(*this, CR);
+  return R;
+}
+
+const HeapSpaceRegion *MemRegionManager::getHeapRegion() {
+  return LazyAllocate(heap);
+}
+
+const UnknownSpaceRegion *MemRegionManager::getUnknownRegion() {
+  return LazyAllocate(unknown);
+}
+
+const CodeSpaceRegion *MemRegionManager::getCodeRegion() {
+  return LazyAllocate(code);
+}
+
+//===----------------------------------------------------------------------===//
+// Constructing regions.
+//===----------------------------------------------------------------------===//
+
+const StringRegion *MemRegionManager::getStringRegion(const StringLiteral *Str){
+  return getSubRegion<StringRegion>(
+      Str, cast<GlobalInternalSpaceRegion>(getGlobalsRegion()));
+}
+
+const ObjCStringRegion *
+MemRegionManager::getObjCStringRegion(const ObjCStringLiteral *Str){
+  return getSubRegion<ObjCStringRegion>(
+      Str, cast<GlobalInternalSpaceRegion>(getGlobalsRegion()));
+}
+
+/// Look through a chain of LocationContexts to either find the
+/// StackFrameContext that matches a DeclContext, or find a VarRegion
+/// for a variable captured by a block.
+static llvm::PointerUnion<const StackFrameContext *, const VarRegion *>
+getStackOrCaptureRegionForDeclContext(const LocationContext *LC,
+                                      const DeclContext *DC,
+                                      const VarDecl *VD) {
+  while (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());
+        }
+      }
+    }
+
+    LC = LC->getParent();
+  }
+  return (const StackFrameContext *)nullptr;
+}
+
+const VarRegion *MemRegionManager::getVarRegion(const VarDecl *D,
+                                                const LocationContext *LC) {
+  const auto *PVD = dyn_cast<ParmVarDecl>(D);
+  if (PVD) {
+    unsigned Index = PVD->getFunctionScopeIndex();
+    const StackFrameContext *SFC = LC->getStackFrame();
+    const Stmt *CallSite = SFC->getCallSite();
+    if (CallSite) {
+      const Decl *D = SFC->getDecl();
+      if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
+        if (Index < FD->param_size() && FD->parameters()[Index] == PVD)
+          return getSubRegion<ParamVarRegion>(cast<Expr>(CallSite), Index,
+                                              getStackArgumentsRegion(SFC));
+      } else if (const auto *BD = dyn_cast<BlockDecl>(D)) {
+        if (Index < BD->param_size() && BD->parameters()[Index] == PVD)
+          return getSubRegion<ParamVarRegion>(cast<Expr>(CallSite), Index,
+                                              getStackArgumentsRegion(SFC));
+      } else {
+        return getSubRegion<ParamVarRegion>(cast<Expr>(CallSite), Index,
+                                            getStackArgumentsRegion(SFC));
+      }
+    }
+  }
+
+  D = D->getCanonicalDecl();
+  const MemRegion *sReg = nullptr;
+
+  if (D->hasGlobalStorage() && !D->isStaticLocal()) {
+    QualType Ty = D->getType();
+    assert(!Ty.isNull());
+    if (Ty.isConstQualified()) {
+      sReg = getGlobalsRegion(MemRegion::GlobalImmutableSpaceRegionKind);
+    } else if (Ctx.getSourceManager().isInSystemHeader(D->getLocation())) {
+      sReg = getGlobalsRegion(MemRegion::GlobalSystemSpaceRegionKind);
+    } else {
+      sReg = getGlobalsRegion(MemRegion::GlobalInternalSpaceRegionKind);
+    }
+
+  // Finally handle static locals.
+  } else {
+    // FIXME: Once we implement scope handling, we will need to properly lookup
+    // 'D' to the proper LocationContext.
+    const DeclContext *DC = D->getDeclContext();
+    llvm::PointerUnion<const StackFrameContext *, const VarRegion *> V =
+      getStackOrCaptureRegionForDeclContext(LC, DC, D);
+
+    if (const auto *VR = dyn_cast_if_present<const VarRegion *>(V))
+      return VR;
+
+    const auto *STC = cast<const StackFrameContext *>(V);
+
+    if (!STC) {
+      // FIXME: Assign a more sensible memory space to static locals
+      // we see from within blocks that we analyze as top-level declarations.
+      sReg = getUnknownRegion();
+    } else {
+      if (D->hasLocalStorage()) {
+        sReg =
+            isa<ParmVarDecl, ImplicitParamDecl>(D)
+                ? static_cast<const MemRegion *>(getStackArgumentsRegion(STC))
+                : static_cast<const MemRegion *>(getStackLocalsRegion(STC));
+      }
+      else {
+        assert(D->isStaticLocal());
+        const Decl *STCD = STC->getDecl();
+        if (isa<FunctionDecl, ObjCMethodDecl>(STCD))
+          sReg = getGlobalsRegion(MemRegion::StaticGlobalSpaceRegionKind,
+                                  getFunctionCodeRegion(cast<NamedDecl>(STCD)));
+        else if (const auto *BD = dyn_cast<BlockDecl>(STCD)) {
+          // FIXME: The fallback type here is totally bogus -- though it should
+          // never be queried, it will prevent uniquing with the real
+          // BlockCodeRegion. Ideally we'd fix the AST so that we always had a
+          // signature.
+          QualType T;
+          if (const TypeSourceInfo *TSI = BD->getSignatureAsWritten())
+            T = TSI->getType();
+          if (T.isNull())
+            T = getContext().VoidTy;
+          if (!T->getAs<FunctionType>()) {
+            FunctionProtoType::ExtProtoInfo Ext;
+            T = getContext().getFunctionType(T, {}, Ext);
+          }
+          T = getContext().getBlockPointerType(T);
+
+          const BlockCodeRegion *BTR =
+            getBlockCodeRegion(BD, Ctx.getCanonicalType(T),
+                               STC->getAnalysisDeclContext());
+          sReg = getGlobalsRegion(MemRegion::StaticGlobalSpaceRegionKind,
+                                  BTR);
+        }
+        else {
+          sReg = getGlobalsRegion();
+        }
+      }
+    }
+  }
+
+  return getNonParamVarRegion(D, sReg);
+}
+
+const NonParamVarRegion *
+MemRegionManager::getNonParamVarRegion(const VarDecl *D,
+                                       const MemRegion *superR) {
+  // Prefer the definition over the canonical decl as the canonical form.
+  D = D->getCanonicalDecl();
+  if (const VarDecl *Def = D->getDefinition())
+    D = Def;
+  return getSubRegion<NonParamVarRegion>(D, superR);
+}
+
+const ParamVarRegion *
+MemRegionManager::getParamVarRegion(const Expr *OriginExpr, unsigned Index,
+                                    const LocationContext *LC) {
+  const StackFrameContext *SFC = LC->getStackFrame();
+  assert(SFC);
+  return getSubRegion<ParamVarRegion>(OriginExpr, Index,
+                                      getStackArgumentsRegion(SFC));
+}
+
+const BlockDataRegion *
+MemRegionManager::getBlockDataRegion(const BlockCodeRegion *BC,
+                                     const LocationContext *LC,
+                                     unsigned blockCount) {
+  const MemSpaceRegion *sReg = nullptr;
+  const BlockDecl *BD = BC->getDecl();
+  if (!BD->hasCaptures()) {
+    // This handles 'static' blocks.
+    sReg = getGlobalsRegion(MemRegion::GlobalImmutableSpaceRegionKind);
+  }
+  else {
+    bool IsArcManagedBlock = Ctx.getLangOpts().ObjCAutoRefCount;
+
+    // ARC managed blocks can be initialized on stack or directly in heap
+    // depending on the implementations.  So we initialize them with
+    // UnknownRegion.
+    if (!IsArcManagedBlock && LC) {
+      // FIXME: Once we implement scope handling, we want the parent region
+      // to be the scope.
+      const StackFrameContext *STC = LC->getStackFrame();
+      assert(STC);
+      sReg = getStackLocalsRegion(STC);
+    } else {
+      // We allow 'LC' to be NULL for cases where want BlockDataRegions
+      // without context-sensitivity.
+      sReg = getUnknownRegion();
+    }
+  }
+
+  return getSubRegion<BlockDataRegion>(BC, LC, blockCount, sReg);
+}
+
+const CompoundLiteralRegion*
+MemRegionManager::getCompoundLiteralRegion(const CompoundLiteralExpr *CL,
+                                           const LocationContext *LC) {
+  const MemSpaceRegion *sReg = nullptr;
+
+  if (CL->isFileScope())
+    sReg = getGlobalsRegion();
+  else {
+    const StackFrameContext *STC = LC->getStackFrame();
+    assert(STC);
+    sReg = getStackLocalsRegion(STC);
+  }
+
+  return getSubRegion<CompoundLiteralRegion>(CL, sReg);
+}
+
+const ElementRegion *
+MemRegionManager::getElementRegion(QualType elementType, NonLoc Idx,
+                                   const SubRegion *superRegion,
+                                   const ASTContext &Ctx) {
+  QualType T = Ctx.getCanonicalType(elementType).getUnqualifiedType();
+
+  llvm::FoldingSetNodeID ID;
+  ElementRegion::ProfileRegion(ID, T, Idx, superRegion);
+
+  void *InsertPos;
+  MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos);
+  auto *R = cast_or_null<ElementRegion>(data);
+
+  if (!R) {
+    R = new (A) ElementRegion(T, Idx, superRegion);
+    Regions.InsertNode(R, InsertPos);
+  }
+
+  return R;
+}
+
+const FunctionCodeRegion *
+MemRegionManager::getFunctionCodeRegion(const NamedDecl *FD) {
+  // To think: should we canonicalize the declaration here?
+  return getSubRegion<FunctionCodeRegion>(FD, getCodeRegion());
+}
+
+const BlockCodeRegion *
+MemRegionManager::getBlockCodeRegion(const BlockDecl *BD, CanQualType locTy,
+                                     AnalysisDeclContext *AC) {
+  return getSubRegion<BlockCodeRegion>(BD, locTy, AC, getCodeRegion());
+}
+
+const SymbolicRegion *
+MemRegionManager::getSymbolicRegion(SymbolRef sym,
+                                    const MemSpaceRegion *MemSpace) {
+  if (MemSpace == nullptr)
+    MemSpace = getUnknownRegion();
+  return getSubRegion<SymbolicRegion>(sym, MemSpace);
+}
+
+const SymbolicRegion *MemRegionManager::getSymbolicHeapRegion(SymbolRef Sym) {
+  return getSubRegion<SymbolicRegion>(Sym, getHeapRegion());
+}
+
+const FieldRegion*
+MemRegionManager::getFieldRegion(const FieldDecl *d,
+                                 const SubRegion* superRegion){
+  return getSubRegion<FieldRegion>(d, superRegion);
+}
+
+const ObjCIvarRegion*
+MemRegionManager::getObjCIvarRegion(const ObjCIvarDecl *d,
+                                    const SubRegion* superRegion) {
+  return getSubRegion<ObjCIvarRegion>(d, superRegion);
+}
+
+const CXXTempObjectRegion*
+MemRegionManager::getCXXTempObjectRegion(Expr const *E,
+                                         LocationContext const *LC) {
+  const StackFrameContext *SFC = LC->getStackFrame();
+  assert(SFC);
+  return getSubRegion<CXXTempObjectRegion>(E, getStackLocalsRegion(SFC));
+}
+
+const CXXLifetimeExtendedObjectRegion *
+MemRegionManager::getCXXLifetimeExtendedObjectRegion(
+    const Expr *Ex, const ValueDecl *VD, const LocationContext *LC) {
+  const StackFrameContext *SFC = LC->getStackFrame();
+  assert(SFC);
+  return getSubRegion<CXXLifetimeExtendedObjectRegion>(
+      Ex, VD, getStackLocalsRegion(SFC));
+}
+
+const CXXLifetimeExtendedObjectRegion *
+MemRegionManager::getCXXStaticLifetimeExtendedObjectRegion(
+    const Expr *Ex, const ValueDecl *VD) {
+  return getSubRegion<CXXLifetimeExtendedObjectRegion>(
+      Ex, VD,
+      getGlobalsRegion(MemRegion::GlobalInternalSpaceRegionKind, nullptr));
+}
+
+/// Checks whether \p BaseClass is a valid virtual or direct non-virtual base
+/// class of the type of \p Super.
+static bool isValidBaseClass(const CXXRecordDecl *BaseClass,
+                             const TypedValueRegion *Super,
+                             bool IsVirtual) {
+  BaseClass = BaseClass->getCanonicalDecl();
+
+  const CXXRecordDecl *Class = Super->getValueType()->getAsCXXRecordDecl();
+  if (!Class)
+    return true;
+
+  if (IsVirtual)
+    return Class->isVirtuallyDerivedFrom(BaseClass);
+
+  for (const auto &I : Class->bases()) {
+    if (I.getType()->getAsCXXRecordDecl()->getCanonicalDecl() == BaseClass)
+      return true;
+  }
+
+  return false;
+}
+
+const CXXBaseObjectRegion *
+MemRegionManager::getCXXBaseObjectRegion(const CXXRecordDecl *RD,
+                                         const SubRegion *Super,
+                                         bool IsVirtual) {
+  if (isa<TypedValueRegion>(Super)) {
+    assert(isValidBaseClass(RD, cast<TypedValueRegion>(Super), IsVirtual));
+    (void)&isValidBaseClass;
+
+    if (IsVirtual) {
+      // Virtual base regions should not be layered, since the layout rules
+      // are different.
+      while (const auto *Base = dyn_cast<CXXBaseObjectRegion>(Super))
+        Super = cast<SubRegion>(Base->getSuperRegion());
+      assert(Super && !isa<MemSpaceRegion>(Super));
+    }
+  }
+
+  return getSubRegion<CXXBaseObjectRegion>(RD, IsVirtual, Super);
+}
+
+const CXXDerivedObjectRegion *
+MemRegionManager::getCXXDerivedObjectRegion(const CXXRecordDecl *RD,
+                                            const SubRegion *Super) {
+  return getSubRegion<CXXDerivedObjectRegion>(RD, Super);
+}
+
+const CXXThisRegion*
+MemRegionManager::getCXXThisRegion(QualType thisPointerTy,
+                                   const LocationContext *LC) {
+  const auto *PT = thisPointerTy->getAs<PointerType>();
+  assert(PT);
+  // Inside the body of the operator() of a lambda a this expr might refer to an
+  // object in one of the parent location contexts.
+  const auto *D = dyn_cast<CXXMethodDecl>(LC->getDecl());
+  // FIXME: when operator() of lambda is analyzed as a top level function and
+  // 'this' refers to a this to the enclosing scope, there is no right region to
+  // return.
+  while (!LC->inTopFrame() && (!D || D->isStatic() ||
+                               PT != D->getThisType()->getAs<PointerType>())) {
+    LC = LC->getParent();
+    D = dyn_cast<CXXMethodDecl>(LC->getDecl());
+  }
+  const StackFrameContext *STC = LC->getStackFrame();
+  assert(STC);
+  return getSubRegion<CXXThisRegion>(PT, getStackArgumentsRegion(STC));
+}
+
+const AllocaRegion*
+MemRegionManager::getAllocaRegion(const Expr *E, unsigned cnt,
+                                  const LocationContext *LC) {
+  const StackFrameContext *STC = LC->getStackFrame();
+  assert(STC);
+  return getSubRegion<AllocaRegion>(E, cnt, getStackLocalsRegion(STC));
+}
+
+const MemSpaceRegion *MemRegion::getRawMemorySpace() const {
+  const MemRegion *R = this;
+  const auto *SR = dyn_cast<SubRegion>(this);
+
+  while (SR) {
+    R = SR->getSuperRegion();
+    SR = dyn_cast<SubRegion>(R);
+  }
+
+  return cast<MemSpaceRegion>(R);
+}
+
+const MemSpaceRegion *MemRegion::getMemorySpace(ProgramStateRef State) const {
+  const MemRegion *MR = getBaseRegion();
+
+  const MemSpaceRegion *MS = MR->getRawMemorySpace();
+  if (!isa<UnknownSpaceRegion>(MS))
+    return MS;
+    
+  const MemSpaceRegion *const *Result = State->get<MemSpacesMap>(MR);
+  return Result ? *Result : MS;
+}
+
+ProgramStateRef MemRegion::setMemSpaceTrait(ProgramStateRef State, const MemSpaceRegion *MS) const {
+  const MemRegion *MR = getBaseRegion();
+
+  // For now, this should only be called to update the trait for memory regions
+  // that have an unknown memory spaces since we assume everywhere else that the
+  // memory space trait is set only for unknown memory spaces (setting this info
+  // otherwise would go unused).
+  assert(isa<UnknownSpaceRegion>(MR->getRawMemorySpace()));
+
+  // Shouldn't use the memory space trait to associate UnknownSpaceRegion with
+  // an already UnknownSpaceRegion
+  assert(!isa<UnknownSpaceRegion>(MS));
+
+  ProgramStateRef NewState = State->set<MemSpacesMap>(MR, MS);
+  return NewState;
+}
+
+bool MemRegion::hasRawStackStorage() const {
+  return isa<StackSpaceRegion>(getRawMemorySpace());
+}
+
+bool MemRegion::hasStackStorage(ProgramStateRef State) const { 
+  return isMemorySpace<StackSpaceRegion>(State); 
+}
+
+bool MemRegion::hasRawStackNonParametersStorage() const {
+  return isa<StackLocalsSpaceRegion>(getRawMemorySpace());
+}
+
+bool MemRegion::hasStackNonParametersStorage(ProgramStateRef State) const {
+  return isMemorySpace<StackLocalsSpaceRegion>(State);
+}
+
+bool MemRegion::hasRawStackParametersStorage() const {
+  return isa<StackArgumentsSpaceRegion>(getRawMemorySpace());
+}
+
+bool MemRegion::hasStackParametersStorage(ProgramStateRef State) const {
+  return isMemorySpace<StackArgumentsSpaceRegion>(State);
+}
+
+// Strips away all elements and fields.
+// Returns the base region of them.
+const MemRegion *MemRegion::getBaseRegion() const {
+  const MemRegion *R = this;
+  while (true) {
+    switch (R->getKind()) {
+      case MemRegion::ElementRegionKind:
+      case MemRegion::FieldRegionKind:
+      case MemRegion::ObjCIvarRegionKind:
+      case MemRegion::CXXBaseObjectRegionKind:
+      case MemRegion::CXXDerivedObjectRegionKind:
+        R = cast<SubRegion>(R)->getSuperRegion();
+        continue;
+      default:
+        break;
+    }
+    break;
+  }
+  return R;
+}
+
+// Returns the region of the root class of a C++ class hierarchy.
+const MemRegion *MemRegion::getMostDerivedObjectRegion() const {
+  const MemRegion *R = this;
+  while (const auto *BR = dyn_cast<CXXBaseObjectRegion>(R))
+    R = BR->getSuperRegion();
+  return R;
+}
+
+bool MemRegion::isSubRegionOf(const MemRegion *) const {
+  return false;
+}
+
+//===----------------------------------------------------------------------===//
+// View handling.
+//===----------------------------------------------------------------------===//
+
+const MemRegion *MemRegion::StripCasts(bool StripBaseAndDerivedCasts) const {
+  const MemRegion *R = this;
+  while (true) {
+    switch (R->getKind()) {
+    case ElementRegionKind: {
+      const auto *ER = cast<ElementRegion>(R);
+      if (!ER->getIndex().isZeroConstant())
+        return R;
+      R = ER->getSuperRegion();
+      break;
+    }
+    case CXXBaseObjectRegionKind:
+    case CXXDerivedObjectRegionKind:
+      if (!StripBaseAndDerivedCasts)
+        return R;
+      R = cast<TypedValueRegion>(R)->getSuperRegion();
+      break;
+    default:
+      return R;
+    }
+  }
+}
+
+const SymbolicRegion *MemRegion::getSymbolicBase() const {
+  const auto *SubR = dyn_cast<SubRegion>(this);
+
+  while (SubR) {
+    if (const auto *SymR = dyn_cast<SymbolicRegion>(SubR))
+      return SymR;
+    SubR = dyn_cast<SubRegion>(SubR->getSuperRegion());
+  }
+  return nullptr;
+}
+
+RegionRawOffset ElementRegion::getAsArrayOffset() const {
+  int64_t offset = 0;
+  const ElementRegion *ER = this;
+  const MemRegion *superR = nullptr;
+  ASTContext &C = getContext();
+
+  // FIXME: Handle multi-dimensional arrays.
+
+  while (ER) {
+    superR = ER->getSuperRegion();
+
+    // FIXME: generalize to symbolic offsets.
+    SVal index = ER->getIndex();
+    if (auto CI = index.getAs<nonloc::ConcreteInt>()) {
+      // Update the offset.
+      if (int64_t i = CI->getValue()->getSExtValue(); i != 0) {
+        QualType elemType = ER->getElementType();
+
+        // If we are pointing to an incomplete type, go no further.
+        if (elemType->isIncompleteType()) {
+          superR = ER;
+          break;
+        }
+
+        int64_t size = C.getTypeSizeInChars(elemType).getQuantity();
+        if (auto NewOffset = llvm::checkedMulAdd(i, size, offset)) {
+          offset = *NewOffset;
+        } else {
+          LLVM_DEBUG(llvm::dbgs() << "MemRegion::getAsArrayOffset: "
+                                  << "offset overflowing, returning unknown\n");
+
+          return nullptr;
+        }
+      }
+
+      // Go to the next ElementRegion (if any).
+      ER = dyn_cast<ElementRegion>(superR);
+      continue;
+    }
+
+    return nullptr;
+  }
+
+  assert(superR && "super region cannot be NULL");
+  return RegionRawOffset(superR, CharUnits::fromQuantity(offset));
+}
+
+/// Returns true if \p Base is an immediate base class of \p Child
+static bool isImmediateBase(const CXXRecordDecl *Child,
+                            const CXXRecordDecl *Base) {
+  assert(Child && "Child must not be null");
+  // Note that we do NOT canonicalize the base class here, because
+  // ASTRecordLayout doesn't either. If that leads us down the wrong path,
+  // so be it; at least we won't crash.
+  for (const auto &I : Child->bases()) {
+    if (I.getType()->getAsCXXRecordDecl() == Base)
+      return true;
+  }
+
+  return false;
+}
+
+static RegionOffset calculateOffset(const MemRegion *R) {
+  const MemRegion *SymbolicOffsetBase = nullptr;
+  int64_t Offset = 0;
+
+  while (true) {
+    switch (R->getKind()) {
+    case MemRegion::CodeSpaceRegionKind:
+    case MemRegion::StackLocalsSpaceRegionKind:
+    case MemRegion::StackArgumentsSpaceRegionKind:
+    case MemRegion::HeapSpaceRegionKind:
+    case MemRegion::UnknownSpaceRegionKind:
+    case MemRegion::StaticGlobalSpaceRegionKind:
+    case MemRegion::GlobalInternalSpaceRegionKind:
+    case MemRegion::GlobalSystemSpaceRegionKind:
+    case MemRegion::GlobalImmutableSpaceRegionKind:
+      // Stores can bind directly to a region space to set a default value.
+      assert(Offset == 0 && !SymbolicOffsetBase);
+      goto Finish;
+
+    case MemRegion::FunctionCodeRegionKind:
+    case MemRegion::BlockCodeRegionKind:
+    case MemRegion::BlockDataRegionKind:
+      // These will never have bindings, but may end up having values requested
+      // if the user does some strange casting.
+      if (Offset != 0)
+        SymbolicOffsetBase = R;
+      goto Finish;
+
+    case MemRegion::SymbolicRegionKind:
+    case MemRegion::AllocaRegionKind:
+    case MemRegion::CompoundLiteralRegionKind:
+    case MemRegion::CXXThisRegionKind:
+    case MemRegion::StringRegionKind:
+    case MemRegion::ObjCStringRegionKind:
+    case MemRegion::NonParamVarRegionKind:
+    case MemRegion::ParamVarRegionKind:
+    case MemRegion::CXXTempObjectRegionKind:
+    case MemRegion::CXXLifetimeExtendedObjectRegionKind:
+      // Usual base regions.
+      goto Finish;
+
+    case MemRegion::ObjCIvarRegionKind:
+      // This is a little strange, but it's a compromise between
+      // ObjCIvarRegions having unknown compile-time offsets (when using the
+      // non-fragile runtime) and yet still being distinct, non-overlapping
+      // regions. Thus we treat them as "like" base regions for the purposes
+      // of computing offsets.
+      goto Finish;
+
+    case MemRegion::CXXBaseObjectRegionKind: {
+      const auto *BOR = cast<CXXBaseObjectRegion>(R);
+      R = BOR->getSuperRegion();
+
+      QualType Ty;
+      bool RootIsSymbolic = false;
+      if (const auto *TVR = dyn_cast<TypedValueRegion>(R)) {
+        Ty = TVR->getDesugaredValueType(R->getContext());
+      } else if (const auto *SR = dyn_cast<SymbolicRegion>(R)) {
+        // If our base region is symbolic, we don't know what type it really is.
+        // Pretend the type of the symbol is the true dynamic type.
+        // (This will at least be self-consistent for the life of the symbol.)
+        Ty = SR->getPointeeStaticType();
+        RootIsSymbolic = true;
+      }
+
+      const CXXRecordDecl *Child = Ty->getAsCXXRecordDecl();
+      if (!Child) {
+        // We cannot compute the offset of the base class.
+        SymbolicOffsetBase = R;
+      } else {
+        if (RootIsSymbolic) {
+          // Base layers on symbolic regions may not be type-correct.
+          // Double-check the inheritance here, and revert to a symbolic offset
+          // if it's invalid (e.g. due to a reinterpret_cast).
+          if (BOR->isVirtual()) {
+            if (!Child->isVirtuallyDerivedFrom(BOR->getDecl()))
+              SymbolicOffsetBase = R;
+          } else {
+            if (!isImmediateBase(Child, BOR->getDecl()))
+              SymbolicOffsetBase = R;
+          }
+        }
+      }
+
+      // Don't bother calculating precise offsets if we already have a
+      // symbolic offset somewhere in the chain.
+      if (SymbolicOffsetBase)
+        continue;
+
+      CharUnits BaseOffset;
+      const ASTRecordLayout &Layout = R->getContext().getASTRecordLayout(Child);
+      if (BOR->isVirtual())
+        BaseOffset = Layout.getVBaseClassOffset(BOR->getDecl());
+      else
+        BaseOffset = Layout.getBaseClassOffset(BOR->getDecl());
+
+      // The base offset is in chars, not in bits.
+      Offset += BaseOffset.getQuantity() * R->getContext().getCharWidth();
+      break;
+    }
+
+    case MemRegion::CXXDerivedObjectRegionKind: {
+      // TODO: Store the base type in the CXXDerivedObjectRegion and use it.
+      goto Finish;
+    }
+
+    case MemRegion::ElementRegionKind: {
+      const auto *ER = cast<ElementRegion>(R);
+      R = ER->getSuperRegion();
+
+      QualType EleTy = ER->getValueType();
+      if (EleTy->isIncompleteType()) {
+        // We cannot compute the offset of the base class.
+        SymbolicOffsetBase = R;
+        continue;
+      }
+
+      SVal Index = ER->getIndex();
+      if (std::optional<nonloc::ConcreteInt> CI =
+              Index.getAs<nonloc::ConcreteInt>()) {
+        // Don't bother calculating precise offsets if we already have a
+        // symbolic offset somewhere in the chain.
+        if (SymbolicOffsetBase)
+          continue;
+
+        int64_t i = CI->getValue()->getSExtValue();
+        // This type size is in bits.
+        Offset += i * R->getContext().getTypeSize(EleTy);
+      } else {
+        // We cannot compute offset for non-concrete index.
+        SymbolicOffsetBase = R;
+      }
+      break;
+    }
+    case MemRegion::FieldRegionKind: {
+      const auto *FR = cast<FieldRegion>(R);
+      R = FR->getSuperRegion();
+      assert(R);
+
+      const RecordDecl *RD = FR->getDecl()->getParent();
+      if (RD->isUnion() || !RD->isCompleteDefinition()) {
+        // We cannot compute offset for incomplete type.
+        // For unions, we could treat everything as offset 0, but we'd rather
+        // treat each field as a symbolic offset so they aren't stored on top
+        // of each other, since we depend on things in typed regions actually
+        // matching their types.
+        SymbolicOffsetBase = R;
+      }
+
+      // Don't bother calculating precise offsets if we already have a
+      // symbolic offset somewhere in the chain.
+      if (SymbolicOffsetBase)
+        continue;
+
+      // Get the field number.
+      unsigned idx = 0;
+      for (RecordDecl::field_iterator FI = RD->field_begin(),
+             FE = RD->field_end(); FI != FE; ++FI, ++idx) {
+        if (FR->getDecl() == *FI)
+          break;
+      }
+      const ASTRecordLayout &Layout = R->getContext().getASTRecordLayout(RD);
+      // This is offset in bits.
+      Offset += Layout.getFieldOffset(idx);
+      break;
+    }
+    }
+  }
+
+ Finish:
+  if (SymbolicOffsetBase)
+    return RegionOffset(SymbolicOffsetBase, RegionOffset::Symbolic);
+  return RegionOffset(R, Offset);
+}
+
+RegionOffset MemRegion::getAsOffset() const {
+  if (!cachedOffset)
+    cachedOffset = calculateOffset(this);
+  return *cachedOffset;
+}
+
+//===----------------------------------------------------------------------===//
+// BlockDataRegion
+//===----------------------------------------------------------------------===//
+
+std::pair<const VarRegion *, const VarRegion *>
+BlockDataRegion::getCaptureRegions(const VarDecl *VD) {
+  MemRegionManager &MemMgr = getMemRegionManager();
+  const VarRegion *VR = nullptr;
+  const VarRegion *OriginalVR = nullptr;
+
+  if (!VD->hasAttr<BlocksAttr>() && VD->hasLocalStorage()) {
+    VR = MemMgr.getNonParamVarRegion(VD, this);
+    OriginalVR = MemMgr.getVarRegion(VD, LC);
+  }
+  else {
+    if (LC) {
+      VR = MemMgr.getVarRegion(VD, LC);
+      OriginalVR = VR;
+    }
+    else {
+      VR = MemMgr.getNonParamVarRegion(VD, MemMgr.getUnknownRegion());
+      OriginalVR = MemMgr.getVarRegion(VD, LC);
+    }
+  }
+  return std::make_pair(VR, OriginalVR);
+}
+
+void BlockDataRegion::LazyInitializeReferencedVars() {
+  if (ReferencedVars)
+    return;
+
+  AnalysisDeclContext *AC = getCodeRegion()->getAnalysisDeclContext();
+  const auto &ReferencedBlockVars = AC->getReferencedBlockVars(BC->getDecl());
+  auto NumBlockVars =
+      std::distance(ReferencedBlockVars.begin(), ReferencedBlockVars.end());
+
+  if (NumBlockVars == 0) {
+    ReferencedVars = (void*) 0x1;
+    return;
+  }
+
+  MemRegionManager &MemMgr = getMemRegionManager();
+  llvm::BumpPtrAllocator &A = MemMgr.getAllocator();
+  BumpVectorContext BC(A);
+
+  using VarVec = BumpVector<const MemRegion *>;
+
+  auto *BV = new (A) VarVec(BC, NumBlockVars);
+  auto *BVOriginal = new (A) VarVec(BC, NumBlockVars);
+
+  for (const auto *VD : ReferencedBlockVars) {
+    const VarRegion *VR = nullptr;
+    const VarRegion *OriginalVR = nullptr;
+    std::tie(VR, OriginalVR) = getCaptureRegions(VD);
+    assert(VR);
+    assert(OriginalVR);
+    BV->push_back(VR, BC);
+    BVOriginal->push_back(OriginalVR, BC);
+  }
+
+  ReferencedVars = BV;
+  OriginalVars = BVOriginal;
+}
+
+BlockDataRegion::referenced_vars_iterator
+BlockDataRegion::referenced_vars_begin() const {
+  const_cast<BlockDataRegion*>(this)->LazyInitializeReferencedVars();
+
+  auto *Vec = static_cast<BumpVector<const MemRegion *> *>(ReferencedVars);
+
+  if (Vec == (void*) 0x1)
+    return BlockDataRegion::referenced_vars_iterator(nullptr, nullptr);
+
+  auto *VecOriginal =
+      static_cast<BumpVector<const MemRegion *> *>(OriginalVars);
+
+  return BlockDataRegion::referenced_vars_iterator(Vec->begin(),
+                                                   VecOriginal->begin());
+}
+
+BlockDataRegion::referenced_vars_iterator
+BlockDataRegion::referenced_vars_end() const {
+  const_cast<BlockDataRegion*>(this)->LazyInitializeReferencedVars();
+
+  auto *Vec = static_cast<BumpVector<const MemRegion *> *>(ReferencedVars);
+
+  if (Vec == (void*) 0x1)
+    return BlockDataRegion::referenced_vars_iterator(nullptr, nullptr);
+
+  auto *VecOriginal =
+      static_cast<BumpVector<const MemRegion *> *>(OriginalVars);
+
+  return BlockDataRegion::referenced_vars_iterator(Vec->end(),
+                                                   VecOriginal->end());
+}
+
+llvm::iterator_range<BlockDataRegion::referenced_vars_iterator>
+BlockDataRegion::referenced_vars() const {
+  return llvm::make_range(referenced_vars_begin(), referenced_vars_end());
+}
+
+const VarRegion *BlockDataRegion::getOriginalRegion(const VarRegion *R) const {
+  for (const auto &I : referenced_vars()) {
+    if (I.getCapturedRegion() == R)
+      return I.getOriginalRegion();
+  }
+  return nullptr;
+}
+
+//===----------------------------------------------------------------------===//
+// RegionAndSymbolInvalidationTraits
+//===----------------------------------------------------------------------===//
+
+void RegionAndSymbolInvalidationTraits::setTrait(SymbolRef Sym,
+                                                 InvalidationKinds IK) {
+  SymTraitsMap[Sym] |= IK;
+}
+
+void RegionAndSymbolInvalidationTraits::setTrait(const MemRegion *MR,
+                                                 InvalidationKinds IK) {
+  assert(MR);
+  if (const auto *SR = dyn_cast<SymbolicRegion>(MR))
+    setTrait(SR->getSymbol(), IK);
+  else
+    MRTraitsMap[MR] |= IK;
+}
+
+bool RegionAndSymbolInvalidationTraits::hasTrait(SymbolRef Sym,
+                                                 InvalidationKinds IK) const {
+  const_symbol_iterator I = SymTraitsMap.find(Sym);
+  if (I != SymTraitsMap.end())
+    return I->second & IK;
+
+  return false;
+}
+
+bool RegionAndSymbolInvalidationTraits::hasTrait(const MemRegion *MR,
+                                                 InvalidationKinds IK) const {
+  if (!MR)
+    return false;
+
+  if (const auto *SR = dyn_cast<SymbolicRegion>(MR))
+    return hasTrait(SR->getSymbol(), IK);
+
+  const_region_iterator I = MRTraitsMap.find(MR);
+  if (I != MRTraitsMap.end())
+    return I->second & IK;
+
+  return false;
+}
diff --git a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp b/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
deleted file mode 100644
index 8221b79b0706c60..000000000000000
--- a/clang/lib/StaticAnalyzer/Core/MemSpaces.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-//===-- MemSpaces.cpp ---------------------------------------------*- C++ -*--//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines getters and setters for the memory space trait which
-// associates memory regions with memory spaces in the program state. It also
-// defines the MemSpacesMap which maps memory regions to memory spaces.
-//
-// These functions keep the following invariants over the MemSpacesMap:
-// 1. (Temporary as an intermediate step) Memory space traits are only
-//    mapped for memory regions that have an unknown memory space
-// 2. Only base memory regions are mapped in the trait
-// 3. Memory regions which have no mapping in the trait are assumed to be
-//    unknown; no memory region is allowed to be mapped to an unknown memory
-//    space in the trait;
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/StaticAnalyzer/Core/PathSensitive/MemSpaces.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
-#include <cassert>
-
-REGISTER_MAP_WITH_PROGRAMSTATE(MemSpacesMap, const clang::ento::MemRegion *,
-                               const clang::ento::MemSpaceRegion *)
-
-namespace clang {
-namespace ento {
-namespace memspace {} // namespace memspace
-} // namespace ento
-} // namespace clang

>From af52435ad56957f99c6afb7bd2a7c10798b7156e Mon Sep 17 00:00:00 2001
From: Michael Flanders <flanders.michaelk at gmail.com>
Date: Mon, 27 Jan 2025 13:13:33 -0600
Subject: [PATCH 21/55] formatting

---
 clang/lib/StaticAnalyzer/Core/MemRegion.cpp | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
index 4b621e5cb4f9758..0741ce2308aa3e2 100644
--- a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -1369,12 +1369,13 @@ const MemSpaceRegion *MemRegion::getMemorySpace(ProgramStateRef State) const {
   const MemSpaceRegion *MS = MR->getRawMemorySpace();
   if (!isa<UnknownSpaceRegion>(MS))
     return MS;
-    
+
   const MemSpaceRegion *const *Result = State->get<MemSpacesMap>(MR);
   return Result ? *Result : MS;
 }
 
-ProgramStateRef MemRegion::setMemSpaceTrait(ProgramStateRef State, const MemSpaceRegion *MS) const {
+ProgramStateRef MemRegion::setMemSpaceTrait(ProgramStateRef State,
+                                            const MemSpaceRegion *MS) const {
   const MemRegion *MR = getBaseRegion();
 
   // For now, this should only be called to update the trait for memory regions
@@ -1395,8 +1396,8 @@ bool MemRegion::hasRawStackStorage() const {
   return isa<StackSpaceRegion>(getRawMemorySpace());
 }
 
-bool MemRegion::hasStackStorage(ProgramStateRef State) const { 
-  return isMemorySpace<StackSpaceRegion>(State); 
+bool MemRegion::hasStackStorage(ProgramStateRef State) const {
+  return isMemorySpace<StackSpaceRegion>(State);
 }
 
 bool MemRegion::hasRawStackNonParametersStorage() const {

>From a779979450386b1a1c3af1b8704144bed586ab86 Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Sun, 2 Feb 2025 18:39:44 +0100
Subject: [PATCH 22/55] NFC Reword comments, drop deprecation doxygen marker

---
 .../StaticAnalyzer/Core/PathSensitive/MemRegion.h      | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index 9abd5882c245485..3c89f0326dbd4d4 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -121,15 +121,15 @@ class MemRegion : public llvm::FoldingSetNode {
   virtual MemRegionManager &getMemRegionManager() const = 0;
 
   /// Deprecated. Gets the 'raw' memory space of a memory region's base region.
-  /// Deprecated in favor of the memory space trait which maps memory regions to
-  /// memory spaces, allowing dynamic updating of a memory region's memory
-  /// space.
-  /// @deprecated Use getMemorySpace(ProgramStateRef) instead.
+  /// If the MemRegion is originally associated with Unknown memspace, then the
+  /// State may have a more accurate memspace for this region.
+  /// Use getMemorySpace(ProgramStateRef) instead.
   LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion *
   getRawMemorySpace() const;
 
   /// Returns the most specific memory space for this memory region in the given
-  /// ProgramStateRef.
+  /// ProgramStateRef. We may infer a more accurate memory space for unknown
+  /// space regions and associate this in the State.
   [[nodiscard]] LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion *
   getMemorySpace(ProgramStateRef State) const;
 

>From 100ad4d256014d0bcef2a03e103d2b382940e860 Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Sun, 2 Feb 2025 18:40:08 +0100
Subject: [PATCH 23/55] NFC Drop hasRawStackStorage

---
 .../clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h     | 3 ---
 .../Checkers/RetainCountChecker/RetainCountChecker.cpp      | 6 +++---
 .../lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp  | 6 ++++--
 3 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index 3c89f0326dbd4d4..26d0c0321e8cc6a 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -160,9 +160,6 @@ class MemRegion : public llvm::FoldingSetNode {
   /// It might return null.
   const SymbolicRegion *getSymbolicBase() const;
 
-  /// @deprecated Use hasStackStorage(ProgramStateRef) instead.
-  bool hasRawStackStorage() const;
-
   [[nodiscard]] bool hasStackStorage(ProgramStateRef State) const;
 
   /// @deprecated Use hasStackNonParametersStorage(ProgramStateRef) instead.
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
index 3887e752a43cec5..1bd003fee2e5343 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
@@ -501,13 +501,13 @@ static bool isSmartPtrField(const MemRegion *MR) {
 /// assigned to a struct field, unless it is a known smart pointer
 /// implementation, about which we know that it is inlined.
 /// FIXME: This could definitely be improved upon.
-static bool shouldEscapeRegion(const MemRegion *R) {
+static bool shouldEscapeRegion(ProgramStateRef State, const MemRegion *R) {
   if (isSmartPtrField(R))
     return false;
 
   const auto *VR = dyn_cast<VarRegion>(R);
 
-  if (!R->hasRawStackStorage() || !VR)
+  if (!R->hasStackStorage(State) || !VR)
     return true;
 
   const VarDecl *VD = VR->getDecl();
@@ -561,7 +561,7 @@ updateOutParameters(ProgramStateRef State, const RetainSummary &Summ,
     if (!Pointee)
       continue;
 
-    if (shouldEscapeRegion(ArgRegion))
+    if (shouldEscapeRegion(State, ArgRegion))
       continue;
 
     auto makeNotOwnedParameter = [&](ProgramStateRef St) {
diff --git a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index 54655c9ea15df71..5094519faa8349a 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -395,6 +395,7 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,
   class CallBack : public StoreManager::BindingsHandler {
   private:
     CheckerContext &Ctx;
+    ProgramStateRef State;
     const StackFrameContext *PoppedFrame;
     const bool TopFrame;
 
@@ -454,7 +455,8 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,
     llvm::SmallPtrSet<const MemRegion *, 4> ExcludedRegions;
 
     CallBack(CheckerContext &CC, bool TopFrame)
-        : Ctx(CC), PoppedFrame(CC.getStackFrame()), TopFrame(TopFrame) {}
+        : Ctx(CC), State(CC.getState()), PoppedFrame(CC.getStackFrame()),
+          TopFrame(TopFrame) {}
 
     bool HandleBinding(StoreManager &SMgr, Store S, const MemRegion *Region,
                        SVal Val) override {
@@ -470,7 +472,7 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,
       if (!isa_and_nonnull<GlobalsSpaceRegion>(
               getStackOrGlobalSpaceRegion(Region)))
         return true;
-      if (VR && VR->hasRawStackStorage() &&
+      if (VR && VR->hasStackStorage(State) &&
           !isNotInCurrentFrame(VR->getRawMemorySpace(), Ctx))
         V.emplace_back(Region, VR);
       return true;

>From 8d47fd8ef209d930d5752e49364ce59e705638f0 Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Sun, 2 Feb 2025 18:42:46 +0100
Subject: [PATCH 24/55] NFC isMemorySpace -> hasMemorySpace

---
 .../StaticAnalyzer/Core/PathSensitive/MemRegion.h      |  4 ++--
 clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp |  6 +++---
 clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp    |  8 ++++----
 clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp      |  2 +-
 .../StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp |  2 +-
 clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp   |  2 +-
 clang/lib/StaticAnalyzer/Core/ExprEngine.cpp           |  2 +-
 clang/lib/StaticAnalyzer/Core/MemRegion.cpp            | 10 +++-------
 8 files changed, 16 insertions(+), 20 deletions(-)

diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index 26d0c0321e8cc6a..7e6781b1c0faff8 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -134,8 +134,8 @@ class MemRegion : public llvm::FoldingSetNode {
   getMemorySpace(ProgramStateRef State) const;
 
   template <typename FirstT, typename... RestT>
-  [[nodiscard]] bool isMemorySpace(ProgramStateRef State) const {
-    return isa_and_nonnull<FirstT, RestT...>(getMemorySpace(State));
+  [[nodiscard]] bool hasMemorySpace(ProgramStateRef State) const {
+    return isa<FirstT, RestT...>(getMemorySpace(State));
   }
 
   [[nodiscard]] ProgramStateRef
diff --git a/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
index 874cc511eecb935..3bfa90e2f901de0 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
@@ -79,7 +79,7 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
 
   // Global variables are fine.
   const MemRegion *RB = R->getBaseRegion();
-  if (RB->isMemorySpace<GlobalsSpaceRegion>(State))
+  if (RB->hasMemorySpace<GlobalsSpaceRegion>(State))
     return;
 
   // Handle _dispatch_once.  In some versions of the OS X SDK we have the case
@@ -118,9 +118,9 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
     if (IVR != R)
       os << " memory within";
     os << " the instance variable '" << IVR->getDecl()->getName() << '\'';
-  } else if (RB->isMemorySpace<HeapSpaceRegion>(State)) {
+  } else if (RB->hasMemorySpace<HeapSpaceRegion>(State)) {
     os << " heap-allocated memory";
-  } else if (RB->isMemorySpace<UnknownSpaceRegion>(State)) {
+  } else if (RB->hasMemorySpace<UnknownSpaceRegion>(State)) {
     // Presence of an IVar superregion has priority over this branch, because
     // ObjC objects are on the heap even if the core doesn't realize this.
     // Presence of a block variable base region has priority over this branch,
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 1b1bd7be15aff63..9135726d127b66b 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -2210,7 +2210,7 @@ MallocChecker::FreeMemAux(CheckerContext &C, const Expr *ArgExpr,
   // - The region has unknown memspace and no trait for further clarification
   //   (i.e., just unknown)
   // - The region has unknown memspace and a heap memspace trait
-  if (!R->isMemorySpace<HeapSpaceRegion, UnknownSpaceRegion>(State)) {
+  if (!R->hasMemorySpace<HeapSpaceRegion, UnknownSpaceRegion>(State)) {
     // Regions returned by malloc() are represented by SymbolicRegion objects
     // within HeapSpaceRegion. Of course, free() can work on memory allocated
     // outside the current function, so UnknownSpaceRegion is also a
@@ -2407,7 +2407,7 @@ bool MallocChecker::SummarizeRegion(ProgramStateRef State, raw_ostream &os,
     os << "a block";
     return true;
   default: {
-    if (MR->isMemorySpace<StackLocalsSpaceRegion>(State)) {
+    if (MR->hasMemorySpace<StackLocalsSpaceRegion>(State)) {
       const VarRegion *VR = dyn_cast<VarRegion>(MR);
       const VarDecl *VD;
       if (VR)
@@ -2422,7 +2422,7 @@ bool MallocChecker::SummarizeRegion(ProgramStateRef State, raw_ostream &os,
       return true;
     }
 
-    if (MR->isMemorySpace<StackArgumentsSpaceRegion>(State)) {
+    if (MR->hasMemorySpace<StackArgumentsSpaceRegion>(State)) {
       const VarRegion *VR = dyn_cast<VarRegion>(MR);
       const VarDecl *VD;
       if (VR)
@@ -2437,7 +2437,7 @@ bool MallocChecker::SummarizeRegion(ProgramStateRef State, raw_ostream &os,
       return true;
     }
 
-    if (MR->isMemorySpace<GlobalsSpaceRegion>(State)) {
+    if (MR->hasMemorySpace<GlobalsSpaceRegion>(State)) {
       const VarRegion *VR = dyn_cast<VarRegion>(MR);
       const VarDecl *VD;
       if (VR)
diff --git a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
index 288cbd03656abef..41493285a879634 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
@@ -560,7 +560,7 @@ MoveChecker::classifyObject(ProgramStateRef State, const MemRegion *MR,
   MR = unwrapRValueReferenceIndirection(MR);
   bool IsLocal =
       isa_and_nonnull<VarRegion, CXXLifetimeExtendedObjectRegion>(MR) &&
-      MR->isMemorySpace<StackSpaceRegion>(State);
+      MR->hasMemorySpace<StackSpaceRegion>(State);
 
   if (!RD || !RD->getDeclContext()->isStdNamespace())
     return { IsLocal, SK_NonStd };
diff --git a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index 5094519faa8349a..e845c30e0b00245 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -142,7 +142,7 @@ StackAddrEscapeChecker::getCapturedStackRegions(const BlockDataRegion &B,
   for (auto Var : B.referenced_vars()) {
     SVal Val = State->getSVal(Var.getCapturedRegion());
     const MemRegion *Region = Val.getAsRegion();
-    if (Region && Region->isMemorySpace<StackSpaceRegion>(State))
+    if (Region && Region->hasMemorySpace<StackSpaceRegion>(State))
       Regions.push_back(Region);
   }
   return Regions;
diff --git a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
index f62ac080c729c12..b6692961c3e6788 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
@@ -411,7 +411,7 @@ void UnixAPIMisuseChecker::CheckPthreadOnce(CheckerContext &C,
   // because that's likely to be bad news.
   ProgramStateRef state = C.getState();
   const MemRegion *R = Call.getArgSVal(0).getAsRegion();
-  if (!R || !R->isMemorySpace<StackSpaceRegion>(state))
+  if (!R || !R->hasMemorySpace<StackSpaceRegion>(state))
     return;
 
   ExplodedNode *N = C.generateErrorNode(state);
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 5a4178b4e695ecf..9ad537d10d15b8e 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -3511,7 +3511,7 @@ ProgramStateRef ExprEngine::processPointerEscapedOnBind(
     // Cases (1) and (2).
     const MemRegion *MR = LocAndVal.first.getAsRegion();
     if (!MR ||
-        !MR->isMemorySpace<StackSpaceRegion, StaticGlobalSpaceRegion>(State)) {
+        !MR->hasMemorySpace<StackSpaceRegion, StaticGlobalSpaceRegion>(State)) {
       Escaped.push_back(LocAndVal.second);
       continue;
     }
diff --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
index 0741ce2308aa3e2..14bed5dc37380ec 100644
--- a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -1392,12 +1392,8 @@ ProgramStateRef MemRegion::setMemSpaceTrait(ProgramStateRef State,
   return NewState;
 }
 
-bool MemRegion::hasRawStackStorage() const {
-  return isa<StackSpaceRegion>(getRawMemorySpace());
-}
-
 bool MemRegion::hasStackStorage(ProgramStateRef State) const {
-  return isMemorySpace<StackSpaceRegion>(State);
+  return hasMemorySpace<StackSpaceRegion>(State);
 }
 
 bool MemRegion::hasRawStackNonParametersStorage() const {
@@ -1405,7 +1401,7 @@ bool MemRegion::hasRawStackNonParametersStorage() const {
 }
 
 bool MemRegion::hasStackNonParametersStorage(ProgramStateRef State) const {
-  return isMemorySpace<StackLocalsSpaceRegion>(State);
+  return hasMemorySpace<StackLocalsSpaceRegion>(State);
 }
 
 bool MemRegion::hasRawStackParametersStorage() const {
@@ -1413,7 +1409,7 @@ bool MemRegion::hasRawStackParametersStorage() const {
 }
 
 bool MemRegion::hasStackParametersStorage(ProgramStateRef State) const {
-  return isMemorySpace<StackArgumentsSpaceRegion>(State);
+  return hasMemorySpace<StackArgumentsSpaceRegion>(State);
 }
 
 // Strips away all elements and fields.

>From f341168bdf7daef636df820c4202d39fc212b084 Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Sun, 2 Feb 2025 18:44:38 +0100
Subject: [PATCH 25/55] NFC Drop hasStackStorage

---
 .../clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h       | 2 --
 .../Checkers/RetainCountChecker/RetainCountChecker.cpp        | 2 +-
 clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp  | 2 +-
 clang/lib/StaticAnalyzer/Core/MemRegion.cpp                   | 4 ----
 4 files changed, 2 insertions(+), 8 deletions(-)

diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index 7e6781b1c0faff8..d0dae6dcd505056 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -160,8 +160,6 @@ class MemRegion : public llvm::FoldingSetNode {
   /// It might return null.
   const SymbolicRegion *getSymbolicBase() const;
 
-  [[nodiscard]] bool hasStackStorage(ProgramStateRef State) const;
-
   /// @deprecated Use hasStackNonParametersStorage(ProgramStateRef) instead.
   bool hasRawStackNonParametersStorage() const;
 
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
index 1bd003fee2e5343..2d75eb4c013abd3 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
@@ -507,7 +507,7 @@ static bool shouldEscapeRegion(ProgramStateRef State, const MemRegion *R) {
 
   const auto *VR = dyn_cast<VarRegion>(R);
 
-  if (!R->hasStackStorage(State) || !VR)
+  if (!R->hasMemorySpace<StackSpaceRegion>(State) || !VR)
     return true;
 
   const VarDecl *VD = VR->getDecl();
diff --git a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index e845c30e0b00245..84a2d346806dc3d 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -472,7 +472,7 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,
       if (!isa_and_nonnull<GlobalsSpaceRegion>(
               getStackOrGlobalSpaceRegion(Region)))
         return true;
-      if (VR && VR->hasStackStorage(State) &&
+      if (VR && VR->hasMemorySpace<StackSpaceRegion>(State) &&
           !isNotInCurrentFrame(VR->getRawMemorySpace(), Ctx))
         V.emplace_back(Region, VR);
       return true;
diff --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
index 14bed5dc37380ec..a3c59c5aa6dd40b 100644
--- a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -1392,10 +1392,6 @@ ProgramStateRef MemRegion::setMemSpaceTrait(ProgramStateRef State,
   return NewState;
 }
 
-bool MemRegion::hasStackStorage(ProgramStateRef State) const {
-  return hasMemorySpace<StackSpaceRegion>(State);
-}
-
 bool MemRegion::hasRawStackNonParametersStorage() const {
   return isa<StackLocalsSpaceRegion>(getRawMemorySpace());
 }

>From 39a054feae49c9921bb71ba47a53bdab10e0ebe9 Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Sun, 2 Feb 2025 18:47:03 +0100
Subject: [PATCH 26/55] NFC Drop hasRawStackNonParametersStorage

---
 .../clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h   | 5 -----
 clang/lib/StaticAnalyzer/Core/MemRegion.cpp               | 8 --------
 clang/lib/StaticAnalyzer/Core/RegionStore.cpp             | 4 ++--
 3 files changed, 2 insertions(+), 15 deletions(-)

diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index d0dae6dcd505056..20c795462474c78 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -160,11 +160,6 @@ class MemRegion : public llvm::FoldingSetNode {
   /// It might return null.
   const SymbolicRegion *getSymbolicBase() const;
 
-  /// @deprecated Use hasStackNonParametersStorage(ProgramStateRef) instead.
-  bool hasRawStackNonParametersStorage() const;
-
-  [[nodiscard]] bool hasStackNonParametersStorage(ProgramStateRef State) const;
-
   /// @deprecated Use hasStackParametersStorage(ProgramStateRef) instead.
   bool hasRawStackParametersStorage() const;
 
diff --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
index a3c59c5aa6dd40b..5f50008347c0093 100644
--- a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -1392,14 +1392,6 @@ ProgramStateRef MemRegion::setMemSpaceTrait(ProgramStateRef State,
   return NewState;
 }
 
-bool MemRegion::hasRawStackNonParametersStorage() const {
-  return isa<StackLocalsSpaceRegion>(getRawMemorySpace());
-}
-
-bool MemRegion::hasStackNonParametersStorage(ProgramStateRef State) const {
-  return hasMemorySpace<StackLocalsSpaceRegion>(State);
-}
-
 bool MemRegion::hasRawStackParametersStorage() const {
   return isa<StackArgumentsSpaceRegion>(getRawMemorySpace());
 }
diff --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
index 927c8094e81aa04..bf1dcf6747b8a7b 100644
--- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -1544,7 +1544,7 @@ SVal RegionStoreManager::getBinding(RegionBindingsConstRef B, Loc L, QualType T)
   // The location does not have a bound value.  This means that it has
   // the value it had upon its creation and/or entry to the analyzed
   // function/method.  These are either symbolic values or 'undefined'.
-  if (R->hasRawStackNonParametersStorage()) {
+  if (isa<StackLocalsSpaceRegion>(R->getRawMemorySpace())) {
     // All stack variables are considered to have undefined values
     // upon creation.  All heap allocated blocks are considered to
     // have undefined values as well unless they are explicitly bound
@@ -2175,7 +2175,7 @@ RegionStoreManager::getBindingForFieldOrElementCommon(RegionBindingsConstRef B,
     SR = dyn_cast<SubRegion>(Base);
   }
 
-  if (R->hasRawStackNonParametersStorage()) {
+  if (isa<StackLocalsSpaceRegion>(R->getRawMemorySpace())) {
     if (isa<ElementRegion>(R)) {
       // Currently we don't reason specially about Clang-style vectors.  Check
       // if superR is a vector and if so return Unknown.

>From dc19205d23a9124da842949e2dd3546e7ba1c5be Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Sun, 2 Feb 2025 18:49:57 +0100
Subject: [PATCH 27/55] NFC Drop hasRawStackParametersStorage

---
 .../clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h   | 5 -----
 clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp          | 2 +-
 clang/lib/StaticAnalyzer/Core/ExprEngine.cpp              | 2 +-
 clang/lib/StaticAnalyzer/Core/MemRegion.cpp               | 8 --------
 4 files changed, 2 insertions(+), 15 deletions(-)

diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index 20c795462474c78..2291eb68496655f 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -160,11 +160,6 @@ class MemRegion : public llvm::FoldingSetNode {
   /// It might return null.
   const SymbolicRegion *getSymbolicBase() const;
 
-  /// @deprecated Use hasStackParametersStorage(ProgramStateRef) instead.
-  bool hasRawStackParametersStorage() const;
-
-  [[nodiscard]] bool hasStackParametersStorage(ProgramStateRef State) const;
-
   /// Compute the offset within the top level memory object.
   RegionOffset getAsOffset() const;
 
diff --git a/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp
index 19f1d03ff4753a6..bb4446df87dbbf9 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp
@@ -134,7 +134,7 @@ static const ParmVarDecl *getOriginParam(SVal V, CheckerContext &C,
   // routine arguments in the heap.
   while (const MemRegion *MR = Sym->getOriginRegion()) {
     const auto *VR = dyn_cast<VarRegion>(MR);
-    if (VR && VR->hasRawStackParametersStorage() &&
+    if (VR && VR->hasMemorySpace<StackArgumentsSpaceRegion>(C.getState()) &&
         VR->getStackFrame()->inTopFrame())
       return cast<ParmVarDecl>(VR->getDecl());
 
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 9ad537d10d15b8e..a5a7b7f2fbeca4c 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -3518,7 +3518,7 @@ ProgramStateRef ExprEngine::processPointerEscapedOnBind(
 
     // Case (3).
     if (const auto *VR = dyn_cast<VarRegion>(MR->getBaseRegion()))
-      if (VR->hasRawStackParametersStorage() &&
+      if (VR->hasMemorySpace<StackArgumentsSpaceRegion>(State) &&
           VR->getStackFrame()->inTopFrame())
         if (const auto *RD = VR->getValueType()->getAsCXXRecordDecl())
           if (!RD->hasTrivialDestructor()) {
diff --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
index 5f50008347c0093..51083ac0f3ce431 100644
--- a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -1392,14 +1392,6 @@ ProgramStateRef MemRegion::setMemSpaceTrait(ProgramStateRef State,
   return NewState;
 }
 
-bool MemRegion::hasRawStackParametersStorage() const {
-  return isa<StackArgumentsSpaceRegion>(getRawMemorySpace());
-}
-
-bool MemRegion::hasStackParametersStorage(ProgramStateRef State) const {
-  return hasMemorySpace<StackArgumentsSpaceRegion>(State);
-}
-
 // Strips away all elements and fields.
 // Returns the base region of them.
 const MemRegion *MemRegion::getBaseRegion() const {

>From a3896d66c9cda172bce1ae632129f161c3b5c367 Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Sun, 2 Feb 2025 18:54:08 +0100
Subject: [PATCH 28/55] fixup! NFC Drop hasStackStorage

---
 .../Checkers/RetainCountChecker/RetainCountChecker.cpp          | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
index 2d75eb4c013abd3..cc1ced73587102f 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
@@ -1141,7 +1141,7 @@ void RetainCountChecker::checkBind(SVal loc, SVal val, const Stmt *S,
 
   // Find all symbols referenced by 'val' that we are tracking
   // and stop tracking them.
-  if (MR && shouldEscapeRegion(MR)) {
+  if (MR && shouldEscapeRegion(state, MR)) {
     state = state->scanReachableSymbols<StopTrackingCallback>(val).getState();
     C.addTransition(state);
   }

>From 34dcef503aa4a30e7041552b7b27161b7da2c37a Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Sun, 2 Feb 2025 18:54:35 +0100
Subject: [PATCH 29/55] Simplify SValExplainer

---
 .../include/clang/StaticAnalyzer/Checkers/SValExplainer.h  | 7 +++++--
 .../lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp  | 2 +-
 2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h b/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
index f07e69621404c44..3786f50b16921c5 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
+++ b/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
@@ -17,6 +17,7 @@
 
 #include "clang/AST/Attr.h"
 #include "clang/AST/DeclCXX.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h"
 #include "llvm/ADT/StringExtras.h"
 
@@ -27,6 +28,7 @@ namespace ento {
 class SValExplainer : public FullSValVisitor<SValExplainer, std::string> {
 private:
   ASTContext &ACtx;
+  ProgramStateRef State;
 
   std::string printStmt(const Stmt *S) {
     std::string Str;
@@ -55,7 +57,8 @@ class SValExplainer : public FullSValVisitor<SValExplainer, std::string> {
   }
 
 public:
-  SValExplainer(ASTContext &Ctx) : ACtx(Ctx) {}
+  SValExplainer(ASTContext &Ctx, ProgramStateRef State)
+      : ACtx(Ctx), State(State) {}
 
   std::string VisitUnknownVal(UnknownVal V) {
     return "unknown value";
@@ -166,7 +169,7 @@ class SValExplainer : public FullSValVisitor<SValExplainer, std::string> {
             .getCanonicalType()->getAs<ObjCObjectPointerType>())
       return "object at " + Visit(R->getSymbol());
     // Other heap-based symbolic regions are also special.
-    if (isa<HeapSpaceRegion>(R->getRawMemorySpace()))
+    if (isa<HeapSpaceRegion>(R->getMemorySpace(State)))
       return "heap segment that starts at " + Visit(R->getSymbol());
     return "pointee of " + Visit(R->getSymbol());
   }
diff --git a/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
index 5534ef86a7bef68..87fb8321543afe3 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
@@ -256,7 +256,7 @@ void ExprInspectionChecker::analyzerExplain(const CallExpr *CE,
     return;
 
   SVal V = C.getSVal(Arg);
-  SValExplainer Ex(C.getASTContext());
+  SValExplainer Ex(C.getASTContext(), C.getState());
   reportBug(Ex.Visit(V), C);
 }
 

>From c9bde9f8c6d2f646d393f461d32e7c6b62a936c1 Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Sun, 2 Feb 2025 19:00:55 +0100
Subject: [PATCH 30/55] Refine setMemSpaceTrait

---
 .../Core/PathSensitive/MemRegion.h            |  4 ++-
 clang/lib/StaticAnalyzer/Core/MemRegion.cpp   | 30 ++++++++-----------
 2 files changed, 15 insertions(+), 19 deletions(-)

diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index 2291eb68496655f..3bd0a8f87a28324 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -138,8 +138,10 @@ class MemRegion : public llvm::FoldingSetNode {
     return isa<FirstT, RestT...>(getMemorySpace(State));
   }
 
+  /// Set the dynamically deduced memory space of a MemRegion that currently has
+  /// UnknownSpaceRegion. \p Space shouldn't be UnknownSpaceRegion.
   [[nodiscard]] ProgramStateRef
-  setMemSpaceTrait(ProgramStateRef State, const MemSpaceRegion *MS) const;
+  setMemSpaceTrait(ProgramStateRef State, const MemSpaceRegion *Space) const;
 
   LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion *getBaseRegion() const;
 
diff --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
index 51083ac0f3ce431..d53c2f768faf857 100644
--- a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -1366,30 +1366,24 @@ const MemSpaceRegion *MemRegion::getRawMemorySpace() const {
 const MemSpaceRegion *MemRegion::getMemorySpace(ProgramStateRef State) const {
   const MemRegion *MR = getBaseRegion();
 
-  const MemSpaceRegion *MS = MR->getRawMemorySpace();
-  if (!isa<UnknownSpaceRegion>(MS))
-    return MS;
+  const MemSpaceRegion *RawSpace = MR->getRawMemorySpace();
+  if (!isa<UnknownSpaceRegion>(RawSpace))
+    return RawSpace;
 
-  const MemSpaceRegion *const *Result = State->get<MemSpacesMap>(MR);
-  return Result ? *Result : MS;
+  const MemSpaceRegion *const *AssociatedSpace = State->get<MemSpacesMap>(MR);
+  return AssociatedSpace ? *AssociatedSpace : RawSpace;
 }
 
 ProgramStateRef MemRegion::setMemSpaceTrait(ProgramStateRef State,
-                                            const MemSpaceRegion *MS) const {
-  const MemRegion *MR = getBaseRegion();
-
-  // For now, this should only be called to update the trait for memory regions
-  // that have an unknown memory spaces since we assume everywhere else that the
-  // memory space trait is set only for unknown memory spaces (setting this info
-  // otherwise would go unused).
-  assert(isa<UnknownSpaceRegion>(MR->getRawMemorySpace()));
+                                            const MemSpaceRegion *Space) const {
+  const MemRegion *Base = getBaseRegion();
 
-  // Shouldn't use the memory space trait to associate UnknownSpaceRegion with
-  // an already UnknownSpaceRegion
-  assert(!isa<UnknownSpaceRegion>(MS));
+  // Shouldn't set unknown space.
+  assert(!isa<UnknownSpaceRegion>(Space));
 
-  ProgramStateRef NewState = State->set<MemSpacesMap>(MR, MS);
-  return NewState;
+  // Currently, it we should have no accurate memspace for this region.
+  assert(isa<UnknownSpaceRegion>(Base->getMemorySpace(State)));
+  return State->set<MemSpacesMap>(Base, Space);
 }
 
 // Strips away all elements and fields.

>From 4d143e47138debe2fc0766bfd0e92f998ebe344d Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Sun, 2 Feb 2025 19:03:06 +0100
Subject: [PATCH 31/55] NFC setMemSpaceTrait -> setMemorySpace

---
 .../clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h       | 2 +-
 clang/lib/StaticAnalyzer/Core/MemRegion.cpp                   | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index 3bd0a8f87a28324..822735078943773 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -141,7 +141,7 @@ class MemRegion : public llvm::FoldingSetNode {
   /// Set the dynamically deduced memory space of a MemRegion that currently has
   /// UnknownSpaceRegion. \p Space shouldn't be UnknownSpaceRegion.
   [[nodiscard]] ProgramStateRef
-  setMemSpaceTrait(ProgramStateRef State, const MemSpaceRegion *Space) const;
+  setMemorySpace(ProgramStateRef State, const MemSpaceRegion *Space) const;
 
   LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion *getBaseRegion() const;
 
diff --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
index d53c2f768faf857..f46bae2e4ac8485 100644
--- a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -1374,8 +1374,8 @@ const MemSpaceRegion *MemRegion::getMemorySpace(ProgramStateRef State) const {
   return AssociatedSpace ? *AssociatedSpace : RawSpace;
 }
 
-ProgramStateRef MemRegion::setMemSpaceTrait(ProgramStateRef State,
-                                            const MemSpaceRegion *Space) const {
+ProgramStateRef MemRegion::setMemorySpace(ProgramStateRef State,
+                                          const MemSpaceRegion *Space) const {
   const MemRegion *Base = getBaseRegion();
 
   // Shouldn't set unknown space.

>From 7110d3f03d670cb85a6455bfb2f91fb1b8200f63 Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Sun, 2 Feb 2025 19:03:25 +0100
Subject: [PATCH 32/55] NFC Simplify hasMemorySpace API

---
 .../clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h      | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index 822735078943773..15f3305271674d7 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -133,9 +133,10 @@ class MemRegion : public llvm::FoldingSetNode {
   [[nodiscard]] LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion *
   getMemorySpace(ProgramStateRef State) const;
 
-  template <typename FirstT, typename... RestT>
+  template <typename... MemorySpaces>
   [[nodiscard]] bool hasMemorySpace(ProgramStateRef State) const {
-    return isa<FirstT, RestT...>(getMemorySpace(State));
+    static_assert(sizeof...(MemorySpaces));
+    return isa<MemorySpaces...>(getMemorySpace(State));
   }
 
   /// Set the dynamically deduced memory space of a MemRegion that currently has

>From 7c90afc7a931ef8f607b0a95c8f371002994688a Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Sun, 2 Feb 2025 19:04:03 +0100
Subject: [PATCH 33/55] Add a [[nodiscard]]

---
 .../include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index 15f3305271674d7..aa46804b36136a0 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -124,7 +124,7 @@ class MemRegion : public llvm::FoldingSetNode {
   /// If the MemRegion is originally associated with Unknown memspace, then the
   /// State may have a more accurate memspace for this region.
   /// Use getMemorySpace(ProgramStateRef) instead.
-  LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion *
+  [[nodiscard]] LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion *
   getRawMemorySpace() const;
 
   /// Returns the most specific memory space for this memory region in the given

>From f16aca7a46bfccca39361c5de6a65c5a5726a5d2 Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Sun, 2 Feb 2025 19:12:49 +0100
Subject: [PATCH 34/55] Drop raw uses from ArrayBoundCheckerV2

---
 .../Checkers/ArrayBoundCheckerV2.cpp          | 41 +++++++++++--------
 1 file changed, 23 insertions(+), 18 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
index 3ac31cce4e46d62..df67e3544a1987c 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
@@ -65,6 +65,7 @@ determineElementSize(const std::optional<QualType> T, const CheckerContext &C) {
 }
 
 class StateUpdateReporter {
+  const MemSpaceRegion *Space;
   const SubRegion *Reg;
   const NonLoc ByteOffsetVal;
   const std::optional<QualType> ElementType;
@@ -75,8 +76,8 @@ class StateUpdateReporter {
 public:
   StateUpdateReporter(const SubRegion *R, NonLoc ByteOffsVal, const Expr *E,
                       CheckerContext &C)
-      : Reg(R), ByteOffsetVal(ByteOffsVal),
-        ElementType(determineElementType(E, C)),
+      : Space(R->getMemorySpace(C.getState())), Reg(R),
+        ByteOffsetVal(ByteOffsVal), ElementType(determineElementType(E, C)),
         ElementSize(determineElementSize(ElementType, C)) {}
 
   void recordNonNegativeAssumption() { AssumedNonNegative = true; }
@@ -336,7 +337,8 @@ compareValueToThreshold(ProgramStateRef State, NonLoc Value, NonLoc Threshold,
   return {nullptr, nullptr};
 }
 
-static std::string getRegionName(const SubRegion *Region) {
+static std::string getRegionName(const MemSpaceRegion *Space,
+                                 const SubRegion *Region) {
   if (std::string RegName = Region->getDescriptiveName(); !RegName.empty())
     return RegName;
 
@@ -351,8 +353,7 @@ static std::string getRegionName(const SubRegion *Region) {
   if (isa<AllocaRegion>(Region))
     return "the memory returned by 'alloca'";
 
-  if (isa<SymbolicRegion>(Region) &&
-      isa<HeapSpaceRegion>(Region->getRawMemorySpace()))
+  if (isa<SymbolicRegion>(Region) && isa<HeapSpaceRegion>(Space))
     return "the heap area";
 
   if (isa<StringRegion>(Region))
@@ -372,8 +373,9 @@ static std::optional<int64_t> getConcreteValue(std::optional<NonLoc> SV) {
   return SV ? getConcreteValue(*SV) : std::nullopt;
 }
 
-static Messages getPrecedesMsgs(const SubRegion *Region, NonLoc Offset) {
-  std::string RegName = getRegionName(Region), OffsetStr = "";
+static Messages getPrecedesMsgs(const MemSpaceRegion *Space,
+                                const SubRegion *Region, NonLoc Offset) {
+  std::string RegName = getRegionName(Space, Region), OffsetStr = "";
 
   if (auto ConcreteOffset = getConcreteValue(Offset))
     OffsetStr = formatv(" {0}", ConcreteOffset);
@@ -403,10 +405,11 @@ static bool tryDividePair(std::optional<int64_t> &Val1,
   return false;
 }
 
-static Messages getExceedsMsgs(ASTContext &ACtx, const SubRegion *Region,
-                               NonLoc Offset, NonLoc Extent, SVal Location,
+static Messages getExceedsMsgs(ASTContext &ACtx, const MemSpaceRegion *Space,
+                               const SubRegion *Region, NonLoc Offset,
+                               NonLoc Extent, SVal Location,
                                bool AlsoMentionUnderflow) {
-  std::string RegName = getRegionName(Region);
+  std::string RegName = getRegionName(Space, Region);
   const auto *EReg = Location.getAsRegion()->getAs<ElementRegion>();
   assert(EReg && "this checker only handles element access");
   QualType ElemType = EReg->getElementType();
@@ -453,9 +456,10 @@ static Messages getExceedsMsgs(ASTContext &ACtx, const SubRegion *Region,
           std::string(Buf)};
 }
 
-static Messages getTaintMsgs(const SubRegion *Region, const char *OffsetName,
+static Messages getTaintMsgs(const MemSpaceRegion *Space,
+                             const SubRegion *Region, const char *OffsetName,
                              bool AlsoMentionUnderflow) {
-  std::string RegName = getRegionName(Region);
+  std::string RegName = getRegionName(Space, Region);
   return {formatv("Potential out of bound access to {0} with tainted {1}",
                   RegName, OffsetName),
           formatv("Access of {0} with a tainted {1} that may be {2}too large",
@@ -524,7 +528,7 @@ std::string StateUpdateReporter::getMessage(PathSensitiveBugReport &BR) const {
           << "' elements in ";
     else
       Out << "the extent of ";
-    Out << getRegionName(Reg);
+    Out << getRegionName(Space, Reg);
   }
   return std::string(Out.str());
 }
@@ -574,7 +578,7 @@ void ArrayBoundCheckerV2::performCheck(const Expr *E, CheckerContext &C) const {
   StateUpdateReporter SUR(Reg, ByteOffset, E, C);
 
   // CHECK LOWER BOUND
-  const MemSpaceRegion *Space = Reg->getRawMemorySpace();
+  const MemSpaceRegion *Space = Reg->getMemorySpace(State);
   if (!(isa<SymbolicRegion>(Reg) && isa<UnknownSpaceRegion>(Space))) {
     // A symbolic region in unknown space represents an unknown pointer that
     // may point into the middle of an array, so we don't look for underflows.
@@ -590,7 +594,7 @@ void ArrayBoundCheckerV2::performCheck(const Expr *E, CheckerContext &C) const {
       // The offset may be invalid (negative)...
       if (!WithinLowerBound) {
         // ...and it cannot be valid (>= 0), so report an error.
-        Messages Msgs = getPrecedesMsgs(Reg, ByteOffset);
+        Messages Msgs = getPrecedesMsgs(Space, Reg, ByteOffset);
         reportOOB(C, PrecedesLowerBound, Msgs, ByteOffset, std::nullopt);
         return;
       }
@@ -632,8 +636,8 @@ void ArrayBoundCheckerV2::performCheck(const Expr *E, CheckerContext &C) const {
         }
 
         Messages Msgs =
-            getExceedsMsgs(C.getASTContext(), Reg, ByteOffset, *KnownSize,
-                           Location, AlsoMentionUnderflow);
+            getExceedsMsgs(C.getASTContext(), Space, Reg, ByteOffset,
+                           *KnownSize, Location, AlsoMentionUnderflow);
         reportOOB(C, ExceedsUpperBound, Msgs, ByteOffset, KnownSize);
         return;
       }
@@ -649,7 +653,8 @@ void ArrayBoundCheckerV2::performCheck(const Expr *E, CheckerContext &C) const {
           if (isTainted(State, ASE->getIdx(), C.getLocationContext()))
             OffsetName = "index";
 
-        Messages Msgs = getTaintMsgs(Reg, OffsetName, AlsoMentionUnderflow);
+        Messages Msgs =
+            getTaintMsgs(Space, Reg, OffsetName, AlsoMentionUnderflow);
         reportOOB(C, ExceedsUpperBound, Msgs, ByteOffset, KnownSize,
                   /*IsTaintBug=*/true);
         return;

>From 6941eb49d93575f077bd592b50e124bc1c69e1ed Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Sun, 2 Feb 2025 19:14:32 +0100
Subject: [PATCH 35/55] Uplift ErrnoChecker

---
 clang/lib/StaticAnalyzer/Checkers/ErrnoChecker.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/ErrnoChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ErrnoChecker.cpp
index c2444aaf125a1b1..4682b67b510ea4e 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ErrnoChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ErrnoChecker.cpp
@@ -231,7 +231,7 @@ ProgramStateRef ErrnoChecker::checkRegionChanges(
 
   // Always reset errno state when the system memory space is invalidated.
   // The ErrnoRegion is not always found in the list in this case.
-  if (llvm::is_contained(Regions, ErrnoRegion->getRawMemorySpace()))
+  if (llvm::is_contained(Regions, ErrnoRegion->getMemorySpace(State)))
     return clearErrnoState(State);
 
   return State;

>From ff3e2f76678203a552553933a27b2654202415ab Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Sun, 2 Feb 2025 19:14:52 +0100
Subject: [PATCH 36/55] NFC Simplify MacOSXAPIChecker

---
 clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
index 3bfa90e2f901de0..41436e923bf8333 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
@@ -75,11 +75,9 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
   if (!R)
     return;
 
-  ProgramStateRef State = C.getState();
-
   // Global variables are fine.
   const MemRegion *RB = R->getBaseRegion();
-  if (RB->hasMemorySpace<GlobalsSpaceRegion>(State))
+  if (RB->hasMemorySpace<GlobalsSpaceRegion>(C.getState()))
     return;
 
   // Handle _dispatch_once.  In some versions of the OS X SDK we have the case

>From aba47932478e36a055f5d4cc4f42815402af0661 Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Sun, 2 Feb 2025 19:19:37 +0100
Subject: [PATCH 37/55] NFC Simplify MallocChecker, remove redundant lookups

---
 .../lib/StaticAnalyzer/Checkers/MallocChecker.cpp | 15 ++++++---------
 1 file changed, 6 insertions(+), 9 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 9135726d127b66b..0d1213ddf8b0142 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -2205,12 +2205,7 @@ MallocChecker::FreeMemAux(CheckerContext &C, const Expr *ArgExpr,
 
   // Parameters, locals, statics, globals, and memory returned by
   // __builtin_alloca() shouldn't be freed.
-  // Should skip this check if:
-  // - The region is in the heap
-  // - The region has unknown memspace and no trait for further clarification
-  //   (i.e., just unknown)
-  // - The region has unknown memspace and a heap memspace trait
-  if (!R->hasMemorySpace<HeapSpaceRegion, UnknownSpaceRegion>(State)) {
+  if (!R->hasMemorySpace<UnknownSpaceRegion, HeapSpaceRegion>(State)) {
     // Regions returned by malloc() are represented by SymbolicRegion objects
     // within HeapSpaceRegion. Of course, free() can work on memory allocated
     // outside the current function, so UnknownSpaceRegion is also a
@@ -2407,7 +2402,9 @@ bool MallocChecker::SummarizeRegion(ProgramStateRef State, raw_ostream &os,
     os << "a block";
     return true;
   default: {
-    if (MR->hasMemorySpace<StackLocalsSpaceRegion>(State)) {
+    const MemSpaceRegion *MS = MR->getMemorySpace(State);
+
+    if (isa<StackLocalsSpaceRegion>(MS)) {
       const VarRegion *VR = dyn_cast<VarRegion>(MR);
       const VarDecl *VD;
       if (VR)
@@ -2422,7 +2419,7 @@ bool MallocChecker::SummarizeRegion(ProgramStateRef State, raw_ostream &os,
       return true;
     }
 
-    if (MR->hasMemorySpace<StackArgumentsSpaceRegion>(State)) {
+    if (isa<StackArgumentsSpaceRegion>(MS)) {
       const VarRegion *VR = dyn_cast<VarRegion>(MR);
       const VarDecl *VD;
       if (VR)
@@ -2437,7 +2434,7 @@ bool MallocChecker::SummarizeRegion(ProgramStateRef State, raw_ostream &os,
       return true;
     }
 
-    if (MR->hasMemorySpace<GlobalsSpaceRegion>(State)) {
+    if (isa<GlobalsSpaceRegion>(MS)) {
       const VarRegion *VR = dyn_cast<VarRegion>(MR);
       const VarDecl *VD;
       if (VR)

>From 466959c916c0bb682fff5d22fb28518cb7f858d2 Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Sun, 2 Feb 2025 19:25:55 +0100
Subject: [PATCH 38/55] fixup! NFC Simplify MacOSXAPIChecker

---
 clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
index 41436e923bf8333..8d6e72a1ba93ccf 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
@@ -90,6 +90,8 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
       FName = TrimmedFName;
   }
 
+  const MemSpaceRegion *Space = RB->getMemorySpace(C.getState());
+
   SmallString<256> S;
   llvm::raw_svector_ostream os(S);
   bool SuggestStatic = false;
@@ -116,9 +118,9 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
     if (IVR != R)
       os << " memory within";
     os << " the instance variable '" << IVR->getDecl()->getName() << '\'';
-  } else if (RB->hasMemorySpace<HeapSpaceRegion>(State)) {
+  } else if (isa<HeapSpaceRegion>(Space)) {
     os << " heap-allocated memory";
-  } else if (RB->hasMemorySpace<UnknownSpaceRegion>(State)) {
+  } else if (isa<UnknownSpaceRegion>(Space)) {
     // Presence of an IVar superregion has priority over this branch, because
     // ObjC objects are on the heap even if the core doesn't realize this.
     // Presence of a block variable base region has priority over this branch,

>From f0337ccb600cf7d8e9984a81aedeff7f21c17064 Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Sun, 2 Feb 2025 19:27:49 +0100
Subject: [PATCH 39/55] NFC Simplify MoveChecker

---
 clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
index 41493285a879634..6ddefe308013a41 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
@@ -408,25 +408,25 @@ ExplodedNode *MoveChecker::tryToReportBug(const MemRegion *Region,
     // Creating the error message.
     llvm::SmallString<128> Str;
     llvm::raw_svector_ostream OS(Str);
-    ProgramStateRef ErrorNodeState = N->getState();
+    ProgramStateRef State = N->getState();
     switch(MK) {
       case MK_FunCall:
         OS << "Method called on moved-from object";
-        explainObject(ErrorNodeState, OS, Region, RD, MK);
+        explainObject(State, OS, Region, RD, MK);
         break;
       case MK_Copy:
         OS << "Moved-from object";
-        explainObject(ErrorNodeState, OS, Region, RD, MK);
+        explainObject(State, OS, Region, RD, MK);
         OS << " is copied";
         break;
       case MK_Move:
         OS << "Moved-from object";
-        explainObject(ErrorNodeState, OS, Region, RD, MK);
+        explainObject(State, OS, Region, RD, MK);
         OS << " is moved";
         break;
       case MK_Dereference:
         OS << "Dereference of null smart pointer";
-        explainObject(ErrorNodeState, OS, Region, RD, MK);
+        explainObject(State, OS, Region, RD, MK);
         break;
     }
 

>From 7ca4d5a628b9baafa59fc410d479b00d050798b3 Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Sun, 2 Feb 2025 19:29:27 +0100
Subject: [PATCH 40/55] Simplify NSErrorChecker

---
 clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
index 2a4a865b16f11ef..312eeea02416d35 100644
--- a/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
@@ -201,9 +201,9 @@ static QualType parameterTypeFromSVal(SVal val, CheckerContext &C) {
   if (std::optional<loc::MemRegionVal> X = val.getAs<loc::MemRegionVal>()) {
     const MemRegion* R = X->getRegion();
     if (const VarRegion *VR = R->getAs<VarRegion>())
-      if (const StackArgumentsSpaceRegion *stackReg =
-              dyn_cast<StackArgumentsSpaceRegion>(VR->getRawMemorySpace()))
-        if (stackReg->getStackFrame() == SFC)
+      if (const auto *StackSpace = dyn_cast<StackArgumentsSpaceRegion>(
+              VR->getMemorySpace(C.getState())))
+        if (StackSpace->getStackFrame() == SFC)
           return VR->getValueType();
   }
 

>From a58845163a6ba4f259aff927a6e0f4fbea335480 Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Sun, 2 Feb 2025 19:31:28 +0100
Subject: [PATCH 41/55] Uplift PutenvStackArrayChecker

---
 .../StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp    | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
index 028f46fbd7273f0..3d6ccc2892c0625 100644
--- a/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
@@ -45,13 +45,10 @@ void PutenvStackArrayChecker::checkPostCall(const CallEvent &Call,
   SVal ArgV = Call.getArgSVal(0);
   const Expr *ArgExpr = Call.getArgExpr(0);
 
-  const MemRegion *MR = ArgV.getAsRegion();
-
-  const StackSpaceRegion *SSR =
-      dyn_cast_if_present<StackSpaceRegion>(MR->getMemorySpace(C.getState()));
+  const auto *SSR = dyn_cast<StackSpaceRegion>(
+      ArgV.getAsRegion()->getMemorySpace(C.getState()));
   if (!SSR)
     return;
-
   const auto *StackFrameFuncD =
       dyn_cast_or_null<FunctionDecl>(SSR->getStackFrame()->getDecl());
   if (StackFrameFuncD && StackFrameFuncD->isMain())

>From 7c67c8fc5a909050a6308815977dafff56bc138e Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Sun, 2 Feb 2025 19:34:53 +0100
Subject: [PATCH 42/55] Simplify RetainCountDiagnostics

---
 .../RetainCountChecker/RetainCountDiagnostics.cpp         | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
index a5905c8d4ad4731..9af9beeb290c4b8 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
@@ -690,11 +690,9 @@ static AllocationInfo GetAllocationSite(ProgramStateManager &StateMgr,
       const MemRegion *R = FB.getRegion();
       // Do not show local variables belonging to a function other than
       // where the error is reported.
-      const StackSpaceRegion *SSR =
-          dyn_cast_if_present<StackSpaceRegion>(R->getMemorySpace(St));
-
-      if (SSR && SSR->getStackFrame() == LeakContext->getStackFrame())
-        FirstBinding = R;
+      if (const auto *MR = dyn_cast<StackSpaceRegion>(R->getMemorySpace(St)))
+        if (MR->getStackFrame() == LeakContext->getStackFrame())
+          FirstBinding = R;
     }
 
     // AllocationNode is the last node in which the symbol was tracked.

>From 1133e0a07adfcc577cb91717959bf84989744190 Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Sun, 2 Feb 2025 19:43:12 +0100
Subject: [PATCH 43/55] Simplify StackAddrEscapeChecker

---
 .../Checkers/StackAddrEscapeChecker.cpp       | 35 ++++++++++---------
 1 file changed, 19 insertions(+), 16 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index 84a2d346806dc3d..56edfcfe4230e67 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -19,6 +19,7 @@
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/Support/raw_ostream.h"
@@ -212,8 +213,9 @@ void StackAddrEscapeChecker::checkAsyncExecutedBlockCaptures(
 
 void StackAddrEscapeChecker::checkReturnedBlockCaptures(
     const BlockDataRegion &B, CheckerContext &C) const {
+  ProgramStateRef State = C.getState();
   for (const MemRegion *Region : getCapturedStackRegions(B, C)) {
-    if (isNotInCurrentFrame(Region->getRawMemorySpace(), C))
+    if (isNotInCurrentFrame(Region->getMemorySpace(State), C))
       continue;
     ExplodedNode *N = C.generateNonFatalErrorNode();
     if (!N)
@@ -290,19 +292,18 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
   EmitStackError(C, R, RetE);
 }
 
-static const MemSpaceRegion *getStackOrGlobalSpaceRegion(const MemRegion *R) {
+static const MemSpaceRegion *getStackOrGlobalSpaceRegion(ProgramStateRef State,
+                                                         const MemRegion *R) {
   assert(R);
-  if (const auto *MemSpace = R->getRawMemorySpace()) {
-    if (const auto *SSR = MemSpace->getAs<StackSpaceRegion>())
-      return SSR;
-    if (const auto *GSR = MemSpace->getAs<GlobalsSpaceRegion>())
-      return GSR;
-  }
+  if (const auto *MemSpace = R->getMemorySpace(State);
+      isa<StackSpaceRegion, GlobalsSpaceRegion>(MemSpace))
+    return MemSpace;
+
   // If R describes a lambda capture, it will be a symbolic region
   // referring to a field region of another symbolic region.
   if (const auto *SymReg = R->getBaseRegion()->getAs<SymbolicRegion>()) {
     if (const auto *OriginReg = SymReg->getSymbol()->getOriginRegion())
-      return getStackOrGlobalSpaceRegion(OriginReg);
+      return getStackOrGlobalSpaceRegion(State, OriginReg);
   }
   return nullptr;
 }
@@ -318,7 +319,8 @@ static const MemRegion *getOriginBaseRegion(const MemRegion *Reg) {
   return Reg;
 }
 
-static std::optional<std::string> printReferrer(const MemRegion *Referrer) {
+static std::optional<std::string> printReferrer(ProgramStateRef State,
+                                                const MemRegion *Referrer) {
   assert(Referrer);
   const StringRef ReferrerMemorySpace = [](const MemSpaceRegion *Space) {
     if (isa<StaticGlobalSpaceRegion>(Space))
@@ -328,7 +330,7 @@ static std::optional<std::string> printReferrer(const MemRegion *Referrer) {
     assert(isa<StackSpaceRegion>(Space));
     // This case covers top-level and inlined analyses.
     return "caller";
-  }(getStackOrGlobalSpaceRegion(Referrer));
+  }(getStackOrGlobalSpaceRegion(State, Referrer));
 
   while (!Referrer->canPrintPretty()) {
     if (const auto *SymReg = dyn_cast<SymbolicRegion>(Referrer);
@@ -404,9 +406,10 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,
     /// referred by an other stack variable from different stack frame.
     bool checkForDanglingStackVariable(const MemRegion *Referrer,
                                        const MemRegion *Referred) {
-      const auto *ReferrerMemSpace = getStackOrGlobalSpaceRegion(Referrer);
+      const auto *ReferrerMemSpace =
+          getStackOrGlobalSpaceRegion(State, Referrer);
       const auto *ReferredMemSpace =
-          Referred->getRawMemorySpace()->getAs<StackSpaceRegion>();
+          dyn_cast<StackSpaceRegion>(Referred->getMemorySpace(State));
 
       if (!ReferrerMemSpace || !ReferredMemSpace)
         return false;
@@ -470,10 +473,10 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,
 
       // Check the globals for the same.
       if (!isa_and_nonnull<GlobalsSpaceRegion>(
-              getStackOrGlobalSpaceRegion(Region)))
+              getStackOrGlobalSpaceRegion(State, Region)))
         return true;
       if (VR && VR->hasMemorySpace<StackSpaceRegion>(State) &&
-          !isNotInCurrentFrame(VR->getRawMemorySpace(), Ctx))
+          !isNotInCurrentFrame(VR->getMemorySpace(State), Ctx))
         V.emplace_back(Region, VR);
       return true;
     }
@@ -522,7 +525,7 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,
       return;
     }
 
-    auto ReferrerVariable = printReferrer(Referrer);
+    auto ReferrerVariable = printReferrer(State, Referrer);
     if (!ReferrerVariable) {
       continue;
     }

>From 6b5e05ca99e90943ef3978269c0dfeb4d09480a1 Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Sun, 2 Feb 2025 19:44:50 +0100
Subject: [PATCH 44/55] Uplift UnixAPIChecker

---
 clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
index b6692961c3e6788..cd54edc93bee423 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
@@ -427,7 +427,8 @@ void UnixAPIMisuseChecker::CheckPthreadOnce(CheckerContext &C,
     os << " stack allocated memory";
   os << " for the \"control\" value.  Using such transient memory for "
   "the control value is potentially dangerous.";
-  if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getRawMemorySpace()))
+  if (isa<VarRegion>(R) &&
+      isa<StackLocalsSpaceRegion>(R->getMemorySpace(state)))
     os << "  Perhaps you intended to declare the variable as 'static'?";
 
   auto report =

>From 070884d55863801ba3f487580e37fc161cb5f30c Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Sun, 2 Feb 2025 19:45:52 +0100
Subject: [PATCH 45/55] Simplify BugReporterVisitors

---
 clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index 6ef333c2bcf1875..ce28ad347598834 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -1192,8 +1192,8 @@ static bool isInitializationOfVar(const ExplodedNode *N, const VarRegion *VR) {
   if (DS->getSingleDecl() != VR->getDecl())
     return false;
 
-  const StackSpaceRegion *FrameSpace =
-      dyn_cast_if_present<StackSpaceRegion>(VR->getMemorySpace(N->getState()));
+  const auto *FrameSpace =
+      dyn_cast<StackSpaceRegion>(VR->getMemorySpace(N->getState()));
 
   if (!FrameSpace) {
     // If we ever directly evaluate global DeclStmts, this assertion will be

>From ad934609bdb20da9223cdd564faa0b0b6b38f138 Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Sun, 2 Feb 2025 19:47:38 +0100
Subject: [PATCH 46/55] Simplify ExprEngine

---
 clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index a5a7b7f2fbeca4c..b845fc94305f680 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -3510,15 +3510,15 @@ ProgramStateRef ExprEngine::processPointerEscapedOnBind(
   for (const std::pair<SVal, SVal> &LocAndVal : LocAndVals) {
     // Cases (1) and (2).
     const MemRegion *MR = LocAndVal.first.getAsRegion();
-    if (!MR ||
-        !MR->hasMemorySpace<StackSpaceRegion, StaticGlobalSpaceRegion>(State)) {
+    const MemSpaceRegion *Space = MR->getMemorySpace(State);
+    if (!MR || !isa<StackSpaceRegion, StaticGlobalSpaceRegion>(Space)) {
       Escaped.push_back(LocAndVal.second);
       continue;
     }
 
     // Case (3).
     if (const auto *VR = dyn_cast<VarRegion>(MR->getBaseRegion()))
-      if (VR->hasMemorySpace<StackArgumentsSpaceRegion>(State) &&
+      if (isa<StackArgumentsSpaceRegion>(Space) &&
           VR->getStackFrame()->inTopFrame())
         if (const auto *RD = VR->getValueType()->getAsCXXRecordDecl())
           if (!RD->hasTrivialDestructor()) {

>From 5c1adadf2d1311cb1561ee84b6d710ab270e6297 Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Sun, 2 Feb 2025 19:51:49 +0100
Subject: [PATCH 47/55] Simplify MemRegion.cpp

---
 clang/lib/StaticAnalyzer/Core/MemRegion.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
index f46bae2e4ac8485..bc325dcaaefa848 100644
--- a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -61,8 +61,8 @@ using namespace ento;
 
 #define DEBUG_TYPE "MemRegion"
 
-REGISTER_MAP_WITH_PROGRAMSTATE(MemSpacesMap, const clang::ento::MemRegion *,
-                               const clang::ento::MemSpaceRegion *)
+REGISTER_MAP_WITH_PROGRAMSTATE(MemSpacesMap, const MemRegion *,
+                               const MemSpaceRegion *)
 
 //===----------------------------------------------------------------------===//
 // MemRegion Construction.

>From 41233e937e53b7f661702dcc2f8c6cbf60884481 Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Sun, 2 Feb 2025 19:55:29 +0100
Subject: [PATCH 48/55] Simplify SimpleSValBuilder

---
 clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
index ab5b21c68f6e7f4..137554b9914aac0 100644
--- a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
@@ -948,8 +948,8 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state,
 
     const MemRegion *LeftBase = LeftMR->getBaseRegion();
     const MemRegion *RightBase = RightMR->getBaseRegion();
-    const MemSpaceRegion *LeftMS = LeftBase->getRawMemorySpace();
-    const MemSpaceRegion *RightMS = RightBase->getRawMemorySpace();
+    const MemSpaceRegion *LeftMS = LeftBase->getMemorySpace(state);
+    const MemSpaceRegion *RightMS = RightBase->getMemorySpace(state);
     const MemSpaceRegion *UnknownMS = MemMgr.getUnknownRegion();
 
     // If the two regions are from different known memory spaces they cannot be

>From e8f579a167bff0f5058de79e59639c6ee9884d1a Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Sun, 2 Feb 2025 20:01:03 +0100
Subject: [PATCH 49/55] Cleanup dyn_cast of getMemSpace using getMemSpaceAs<T>

---
 .../clang/StaticAnalyzer/Checkers/SValExplainer.h     |  2 +-
 .../StaticAnalyzer/Core/PathSensitive/MemRegion.h     | 11 +++++++++++
 .../RetainCountChecker/RetainCountDiagnostics.cpp     |  2 +-
 .../Checkers/StackAddrEscapeChecker.cpp               |  2 +-
 clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp  |  3 +--
 clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp |  2 +-
 clang/lib/StaticAnalyzer/Core/MemRegion.cpp           |  2 +-
 7 files changed, 17 insertions(+), 7 deletions(-)

diff --git a/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h b/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
index 3786f50b16921c5..a2f976b8e009850 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
+++ b/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
@@ -169,7 +169,7 @@ class SValExplainer : public FullSValVisitor<SValExplainer, std::string> {
             .getCanonicalType()->getAs<ObjCObjectPointerType>())
       return "object at " + Visit(R->getSymbol());
     // Other heap-based symbolic regions are also special.
-    if (isa<HeapSpaceRegion>(R->getMemorySpace(State)))
+    if (R->hasMemorySpace<HeapSpaceRegion>(State))
       return "heap segment that starts at " + Visit(R->getSymbol());
     return "pointee of " + Visit(R->getSymbol());
   }
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index aa46804b36136a0..6c80b9f45c73cb6 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -127,12 +127,23 @@ class MemRegion : public llvm::FoldingSetNode {
   [[nodiscard]] LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion *
   getRawMemorySpace() const;
 
+  /// Deprecated. Use getMemorySpace(ProgramStateRef) instead.
+  template <class MemSpace>
+  [[nodiscard]] const MemSpace *getRawMemorySpaceAs() const {
+    return dyn_cast<MemSpace>(getRawMemorySpace());
+  }
+
   /// Returns the most specific memory space for this memory region in the given
   /// ProgramStateRef. We may infer a more accurate memory space for unknown
   /// space regions and associate this in the State.
   [[nodiscard]] LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion *
   getMemorySpace(ProgramStateRef State) const;
 
+  template <class MemSpace>
+  [[nodiscard]] const MemSpace *getMemorySpaceAs(ProgramStateRef State) const {
+    return dyn_cast<MemSpace>(getMemorySpace(State));
+  }
+
   template <typename... MemorySpaces>
   [[nodiscard]] bool hasMemorySpace(ProgramStateRef State) const {
     static_assert(sizeof...(MemorySpaces));
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
index 9af9beeb290c4b8..77258958ae027f5 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
@@ -690,7 +690,7 @@ static AllocationInfo GetAllocationSite(ProgramStateManager &StateMgr,
       const MemRegion *R = FB.getRegion();
       // Do not show local variables belonging to a function other than
       // where the error is reported.
-      if (const auto *MR = dyn_cast<StackSpaceRegion>(R->getMemorySpace(St)))
+      if (const auto *MR = R->getMemorySpaceAs<StackSpaceRegion>(St))
         if (MR->getStackFrame() == LeakContext->getStackFrame())
           FirstBinding = R;
     }
diff --git a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index 56edfcfe4230e67..1817bede000e0fc 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -409,7 +409,7 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,
       const auto *ReferrerMemSpace =
           getStackOrGlobalSpaceRegion(State, Referrer);
       const auto *ReferredMemSpace =
-          dyn_cast<StackSpaceRegion>(Referred->getMemorySpace(State));
+          Referred->getMemorySpaceAs<StackSpaceRegion>(State);
 
       if (!ReferrerMemSpace || !ReferredMemSpace)
         return false;
diff --git a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
index cd54edc93bee423..a05361f89ed89cd 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
@@ -427,8 +427,7 @@ void UnixAPIMisuseChecker::CheckPthreadOnce(CheckerContext &C,
     os << " stack allocated memory";
   os << " for the \"control\" value.  Using such transient memory for "
   "the control value is potentially dangerous.";
-  if (isa<VarRegion>(R) &&
-      isa<StackLocalsSpaceRegion>(R->getMemorySpace(state)))
+  if (isa<VarRegion>(R) && R->hasMemorySpace<StackLocalsSpaceRegion>(state))
     os << "  Perhaps you intended to declare the variable as 'static'?";
 
   auto report =
diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index ce28ad347598834..6b617c2c02d8719 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -1193,7 +1193,7 @@ static bool isInitializationOfVar(const ExplodedNode *N, const VarRegion *VR) {
     return false;
 
   const auto *FrameSpace =
-      dyn_cast<StackSpaceRegion>(VR->getMemorySpace(N->getState()));
+      VR->getMemorySpaceAs<StackSpaceRegion>(N->getState());
 
   if (!FrameSpace) {
     // If we ever directly evaluate global DeclStmts, this assertion will be
diff --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
index bc325dcaaefa848..915631c5b9ce0ee 100644
--- a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -1382,7 +1382,7 @@ ProgramStateRef MemRegion::setMemorySpace(ProgramStateRef State,
   assert(!isa<UnknownSpaceRegion>(Space));
 
   // Currently, it we should have no accurate memspace for this region.
-  assert(isa<UnknownSpaceRegion>(Base->getMemorySpace(State)));
+  assert(Base->hasMemorySpace<UnknownSpaceRegion>(State));
   return State->set<MemSpacesMap>(Base, Space);
 }
 

>From d1c9f81370e94f99e00373b1e6b8553f86c9963e Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Sun, 2 Feb 2025 20:04:50 +0100
Subject: [PATCH 50/55] Further cleanup MacOSXAPIChecker

---
 clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
index 8d6e72a1ba93ccf..d7173d7a464e956 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
@@ -76,8 +76,8 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
     return;
 
   // Global variables are fine.
-  const MemRegion *RB = R->getBaseRegion();
-  if (RB->hasMemorySpace<GlobalsSpaceRegion>(C.getState()))
+  const MemSpaceRegion *Space = R->getMemorySpace(C.getState());
+  if (isa<GlobalsSpaceRegion>(Space))
     return;
 
   // Handle _dispatch_once.  In some versions of the OS X SDK we have the case
@@ -90,13 +90,11 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
       FName = TrimmedFName;
   }
 
-  const MemSpaceRegion *Space = RB->getMemorySpace(C.getState());
-
   SmallString<256> S;
   llvm::raw_svector_ostream os(S);
   bool SuggestStatic = false;
   os << "Call to '" << FName << "' uses";
-  if (const VarRegion *VR = dyn_cast<VarRegion>(RB)) {
+  if (const VarRegion *VR = dyn_cast<VarRegion>(R->getBaseRegion())) {
     const VarDecl *VD = VR->getDecl();
     // FIXME: These should have correct memory space and thus should be filtered
     // out earlier. This branch only fires when we're looking from a block,

>From f887084c3d21e4935563e89f5cc942457525c65a Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Sun, 2 Feb 2025 20:06:36 +0100
Subject: [PATCH 51/55] fixup! Cleanup dyn_cast of getMemSpace using
 getMemSpaceAs<T>

---
 clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
index 3d6ccc2892c0625..76f86005961b359 100644
--- a/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
@@ -45,8 +45,8 @@ void PutenvStackArrayChecker::checkPostCall(const CallEvent &Call,
   SVal ArgV = Call.getArgSVal(0);
   const Expr *ArgExpr = Call.getArgExpr(0);
 
-  const auto *SSR = dyn_cast<StackSpaceRegion>(
-      ArgV.getAsRegion()->getMemorySpace(C.getState()));
+  const auto *SSR =
+      ArgV.getAsRegion()->getMemorySpaceAs<StackSpaceRegion>(C.getState());
   if (!SSR)
     return;
   const auto *StackFrameFuncD =

>From 95d45295e4475c3fb217c631527ae875291b9fd3 Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Sun, 2 Feb 2025 20:09:10 +0100
Subject: [PATCH 52/55] fixup! Simplify ExprEngine

---
 clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index b845fc94305f680..390805fc555d087 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -3510,7 +3510,7 @@ ProgramStateRef ExprEngine::processPointerEscapedOnBind(
   for (const std::pair<SVal, SVal> &LocAndVal : LocAndVals) {
     // Cases (1) and (2).
     const MemRegion *MR = LocAndVal.first.getAsRegion();
-    const MemSpaceRegion *Space = MR->getMemorySpace(State);
+    const MemSpaceRegion *Space = MR ? MR->getMemorySpace(State) : nullptr;
     if (!MR || !isa<StackSpaceRegion, StaticGlobalSpaceRegion>(Space)) {
       Escaped.push_back(LocAndVal.second);
       continue;

>From b8b1aff196f25f5d379928264a938d3512d7083b Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Sun, 2 Feb 2025 20:11:52 +0100
Subject: [PATCH 53/55] Fix possible nullderef in PutenvStackArrayChecker

---
 clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
index 76f86005961b359..ea0fd4165d6760a 100644
--- a/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
@@ -45,6 +45,9 @@ void PutenvStackArrayChecker::checkPostCall(const CallEvent &Call,
   SVal ArgV = Call.getArgSVal(0);
   const Expr *ArgExpr = Call.getArgExpr(0);
 
+  if (!ArgV.getAsRegion())
+    return;
+
   const auto *SSR =
       ArgV.getAsRegion()->getMemorySpaceAs<StackSpaceRegion>(C.getState());
   if (!SSR)

>From d772be99b92e699baf759bb733d16c2b3b529c9b Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Sun, 2 Feb 2025 20:12:05 +0100
Subject: [PATCH 54/55] Further cleanup NSErrorChecker

---
 clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
index 312eeea02416d35..15fd9a0b76cc399 100644
--- a/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
@@ -201,8 +201,8 @@ static QualType parameterTypeFromSVal(SVal val, CheckerContext &C) {
   if (std::optional<loc::MemRegionVal> X = val.getAs<loc::MemRegionVal>()) {
     const MemRegion* R = X->getRegion();
     if (const VarRegion *VR = R->getAs<VarRegion>())
-      if (const auto *StackSpace = dyn_cast<StackArgumentsSpaceRegion>(
-              VR->getMemorySpace(C.getState())))
+      if (const auto *StackSpace =
+              VR->getMemorySpaceAs<StackArgumentsSpaceRegion>(C.getState()))
         if (StackSpace->getStackFrame() == SFC)
           return VR->getValueType();
   }

>From 0c900fafee1e446e2feea40d0cd2f38bac0ec2e2 Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Sun, 2 Feb 2025 20:19:43 +0100
Subject: [PATCH 55/55] Further simplify StackAddrEscapeChecker

---
 .../Checkers/StackAddrEscapeChecker.cpp       | 46 +++++++++++--------
 1 file changed, 28 insertions(+), 18 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index 1817bede000e0fc..b5597c58d16205d 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -21,6 +21,7 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/Support/raw_ostream.h"
 using namespace clang;
@@ -60,9 +61,10 @@ class StackAddrEscapeChecker
   bool isSemaphoreCaptured(const BlockDecl &B) const;
   static SourceRange genName(raw_ostream &os, const MemRegion *R,
                              ASTContext &Ctx);
-  static SmallVector<const MemRegion *, 4>
+  static SmallVector<std::pair<const MemRegion *, const StackSpaceRegion *>, 4>
   getCapturedStackRegions(const BlockDataRegion &B, CheckerContext &C);
-  static bool isNotInCurrentFrame(const MemSpaceRegion *MS, CheckerContext &C);
+  static bool isNotInCurrentFrame(const StackSpaceRegion *MS,
+                                  CheckerContext &C);
 };
 } // namespace
 
@@ -118,10 +120,9 @@ SourceRange StackAddrEscapeChecker::genName(raw_ostream &os, const MemRegion *R,
   return range;
 }
 
-bool StackAddrEscapeChecker::isNotInCurrentFrame(const MemSpaceRegion *MS,
+bool StackAddrEscapeChecker::isNotInCurrentFrame(const StackSpaceRegion *MS,
                                                  CheckerContext &C) {
-  const StackSpaceRegion *S = cast<StackSpaceRegion>(MS);
-  return S->getStackFrame() != C.getStackFrame();
+  return MS->getStackFrame() != C.getStackFrame();
 }
 
 bool StackAddrEscapeChecker::isSemaphoreCaptured(const BlockDecl &B) const {
@@ -135,16 +136,20 @@ bool StackAddrEscapeChecker::isSemaphoreCaptured(const BlockDecl &B) const {
   return false;
 }
 
-SmallVector<const MemRegion *, 4>
+SmallVector<std::pair<const MemRegion *, const StackSpaceRegion *>, 4>
 StackAddrEscapeChecker::getCapturedStackRegions(const BlockDataRegion &B,
                                                 CheckerContext &C) {
-  SmallVector<const MemRegion *, 4> Regions;
+  SmallVector<std::pair<const MemRegion *, const StackSpaceRegion *>, 4>
+      Regions;
   ProgramStateRef State = C.getState();
   for (auto Var : B.referenced_vars()) {
     SVal Val = State->getSVal(Var.getCapturedRegion());
-    const MemRegion *Region = Val.getAsRegion();
-    if (Region && Region->hasMemorySpace<StackSpaceRegion>(State))
-      Regions.push_back(Region);
+    if (const MemRegion *Region = Val.getAsRegion()) {
+      if (const auto *Space =
+              Region->getMemorySpaceAs<StackSpaceRegion>(State)) {
+        Regions.emplace_back(Region, Space);
+      }
+    }
   }
   return Regions;
 }
@@ -183,7 +188,8 @@ void StackAddrEscapeChecker::checkAsyncExecutedBlockCaptures(
   // a variable of the type "dispatch_semaphore_t".
   if (isSemaphoreCaptured(*B.getDecl()))
     return;
-  for (const MemRegion *Region : getCapturedStackRegions(B, C)) {
+  for (const MemRegion *Region :
+       llvm::make_first_range(getCapturedStackRegions(B, C))) {
     // The block passed to dispatch_async may capture another block
     // created on the stack. However, there is no leak in this situaton,
     // no matter if ARC or no ARC is enabled:
@@ -214,8 +220,8 @@ void StackAddrEscapeChecker::checkAsyncExecutedBlockCaptures(
 void StackAddrEscapeChecker::checkReturnedBlockCaptures(
     const BlockDataRegion &B, CheckerContext &C) const {
   ProgramStateRef State = C.getState();
-  for (const MemRegion *Region : getCapturedStackRegions(B, C)) {
-    if (isNotInCurrentFrame(Region->getMemorySpace(State), C))
+  for (auto [Region, StackSpace] : getCapturedStackRegions(B, C)) {
+    if (isNotInCurrentFrame(StackSpace, C))
       continue;
     ExplodedNode *N = C.generateNonFatalErrorNode();
     if (!N)
@@ -268,8 +274,8 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
   if (const BlockDataRegion *B = dyn_cast<BlockDataRegion>(R))
     checkReturnedBlockCaptures(*B, C);
 
-  const MemSpaceRegion *MS = R->getMemorySpace(C.getState());
-  if (!isa<StackSpaceRegion>(MS) || isNotInCurrentFrame(MS, C))
+  const auto *StackSpace = R->getMemorySpaceAs<StackSpaceRegion>(C.getState());
+  if (!StackSpace || isNotInCurrentFrame(StackSpace, C))
     return;
 
   // Returning a record by value is fine. (In this case, the returned
@@ -475,9 +481,13 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,
       if (!isa_and_nonnull<GlobalsSpaceRegion>(
               getStackOrGlobalSpaceRegion(State, Region)))
         return true;
-      if (VR && VR->hasMemorySpace<StackSpaceRegion>(State) &&
-          !isNotInCurrentFrame(VR->getMemorySpace(State), Ctx))
-        V.emplace_back(Region, VR);
+
+      if (VR) {
+        if (const auto *S = VR->getMemorySpaceAs<StackSpaceRegion>(State);
+            S && !isNotInCurrentFrame(S, Ctx)) {
+          V.emplace_back(Region, VR);
+        }
+      }
       return true;
     }
   };



More information about the cfe-commits mailing list