https://github.com/steakhal created 
https://github.com/llvm/llvm-project/pull/210938

Walking a StackFrame's parent chain was open-coded across the Analysis library 
and Static Analyzer as hand-rolled loops of the form `for (const StackFrame *SF 
= X; SF; SF = SF->getParent())`.

Add range-based traversal helpers and convert the applicable loops:

  * StackFrame::parents()             - strict ancestors (excludes *this)
  * StackFrame::parentsIncludingSelf() - *this then all ancestors

Both are built on a small forward `parent_iterator` that dereferences to `const 
StackFrame &` and advances via getParent(), with a null past-the-end sentinel.

For the common case of obtaining the current frame from an ExplodedNode or 
CheckerContext, add a self-inclusive `stackframes()` convenience on each that 
delegates to `getStackFrame()->parentsIncludingSelf()`.

Converted call-sites additionally adopt llvm::any_of / llvm::enumerate / 
make_pointer_range where it makes the traversal more declarative. Loops that 
stop at a target frame or advance conditionally (i.e. not "walk until null") 
are intentionally left as-is.

From c79cc42619fa9b6d9e933503dc6ae19b902a6214 Mon Sep 17 00:00:00 2001
From: Balazs Benics <[email protected]>
Date: Tue, 21 Jul 2026 09:14:28 +0100
Subject: [PATCH] [analyzer][NFC] Add StackFrame parent-chain range helpers

Walking a StackFrame's parent chain was open-coded across the Analysis
library and Static Analyzer as hand-rolled loops of the form
`for (const StackFrame *SF = X; SF; SF = SF->getParent())`.

Add range-based traversal helpers and convert the applicable loops:

  * StackFrame::parents()             - strict ancestors (excludes *this)
  * StackFrame::parentsIncludingSelf() - *this then all ancestors

Both are built on a small forward `parent_iterator` that dereferences to
`const StackFrame &` and advances via getParent(), with a null past-the-end
sentinel.

For the common case of obtaining the current frame from an ExplodedNode or
CheckerContext, add a self-inclusive `stackframes()` convenience on each that
delegates to `getStackFrame()->parentsIncludingSelf()`.

Converted call-sites additionally adopt llvm::any_of / llvm::enumerate /
make_pointer_range where it makes the traversal more declarative. Loops that
stop at a target frame or advance conditionally (i.e. not "walk until null")
are intentionally left as-is.

This is NFC.
---
 .../clang/Analysis/AnalysisDeclContext.h      | 48 +++++++++++++++++++
 .../Core/PathSensitive/CheckerContext.h       |  5 ++
 .../Core/PathSensitive/ExplodedGraph.h        |  5 ++
 .../Core/PathSensitive/ExprEngine.h           |  6 ++-
 clang/lib/Analysis/AnalysisDeclContext.cpp    | 38 ++++++---------
 .../Checkers/CheckObjCDealloc.cpp             | 14 ++----
 .../StaticAnalyzer/Checkers/MallocChecker.cpp |  6 +--
 .../StaticAnalyzer/Checkers/MoveChecker.cpp   | 24 +++++-----
 .../Checkers/TraversalChecker.cpp             | 13 ++---
 .../UninitializedObjectChecker.cpp            | 32 +++++--------
 .../Core/BugReporterVisitors.cpp              |  4 +-
 clang/lib/StaticAnalyzer/Core/Environment.cpp |  5 +-
 .../Core/ExprEngineCallAndReturn.cpp          | 13 +++--
 clang/lib/StaticAnalyzer/Core/MemRegion.cpp   | 27 +++++------
 14 files changed, 136 insertions(+), 104 deletions(-)

diff --git a/clang/include/clang/Analysis/AnalysisDeclContext.h 
b/clang/include/clang/Analysis/AnalysisDeclContext.h
index 84877136f842b..83e2cbce6118b 100644
--- a/clang/include/clang/Analysis/AnalysisDeclContext.h
+++ b/clang/include/clang/Analysis/AnalysisDeclContext.h
@@ -29,6 +29,7 @@
 #include "llvm/ADT/iterator_range.h"
 #include "llvm/Support/Allocator.h"
 #include <functional>
+#include <iterator>
 #include <memory>
 
 namespace clang {
@@ -247,6 +248,53 @@ class StackFrame final : public llvm::FoldingSetNode {
   /// It might return null.
   const StackFrame *getParent() const { return Parent; }
 
+  /// Forward iterator over a chain of \c StackFrame parents. Advancing follows
+  /// \c getParent(); the past-the-end iterator holds a null frame.
+  class parent_iterator {
+    const StackFrame *Current = nullptr;
+
+  public:
+    using iterator_category = std::forward_iterator_tag;
+    using value_type = const StackFrame;
+    using difference_type = std::ptrdiff_t;
+    using pointer = const StackFrame *;
+    using reference = const StackFrame &;
+
+    parent_iterator() = default;
+    explicit parent_iterator(const StackFrame *SF) : Current(SF) {}
+
+    reference operator*() const { return *Current; }
+    pointer operator->() const { return Current; }
+    parent_iterator &operator++() {
+      assert(Current && "Cannot call ++ on the end iterator");
+      Current = Current->getParent();
+      return *this;
+    }
+    parent_iterator operator++(int) {
+      parent_iterator Tmp = *this;
+      ++*this;
+      return Tmp;
+    }
+    bool operator==(const parent_iterator &Other) const {
+      return Current == Other.Current;
+    }
+    bool operator!=(const parent_iterator &Other) const {
+      return !(*this == Other);
+    }
+  };
+
+  /// Iterates over the strict ancestors of this frame, i.e. \c getParent(),
+  /// \c getParent()->getParent(), ... up to (but excluding) the null frame.
+  /// Does not include \c *this.
+  llvm::iterator_range<parent_iterator> parents() const {
+    return {parent_iterator(getParent()), parent_iterator()};
+  }
+
+  /// Iterates over this frame followed by all of its ancestors.
+  llvm::iterator_range<parent_iterator> parentsIncludingSelf() const {
+    return {parent_iterator(this), parent_iterator()};
+  }
+
   int64_t getID() const { return ID; }
 
   bool isParentOf(const StackFrame *SF) const;
diff --git 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
index b853769148625..18e55862bc855 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
@@ -103,6 +103,11 @@ class CheckerContext {
 
   const StackFrame *getStackFrame() const { return Pred->getStackFrame(); }
 
+  /// Iterates over the current stack frame and all of its ancestors.
+  llvm::iterator_range<StackFrame::parent_iterator> stackframes() const {
+    return getStackFrame()->parentsIncludingSelf();
+  }
+
   /// Return true if the current StackFrame has no caller context.
   bool inTopFrame() const { return getStackFrame()->inTopFrame(); }
 
diff --git 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
index f5bb5ad81d680..9e48dfe2297e8 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
@@ -144,6 +144,11 @@ class ExplodedNode : public llvm::FoldingSetNode {
     return getLocation().getStackFrame();
   }
 
+  /// Iterates over the current stack frame and all of its ancestors.
+  llvm::iterator_range<StackFrame::parent_iterator> stackframes() const {
+    return getStackFrame()->parentsIncludingSelf();
+  }
+
   const Decl &getCodeDecl() const { return *getStackFrame()->getDecl(); }
 
   CFG &getCFG() const { return *getStackFrame()->getCFG(); }
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index 327d5858e9c6b..b50b7f2b05747 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -843,8 +843,10 @@ class ExprEngine {
                     bool isLoad);
 
   /// Count the stack depth and determine if the call is recursive.
-  void examineStackFrames(const Decl *D, const StackFrame *SF,
-                          bool &IsRecursive, unsigned &StackDepth);
+  void
+  examineStackFrames(const Decl *D,
+                     llvm::iterator_range<StackFrame::parent_iterator> Frames,
+                     bool &IsRecursive, unsigned &StackDepth);
 
   enum CallInlinePolicy {
     CIP_Allowed,
diff --git a/clang/lib/Analysis/AnalysisDeclContext.cpp 
b/clang/lib/Analysis/AnalysisDeclContext.cpp
index 437360a775275..649035c46d019 100644
--- a/clang/lib/Analysis/AnalysisDeclContext.cpp
+++ b/clang/lib/Analysis/AnalysisDeclContext.cpp
@@ -36,6 +36,7 @@
 #include "clang/Basic/SourceManager.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/iterator_range.h"
 #include "llvm/Support/Allocator.h"
@@ -424,15 +425,8 @@ const StackFrame *StackFrameManager::getStackFrame(
 
//===----------------------------------------------------------------------===//
 
 bool StackFrame::isParentOf(const StackFrame *SF) const {
-  do {
-    const StackFrame *Parent = SF->getParent();
-    if (Parent == this)
-      return true;
-    else
-      SF = Parent;
-  } while (SF);
-
-  return false;
+  return llvm::any_of(SF->parents(),
+                      [this](const StackFrame &A) { return &A == this; });
 }
 
 static void printLocation(raw_ostream &Out, const SourceManager &SM,
@@ -451,15 +445,13 @@ void StackFrame::dumpStack(raw_ostream &Out) const {
   const SourceManager &SM =
       getAnalysisDeclContext()->getASTContext().getSourceManager();
 
-  unsigned Frame = 0;
-  for (const StackFrame *SF = this; SF; SF = SF->getParent()) {
-    Out << "\t#" << Frame << ' ';
-    ++Frame;
-    if (const auto *D = dyn_cast<NamedDecl>(SF->getDecl()))
+  for (auto [Idx, SF] : llvm::enumerate(parentsIncludingSelf())) {
+    Out << "\t#" << Idx << ' ';
+    if (const auto *D = dyn_cast<NamedDecl>(SF.getDecl()))
       Out << "Calling " << AnalysisDeclContext::getFunctionName(D);
     else
       Out << "Calling anonymous code";
-    if (const Expr *E = SF->getCallSite()) {
+    if (const Expr *E = SF.getCallSite()) {
       Out << " at line ";
       printLocation(Out, SM, E->getBeginLoc());
     }
@@ -477,19 +469,17 @@ void StackFrame::printJson(
   const SourceManager &SM =
       getAnalysisDeclContext()->getASTContext().getSourceManager();
 
-  unsigned Frame = 0;
-  for (const StackFrame *SF = this; SF; SF = SF->getParent()) {
+  for (auto [Idx, SF] : llvm::enumerate(parentsIncludingSelf())) {
     Indent(Out, Space, IsDot)
-        << "{ \"lctx_id\": " << SF->getID() << ", \"location_context\": \"";
-    Out << '#' << Frame << " Call\", \"calling\": \"";
-    ++Frame;
-    if (const auto *D = dyn_cast<NamedDecl>(SF->getDecl()))
+        << "{ \"lctx_id\": " << SF.getID() << ", \"location_context\": \"";
+    Out << '#' << Idx << " Call\", \"calling\": \"";
+    if (const auto *D = dyn_cast<NamedDecl>(SF.getDecl()))
       Out << D->getQualifiedNameAsString();
     else
       Out << "anonymous code";
 
     Out << "\", \"location\": ";
-    if (const Expr *E = SF->getCallSite()) {
+    if (const Expr *E = SF.getCallSite()) {
       printSourceLocationAsJson(Out, E->getBeginLoc(), SM);
     } else {
       Out << "null";
@@ -497,10 +487,10 @@ void StackFrame::printJson(
 
     Out << ", \"items\": ";
 
-    printMoreInfoPerStackFrame(SF);
+    printMoreInfoPerStackFrame(&SF);
 
     Out << '}';
-    if (SF->getParent())
+    if (SF.getParent())
       Out << ',';
     Out << NL;
   }
diff --git a/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp 
b/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
index 9006a6a19ca90..042e19fa20218 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
@@ -44,6 +44,7 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/Support/raw_ostream.h"
 #include <optional>
 
@@ -983,16 +984,9 @@ bool ObjCDeallocChecker::isInInstanceDealloc(const 
CheckerContext &C,
 /// 'self' in the frame for -dealloc.
 bool ObjCDeallocChecker::instanceDeallocIsOnStack(const CheckerContext &C,
                                                   SVal &InstanceValOut) const {
-  const StackFrame *SF = C.getStackFrame();
-
-  while (SF) {
-    if (isInInstanceDealloc(C, SF, InstanceValOut))
-      return true;
-
-    SF = SF->getParent();
-  }
-
-  return false;
+  return llvm::any_of(C.stackframes(), [&](const StackFrame &SF) {
+    return isInInstanceDealloc(C, &SF, InstanceValOut);
+  });
 }
 
 /// Returns true if the ID is a class in which is known to have
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 287824984623c..df911f3ce3d0e 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -4112,8 +4112,8 @@ PathDiagnosticPieceRef MallocBugVisitor::VisitNode(const 
ExplodedNode *N,
         ReleaseFunctionSF = CurrentSF;
         // ...but if the stack contains a destructor call, then we say that the
         // outermost destructor stack frame is the _responsible_ one:
-        for (const StackFrame *SF = CurrentSF; SF; SF = SF->getParent()) {
-          if (const auto *DD = dyn_cast<CXXDestructorDecl>(SF->getDecl())) {
+        for (const StackFrame &SF : N->stackframes()) {
+          if (const auto *DD = dyn_cast<CXXDestructorDecl>(SF.getDecl())) {
             if (isReferenceCountingPointerDestructor(DD)) {
               // This immediately looks like a reference-counting destructor.
               // We're bad at guessing the original reference count of the
@@ -4149,7 +4149,7 @@ PathDiagnosticPieceRef MallocBugVisitor::VisitNode(const 
ExplodedNode *N,
             //   if (refPut(data))
             //     doFree(data);
             // }
-            ReleaseFunctionSF = SF;
+            ReleaseFunctionSF = &SF;
           }
         }
 
diff --git a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
index d6787ae517f6c..9c616a2d17783 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
@@ -24,6 +24,7 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringSet.h"
 
 using namespace clang;
@@ -227,7 +228,7 @@ class MoveChecker
   ExplodedNode *tryToReportBug(const MemRegion *Region, const CXXRecordDecl 
*RD,
                                CheckerContext &C, MisuseKind MK) const;
 
-  bool isInMoveSafeStackFrame(const StackFrame *SF) const;
+  bool isInMoveSafeStackFrame(const CheckerContext &C) const;
   bool isStateResetMethod(const CXXMethodDecl *MethodDec) const;
   bool isMoveSafeMethod(const CXXMethodDecl *MethodDec) const;
   const ExplodedNode *getMoveLocation(const ExplodedNode *N,
@@ -374,8 +375,7 @@ void MoveChecker::modelUse(ProgramStateRef State, const 
MemRegion *Region,
   if (MK == MK_Dereference && OK.StdKind != SK_SmartPtr)
     MK = MK_FunCall;
 
-  if (!RS || !shouldWarnAbout(OK, MK) ||
-      isInMoveSafeStackFrame(C.getStackFrame())) {
+  if (!RS || !shouldWarnAbout(OK, MK) || isInMoveSafeStackFrame(C)) {
     // Finalize changes made by the caller.
     C.addTransition(State);
     return;
@@ -615,19 +615,17 @@ bool MoveChecker::isStateResetMethod(const CXXMethodDecl 
*MethodDec) const {
 
 // Don't report an error inside a move related operation.
 // We assume that the programmer knows what she does.
-bool MoveChecker::isInMoveSafeStackFrame(const StackFrame *SF) const {
-  do {
-    const auto *SFDec = SF->getDecl();
+bool MoveChecker::isInMoveSafeStackFrame(const CheckerContext &C) const {
+  return llvm::any_of(C.stackframes(), [this](const StackFrame &Frame) {
+    const auto *SFDec = Frame.getDecl();
     auto *CtorDec = dyn_cast_or_null<CXXConstructorDecl>(SFDec);
     auto *DtorDec = dyn_cast_or_null<CXXDestructorDecl>(SFDec);
     auto *MethodDec = dyn_cast_or_null<CXXMethodDecl>(SFDec);
-    if (DtorDec || (CtorDec && CtorDec->isCopyOrMoveConstructor()) ||
-        (MethodDec && MethodDec->isOverloadedOperator() &&
-         MethodDec->getOverloadedOperator() == OO_Equal) ||
-        isStateResetMethod(MethodDec) || isMoveSafeMethod(MethodDec))
-      return true;
-  } while ((SF = SF->getParent()));
-  return false;
+    return DtorDec || (CtorDec && CtorDec->isCopyOrMoveConstructor()) ||
+           (MethodDec && MethodDec->isOverloadedOperator() &&
+            MethodDec->getOverloadedOperator() == OO_Equal) ||
+           isStateResetMethod(MethodDec) || isMoveSafeMethod(MethodDec);
+  });
 }
 
 bool MoveChecker::belongsTo(const CXXRecordDecl *RD,
diff --git a/clang/lib/StaticAnalyzer/Checkers/TraversalChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/TraversalChecker.cpp
index 95e03d1e4947f..2b3befb099e06 100644
--- a/clang/lib/StaticAnalyzer/Checkers/TraversalChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/TraversalChecker.cpp
@@ -18,6 +18,7 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
 #include "llvm/Support/raw_ostream.h"
+#include <iterator>
 
 using namespace clang;
 using namespace ento;
@@ -66,10 +67,8 @@ class CallDumper : public Checker< check::PreCall,
 }
 
 void CallDumper::checkPreCall(const CallEvent &Call, CheckerContext &C) const {
-  unsigned Indentation = 0;
-  for (const StackFrame *SF = C.getStackFrame()->getParent(); SF != nullptr;
-       SF = SF->getParent())
-    ++Indentation;
+  auto Parents = C.getStackFrame()->parents();
+  unsigned Indentation = std::distance(Parents.begin(), Parents.end());
 
   // It is mildly evil to print directly to llvm::outs() rather than emitting
   // warnings, but this ensures things do not get filtered out by the rest of
@@ -83,10 +82,8 @@ void CallDumper::checkPostCall(const CallEvent &Call, 
CheckerContext &C) const {
   if (!CallE)
     return;
 
-  unsigned Indentation = 0;
-  for (const StackFrame *SF = C.getStackFrame()->getParent(); SF != nullptr;
-       SF = SF->getParent())
-    ++Indentation;
+  auto Parents = C.getStackFrame()->parents();
+  unsigned Indentation = std::distance(Parents.begin(), Parents.end());
 
   // It is mildly evil to print directly to llvm::outs() rather than emitting
   // warnings, but this ensures things do not get filtered out by the rest of
diff --git 
a/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
 
b/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
index 19f170cc0ae4a..7105276d46053 100644
--- 
a/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
+++ 
b/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
@@ -25,6 +25,7 @@
 #include "clang/StaticAnalyzer/Core/Checker.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
+#include "llvm/ADT/STLExtras.h"
 
 using namespace clang;
 using namespace clang::ento;
@@ -492,25 +493,18 @@ static bool willObjectBeAnalyzedLater(const 
CXXConstructorDecl *Ctor,
   if (!CurrRegion)
     return false;
 
-  const StackFrame *SF = Context.getStackFrame();
-  while ((SF = SF->getParent())) {
-
-    // If \p Ctor was called by another constructor.
-    const auto *OtherCtor = dyn_cast<CXXConstructorDecl>(SF->getDecl());
-    if (!OtherCtor)
-      continue;
-
-    const SubRegion *OtherRegion = getConstructedSubRegion(OtherCtor, Context);
-    if (!OtherRegion)
-      continue;
-
-    // If the CurrRegion is a subregion of OtherRegion, it will be analyzed
-    // during the analysis of OtherRegion.
-    if (CurrRegion->isSubRegionOf(OtherRegion))
-      return true;
-  }
-
-  return false;
+  // Returns true if \p Ctor was called by another constructor whose region
+  // contains CurrRegion, so CurrRegion will be analyzed during that analysis.
+  return llvm::any_of(
+      Context.getStackFrame()->parents(), [&](const StackFrame &SF) {
+        const auto *OtherCtor = dyn_cast<CXXConstructorDecl>(SF.getDecl());
+        if (!OtherCtor)
+          return false;
+
+        const SubRegion *OtherRegion =
+            getConstructedSubRegion(OtherCtor, Context);
+        return OtherRegion && CurrRegion->isSubRegionOf(OtherRegion);
+      });
 }
 
 static bool shouldIgnoreRecord(const RecordDecl *RD, StringRef Pattern) {
diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp 
b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index f3c7f3a25b716..8ab375b32af89 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -3292,8 +3292,8 @@ void 
LikelyFalsePositiveSuppressionBRVisitor::finalizeVisitor(
         }
       }
 
-      for (const auto *SF = N->getStackFrame(); SF; SF = SF->getParent()) {
-        const auto *MD = dyn_cast<CXXMethodDecl>(SF->getDecl());
+      for (const StackFrame &SF : N->stackframes()) {
+        const auto *MD = dyn_cast<CXXMethodDecl>(SF.getDecl());
         if (!MD)
           continue;
 
diff --git a/clang/lib/StaticAnalyzer/Core/Environment.cpp 
b/clang/lib/StaticAnalyzer/Core/Environment.cpp
index 8494f7600ebbe..12f61c0416a13 100644
--- a/clang/lib/StaticAnalyzer/Core/Environment.cpp
+++ b/clang/lib/StaticAnalyzer/Core/Environment.cpp
@@ -26,6 +26,7 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
 #include "llvm/ADT/ImmutableMap.h"
 #include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/iterator.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/raw_ostream.h"
 #include <cassert>
@@ -206,8 +207,8 @@ void Environment::printJson(raw_ostream &Out, const 
ASTContext &Ctx,
       if (FoundStackFrames.count(CurrentSF) == 0) {
         // This stack frame is fresher than all other stack frames so far.
         SF = CurrentSF;
-        for (const StackFrame *SFI = CurrentSF; SFI; SFI = SFI->getParent())
-          FoundStackFrames.insert(SFI);
+        FoundStackFrames.insert_range(
+            llvm::make_pointer_range(CurrentSF->parentsIncludingSelf()));
       }
     }
   }
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp 
b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index b66b5c5e358e4..e0139484b2b48 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -450,20 +450,20 @@ bool ExprEngine::isHuge(AnalysisDeclContext *ADC) const {
   return Cfg->getNumBlockIDs() > AMgr.options.MaxInlinableSize;
 }
 
-void ExprEngine::examineStackFrames(const Decl *D, const StackFrame *SF,
-                                    bool &IsRecursive, unsigned &StackDepth) {
+void ExprEngine::examineStackFrames(
+    const Decl *D, llvm::iterator_range<StackFrame::parent_iterator> Frames,
+    bool &IsRecursive, unsigned &StackDepth) {
   IsRecursive = false;
   StackDepth = 0;
 
-  while (SF) {
-    const Decl *DI = SF->getDecl();
+  for (const StackFrame &Frame : Frames) {
+    const Decl *DI = Frame.getDecl();
 
     // Mark recursive (and mutually recursive) functions and always count
     // them when measuring the stack depth.
     if (DI == D) {
       IsRecursive = true;
       ++StackDepth;
-      SF = SF->getParent();
       continue;
     }
 
@@ -471,7 +471,6 @@ void ExprEngine::examineStackFrames(const Decl *D, const 
StackFrame *SF,
     AnalysisDeclContext *CalleeADC = AMgr.getAnalysisDeclContext(DI);
     if (!isSmall(CalleeADC))
       ++StackDepth;
-    SF = SF->getParent();
   }
 }
 
@@ -1123,7 +1122,7 @@ bool ExprEngine::shouldInlineCall(const CallEvent &Call, 
const Decl *D,
   // Do not inline if recursive or we've reached max stack frame count.
   bool IsRecursive = false;
   unsigned StackDepth = 0;
-  examineStackFrames(D, Pred->getStackFrame(), IsRecursive, StackDepth);
+  examineStackFrames(D, Pred->stackframes(), IsRecursive, StackDepth);
   if ((StackDepth >= Opts.InlineMaxStackDepth) &&
       (!isSmall(CalleeADC) || IsRecursive))
     return false;
diff --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp 
b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
index f3fe21101792c..b26c63f50ef06 100644
--- a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -998,23 +998,22 @@ static llvm::PointerUnion<const StackFrame *, const 
VarRegion *>
 getStackOrCaptureRegionForDeclContext(const StackFrame *SF,
                                       const DeclContext *DC,
                                       const VarDecl *VD) {
-  while (SF) {
-    if (cast<DeclContext>(SF->getDecl()) == DC)
-      return SF;
-    if (SF->getData()) {
-      // FIXME: This can be made more efficient.
-      for (auto Var : static_cast<const BlockDataRegion *>(SF->getData())
-                          ->referenced_vars()) {
-        const TypedValueRegion *OrigR = Var.getOriginalRegion();
-        if (const auto *VR = dyn_cast<VarRegion>(OrigR)) {
-          if (VR->getDecl() == VD)
-            return cast<VarRegion>(Var.getCapturedRegion());
+  if (SF)
+    for (const StackFrame &Frame : SF->parentsIncludingSelf()) {
+      if (cast<DeclContext>(Frame.getDecl()) == DC)
+        return &Frame;
+      if (Frame.getData()) {
+        // FIXME: This can be made more efficient.
+        for (auto Var : static_cast<const BlockDataRegion *>(Frame.getData())
+                            ->referenced_vars()) {
+          const TypedValueRegion *OrigR = Var.getOriginalRegion();
+          if (const auto *VR = dyn_cast<VarRegion>(OrigR)) {
+            if (VR->getDecl() == VD)
+              return cast<VarRegion>(Var.getCapturedRegion());
+          }
         }
       }
     }
-
-    SF = SF->getParent();
-  }
   return (const StackFrame *)nullptr;
 }
 

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

Reply via email to