[clang] [analyzer][NFC] Add StackFrame parent-chain range helpers (PR #210938)
Balázs Benics via cfe-commits
cfe-commits at lists.llvm.org
Tue Jul 21 03:50:00 PDT 2026
https://github.com/steakhal updated https://github.com/llvm/llvm-project/pull/210938
>From 73cd0545e1f67a263f2e44771e8c0660f367f9b2 Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
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 | 18 +++----
.../StaticAnalyzer/Checkers/MallocChecker.cpp | 6 +--
.../StaticAnalyzer/Checkers/MoveChecker.cpp | 24 +++++-----
.../Checkers/TraversalChecker.cpp | 15 +++---
.../UninitializedObjectChecker.cpp | 34 ++++++-------
.../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, 140 insertions(+), 108 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..e5357d9a2dfab 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
@@ -27,14 +27,14 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
-#include "clang/Analysis/PathDiagnostic.h"
#include "clang/AST/Attr.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/Analysis/PathDiagnostic.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
@@ -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..a362958630b7c 100644
--- a/clang/lib/StaticAnalyzer/Checkers/TraversalChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/TraversalChecker.cpp
@@ -10,14 +10,15 @@
// as it builds the ExplodedGraph.
//
//===----------------------------------------------------------------------===//
-#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/AST/ParentMap.h"
#include "clang/AST/StmtObjC.h"
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#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..4d54f11efe158 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
@@ -17,14 +17,15 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "UninitializedObject.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#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;
}
More information about the cfe-commits
mailing list