aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/StaticAnalyzer/Core
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/StaticAnalyzer/Core')
-rw-r--r--clang/lib/StaticAnalyzer/Core/APSIntType.cpp4
-rw-r--r--clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp11
-rw-r--r--clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp20
-rw-r--r--clang/lib/StaticAnalyzer/Core/BugReporter.cpp17
-rw-r--r--clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp29
-rw-r--r--clang/lib/StaticAnalyzer/Core/CallEvent.cpp40
-rw-r--r--clang/lib/StaticAnalyzer/Core/CheckerContext.cpp1
-rw-r--r--clang/lib/StaticAnalyzer/Core/CommonBugCategories.cpp1
-rw-r--r--clang/lib/StaticAnalyzer/Core/Environment.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp23
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngine.cpp67
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp111
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp124
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp20
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp4
-rw-r--r--clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp6
-rw-r--r--clang/lib/StaticAnalyzer/Core/MemRegion.cpp214
-rw-r--r--clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp16
-rw-r--r--clang/lib/StaticAnalyzer/Core/ProgramState.cpp25
-rw-r--r--clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp15
-rw-r--r--clang/lib/StaticAnalyzer/Core/RegionStore.cpp121
-rw-r--r--clang/lib/StaticAnalyzer/Core/SValBuilder.cpp1
-rw-r--r--clang/lib/StaticAnalyzer/Core/SVals.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Core/Store.cpp7
-rw-r--r--clang/lib/StaticAnalyzer/Core/SymbolManager.cpp36
-rw-r--r--clang/lib/StaticAnalyzer/Core/TextDiagnostics.cpp5
26 files changed, 451 insertions, 472 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/APSIntType.cpp b/clang/lib/StaticAnalyzer/Core/APSIntType.cpp
index a1de10c89ed9..1185cdaa044a 100644
--- a/clang/lib/StaticAnalyzer/Core/APSIntType.cpp
+++ b/clang/lib/StaticAnalyzer/Core/APSIntType.cpp
@@ -23,7 +23,7 @@ APSIntType::testInRange(const llvm::APSInt &Value,
unsigned MinBits;
if (AllowSignConversions) {
if (Value.isSigned() && !IsUnsigned)
- MinBits = Value.getMinSignedBits();
+ MinBits = Value.getSignificantBits();
else
MinBits = Value.getActiveBits();
@@ -33,7 +33,7 @@ APSIntType::testInRange(const llvm::APSInt &Value,
// Unsigned integers can be converted to unsigned integers of the same width
// or signed integers with one more bit.
if (Value.isSigned())
- MinBits = Value.getMinSignedBits() - IsUnsigned;
+ MinBits = Value.getSignificantBits() - IsUnsigned;
else
MinBits = Value.getActiveBits() + !IsUnsigned;
}
diff --git a/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp b/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp
index ecfc7106560e..f9750db7b501 100644
--- a/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp
@@ -50,17 +50,14 @@ AnalysisManager::AnalysisManager(ASTContext &ASTCtx, Preprocessor &PP,
AnalysisManager::~AnalysisManager() {
FlushDiagnostics();
- for (PathDiagnosticConsumers::iterator I = PathConsumers.begin(),
- E = PathConsumers.end(); I != E; ++I) {
- delete *I;
+ for (PathDiagnosticConsumer *Consumer : PathConsumers) {
+ delete Consumer;
}
}
void AnalysisManager::FlushDiagnostics() {
PathDiagnosticConsumer::FilesMade filesMade;
- for (PathDiagnosticConsumers::iterator I = PathConsumers.begin(),
- E = PathConsumers.end();
- I != E; ++I) {
- (*I)->FlushDiagnostics(&filesMade);
+ for (PathDiagnosticConsumer *Consumer : PathConsumers) {
+ Consumer->FlushDiagnostics(&filesMade);
}
}
diff --git a/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp b/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
index 40cdaef1bfa7..5924f6a671c2 100644
--- a/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
@@ -97,8 +97,7 @@ const llvm::APSInt& BasicValueFactory::getValue(const llvm::APSInt& X) {
FoldNodeTy* P = APSIntSet.FindNodeOrInsertPos(ID, InsertPos);
if (!P) {
- P = (FoldNodeTy*) BPAlloc.Allocate<FoldNodeTy>();
- new (P) FoldNodeTy(X);
+ P = new (BPAlloc) FoldNodeTy(X);
APSIntSet.InsertNode(P, InsertPos);
}
@@ -132,8 +131,7 @@ BasicValueFactory::getCompoundValData(QualType T,
CompoundValData* D = CompoundValDataSet.FindNodeOrInsertPos(ID, InsertPos);
if (!D) {
- D = (CompoundValData*) BPAlloc.Allocate<CompoundValData>();
- new (D) CompoundValData(T, Vals);
+ D = new (BPAlloc) CompoundValData(T, Vals);
CompoundValDataSet.InsertNode(D, InsertPos);
}
@@ -151,8 +149,7 @@ BasicValueFactory::getLazyCompoundValData(const StoreRef &store,
LazyCompoundValDataSet.FindNodeOrInsertPos(ID, InsertPos);
if (!D) {
- D = (LazyCompoundValData*) BPAlloc.Allocate<LazyCompoundValData>();
- new (D) LazyCompoundValData(store, region);
+ D = new (BPAlloc) LazyCompoundValData(store, region);
LazyCompoundValDataSet.InsertNode(D, InsertPos);
}
@@ -169,8 +166,7 @@ const PointerToMemberData *BasicValueFactory::getPointerToMemberData(
PointerToMemberDataSet.FindNodeOrInsertPos(ID, InsertPos);
if (!D) {
- D = (PointerToMemberData *)BPAlloc.Allocate<PointerToMemberData>();
- new (D) PointerToMemberData(ND, L);
+ D = new (BPAlloc) PointerToMemberData(ND, L);
PointerToMemberDataSet.InsertNode(D, InsertPos);
}
@@ -288,7 +284,7 @@ BasicValueFactory::evalAPSInt(BinaryOperator::Opcode Op,
if (V1.isSigned() && V1.isNegative())
return nullptr;
- if (V1.isSigned() && Amt > V1.countLeadingZeros())
+ if (V1.isSigned() && Amt > V1.countl_zero())
return nullptr;
}
@@ -358,8 +354,7 @@ BasicValueFactory::getPersistentSValWithData(const SVal& V, uintptr_t Data) {
FoldNodeTy* P = Map.FindNodeOrInsertPos(ID, InsertPos);
if (!P) {
- P = (FoldNodeTy*) BPAlloc.Allocate<FoldNodeTy>();
- new (P) FoldNodeTy(std::make_pair(V, Data));
+ P = new (BPAlloc) FoldNodeTy(std::make_pair(V, Data));
Map.InsertNode(P, InsertPos);
}
@@ -383,8 +378,7 @@ BasicValueFactory::getPersistentSValPair(const SVal& V1, const SVal& V2) {
FoldNodeTy* P = Map.FindNodeOrInsertPos(ID, InsertPos);
if (!P) {
- P = (FoldNodeTy*) BPAlloc.Allocate<FoldNodeTy>();
- new (P) FoldNodeTy(std::make_pair(V1, V2));
+ P = new (BPAlloc) FoldNodeTy(std::make_pair(V1, V2));
Map.InsertNode(P, InsertPos);
}
diff --git a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp
index a7f149b87e79..dc9820b61f1f 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -296,26 +296,24 @@ std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){
return {};
// Check if one of the parameters are set to the interesting symbol.
- unsigned ArgIndex = 0;
- for (CallExpr::const_arg_iterator I = CE->arg_begin(),
- E = CE->arg_end(); I != E; ++I, ++ArgIndex){
- SVal SV = N->getSVal(*I);
+ for (auto [Idx, ArgExpr] : llvm::enumerate(CE->arguments())) {
+ SVal SV = N->getSVal(ArgExpr);
// Check if the variable corresponding to the symbol is passed by value.
SymbolRef AS = SV.getAsLocSymbol();
if (AS == Sym) {
- return getMessageForArg(*I, ArgIndex);
+ return getMessageForArg(ArgExpr, Idx);
}
// Check if the parameter is a pointer to the symbol.
if (std::optional<loc::MemRegionVal> Reg = SV.getAs<loc::MemRegionVal>()) {
// Do not attempt to dereference void*.
- if ((*I)->getType()->isVoidPointerType())
+ if (ArgExpr->getType()->isVoidPointerType())
continue;
SVal PSV = N->getState()->getSVal(Reg->getRegion());
SymbolRef AS = PSV.getAsLocSymbol();
if (AS == Sym) {
- return getMessageForArg(*I, ArgIndex);
+ return getMessageForArg(ArgExpr, Idx);
}
}
}
@@ -766,7 +764,7 @@ PathDiagnosticPieceRef PathDiagnosticBuilder::generateDiagForSwitchOP(
case Stmt::CaseStmtClass: {
os << "Control jumps to 'case ";
const auto *Case = cast<CaseStmt>(S);
- const Expr *LHS = Case->getLHS()->IgnoreParenCasts();
+ const Expr *LHS = Case->getLHS()->IgnoreParenImpCasts();
// Determine if it is an enum.
bool GetRawInt = true;
@@ -2627,8 +2625,7 @@ BugPathInfo *BugPathGetter::getNextBugPath() {
const ExplodedNode *OrigN;
std::tie(CurrentBugPath.Report, OrigN) = ReportNodes.pop_back_val();
- assert(PriorityMap.find(OrigN) != PriorityMap.end() &&
- "error node not accessible from root");
+ assert(PriorityMap.contains(OrigN) && "error node not accessible from root");
// Create a new graph with a single path. This is the graph that will be
// returned to the caller.
diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index 2b461acf9a73..42d03f67510c 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -1786,6 +1786,7 @@ PathDiagnosticPieceRef StoreSiteFinder::VisitNode(const ExplodedNode *Succ,
void TrackConstraintBRVisitor::Profile(llvm::FoldingSetNodeID &ID) const {
static int tag = 0;
ID.AddPointer(&tag);
+ ID.AddString(Message);
ID.AddBoolean(Assumption);
ID.Add(Constraint);
}
@@ -1796,8 +1797,12 @@ const char *TrackConstraintBRVisitor::getTag() {
return "TrackConstraintBRVisitor";
}
+bool TrackConstraintBRVisitor::isZeroCheck() const {
+ return !Assumption && Constraint.getAs<Loc>();
+}
+
bool TrackConstraintBRVisitor::isUnderconstrained(const ExplodedNode *N) const {
- if (IsZeroCheck)
+ if (isZeroCheck())
return N->getState()->isNull(Constraint).isUnderconstrained();
return (bool)N->getState()->assume(Constraint, !Assumption);
}
@@ -1827,19 +1832,6 @@ PathDiagnosticPieceRef TrackConstraintBRVisitor::VisitNode(
// the transition point.
assert(!isUnderconstrained(N));
- // We found the transition point for the constraint. We now need to
- // pretty-print the constraint. (work-in-progress)
- SmallString<64> sbuf;
- llvm::raw_svector_ostream os(sbuf);
-
- if (isa<Loc>(Constraint)) {
- os << "Assuming pointer value is ";
- os << (Assumption ? "non-null" : "null");
- }
-
- if (os.str().empty())
- return nullptr;
-
// Construct a new PathDiagnosticPiece.
ProgramPoint P = N->getLocation();
@@ -1854,7 +1846,7 @@ PathDiagnosticPieceRef TrackConstraintBRVisitor::VisitNode(
if (!L.isValid())
return nullptr;
- auto X = std::make_shared<PathDiagnosticEventPiece>(L, os.str());
+ auto X = std::make_shared<PathDiagnosticEventPiece>(L, Message);
X->setTag(getTag());
return std::move(X);
}
@@ -2366,8 +2358,9 @@ public:
// null.
if (V.getAsLocSymbol(/*IncludeBaseRegions=*/true))
if (LVState->isNull(V).isConstrainedTrue())
- Report.addVisitor<TrackConstraintBRVisitor>(V.castAs<DefinedSVal>(),
- false);
+ Report.addVisitor<TrackConstraintBRVisitor>(
+ V.castAs<DefinedSVal>(),
+ /*Assumption=*/false, "Assuming pointer value is null");
// Add visitor, which will suppress inline defensive checks.
if (auto DV = V.getAs<DefinedSVal>())
@@ -2531,7 +2524,7 @@ public:
Report.markInteresting(RegionRVal, Opts.Kind);
Report.addVisitor<TrackConstraintBRVisitor>(
loc::MemRegionVal(RegionRVal),
- /*assumption=*/false);
+ /*Assumption=*/false, "Assuming pointer value is null");
Result.FoundSomethingToTrack = true;
}
}
diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
index 8516e3643425..195940e5e643 100644
--- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -287,6 +287,7 @@ ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount,
ProgramPoint CallEvent::getProgramPoint(bool IsPreVisit,
const ProgramPointTag *Tag) const {
+
if (const Expr *E = getOriginExpr()) {
if (IsPreVisit)
return PreStmt(E, getLocationContext(), Tag);
@@ -295,11 +296,13 @@ ProgramPoint CallEvent::getProgramPoint(bool IsPreVisit,
const Decl *D = getDecl();
assert(D && "Cannot get a program point without a statement or decl");
+ assert(ElemRef.getParent() &&
+ "Cannot get a program point without a CFGElementRef");
SourceLocation Loc = getSourceRange().getBegin();
if (IsPreVisit)
- return PreImplicitCall(D, Loc, getLocationContext(), Tag);
- return PostImplicitCall(D, Loc, getLocationContext(), Tag);
+ return PreImplicitCall(D, Loc, getLocationContext(), ElemRef, Tag);
+ return PostImplicitCall(D, Loc, getLocationContext(), ElemRef, Tag);
}
SVal CallEvent::getArgSVal(unsigned Index) const {
@@ -1373,23 +1376,24 @@ void ObjCMethodCall::getInitialStackFrameContents(
CallEventRef<>
CallEventManager::getSimpleCall(const CallExpr *CE, ProgramStateRef State,
- const LocationContext *LCtx) {
+ const LocationContext *LCtx,
+ CFGBlock::ConstCFGElementRef ElemRef) {
if (const auto *MCE = dyn_cast<CXXMemberCallExpr>(CE))
- return create<CXXMemberCall>(MCE, State, LCtx);
+ return create<CXXMemberCall>(MCE, State, LCtx, ElemRef);
if (const auto *OpCE = dyn_cast<CXXOperatorCallExpr>(CE)) {
const FunctionDecl *DirectCallee = OpCE->getDirectCallee();
if (const auto *MD = dyn_cast<CXXMethodDecl>(DirectCallee))
if (MD->isInstance())
- return create<CXXMemberOperatorCall>(OpCE, State, LCtx);
+ return create<CXXMemberOperatorCall>(OpCE, State, LCtx, ElemRef);
} else if (CE->getCallee()->getType()->isBlockPointerType()) {
- return create<BlockCall>(CE, State, LCtx);
+ return create<BlockCall>(CE, State, LCtx, ElemRef);
}
// Otherwise, it's a normal function call, static member function call, or
// something we can't reason about.
- return create<SimpleFunctionCall>(CE, State, LCtx);
+ return create<SimpleFunctionCall>(CE, State, LCtx, ElemRef);
}
CallEventRef<>
@@ -1397,12 +1401,14 @@ CallEventManager::getCaller(const StackFrameContext *CalleeCtx,
ProgramStateRef State) {
const LocationContext *ParentCtx = CalleeCtx->getParent();
const LocationContext *CallerCtx = ParentCtx->getStackFrame();
+ CFGBlock::ConstCFGElementRef ElemRef = {CalleeCtx->getCallSiteBlock(),
+ CalleeCtx->getIndex()};
assert(CallerCtx && "This should not be used for top-level stack frames");
const Stmt *CallSite = CalleeCtx->getCallSite();
if (CallSite) {
- if (CallEventRef<> Out = getCall(CallSite, State, CallerCtx))
+ if (CallEventRef<> Out = getCall(CallSite, State, CallerCtx, ElemRef))
return Out;
SValBuilder &SVB = State->getStateManager().getSValBuilder();
@@ -1411,10 +1417,11 @@ CallEventManager::getCaller(const StackFrameContext *CalleeCtx,
SVal ThisVal = State->getSVal(ThisPtr);
if (const auto *CE = dyn_cast<CXXConstructExpr>(CallSite))
- return getCXXConstructorCall(CE, ThisVal.getAsRegion(), State, CallerCtx);
+ return getCXXConstructorCall(CE, ThisVal.getAsRegion(), State, CallerCtx,
+ ElemRef);
else if (const auto *CIE = dyn_cast<CXXInheritedCtorInitExpr>(CallSite))
return getCXXInheritedConstructorCall(CIE, ThisVal.getAsRegion(), State,
- CallerCtx);
+ CallerCtx, ElemRef);
else {
// All other cases are handled by getCall.
llvm_unreachable("This is not an inlineable statement");
@@ -1444,19 +1451,20 @@ CallEventManager::getCaller(const StackFrameContext *CalleeCtx,
return getCXXDestructorCall(Dtor, Trigger, ThisVal.getAsRegion(),
E.getAs<CFGBaseDtor>().has_value(), State,
- CallerCtx);
+ CallerCtx, ElemRef);
}
CallEventRef<> CallEventManager::getCall(const Stmt *S, ProgramStateRef State,
- const LocationContext *LC) {
+ const LocationContext *LC,
+ CFGBlock::ConstCFGElementRef ElemRef) {
if (const auto *CE = dyn_cast<CallExpr>(S)) {
- return getSimpleCall(CE, State, LC);
+ return getSimpleCall(CE, State, LC, ElemRef);
} else if (const auto *NE = dyn_cast<CXXNewExpr>(S)) {
- return getCXXAllocatorCall(NE, State, LC);
+ return getCXXAllocatorCall(NE, State, LC, ElemRef);
} else if (const auto *DE = dyn_cast<CXXDeleteExpr>(S)) {
- return getCXXDeallocatorCall(DE, State, LC);
+ return getCXXDeallocatorCall(DE, State, LC, ElemRef);
} else if (const auto *ME = dyn_cast<ObjCMessageExpr>(S)) {
- return getObjCMethodCall(ME, State, LC);
+ return getObjCMethodCall(ME, State, LC, ElemRef);
} else {
return nullptr;
}
diff --git a/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp b/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp
index 1e2532d27633..c25165cce128 100644
--- a/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp
@@ -14,6 +14,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/Basic/Builtins.h"
#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/StringExtras.h"
using namespace clang;
using namespace ento;
diff --git a/clang/lib/StaticAnalyzer/Core/CommonBugCategories.cpp b/clang/lib/StaticAnalyzer/Core/CommonBugCategories.cpp
index d12c35ef156a..e9cc080caf5f 100644
--- a/clang/lib/StaticAnalyzer/Core/CommonBugCategories.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CommonBugCategories.cpp
@@ -23,6 +23,7 @@ const char *const CXXObjectLifecycle = "C++ object lifecycle";
const char *const CXXMoveSemantics = "C++ move semantics";
const char *const SecurityError = "Security error";
const char *const UnusedCode = "Unused code";
+const char *const TaintedData = "Tainted data used";
} // namespace categories
} // namespace ento
} // namespace clang
diff --git a/clang/lib/StaticAnalyzer/Core/Environment.cpp b/clang/lib/StaticAnalyzer/Core/Environment.cpp
index 3d017b81762a..0102f743c911 100644
--- a/clang/lib/StaticAnalyzer/Core/Environment.cpp
+++ b/clang/lib/StaticAnalyzer/Core/Environment.cpp
@@ -17,9 +17,9 @@
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtObjC.h"
#include "clang/Analysis/AnalysisDeclContext.h"
+#include "clang/Basic/JsonSupport.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/LangOptions.h"
-#include "clang/Basic/JsonSupport.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
diff --git a/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp b/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
index d274d4d16db3..f84da769d182 100644
--- a/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
@@ -233,8 +233,7 @@ void ExplodedNode::NodeGroup::addNode(ExplodedNode *N, ExplodedGraph &G) {
ExplodedNode *Old = Storage.get<ExplodedNode *>();
BumpVectorContext &Ctx = G.getNodeAllocator();
- V = G.getAllocator().Allocate<ExplodedNodeVector>();
- new (V) ExplodedNodeVector(Ctx, 4);
+ V = new (G.getAllocator()) ExplodedNodeVector(Ctx, 4);
V->push_back(Old, Ctx);
Storage = V;
@@ -408,7 +407,7 @@ ExplodedNode *ExplodedGraph::getNode(const ProgramPoint &L,
}
else {
// Allocate a new node.
- V = (NodeTy*) getAllocator().Allocate<NodeTy>();
+ V = getAllocator().Allocate<NodeTy>();
}
++NumNodes;
@@ -432,7 +431,7 @@ ExplodedNode *ExplodedGraph::createUncachedNode(const ProgramPoint &L,
ProgramStateRef State,
int64_t Id,
bool IsSink) {
- NodeTy *V = (NodeTy *) getAllocator().Allocate<NodeTy>();
+ NodeTy *V = getAllocator().Allocate<NodeTy>();
new (V) NodeTy(L, State, Id, IsSink);
return V;
}
@@ -488,7 +487,7 @@ ExplodedGraph::trim(ArrayRef<const NodeTy *> Sinks,
const ExplodedNode *N = WL2.pop_back_val();
// Skip this node if we have already processed it.
- if (Pass2.find(N) != Pass2.end())
+ if (Pass2.contains(N))
continue;
// Create the corresponding node in the new graph and record the mapping
@@ -509,9 +508,8 @@ ExplodedGraph::trim(ArrayRef<const NodeTy *> Sinks,
// Walk through the predecessors of 'N' and hook up their corresponding
// nodes in the new graph (if any) to the freshly created node.
- for (ExplodedNode::pred_iterator I = N->Preds.begin(), E = N->Preds.end();
- I != E; ++I) {
- Pass2Ty::iterator PI = Pass2.find(*I);
+ for (const ExplodedNode *Pred : N->Preds) {
+ Pass2Ty::iterator PI = Pass2.find(Pred);
if (PI == Pass2.end())
continue;
@@ -522,17 +520,16 @@ ExplodedGraph::trim(ArrayRef<const NodeTy *> Sinks,
// been created, we should hook them up as successors. Otherwise, enqueue
// the new nodes from the original graph that should have nodes created
// in the new graph.
- for (ExplodedNode::succ_iterator I = N->Succs.begin(), E = N->Succs.end();
- I != E; ++I) {
- Pass2Ty::iterator PI = Pass2.find(*I);
+ for (const ExplodedNode *Succ : N->Succs) {
+ Pass2Ty::iterator PI = Pass2.find(Succ);
if (PI != Pass2.end()) {
const_cast<ExplodedNode *>(PI->second)->addPredecessor(NewN, *G);
continue;
}
// Enqueue nodes to the worklist that were marked during pass 1.
- if (Pass1.count(*I))
- WL2.push_back(*I);
+ if (Pass1.count(Succ))
+ WL2.push_back(Succ);
}
}
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 977c2b7f51fd..144f034a9dfe 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -65,6 +65,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/ImmutableMap.h"
#include "llvm/ADT/ImmutableSet.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Casting.h"
@@ -386,15 +387,19 @@ ProgramStateRef ExprEngine::createTemporaryRegionIfNeeded(
State = finishObjectConstruction(State, MT, LC);
State = State->BindExpr(Result, LC, *V);
return State;
- } else {
+ } else if (const ValueDecl *VD = MT->getExtendingDecl()) {
StorageDuration SD = MT->getStorageDuration();
+ assert(SD != SD_FullExpression);
// If this object is bound to a reference with static storage duration, we
// put it in a different region to prevent "address leakage" warnings.
if (SD == SD_Static || SD == SD_Thread) {
- TR = MRMgr.getCXXStaticTempObjectRegion(Init);
+ TR = MRMgr.getCXXStaticLifetimeExtendedObjectRegion(Init, VD);
} else {
- TR = MRMgr.getCXXTempObjectRegion(Init, LC);
+ TR = MRMgr.getCXXLifetimeExtendedObjectRegion(Init, VD, LC);
}
+ } else {
+ assert(MT->getStorageDuration() == SD_FullExpression);
+ TR = MRMgr.getCXXTempObjectRegion(Init, LC);
}
} else {
TR = MRMgr.getCXXTempObjectRegion(Init, LC);
@@ -1242,7 +1247,7 @@ ExprEngine::prepareStateForArrayDestruction(const ProgramStateRef State,
const QualType &ElementTy,
const LocationContext *LCtx,
SVal *ElementCountVal) {
- assert(Region != nullptr && "Not-null region expected");
+ assert(Region != nullptr && "Not-null region expected");
QualType Ty = ElementTy.getDesugaredType(getContext());
while (const auto *NTy = dyn_cast<ArrayType>(Ty))
@@ -1313,7 +1318,8 @@ void ExprEngine::ProcessNewAllocator(const CXXNewExpr *NE,
else {
NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
const LocationContext *LCtx = Pred->getLocationContext();
- PostImplicitCall PP(NE->getOperatorNew(), NE->getBeginLoc(), LCtx);
+ PostImplicitCall PP(NE->getOperatorNew(), NE->getBeginLoc(), LCtx,
+ getCFGElementRef());
Bldr.generateNode(PP, Pred->getState(), Pred);
}
Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
@@ -1361,7 +1367,8 @@ void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor Dtor,
static SimpleProgramPointTag PT(
"ExprEngine", "Skipping automatic 0 length array destruction, "
"which shouldn't be in the CFG.");
- PostImplicitCall PP(DtorDecl, varDecl->getLocation(), LCtx, &PT);
+ PostImplicitCall PP(DtorDecl, varDecl->getLocation(), LCtx,
+ getCFGElementRef(), &PT);
NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
Bldr.generateSink(PP, Pred->getState(), Pred);
return;
@@ -1378,7 +1385,8 @@ void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor Dtor,
static SimpleProgramPointTag PT("ExprEngine",
"Prepare for object destruction");
- PreImplicitCall PP(DtorDecl, varDecl->getLocation(), LCtx, &PT);
+ PreImplicitCall PP(DtorDecl, varDecl->getLocation(), LCtx, getCFGElementRef(),
+ &PT);
Pred = Bldr.generateNode(PP, state, Pred);
if (!Pred)
@@ -1406,7 +1414,7 @@ void ExprEngine::ProcessDeleteDtor(const CFGDeleteDtor Dtor,
const CXXRecordDecl *RD = BTy->getAsCXXRecordDecl();
const CXXDestructorDecl *Dtor = RD->getDestructor();
- PostImplicitCall PP(Dtor, DE->getBeginLoc(), LCtx);
+ PostImplicitCall PP(Dtor, DE->getBeginLoc(), LCtx, getCFGElementRef());
NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
Bldr.generateNode(PP, Pred->getState(), Pred);
return;
@@ -1439,7 +1447,8 @@ void ExprEngine::ProcessDeleteDtor(const CFGDeleteDtor Dtor,
static SimpleProgramPointTag PT(
"ExprEngine", "Skipping 0 length array delete destruction");
- PostImplicitCall PP(getDtorDecl(DTy), DE->getBeginLoc(), LCtx, &PT);
+ PostImplicitCall PP(getDtorDecl(DTy), DE->getBeginLoc(), LCtx,
+ getCFGElementRef(), &PT);
NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
Bldr.generateNode(PP, Pred->getState(), Pred);
return;
@@ -1453,7 +1462,8 @@ void ExprEngine::ProcessDeleteDtor(const CFGDeleteDtor Dtor,
NodeBuilder Bldr(Pred, Dst, getBuilderContext());
static SimpleProgramPointTag PT("ExprEngine",
"Prepare for object destruction");
- PreImplicitCall PP(getDtorDecl(DTy), DE->getBeginLoc(), LCtx, &PT);
+ PreImplicitCall PP(getDtorDecl(DTy), DE->getBeginLoc(), LCtx,
+ getCFGElementRef(), &PT);
Pred = Bldr.generateNode(PP, State, Pred);
if (!Pred)
@@ -1513,7 +1523,8 @@ void ExprEngine::ProcessMemberDtor(const CFGMemberDtor D,
static SimpleProgramPointTag PT(
"ExprEngine", "Skipping member 0 length array destruction, which "
"shouldn't be in the CFG.");
- PostImplicitCall PP(DtorDecl, Member->getLocation(), LCtx, &PT);
+ PostImplicitCall PP(DtorDecl, Member->getLocation(), LCtx,
+ getCFGElementRef(), &PT);
NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
Bldr.generateSink(PP, Pred->getState(), Pred);
return;
@@ -1529,7 +1540,8 @@ void ExprEngine::ProcessMemberDtor(const CFGMemberDtor D,
static SimpleProgramPointTag PT("ExprEngine",
"Prepare for object destruction");
- PreImplicitCall PP(DtorDecl, Member->getLocation(), LCtx, &PT);
+ PreImplicitCall PP(DtorDecl, Member->getLocation(), LCtx, getCFGElementRef(),
+ &PT);
Pred = Bldr.generateNode(PP, State, Pred);
if (!Pred)
@@ -1565,7 +1577,7 @@ void ExprEngine::ProcessTemporaryDtor(const CFGTemporaryDtor D,
NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
PostImplicitCall PP(D.getDestructorDecl(getContext()),
D.getBindTemporaryExpr()->getBeginLoc(),
- Pred->getLocationContext());
+ Pred->getLocationContext(), getCFGElementRef());
Bldr.generateNode(PP, State, Pred);
return;
}
@@ -2114,7 +2126,6 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
}
}
}
- // FALLTHROUGH
[[fallthrough]];
}
@@ -2630,9 +2641,7 @@ static const Stmt *ResolveCondition(const Stmt *Condition,
// The invariants are still shifting, but it is possible that the
// last element in a CFGBlock is not a CFGStmt. Look for the last
// CFGStmt as the value of the condition.
- CFGBlock::const_reverse_iterator I = B->rbegin(), E = B->rend();
- for (; I != E; ++I) {
- CFGElement Elem = *I;
+ for (CFGElement Elem : llvm::reverse(*B)) {
std::optional<CFGStmt> CS = Elem.getAs<CFGStmt>();
if (!CS)
continue;
@@ -2840,9 +2849,9 @@ void ExprEngine::processIndirectGoto(IndirectGotoNodeBuilder &builder) {
if (std::optional<loc::GotoLabel> LV = V.getAs<loc::GotoLabel>()) {
const LabelDecl *L = LV->getLabel();
- for (iterator I = builder.begin(), E = builder.end(); I != E; ++I) {
- if (I.getLabel() == L) {
- builder.generateNode(I, state);
+ for (iterator Succ : builder) {
+ if (Succ.getLabel() == L) {
+ builder.generateNode(Succ, state);
return;
}
}
@@ -2861,8 +2870,8 @@ void ExprEngine::processIndirectGoto(IndirectGotoNodeBuilder &builder) {
// This is really a catch-all. We don't support symbolics yet.
// FIXME: Implement dispatch for symbolic pointers.
- for (iterator I = builder.begin(), E = builder.end(); I != E; ++I)
- builder.generateNode(I, state);
+ for (iterator Succ : builder)
+ builder.generateNode(Succ, state);
}
void ExprEngine::processBeginOfFunction(NodeBuilderContext &BC,
@@ -3795,12 +3804,9 @@ struct DOTGraphTraits<ExplodedGraph*> : public DefaultDOTGraphTraits {
BugReporter &BR = static_cast<ExprEngine &>(
N->getState()->getStateManager().getOwningEngine()).getBugReporter();
- const auto EQClasses =
- llvm::make_range(BR.EQClasses_begin(), BR.EQClasses_end());
-
- for (const auto &EQ : EQClasses) {
- for (const auto &I : EQ.getReports()) {
- const auto *PR = dyn_cast<PathSensitiveBugReport>(I.get());
+ for (const auto &Class : BR.equivalenceClasses()) {
+ for (const auto &Report : Class.getReports()) {
+ const auto *PR = dyn_cast<PathSensitiveBugReport>(Report.get());
if (!PR)
continue;
const ExplodedNode *EN = PR->getErrorNode();
@@ -3898,10 +3904,9 @@ std::string ExprEngine::DumpGraph(bool trim, StringRef Filename) {
std::vector<const ExplodedNode *> Src;
// Iterate through the reports and get their nodes.
- for (BugReporter::EQClasses_iterator
- EI = BR.EQClasses_begin(), EE = BR.EQClasses_end(); EI != EE; ++EI) {
+ for (const auto &Class : BR.equivalenceClasses()) {
const auto *R =
- dyn_cast<PathSensitiveBugReport>(EI->getReports()[0].get());
+ dyn_cast<PathSensitiveBugReport>(Class.getReports()[0].get());
if (!R)
continue;
const auto *N = const_cast<ExplodedNode *>(R->getErrorNode());
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 6652c065e04f..2a47116db55a 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -10,8 +10,8 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/AST/ExprCXX.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include <optional>
@@ -133,11 +133,9 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
SVal location = LeftV;
evalLoad(Tmp, B, LHS, *it, state, location);
- for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E;
- ++I) {
-
- state = (*I)->getState();
- const LocationContext *LCtx = (*I)->getLocationContext();
+ for (ExplodedNode *N : Tmp) {
+ state = N->getState();
+ const LocationContext *LCtx = N->getLocationContext();
SVal V = state->getSVal(LHS, LCtx);
// Get the computation type.
@@ -171,8 +169,7 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
currBldrCtx->blockCount());
// However, we need to convert the symbol to the computation type.
Result = svalBuilder.evalCast(LHSVal, CTy, LTy);
- }
- else {
+ } else {
// The left-hand side may bind to a different value then the
// computation type.
LHSVal = svalBuilder.evalCast(Result, LTy, CTy);
@@ -185,7 +182,7 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
else
state = state->BindExpr(B, LCtx, Result);
- evalStore(Tmp2, B, LHS, *I, state, location, LHSVal);
+ evalStore(Tmp2, B, LHS, N, state, location, LHSVal);
}
}
@@ -211,14 +208,12 @@ void ExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred,
if (const BlockDataRegion *BDR =
dyn_cast_or_null<BlockDataRegion>(V.getAsRegion())) {
- BlockDataRegion::referenced_vars_iterator I = BDR->referenced_vars_begin(),
- E = BDR->referenced_vars_end();
-
+ auto ReferencedVars = BDR->referenced_vars();
auto CI = BD->capture_begin();
auto CE = BD->capture_end();
- for (; I != E; ++I) {
- const VarRegion *capturedR = I.getCapturedRegion();
- const TypedValueRegion *originalR = I.getOriginalRegion();
+ for (auto Var : ReferencedVars) {
+ const VarRegion *capturedR = Var.getCapturedRegion();
+ const TypedValueRegion *originalR = Var.getOriginalRegion();
// If the capture had a copy expression, use the result of evaluating
// that expression, otherwise use the original value.
@@ -291,9 +286,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
if (CastE->getCastKind() == CK_LValueToRValue ||
CastE->getCastKind() == CK_LValueToRValueBitCast) {
- for (ExplodedNodeSet::iterator I = dstPreStmt.begin(), E = dstPreStmt.end();
- I!=E; ++I) {
- ExplodedNode *subExprNode = *I;
+ for (ExplodedNode *subExprNode : dstPreStmt) {
ProgramStateRef state = subExprNode->getState();
const LocationContext *LCtx = subExprNode->getLocationContext();
evalLoad(Dst, CastE, CastE, subExprNode, state, state->getSVal(Ex, LCtx));
@@ -309,10 +302,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
T = ExCast->getTypeAsWritten();
StmtNodeBuilder Bldr(dstPreStmt, Dst, *currBldrCtx);
- for (ExplodedNodeSet::iterator I = dstPreStmt.begin(), E = dstPreStmt.end();
- I != E; ++I) {
-
- Pred = *I;
+ for (ExplodedNode *Pred : dstPreStmt) {
ProgramStateRef state = Pred->getState();
const LocationContext *LCtx = Pred->getLocationContext();
@@ -883,8 +873,7 @@ VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex,
QualType T = Ex->getTypeOfArgument();
- for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end();
- I != E; ++I) {
+ for (ExplodedNode *N : CheckedSet) {
if (Ex->getKind() == UETT_SizeOf) {
if (!T->isIncompleteType() && !T->isConstantSizeType()) {
assert(T->isVariableArrayType() && "Unknown non-constant-sized type.");
@@ -903,18 +892,17 @@ VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex,
APSInt Value = Ex->EvaluateKnownConstInt(getContext());
CharUnits amt = CharUnits::fromQuantity(Value.getZExtValue());
- ProgramStateRef state = (*I)->getState();
- state = state->BindExpr(Ex, (*I)->getLocationContext(),
- svalBuilder.makeIntVal(amt.getQuantity(),
- Ex->getType()));
- Bldr.generateNode(Ex, *I, state);
+ ProgramStateRef state = N->getState();
+ state = state->BindExpr(
+ Ex, N->getLocationContext(),
+ svalBuilder.makeIntVal(amt.getQuantity(), Ex->getType()));
+ Bldr.generateNode(Ex, N, state);
}
getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, Ex, *this);
}
-void ExprEngine::handleUOExtension(ExplodedNodeSet::iterator I,
- const UnaryOperator *U,
+void ExprEngine::handleUOExtension(ExplodedNode *N, const UnaryOperator *U,
StmtNodeBuilder &Bldr) {
// FIXME: We can probably just have some magic in Environment::getSVal()
// that propagates values, instead of creating a new node here.
@@ -924,10 +912,9 @@ void ExprEngine::handleUOExtension(ExplodedNodeSet::iterator I,
// generate an extra node that just propagates the value of the
// subexpression.
const Expr *Ex = U->getSubExpr()->IgnoreParens();
- ProgramStateRef state = (*I)->getState();
- const LocationContext *LCtx = (*I)->getLocationContext();
- Bldr.generateNode(U, *I, state->BindExpr(U, LCtx,
- state->getSVal(Ex, LCtx)));
+ ProgramStateRef state = N->getState();
+ const LocationContext *LCtx = N->getLocationContext();
+ Bldr.generateNode(U, N, state->BindExpr(U, LCtx, state->getSVal(Ex, LCtx)));
}
void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, ExplodedNode *Pred,
@@ -939,13 +926,12 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, ExplodedNode *Pred,
ExplodedNodeSet EvalSet;
StmtNodeBuilder Bldr(CheckedSet, EvalSet, *currBldrCtx);
- for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end();
- I != E; ++I) {
+ for (ExplodedNode *N : CheckedSet) {
switch (U->getOpcode()) {
default: {
- Bldr.takeNodes(*I);
+ Bldr.takeNodes(N);
ExplodedNodeSet Tmp;
- VisitIncrementDecrementOperator(U, *I, Tmp);
+ VisitIncrementDecrementOperator(U, N, Tmp);
Bldr.addNodes(Tmp);
break;
}
@@ -960,10 +946,10 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, ExplodedNode *Pred,
// For all other types, UO_Real is an identity operation.
assert (U->getType() == Ex->getType());
- ProgramStateRef state = (*I)->getState();
- const LocationContext *LCtx = (*I)->getLocationContext();
- Bldr.generateNode(U, *I, state->BindExpr(U, LCtx,
- state->getSVal(Ex, LCtx)));
+ ProgramStateRef state = N->getState();
+ const LocationContext *LCtx = N->getLocationContext();
+ Bldr.generateNode(U, N,
+ state->BindExpr(U, LCtx, state->getSVal(Ex, LCtx)));
break;
}
@@ -975,10 +961,10 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, ExplodedNode *Pred,
break;
}
// For all other types, UO_Imag returns 0.
- ProgramStateRef state = (*I)->getState();
- const LocationContext *LCtx = (*I)->getLocationContext();
+ ProgramStateRef state = N->getState();
+ const LocationContext *LCtx = N->getLocationContext();
SVal X = svalBuilder.makeZeroVal(Ex->getType());
- Bldr.generateNode(U, *I, state->BindExpr(U, LCtx, X));
+ Bldr.generateNode(U, N, state->BindExpr(U, LCtx, X));
break;
}
@@ -989,15 +975,15 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, ExplodedNode *Pred,
const ValueDecl *VD = DRE->getDecl();
if (isa<CXXMethodDecl, FieldDecl, IndirectFieldDecl>(VD)) {
- ProgramStateRef State = (*I)->getState();
- const LocationContext *LCtx = (*I)->getLocationContext();
+ ProgramStateRef State = N->getState();
+ const LocationContext *LCtx = N->getLocationContext();
SVal SV = svalBuilder.getMemberPointer(cast<NamedDecl>(VD));
- Bldr.generateNode(U, *I, State->BindExpr(U, LCtx, SV));
+ Bldr.generateNode(U, N, State->BindExpr(U, LCtx, SV));
break;
}
}
// Explicitly proceed with default handler for this case cascade.
- handleUOExtension(I, U, Bldr);
+ handleUOExtension(N, U, Bldr);
break;
}
case UO_Plus:
@@ -1005,7 +991,7 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, ExplodedNode *Pred,
[[fallthrough]];
case UO_Deref:
case UO_Extension: {
- handleUOExtension(I, U, Bldr);
+ handleUOExtension(N, U, Bldr);
break;
}
@@ -1014,14 +1000,14 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, ExplodedNode *Pred,
case UO_Not: {
assert (!U->isGLValue());
const Expr *Ex = U->getSubExpr()->IgnoreParens();
- ProgramStateRef state = (*I)->getState();
- const LocationContext *LCtx = (*I)->getLocationContext();
+ ProgramStateRef state = N->getState();
+ const LocationContext *LCtx = N->getLocationContext();
// Get the value of the subexpression.
SVal V = state->getSVal(Ex, LCtx);
if (V.isUnknownOrUndef()) {
- Bldr.generateNode(U, *I, state->BindExpr(U, LCtx, V));
+ Bldr.generateNode(U, N, state->BindExpr(U, LCtx, V));
break;
}
@@ -1058,7 +1044,7 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, ExplodedNode *Pred,
state = state->BindExpr(U, LCtx, Result);
break;
}
- Bldr.generateNode(U, *I, state);
+ Bldr.generateNode(U, N, state);
break;
}
}
@@ -1084,10 +1070,9 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U,
ExplodedNodeSet Dst2;
StmtNodeBuilder Bldr(Tmp, Dst2, *currBldrCtx);
- for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end();I!=E;++I) {
-
- state = (*I)->getState();
- assert(LCtx == (*I)->getLocationContext());
+ for (ExplodedNode *N : Tmp) {
+ state = N->getState();
+ assert(LCtx == N->getLocationContext());
SVal V2_untested = state->getSVal(Ex, LCtx);
// Propagate unknown and undefined values.
@@ -1095,9 +1080,9 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U,
state = state->BindExpr(U, LCtx, V2_untested);
// Perform the store, so that the uninitialized value detection happens.
- Bldr.takeNodes(*I);
+ Bldr.takeNodes(N);
ExplodedNodeSet Dst3;
- evalStore(Dst3, U, Ex, *I, state, loc, V2_untested);
+ evalStore(Dst3, U, Ex, N, state, loc, V2_untested);
Bldr.addNodes(Dst3);
continue;
@@ -1163,9 +1148,9 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U,
state = state->BindExpr(U, LCtx, U->isPostfix() ? V2 : Result);
// Perform the store.
- Bldr.takeNodes(*I);
+ Bldr.takeNodes(N);
ExplodedNodeSet Dst3;
- evalStore(Dst3, U, Ex, *I, state, loc, Result);
+ evalStore(Dst3, U, Ex, N, state, loc, Result);
Bldr.addNodes(Dst3);
}
Dst.insert(Dst2);
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 6eb37287b136..7ee7c1394a67 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -20,6 +20,8 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Sequence.h"
#include <optional>
using namespace clang;
@@ -59,40 +61,39 @@ void ExprEngine::performTrivialCopy(NodeBuilder &Bldr, ExplodedNode *Pred,
AlwaysReturnsLValue = true;
}
- assert(ThisRD);
- if (ThisRD->isEmpty()) {
- // Do nothing for empty classes. Otherwise it'd retrieve an UnknownVal
- // and bind it and RegionStore would think that the actual value
- // in this region at this offset is unknown.
- return;
- }
-
const LocationContext *LCtx = Pred->getLocationContext();
+ const Expr *CallExpr = Call.getOriginExpr();
ExplodedNodeSet Dst;
Bldr.takeNodes(Pred);
- SVal V = Call.getArgSVal(0);
-
- // If the value being copied is not unknown, load from its location to get
- // an aggregate rvalue.
- if (std::optional<Loc> L = V.getAs<Loc>())
- V = Pred->getState()->getSVal(*L);
- else
- assert(V.isUnknownOrUndef());
+ assert(ThisRD);
+ if (!ThisRD->isEmpty()) {
+ // Load the source value only for non-empty classes.
+ // Otherwise it'd retrieve an UnknownVal
+ // and bind it and RegionStore would think that the actual value
+ // in this region at this offset is unknown.
+ SVal V = Call.getArgSVal(0);
- const Expr *CallExpr = Call.getOriginExpr();
- evalBind(Dst, CallExpr, Pred, ThisVal, V, true);
+ // If the value being copied is not unknown, load from its location to get
+ // an aggregate rvalue.
+ if (std::optional<Loc> L = V.getAs<Loc>())
+ V = Pred->getState()->getSVal(*L);
+ else
+ assert(V.isUnknownOrUndef());
+ evalBind(Dst, CallExpr, Pred, ThisVal, V, true);
+ } else {
+ Dst.Add(Pred);
+ }
PostStmt PS(CallExpr, LCtx);
- for (ExplodedNodeSet::iterator I = Dst.begin(), E = Dst.end();
- I != E; ++I) {
- ProgramStateRef State = (*I)->getState();
+ for (ExplodedNode *N : Dst) {
+ ProgramStateRef State = N->getState();
if (AlwaysReturnsLValue)
State = State->BindExpr(CallExpr, LCtx, ThisVal);
else
State = bindReturnValue(Call, LCtx, State);
- Bldr.generateNode(PS, State, *I);
+ Bldr.generateNode(PS, State, N);
}
}
@@ -284,7 +285,8 @@ SVal ExprEngine::computeObjectUnderConstruction(
CallOpts.IsTemporaryCtorOrDtor = true;
if (MTE) {
if (const ValueDecl *VD = MTE->getExtendingDecl()) {
- assert(MTE->getStorageDuration() != SD_FullExpression);
+ StorageDuration SD = MTE->getStorageDuration();
+ assert(SD != SD_FullExpression);
if (!VD->getType()->isReferenceType()) {
// We're lifetime-extended by a surrounding aggregate.
// Automatic destructors aren't quite working in this case
@@ -293,11 +295,15 @@ SVal ExprEngine::computeObjectUnderConstruction(
// the MaterializeTemporaryExpr?
CallOpts.IsTemporaryLifetimeExtendedViaAggregate = true;
}
- }
- if (MTE->getStorageDuration() == SD_Static ||
- MTE->getStorageDuration() == SD_Thread)
- return loc::MemRegionVal(MRMgr.getCXXStaticTempObjectRegion(E));
+ if (SD == SD_Static || SD == SD_Thread)
+ return loc::MemRegionVal(
+ MRMgr.getCXXStaticLifetimeExtendedObjectRegion(E, VD));
+
+ return loc::MemRegionVal(
+ MRMgr.getCXXLifetimeExtendedObjectRegion(E, VD, LCtx));
+ }
+ assert(MTE->getStorageDuration() == SD_FullExpression);
}
return loc::MemRegionVal(MRMgr.getCXXTempObjectRegion(E, LCtx));
@@ -357,7 +363,8 @@ SVal ExprEngine::computeObjectUnderConstruction(
};
if (const auto *CE = dyn_cast<CallExpr>(E)) {
- CallEventRef<> Caller = CEMgr.getSimpleCall(CE, State, LCtx);
+ CallEventRef<> Caller =
+ CEMgr.getSimpleCall(CE, State, LCtx, getCFGElementRef());
if (std::optional<SVal> V = getArgLoc(Caller))
return *V;
else
@@ -365,14 +372,15 @@ SVal ExprEngine::computeObjectUnderConstruction(
} else if (const auto *CCE = dyn_cast<CXXConstructExpr>(E)) {
// Don't bother figuring out the target region for the future
// constructor because we won't need it.
- CallEventRef<> Caller =
- CEMgr.getCXXConstructorCall(CCE, /*Target=*/nullptr, State, LCtx);
+ CallEventRef<> Caller = CEMgr.getCXXConstructorCall(
+ CCE, /*Target=*/nullptr, State, LCtx, getCFGElementRef());
if (std::optional<SVal> V = getArgLoc(Caller))
return *V;
else
break;
} else if (const auto *ME = dyn_cast<ObjCMessageExpr>(E)) {
- CallEventRef<> Caller = CEMgr.getObjCMethodCall(ME, State, LCtx);
+ CallEventRef<> Caller =
+ CEMgr.getObjCMethodCall(ME, State, LCtx, getCFGElementRef());
if (std::optional<SVal> V = getArgLoc(Caller))
return *V;
else
@@ -726,9 +734,9 @@ void ExprEngine::handleConstructor(const Expr *E,
CallEventManager &CEMgr = getStateManager().getCallEventManager();
CallEventRef<> Call =
CIE ? (CallEventRef<>)CEMgr.getCXXInheritedConstructorCall(
- CIE, TargetRegion, State, LCtx)
+ CIE, TargetRegion, State, LCtx, getCFGElementRef())
: (CallEventRef<>)CEMgr.getCXXConstructorCall(
- CE, TargetRegion, State, LCtx);
+ CE, TargetRegion, State, LCtx, getCFGElementRef());
ExplodedNodeSet DstPreVisit;
getCheckerManager().runCheckersForPreStmt(DstPreVisit, Pred, E, *this);
@@ -737,10 +745,8 @@ void ExprEngine::handleConstructor(const Expr *E,
if (CE) {
// FIXME: Is it possible and/or useful to do this before PreStmt?
StmtNodeBuilder Bldr(DstPreVisit, PreInitialized, *currBldrCtx);
- for (ExplodedNodeSet::iterator I = DstPreVisit.begin(),
- E = DstPreVisit.end();
- I != E; ++I) {
- ProgramStateRef State = (*I)->getState();
+ for (ExplodedNode *N : DstPreVisit) {
+ ProgramStateRef State = N->getState();
if (CE->requiresZeroInitialization()) {
// FIXME: Once we properly handle constructors in new-expressions, we'll
// need to invalidate the region before setting a default value, to make
@@ -757,7 +763,7 @@ void ExprEngine::handleConstructor(const Expr *E,
State = State->bindDefaultZero(Target, LCtx);
}
- Bldr.generateNode(CE, *I, State, /*tag=*/nullptr,
+ Bldr.generateNode(CE, N, State, /*tag=*/nullptr,
ProgramPoint::PreStmtKind);
}
} else {
@@ -775,14 +781,12 @@ void ExprEngine::handleConstructor(const Expr *E,
!CallOpts.IsArrayCtorOrDtor) {
StmtNodeBuilder Bldr(DstPreCall, DstEvaluated, *currBldrCtx);
// FIXME: Handle other kinds of trivial constructors as well.
- for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
- I != E; ++I)
- performTrivialCopy(Bldr, *I, *Call);
+ for (ExplodedNode *N : DstPreCall)
+ performTrivialCopy(Bldr, N, *Call);
} else {
- for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
- I != E; ++I)
- getCheckerManager().runCheckersForEvalCall(DstEvaluated, *I, *Call, *this,
+ for (ExplodedNode *N : DstPreCall)
+ getCheckerManager().runCheckersForEvalCall(DstEvaluated, N, *Call, *this,
CallOpts);
}
@@ -797,7 +801,8 @@ void ExprEngine::handleConstructor(const Expr *E,
StmtNodeBuilder Bldr(DstEvaluated, DstEvaluatedPostProcessed, *currBldrCtx);
const AnalysisDeclContext *ADC = LCtx->getAnalysisDeclContext();
if (!ADC->getCFGBuildOptions().AddTemporaryDtors) {
- if (llvm::isa_and_nonnull<CXXTempObjectRegion>(TargetRegion) &&
+ if (llvm::isa_and_nonnull<CXXTempObjectRegion,
+ CXXLifetimeExtendedObjectRegion>(TargetRegion) &&
cast<CXXConstructorDecl>(Call->getDecl())
->getParent()
->isAnyDestructorNoReturn()) {
@@ -869,7 +874,8 @@ void ExprEngine::VisitCXXDestructor(QualType ObjectType,
// it would interrupt the analysis instead.
static SimpleProgramPointTag T("ExprEngine", "SkipInvalidDestructor");
// FIXME: PostImplicitCall with a null decl may crash elsewhere anyway.
- PostImplicitCall PP(/*Decl=*/nullptr, S->getEndLoc(), LCtx, &T);
+ PostImplicitCall PP(/*Decl=*/nullptr, S->getEndLoc(), LCtx,
+ getCFGElementRef(), &T);
NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
Bldr.generateNode(PP, Pred->getState(), Pred);
return;
@@ -894,8 +900,8 @@ void ExprEngine::VisitCXXDestructor(QualType ObjectType,
}
CallEventManager &CEMgr = getStateManager().getCallEventManager();
- CallEventRef<CXXDestructorCall> Call =
- CEMgr.getCXXDestructorCall(DtorDecl, S, Dest, IsBaseDtor, State, LCtx);
+ CallEventRef<CXXDestructorCall> Call = CEMgr.getCXXDestructorCall(
+ DtorDecl, S, Dest, IsBaseDtor, State, LCtx, getCFGElementRef());
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
Call->getSourceRange().getBegin(),
@@ -907,9 +913,8 @@ void ExprEngine::VisitCXXDestructor(QualType ObjectType,
ExplodedNodeSet DstInvalidated;
StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx);
- for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
- I != E; ++I)
- defaultEvalCall(Bldr, *I, *Call, CallOpts);
+ for (ExplodedNode *N : DstPreCall)
+ defaultEvalCall(Bldr, N, *Call, CallOpts);
getCheckerManager().runCheckersForPostCall(Dst, DstInvalidated,
*Call, *this);
@@ -925,7 +930,7 @@ void ExprEngine::VisitCXXNewAllocatorCall(const CXXNewExpr *CNE,
"Error evaluating New Allocator Call");
CallEventManager &CEMgr = getStateManager().getCallEventManager();
CallEventRef<CXXAllocatorCall> Call =
- CEMgr.getCXXAllocatorCall(CNE, State, LCtx);
+ CEMgr.getCXXAllocatorCall(CNE, State, LCtx, getCFGElementRef());
ExplodedNodeSet DstPreCall;
getCheckerManager().runCheckersForPreCall(DstPreCall, Pred,
@@ -1023,7 +1028,7 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
CallEventManager &CEMgr = getStateManager().getCallEventManager();
CallEventRef<CXXAllocatorCall> Call =
- CEMgr.getCXXAllocatorCall(CNE, State, LCtx);
+ CEMgr.getCXXAllocatorCall(CNE, State, LCtx, getCFGElementRef());
if (!AMgr.getAnalyzerOptions().MayInlineCXXAllocator) {
// Invalidate placement args.
@@ -1124,7 +1129,7 @@ void ExprEngine::VisitCXXDeleteExpr(const CXXDeleteExpr *CDE,
CallEventManager &CEMgr = getStateManager().getCallEventManager();
CallEventRef<CXXDeallocatorCall> Call = CEMgr.getCXXDeallocatorCall(
- CDE, Pred->getState(), Pred->getLocationContext());
+ CDE, Pred->getState(), Pred->getLocationContext(), getCFGElementRef());
ExplodedNodeSet DstPreCall;
getCheckerManager().runCheckersForPreCall(DstPreCall, Pred, *Call, *this);
@@ -1188,18 +1193,13 @@ void ExprEngine::VisitLambdaExpr(const LambdaExpr *LE, ExplodedNode *Pred,
// If we created a new MemRegion for the lambda, we should explicitly bind
// the captures.
- unsigned Idx = 0;
- CXXRecordDecl::field_iterator CurField = LE->getLambdaClass()->field_begin();
- for (LambdaExpr::const_capture_init_iterator i = LE->capture_init_begin(),
- e = LE->capture_init_end();
- i != e; ++i, ++CurField, ++Idx) {
- FieldDecl *FieldForCapture = *CurField;
+ for (auto const [Idx, FieldForCapture, InitExpr] :
+ llvm::zip(llvm::seq<unsigned>(0, -1), LE->getLambdaClass()->fields(),
+ LE->capture_inits())) {
SVal FieldLoc = State->getLValue(FieldForCapture, V);
SVal InitVal;
if (!FieldForCapture->hasCapturedVLAType()) {
- const Expr *InitExpr = *i;
-
assert(InitExpr && "Capture missing initialization expression");
// Capturing a 0 length array is a no-op, so we ignore it to get a more
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index 54528475cb31..b987ce278936 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -374,17 +374,15 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
CleanedNodes.Add(CEBNode);
}
- for (ExplodedNodeSet::iterator I = CleanedNodes.begin(),
- E = CleanedNodes.end(); I != E; ++I) {
-
+ for (ExplodedNode *N : CleanedNodes) {
// Step 4: Generate the CallExit and leave the callee's context.
// CleanedNodes -> CEENode
CallExitEnd Loc(calleeCtx, callerCtx);
bool isNew;
- ProgramStateRef CEEState = (*I == CEBNode) ? state : (*I)->getState();
+ ProgramStateRef CEEState = (N == CEBNode) ? state : N->getState();
ExplodedNode *CEENode = G.getNode(Loc, CEEState, false, &isNew);
- CEENode->addPredecessor(*I, G);
+ CEENode->addPredecessor(N, G);
if (!isNew)
return;
@@ -610,15 +608,14 @@ void ExprEngine::VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred,
// Get the call in its initial state. We use this as a template to perform
// all the checks.
CallEventManager &CEMgr = getStateManager().getCallEventManager();
- CallEventRef<> CallTemplate
- = CEMgr.getSimpleCall(CE, Pred->getState(), Pred->getLocationContext());
+ CallEventRef<> CallTemplate = CEMgr.getSimpleCall(
+ CE, Pred->getState(), Pred->getLocationContext(), getCFGElementRef());
// Evaluate the function call. We try each of the checkers
// to see if the can evaluate the function call.
ExplodedNodeSet dstCallEvaluated;
- for (ExplodedNodeSet::iterator I = dstPreVisit.begin(), E = dstPreVisit.end();
- I != E; ++I) {
- evalCall(dstCallEvaluated, *I, *CallTemplate);
+ for (ExplodedNode *N : dstPreVisit) {
+ evalCall(dstCallEvaluated, N, *CallTemplate);
}
// Finally, perform the post-condition check of the CallExpr and store
@@ -837,7 +834,8 @@ void ExprEngine::conservativeEvalCall(const CallEvent &Call, NodeBuilder &Bldr,
State = bindReturnValue(Call, Pred->getLocationContext(), State);
// And make the result node.
- Bldr.generateNode(Call.getProgramPoint(), State, Pred);
+ static SimpleProgramPointTag PT("ExprEngine", "Conservative eval call");
+ Bldr.generateNode(Call.getProgramPoint(false, &PT), State, Pred);
}
ExprEngine::CallInlinePolicy
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
index 25c36e9aea24..8072531ef6fd 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
@@ -148,8 +148,8 @@ void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
CallEventManager &CEMgr = getStateManager().getCallEventManager();
- CallEventRef<ObjCMethodCall> Msg =
- CEMgr.getObjCMethodCall(ME, Pred->getState(), Pred->getLocationContext());
+ CallEventRef<ObjCMethodCall> Msg = CEMgr.getObjCMethodCall(
+ ME, Pred->getState(), Pred->getLocationContext(), getCFGElementRef());
// There are three cases for the receiver:
// (1) it is definitely nil,
diff --git a/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
index b4578385a147..0fe0c93dc016 100644
--- a/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
+++ b/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
@@ -602,9 +602,9 @@ void HTMLDiagnostics::FinalizeHTML(const PathDiagnostic& D, Rewriter &R,
// Output any other meta data.
- for (PathDiagnostic::meta_iterator I = D.meta_begin(), E = D.meta_end();
- I != E; ++I) {
- os << "<tr><td></td><td>" << html::EscapeText(*I) << "</td></tr>\n";
+ for (const std::string &Metadata :
+ llvm::make_range(D.meta_begin(), D.meta_end())) {
+ os << "<tr><td></td><td>" << html::EscapeText(Metadata) << "</td></tr>\n";
}
os << R"<<<(
diff --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
index 0c126a632f74..16db6b249dc9 100644
--- a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -39,6 +39,7 @@
#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"
@@ -73,8 +74,7 @@ RegionTy* MemRegionManager::getSubRegion(const Arg1Ty arg1,
auto *R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID, InsertPos));
if (!R) {
- R = A.Allocate<RegionTy>();
- new (R) RegionTy(arg1, superRegion);
+ R = new (A) RegionTy(arg1, superRegion);
Regions.InsertNode(R, InsertPos);
}
@@ -90,8 +90,7 @@ RegionTy* MemRegionManager::getSubRegion(const Arg1Ty arg1, const Arg2Ty arg2,
auto *R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID, InsertPos));
if (!R) {
- R = A.Allocate<RegionTy>();
- new (R) RegionTy(arg1, arg2, superRegion);
+ R = new (A) RegionTy(arg1, arg2, superRegion);
Regions.InsertNode(R, InsertPos);
}
@@ -109,8 +108,7 @@ RegionTy* MemRegionManager::getSubRegion(const Arg1Ty arg1, const Arg2Ty arg2,
auto *R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID, InsertPos));
if (!R) {
- R = A.Allocate<RegionTy>();
- new (R) RegionTy(arg1, arg2, arg3, superRegion);
+ R = new (A) RegionTy(arg1, arg2, arg3, superRegion);
Regions.InsertNode(R, InsertPos);
}
@@ -161,6 +159,18 @@ const StackFrameContext *VarRegion::getStackFrame() const {
return SSR ? SSR->getStackFrame() : nullptr;
}
+const StackFrameContext *
+CXXLifetimeExtendedObjectRegion::getStackFrame() const {
+ const auto *SSR = dyn_cast<StackSpaceRegion>(getMemorySpace());
+ return SSR ? SSR->getStackFrame() : nullptr;
+}
+
+const StackFrameContext *CXXTempObjectRegion::getStackFrame() const {
+ assert(isa<StackSpaceRegion>(getMemorySpace()) &&
+ "A temporary object can only be allocated on the stack");
+ return cast<StackSpaceRegion>(getMemorySpace())->getStackFrame();
+}
+
ObjCIvarRegion::ObjCIvarRegion(const ObjCIvarDecl *ivd, const SubRegion *sReg)
: DeclRegion(sReg, ObjCIvarRegionKind), IVD(ivd) {
assert(IVD);
@@ -392,6 +402,20 @@ 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,
@@ -468,11 +492,9 @@ void BlockCodeRegion::dumpToStream(raw_ostream &os) const {
void BlockDataRegion::dumpToStream(raw_ostream &os) const {
os << "block_data{" << BC;
os << "; ";
- for (BlockDataRegion::referenced_vars_iterator
- I = referenced_vars_begin(),
- E = referenced_vars_end(); I != E; ++I)
- os << "(" << I.getCapturedRegion() << "<-" <<
- I.getOriginalRegion() << ") ";
+ for (auto Var : referenced_vars())
+ os << "(" << Var.getCapturedRegion() << "<-" << Var.getOriginalRegion()
+ << ") ";
os << '}';
}
@@ -486,6 +508,16 @@ void CXXTempObjectRegion::dumpToStream(raw_ostream &os) const {
<< "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() << '}';
}
@@ -712,21 +744,17 @@ std::string MemRegion::getDescriptiveName(bool UseQuotes) const {
}
SourceRange MemRegion::sourceRange() const {
- const auto *const VR = dyn_cast<VarRegion>(this->getBaseRegion());
- const auto *const FR = dyn_cast<FieldRegion>(this);
-
// Check for more specific regions first.
- // FieldRegion
- if (FR) {
+ if (auto *FR = dyn_cast<FieldRegion>(this)) {
return FR->getDecl()->getSourceRange();
}
- // VarRegion
- else if (VR) {
+
+ if (auto *VR = dyn_cast<VarRegion>(this->getBaseRegion())) {
return VR->getDecl()->getSourceRange();
}
+
// Return invalid source range (can be checked by client).
- else
- return {};
+ return {};
}
//===----------------------------------------------------------------------===//
@@ -750,6 +778,7 @@ DefinedOrUnknownSVal MemRegionManager::getStaticSize(const MemRegion *MR,
case MemRegion::CXXBaseObjectRegionKind:
case MemRegion::CXXDerivedObjectRegionKind:
case MemRegion::CXXTempObjectRegionKind:
+ case MemRegion::CXXLifetimeExtendedObjectRegionKind:
case MemRegion::CXXThisRegionKind:
case MemRegion::ObjCIvarRegionKind:
case MemRegion::NonParamVarRegionKind:
@@ -776,49 +805,46 @@ DefinedOrUnknownSVal MemRegionManager::getStaticSize(const MemRegion *MR,
// 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 (*)
- // (*): Consider single element array object members as FAM candidates only
- // if the consider-single-element-arrays-as-flexible-array-members
- // analyzer option is true.
+ // - int array[1]; of ConstantArrayType with size 1
// https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
- const auto isFlexibleArrayMemberCandidate = [this,
- &SVB](QualType Ty) -> bool {
- const ArrayType *AT = Ctx.getAsArrayType(Ty);
+ const auto isFlexibleArrayMemberCandidate =
+ [this](const ArrayType *AT) -> bool {
if (!AT)
return false;
- if (isa<IncompleteArrayType>(AT))
- return true;
- if (const auto *CAT = dyn_cast<ConstantArrayType>(AT)) {
- using FAMKind = LangOptions::StrictFlexArraysLevelKind;
- const FAMKind StrictFlexArraysLevel =
+ auto IsIncompleteArray = [](const ArrayType *AT) {
+ return isa<IncompleteArrayType>(AT);
+ };
+ auto IsArrayOfZero = [](const ArrayType *AT) {
+ const auto *CAT = dyn_cast<ConstantArrayType>(AT);
+ return CAT && CAT->getSize() == 0;
+ };
+ 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();
- const AnalyzerOptions &Opts = SVB.getAnalyzerOptions();
- const llvm::APInt &Size = CAT->getSize();
-
- if (StrictFlexArraysLevel <= FAMKind::ZeroOrIncomplete && Size.isZero())
- return true;
-
- // The "-fstrict-flex-arrays" should have precedence over
- // consider-single-element-arrays-as-flexible-array-members
- // analyzer-config when checking single element arrays.
- if (StrictFlexArraysLevel == FAMKind::Default) {
- // FIXME: After clang-17 released, we should remove this branch.
- if (Opts.ShouldConsiderSingleElementArraysAsFlexibleArrayMembers &&
- Size.isOne())
- return true;
- } else {
- // -fstrict-flex-arrays was specified, since it's not the default, so
- // ignore analyzer-config.
- if (StrictFlexArraysLevel <= FAMKind::OneZeroOrIncomplete &&
- Size.isOne())
- return true;
- }
- }
- return false;
+
+ // "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(Ty))
+ if (isFlexibleArrayMemberCandidate(Ctx.getAsArrayType(Ty)))
return UnknownVal();
return Size;
@@ -838,8 +864,7 @@ DefinedOrUnknownSVal MemRegionManager::getStaticSize(const MemRegion *MR,
template <typename REG>
const REG *MemRegionManager::LazyAllocate(REG*& region) {
if (!region) {
- region = A.Allocate<REG>();
- new (region) REG(*this);
+ region = new (A) REG(*this);
}
return region;
@@ -848,8 +873,7 @@ const REG *MemRegionManager::LazyAllocate(REG*& region) {
template <typename REG, typename ARG>
const REG *MemRegionManager::LazyAllocate(REG*& region, ARG a) {
if (!region) {
- region = A.Allocate<REG>();
- new (region) REG(this, a);
+ region = new (A) REG(this, a);
}
return region;
@@ -863,8 +887,7 @@ MemRegionManager::getStackLocalsRegion(const StackFrameContext *STC) {
if (R)
return R;
- R = A.Allocate<StackLocalsSpaceRegion>();
- new (R) StackLocalsSpaceRegion(*this, STC);
+ R = new (A) StackLocalsSpaceRegion(*this, STC);
return R;
}
@@ -876,8 +899,7 @@ MemRegionManager::getStackArgumentsRegion(const StackFrameContext *STC) {
if (R)
return R;
- R = A.Allocate<StackArgumentsSpaceRegion>();
- new (R) StackArgumentsSpaceRegion(*this, STC);
+ R = new (A) StackArgumentsSpaceRegion(*this, STC);
return R;
}
@@ -898,8 +920,7 @@ const GlobalsSpaceRegion
if (R)
return R;
- R = A.Allocate<StaticGlobalSpaceRegion>();
- new (R) StaticGlobalSpaceRegion(*this, CR);
+ R = new (A) StaticGlobalSpaceRegion(*this, CR);
return R;
}
@@ -945,13 +966,11 @@ getStackOrCaptureRegionForDeclContext(const LocationContext *LC,
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 (BlockDataRegion::referenced_vars_iterator
- I = BR->referenced_vars_begin(),
- E = BR->referenced_vars_end(); I != E; ++I) {
- const TypedValueRegion *OrigR = I.getOriginalRegion();
+ 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>(I.getCapturedRegion());
+ return cast<VarRegion>(Var.getCapturedRegion());
}
}
}
@@ -1058,13 +1077,16 @@ const VarRegion *MemRegionManager::getVarRegion(const VarDecl *D,
}
}
- return getSubRegion<NonParamVarRegion>(D, sReg);
+ 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);
}
@@ -1109,12 +1131,6 @@ MemRegionManager::getBlockDataRegion(const BlockCodeRegion *BC,
return getSubRegion<BlockDataRegion>(BC, LC, blockCount, sReg);
}
-const CXXTempObjectRegion *
-MemRegionManager::getCXXStaticTempObjectRegion(const Expr *Ex) {
- return getSubRegion<CXXTempObjectRegion>(
- Ex, getGlobalsRegion(MemRegion::GlobalInternalSpaceRegionKind, nullptr));
-}
-
const CompoundLiteralRegion*
MemRegionManager::getCompoundLiteralRegion(const CompoundLiteralExpr *CL,
const LocationContext *LC) {
@@ -1145,8 +1161,7 @@ MemRegionManager::getElementRegion(QualType elementType, NonLoc Idx,
auto *R = cast_or_null<ElementRegion>(data);
if (!R) {
- R = A.Allocate<ElementRegion>();
- new (R) ElementRegion(T, Idx, superRegion);
+ R = new (A) ElementRegion(T, Idx, superRegion);
Regions.InsertNode(R, InsertPos);
}
@@ -1197,6 +1212,23 @@ MemRegionManager::getCXXTempObjectRegion(Expr const *E,
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,
@@ -1283,7 +1315,7 @@ const MemSpaceRegion *MemRegion::getMemorySpace() const {
SR = dyn_cast<SubRegion>(R);
}
- return dyn_cast<MemSpaceRegion>(R);
+ return cast<MemSpaceRegion>(R);
}
bool MemRegion::hasStackStorage() const {
@@ -1298,10 +1330,6 @@ bool MemRegion::hasStackParametersStorage() const {
return isa<StackArgumentsSpaceRegion>(getMemorySpace());
}
-bool MemRegion::hasGlobalsOrParametersStorage() const {
- return isa<StackArgumentsSpaceRegion, GlobalsSpaceRegion>(getMemorySpace());
-}
-
// Strips away all elements and fields.
// Returns the base region of them.
const MemRegion *MemRegion::getBaseRegion() const {
@@ -1474,6 +1502,7 @@ static RegionOffset calculateOffset(const MemRegion *R) {
case MemRegion::NonParamVarRegionKind:
case MemRegion::ParamVarRegionKind:
case MemRegion::CXXTempObjectRegionKind:
+ case MemRegion::CXXLifetimeExtendedObjectRegionKind:
// Usual base regions.
goto Finish;
@@ -1664,10 +1693,8 @@ void BlockDataRegion::LazyInitializeReferencedVars() {
using VarVec = BumpVector<const MemRegion *>;
- auto *BV = A.Allocate<VarVec>();
- new (BV) VarVec(BC, NumBlockVars);
- auto *BVOriginal = A.Allocate<VarVec>();
- new (BVOriginal) VarVec(BC, NumBlockVars);
+ auto *BV = new (A) VarVec(BC, NumBlockVars);
+ auto *BVOriginal = new (A) VarVec(BC, NumBlockVars);
for (const auto *VD : ReferencedBlockVars) {
const VarRegion *VR = nullptr;
@@ -1715,10 +1742,13 @@ BlockDataRegion::referenced_vars_end() const {
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 (referenced_vars_iterator I = referenced_vars_begin(),
- E = referenced_vars_end();
- I != E; ++I) {
+ for (const auto &I : referenced_vars()) {
if (I.getCapturedRegion() == R)
return I.getOriginalRegion();
}
diff --git a/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp b/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
index a3b08d4581a5..bdf485364cef 100644
--- a/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
+++ b/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
@@ -367,10 +367,8 @@ void PlistPrinter::ReportMacroSubPieces(raw_ostream &o,
unsigned indent, unsigned depth) {
MacroPieces.push_back(&P);
- for (PathPieces::const_iterator I = P.subPieces.begin(),
- E = P.subPieces.end();
- I != E; ++I) {
- ReportPiece(o, **I, indent, depth, /*includeControlFlow*/ false);
+ for (const auto &SubPiece : P.subPieces) {
+ ReportPiece(o, *SubPiece, indent, depth, /*includeControlFlow*/ false);
}
assert(P.getFixits().size() == 0 &&
@@ -500,12 +498,12 @@ static void printCoverage(const PathDiagnostic *D,
// Mapping from file IDs to executed lines.
const FilesToLineNumsMap &ExecutedLines = D->getExecutedLines();
- for (auto I = ExecutedLines.begin(), E = ExecutedLines.end(); I != E; ++I) {
- unsigned FileKey = AddFID(FM, Fids, I->first);
+ for (const auto &[FID, Lines] : ExecutedLines) {
+ unsigned FileKey = AddFID(FM, Fids, FID);
Indent(o, IndentLevel) << "<key>" << FileKey << "</key>\n";
Indent(o, IndentLevel) << "<array>\n";
IndentLevel++;
- for (unsigned LineNo : I->second) {
+ for (unsigned LineNo : Lines) {
Indent(o, IndentLevel);
EmitInteger(o, LineNo) << "\n";
}
@@ -597,8 +595,8 @@ void PlistDiagnostics::printBugPath(llvm::raw_ostream &o, const FIDMap &FM,
o << " <array>\n";
- for (PathPieces::const_iterator E = Path.end(); I != E; ++I)
- Printer.ReportDiag(o, **I);
+ for (const auto &Piece : llvm::make_range(I, Path.end()))
+ Printer.ReportDiag(o, *Piece);
o << " </array>\n";
diff --git a/clang/lib/StaticAnalyzer/Core/ProgramState.cpp b/clang/lib/StaticAnalyzer/Core/ProgramState.cpp
index 90ebbaad2bf3..f12f1a5ac970 100644
--- a/clang/lib/StaticAnalyzer/Core/ProgramState.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ProgramState.cpp
@@ -156,9 +156,8 @@ ProgramState::invalidateRegions(RegionList Regions,
const CallEvent *Call,
RegionAndSymbolInvalidationTraits *ITraits) const {
SmallVector<SVal, 8> Values;
- for (RegionList::const_iterator I = Regions.begin(),
- End = Regions.end(); I != End; ++I)
- Values.push_back(loc::MemRegionVal(*I));
+ for (const MemRegion *Reg : Regions)
+ Values.push_back(loc::MemRegionVal(Reg));
return invalidateRegionsImpl(Values, E, Count, LCtx, CausedByPointerEscape,
IS, ITraits, Call);
@@ -424,7 +423,7 @@ ProgramStateRef ProgramStateManager::getPersistentState(ProgramState &State) {
freeStates.pop_back();
}
else {
- newState = (ProgramState*) Alloc.Allocate<ProgramState>();
+ newState = Alloc.Allocate<ProgramState>();
}
new (newState) ProgramState(State);
StateSet.InsertNode(newState, InsertPos);
@@ -556,22 +555,20 @@ bool ScanReachableSymbols::scan(nonloc::LazyCompoundVal val) {
}
bool ScanReachableSymbols::scan(nonloc::CompoundVal val) {
- for (nonloc::CompoundVal::iterator I=val.begin(), E=val.end(); I!=E; ++I)
- if (!scan(*I))
+ for (SVal V : val)
+ if (!scan(V))
return false;
return true;
}
bool ScanReachableSymbols::scan(const SymExpr *sym) {
- for (SymExpr::symbol_iterator SI = sym->symbol_begin(),
- SE = sym->symbol_end();
- SI != SE; ++SI) {
- bool wasVisited = !visited.insert(*SI).second;
+ for (SymbolRef SubSym : sym->symbols()) {
+ bool wasVisited = !visited.insert(SubSym).second;
if (wasVisited)
continue;
- if (!visitor.VisitSymbol(*SI))
+ if (!visitor.VisitSymbol(SubSym))
return false;
}
@@ -630,10 +627,8 @@ bool ScanReachableSymbols::scan(const MemRegion *R) {
// Regions captured by a block are also implicitly reachable.
if (const BlockDataRegion *BDR = dyn_cast<BlockDataRegion>(R)) {
- BlockDataRegion::referenced_vars_iterator I = BDR->referenced_vars_begin(),
- E = BDR->referenced_vars_end();
- for ( ; I != E; ++I) {
- if (!scan(I.getCapturedRegion()))
+ for (auto Var : BDR->referenced_vars()) {
+ if (!scan(Var.getCapturedRegion()))
return false;
}
}
diff --git a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
index 1017dff2b0f3..5de99384449a 100644
--- a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -1083,7 +1083,7 @@ areFeasible(ConstraintRangeTy Constraints) {
///
/// \returns true if assuming this Sym to be true means equality of operands
/// false if it means disequality of operands
-/// None otherwise
+/// std::nullopt otherwise
std::optional<bool> meansEquality(const SymSymExpr *Sym) {
switch (Sym->getOpcode()) {
case BO_Sub:
@@ -2678,7 +2678,18 @@ EquivalenceClass::simplify(SValBuilder &SVB, RangeSet::Factory &F,
if (OldState == State)
continue;
- assert(find(State, MemberSym) == find(State, SimplifiedMemberSym));
+ // Be aware that `SimplifiedMemberSym` might refer to an already dead
+ // symbol. In that case, the eqclass of that might not be the same as the
+ // eqclass of `MemberSym`. This is because the dead symbols are not
+ // preserved in the `ClassMap`, hence
+ // `find(State, SimplifiedMemberSym)` will result in a trivial eqclass
+ // compared to the eqclass of `MemberSym`.
+ // These eqclasses should be the same if `SimplifiedMemberSym` is alive.
+ // --> assert(find(State, MemberSym) == find(State, SimplifiedMemberSym))
+ //
+ // Note that `MemberSym` must be alive here since that is from the
+ // `ClassMembers` where all the symbols are alive.
+
// Remove the old and more complex symbol.
State = find(State, MemberSym).removeMember(State, MemberSym);
diff --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
index 46948c12617c..c773cef30d5e 100644
--- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -28,6 +28,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "llvm/ADT/ImmutableMap.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/raw_ostream.h"
#include <optional>
#include <utility>
@@ -231,7 +232,7 @@ public:
void printJson(raw_ostream &Out, const char *NL = "\n",
unsigned int Space = 0, bool IsDot = false) const {
- for (iterator I = begin(); I != end(); ++I) {
+ for (iterator I = begin(), E = end(); I != E; ++I) {
// TODO: We might need a .printJson for I.getKey() as well.
Indent(Out, Space, IsDot)
<< "{ \"cluster\": \"" << I.getKey() << "\", \"pointer\": \""
@@ -239,18 +240,19 @@ public:
++Space;
const ClusterBindings &CB = I.getData();
- for (ClusterBindings::iterator CI = CB.begin(); CI != CB.end(); ++CI) {
+ for (ClusterBindings::iterator CI = CB.begin(), CE = CB.end(); CI != CE;
+ ++CI) {
Indent(Out, Space, IsDot) << "{ " << CI.getKey() << ", \"value\": ";
CI.getData().printJson(Out, /*AddQuotes=*/true);
Out << " }";
- if (std::next(CI) != CB.end())
+ if (std::next(CI) != CE)
Out << ',';
Out << NL;
}
--Space;
Indent(Out, Space, IsDot) << "]}";
- if (std::next(I) != end())
+ if (std::next(I) != E)
Out << ',';
Out << NL;
}
@@ -644,16 +646,13 @@ public: // Part of public interface to class.
void iterBindings(Store store, BindingsHandler& f) override {
RegionBindingsRef B = getRegionBindings(store);
- for (RegionBindingsRef::iterator I = B.begin(), E = B.end(); I != E; ++I) {
- const ClusterBindings &Cluster = I.getData();
- for (ClusterBindings::iterator CI = Cluster.begin(), CE = Cluster.end();
- CI != CE; ++CI) {
- const BindingKey &K = CI.getKey();
- if (!K.isDirect())
+ for (const auto &[Region, Cluster] : B) {
+ for (const auto &[Key, Value] : Cluster) {
+ if (!Key.isDirect())
continue;
- if (const SubRegion *R = dyn_cast<SubRegion>(K.getRegion())) {
+ if (const SubRegion *R = dyn_cast<SubRegion>(Key.getRegion())) {
// FIXME: Possibly incorporate the offset?
- if (!f.HandleBinding(*this, store, R, CI.getData()))
+ if (!f.HandleBinding(*this, store, R, Value))
return;
}
}
@@ -874,9 +873,8 @@ collectSubRegionBindings(SmallVectorImpl<BindingPair> &Bindings,
Length = FR->getDecl()->getBitWidthValue(SVB.getContext());
}
- for (ClusterBindings::iterator I = Cluster.begin(), E = Cluster.end();
- I != E; ++I) {
- BindingKey NextKey = I.getKey();
+ for (const auto &StoreEntry : Cluster) {
+ BindingKey NextKey = StoreEntry.first;
if (NextKey.getRegion() == TopKey.getRegion()) {
// FIXME: This doesn't catch the case where we're really invalidating a
// region with a symbolic offset. Example:
@@ -887,7 +885,7 @@ collectSubRegionBindings(SmallVectorImpl<BindingPair> &Bindings,
NextKey.getOffset() - TopKey.getOffset() < Length) {
// Case 1: The next binding is inside the region we're invalidating.
// Include it.
- Bindings.push_back(*I);
+ Bindings.push_back(StoreEntry);
} else if (NextKey.getOffset() == TopKey.getOffset()) {
// Case 2: The next binding is at the same offset as the region we're
@@ -897,7 +895,7 @@ collectSubRegionBindings(SmallVectorImpl<BindingPair> &Bindings,
// FIXME: This is probably incorrect; consider invalidating an outer
// struct whose first field is bound to a LazyCompoundVal.
if (IncludeAllDefaultBindings || NextKey.isDirect())
- Bindings.push_back(*I);
+ Bindings.push_back(StoreEntry);
}
} else if (NextKey.hasSymbolicOffset()) {
@@ -908,13 +906,13 @@ collectSubRegionBindings(SmallVectorImpl<BindingPair> &Bindings,
// we'll be conservative and include it.
if (IncludeAllDefaultBindings || NextKey.isDirect())
if (isCompatibleWithFields(NextKey, FieldsInSymbolicSubregions))
- Bindings.push_back(*I);
+ Bindings.push_back(StoreEntry);
} else if (const SubRegion *BaseSR = dyn_cast<SubRegion>(Base)) {
// Case 4: The next key is symbolic, but we changed a known
// super-region. In this case the binding is certainly included.
if (BaseSR->isSubRegionOf(Top))
if (isCompatibleWithFields(NextKey, FieldsInSymbolicSubregions))
- Bindings.push_back(*I);
+ Bindings.push_back(StoreEntry);
}
}
}
@@ -956,10 +954,8 @@ RegionStoreManager::removeSubRegionBindings(RegionBindingsConstRef B,
/*IncludeAllDefaultBindings=*/false);
ClusterBindingsRef Result(*Cluster, CBFactory);
- for (SmallVectorImpl<BindingPair>::const_iterator I = Bindings.begin(),
- E = Bindings.end();
- I != E; ++I)
- Result = Result.remove(I->first);
+ for (BindingKey Key : llvm::make_first_range(Bindings))
+ Result = Result.remove(Key);
// If we're invalidating a region with a symbolic offset, we need to make sure
// we don't treat the base region as uninitialized anymore.
@@ -1056,8 +1052,8 @@ void InvalidateRegionsWorker::VisitCluster(const MemRegion *baseR,
RegionAndSymbolInvalidationTraits::TK_PreserveContents);
if (C) {
- for (ClusterBindings::iterator I = C->begin(), E = C->end(); I != E; ++I)
- VisitBinding(I.getData());
+ for (SVal Val : llvm::make_second_range(*C))
+ VisitBinding(Val);
// Invalidate regions contents.
if (!PreserveRegionsContents)
@@ -1093,10 +1089,8 @@ void InvalidateRegionsWorker::VisitCluster(const MemRegion *baseR,
// BlockDataRegion? If so, invalidate captured variables that are passed
// by reference.
if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(baseR)) {
- for (BlockDataRegion::referenced_vars_iterator
- BI = BR->referenced_vars_begin(), BE = BR->referenced_vars_end() ;
- BI != BE; ++BI) {
- const VarRegion *VR = BI.getCapturedRegion();
+ for (auto Var : BR->referenced_vars()) {
+ const VarRegion *VR = Var.getCapturedRegion();
const VarDecl *VD = VR->getDecl();
if (VD->hasAttr<BlocksAttr>() || !VD->hasLocalStorage()) {
AddToWorkList(VR);
@@ -1200,9 +1194,7 @@ void InvalidateRegionsWorker::VisitCluster(const MemRegion *baseR,
if (!C)
goto conjure_default;
- for (ClusterBindings::iterator I = C->begin(), E = C->end(); I != E;
- ++I) {
- const BindingKey &BK = I.getKey();
+ for (const auto &[BK, V] : *C) {
std::optional<uint64_t> ROffset =
BK.hasSymbolicOffset() ? std::optional<uint64_t>() : BK.getOffset();
@@ -1213,10 +1205,9 @@ void InvalidateRegionsWorker::VisitCluster(const MemRegion *baseR,
(UpperOverflow &&
(*ROffset >= LowerOffset || *ROffset < UpperOffset)) ||
(LowerOffset == UpperOffset && *ROffset == LowerOffset))) {
- B = B.removeBinding(I.getKey());
+ B = B.removeBinding(BK);
// Bound symbolic regions need to be invalidated for dead symbol
// detection.
- SVal V = I.getData();
const MemRegion *R = V.getAsRegion();
if (isa_and_nonnull<SymbolicRegion>(R))
VisitBinding(V);
@@ -1289,12 +1280,8 @@ RegionStoreManager::invalidateGlobalRegion(MemRegion::Kind K,
void RegionStoreManager::populateWorkList(InvalidateRegionsWorker &W,
ArrayRef<SVal> Values,
InvalidatedRegions *TopLevelRegions) {
- for (ArrayRef<SVal>::iterator I = Values.begin(),
- E = Values.end(); I != E; ++I) {
- SVal V = *I;
- if (std::optional<nonloc::LazyCompoundVal> LCS =
- V.getAs<nonloc::LazyCompoundVal>()) {
-
+ for (SVal V : Values) {
+ if (auto LCS = V.getAs<nonloc::LazyCompoundVal>()) {
for (SVal S : getInterestingValues(*LCS))
if (const MemRegion *R = S.getAsRegion())
W.AddToWorkList(R);
@@ -1849,8 +1836,12 @@ std::optional<SVal> RegionStoreManager::getSValFromInitListExpr(
// Go to the nested initializer list.
ILE = IL;
}
- llvm_unreachable(
- "Unhandled InitListExpr sub-expressions or invalid offsets.");
+
+ assert(ILE);
+
+ // FIXME: Unhandeled InitListExpr sub-expression, possibly constructing an
+ // enum?
+ return std::nullopt;
}
/// Returns an SVal, if possible, for the specified position in a string
@@ -2277,10 +2268,7 @@ RegionStoreManager::getInterestingValues(nonloc::LazyCompoundVal LCV) {
SmallVector<BindingPair, 32> Bindings;
collectSubRegionBindings(Bindings, svalBuilder, *Cluster, LazyR,
/*IncludeAllDefaultBindings=*/true);
- for (SmallVectorImpl<BindingPair>::const_iterator I = Bindings.begin(),
- E = Bindings.end();
- I != E; ++I) {
- SVal V = I->second;
+ for (SVal V : llvm::make_second_range(Bindings)) {
if (V.isUnknownOrUndef() || V.isConstant())
continue;
@@ -2605,11 +2593,11 @@ std::optional<RegionBindingsRef> RegionStoreManager::tryBindSmallStruct(
RegionBindingsRef NewB = B;
- for (FieldVector::iterator I = Fields.begin(), E = Fields.end(); I != E; ++I){
- const FieldRegion *SourceFR = MRMgr.getFieldRegion(*I, LCV.getRegion());
+ for (const FieldDecl *Field : Fields) {
+ const FieldRegion *SourceFR = MRMgr.getFieldRegion(Field, LCV.getRegion());
SVal V = getBindingForField(getRegionBindings(LCV.getStore()), SourceFR);
- const FieldRegion *DestFR = MRMgr.getFieldRegion(*I, R);
+ const FieldRegion *DestFR = MRMgr.getFieldRegion(Field, R);
NewB = bind(NewB, loc::MemRegionVal(DestFR), V);
}
@@ -2825,11 +2813,11 @@ void RemoveDeadBindingsWorker::VisitCluster(const MemRegion *baseR,
if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(baseR))
SymReaper.markLive(SymR->getSymbol());
- for (ClusterBindings::iterator I = C->begin(), E = C->end(); I != E; ++I) {
+ for (const auto &[Key, Val] : *C) {
// Element index of a binding key is live.
- SymReaper.markElementIndicesLive(I.getKey().getRegion());
+ SymReaper.markElementIndicesLive(Key.getRegion());
- VisitBinding(I.getData());
+ VisitBinding(Val);
}
}
@@ -2856,17 +2844,15 @@ void RemoveDeadBindingsWorker::VisitBinding(SVal V) {
// All regions captured by a block are also live.
if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(R)) {
- BlockDataRegion::referenced_vars_iterator I = BR->referenced_vars_begin(),
- E = BR->referenced_vars_end();
- for ( ; I != E; ++I)
- AddToWorkList(I.getCapturedRegion());
+ for (auto Var : BR->referenced_vars())
+ AddToWorkList(Var.getCapturedRegion());
}
}
// Update the set of live symbols.
- for (auto SI = V.symbol_begin(), SE = V.symbol_end(); SI!=SE; ++SI)
- SymReaper.markLive(*SI);
+ for (SymbolRef Sym : V.symbols())
+ SymReaper.markLive(Sym);
}
bool RemoveDeadBindingsWorker::UpdatePostponed() {
@@ -2874,12 +2860,10 @@ bool RemoveDeadBindingsWorker::UpdatePostponed() {
// having done a scan.
bool Changed = false;
- for (auto I = Postponed.begin(), E = Postponed.end(); I != E; ++I) {
- if (const SymbolicRegion *SR = *I) {
- if (SymReaper.isLive(SR->getSymbol())) {
- Changed |= AddToWorkList(SR);
- *I = nullptr;
- }
+ for (const SymbolicRegion *SR : Postponed) {
+ if (SymReaper.isLive(SR->getSymbol())) {
+ Changed |= AddToWorkList(SR);
+ SR = nullptr;
}
}
@@ -2894,9 +2878,8 @@ StoreRef RegionStoreManager::removeDeadBindings(Store store,
W.GenerateClusters();
// Enqueue the region roots onto the worklist.
- for (SymbolReaper::region_iterator I = SymReaper.region_begin(),
- E = SymReaper.region_end(); I != E; ++I) {
- W.AddToWorkList(*I);
+ for (const MemRegion *Reg : SymReaper.regions()) {
+ W.AddToWorkList(Reg);
}
do W.RunWorkList(); while (W.UpdatePostponed());
@@ -2904,9 +2887,7 @@ StoreRef RegionStoreManager::removeDeadBindings(Store store,
// We have now scanned the store, marking reachable regions and symbols
// as live. We now remove all the regions that are dead from the store
// as well as update DSymbols with the set symbols that are now dead.
- for (RegionBindingsRef::iterator I = B.begin(), E = B.end(); I != E; ++I) {
- const MemRegion *Base = I.getKey();
-
+ for (const MemRegion *Base : llvm::make_first_range(B)) {
// If the cluster has been visited, we know the region has been marked.
// Otherwise, remove the dead entry.
if (!W.isVisited(Base))
diff --git a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
index fed17c77f03d..4fe828bdf768 100644
--- a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -395,7 +395,6 @@ std::optional<SVal> SValBuilder::getConstantVal(const Expr *E) {
return evalCast(*Val, CE->getType(), SE->getType());
}
}
- // FALLTHROUGH
[[fallthrough]];
}
diff --git a/clang/lib/StaticAnalyzer/Core/SVals.cpp b/clang/lib/StaticAnalyzer/Core/SVals.cpp
index bc9c1e40d808..2a43a01ff886 100644
--- a/clang/lib/StaticAnalyzer/Core/SVals.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SVals.cpp
@@ -174,6 +174,9 @@ public:
QualType VisitSymbolicRegion(const SymbolicRegion *SR) {
return Visit(SR->getSymbol());
}
+ QualType VisitAllocaRegion(const AllocaRegion *) {
+ return QualType{Context.VoidPtrTy};
+ }
QualType VisitTypedRegion(const TypedRegion *TR) {
return TR->getLocationType();
}
diff --git a/clang/lib/StaticAnalyzer/Core/Store.cpp b/clang/lib/StaticAnalyzer/Core/Store.cpp
index fe1fa22af7ab..7577b7682a95 100644
--- a/clang/lib/StaticAnalyzer/Core/Store.cpp
+++ b/clang/lib/StaticAnalyzer/Core/Store.cpp
@@ -144,6 +144,7 @@ std::optional<const MemRegion *> StoreManager::castRegion(const MemRegion *R,
case MemRegion::NonParamVarRegionKind:
case MemRegion::ParamVarRegionKind:
case MemRegion::CXXTempObjectRegionKind:
+ case MemRegion::CXXLifetimeExtendedObjectRegionKind:
case MemRegion::CXXBaseObjectRegionKind:
case MemRegion::CXXDerivedObjectRegionKind:
return MakeElementRegion(cast<SubRegion>(R), PointeeTy);
@@ -256,10 +257,8 @@ SVal StoreManager::evalDerivedToBase(SVal Derived, const CastExpr *Cast) {
// Walk through the cast path to create nested CXXBaseRegions.
SVal Result = Derived;
- for (CastExpr::path_const_iterator I = Cast->path_begin(),
- E = Cast->path_end();
- I != E; ++I) {
- Result = evalDerivedToBase(Result, (*I)->getType(), (*I)->isVirtual());
+ for (const CXXBaseSpecifier *Base : Cast->path()) {
+ Result = evalDerivedToBase(Result, Base->getType(), Base->isVirtual());
}
return Result;
}
diff --git a/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp b/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp
index 3e97f0c95fc3..9025e11a3f51 100644
--- a/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp
@@ -170,8 +170,7 @@ SymbolManager::getRegionValueSymbol(const TypedValueRegion* R) {
void *InsertPos;
SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
if (!SD) {
- SD = (SymExpr*) BPAlloc.Allocate<SymbolRegionValue>();
- new (SD) SymbolRegionValue(SymbolCounter, R);
+ SD = new (BPAlloc) SymbolRegionValue(SymbolCounter, R);
DataSet.InsertNode(SD, InsertPos);
++SymbolCounter;
}
@@ -189,8 +188,7 @@ const SymbolConjured* SymbolManager::conjureSymbol(const Stmt *E,
void *InsertPos;
SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
if (!SD) {
- SD = (SymExpr*) BPAlloc.Allocate<SymbolConjured>();
- new (SD) SymbolConjured(SymbolCounter, E, LCtx, T, Count, SymbolTag);
+ SD = new (BPAlloc) SymbolConjured(SymbolCounter, E, LCtx, T, Count, SymbolTag);
DataSet.InsertNode(SD, InsertPos);
++SymbolCounter;
}
@@ -206,8 +204,7 @@ SymbolManager::getDerivedSymbol(SymbolRef parentSymbol,
void *InsertPos;
SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
if (!SD) {
- SD = (SymExpr*) BPAlloc.Allocate<SymbolDerived>();
- new (SD) SymbolDerived(SymbolCounter, parentSymbol, R);
+ SD = new (BPAlloc) SymbolDerived(SymbolCounter, parentSymbol, R);
DataSet.InsertNode(SD, InsertPos);
++SymbolCounter;
}
@@ -222,8 +219,7 @@ SymbolManager::getExtentSymbol(const SubRegion *R) {
void *InsertPos;
SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
if (!SD) {
- SD = (SymExpr*) BPAlloc.Allocate<SymbolExtent>();
- new (SD) SymbolExtent(SymbolCounter, R);
+ SD = new (BPAlloc) SymbolExtent(SymbolCounter, R);
DataSet.InsertNode(SD, InsertPos);
++SymbolCounter;
}
@@ -240,8 +236,7 @@ SymbolManager::getMetadataSymbol(const MemRegion* R, const Stmt *S, QualType T,
void *InsertPos;
SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
if (!SD) {
- SD = (SymExpr*) BPAlloc.Allocate<SymbolMetadata>();
- new (SD) SymbolMetadata(SymbolCounter, R, S, T, LCtx, Count, SymbolTag);
+ SD = new (BPAlloc) SymbolMetadata(SymbolCounter, R, S, T, LCtx, Count, SymbolTag);
DataSet.InsertNode(SD, InsertPos);
++SymbolCounter;
}
@@ -257,8 +252,7 @@ SymbolManager::getCastSymbol(const SymExpr *Op,
void *InsertPos;
SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos);
if (!data) {
- data = (SymbolCast*) BPAlloc.Allocate<SymbolCast>();
- new (data) SymbolCast(Op, From, To);
+ data = new (BPAlloc) SymbolCast(Op, From, To);
DataSet.InsertNode(data, InsertPos);
}
@@ -275,8 +269,7 @@ const SymIntExpr *SymbolManager::getSymIntExpr(const SymExpr *lhs,
SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos);
if (!data) {
- data = (SymIntExpr*) BPAlloc.Allocate<SymIntExpr>();
- new (data) SymIntExpr(lhs, op, v, t);
+ data = new (BPAlloc) SymIntExpr(lhs, op, v, t);
DataSet.InsertNode(data, InsertPos);
}
@@ -293,8 +286,7 @@ const IntSymExpr *SymbolManager::getIntSymExpr(const llvm::APSInt& lhs,
SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos);
if (!data) {
- data = (IntSymExpr*) BPAlloc.Allocate<IntSymExpr>();
- new (data) IntSymExpr(lhs, op, rhs, t);
+ data = new (BPAlloc) IntSymExpr(lhs, op, rhs, t);
DataSet.InsertNode(data, InsertPos);
}
@@ -311,8 +303,7 @@ const SymSymExpr *SymbolManager::getSymSymExpr(const SymExpr *lhs,
SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos);
if (!data) {
- data = (SymSymExpr*) BPAlloc.Allocate<SymSymExpr>();
- new (data) SymSymExpr(lhs, op, rhs, t);
+ data = new (BPAlloc) SymSymExpr(lhs, op, rhs, t);
DataSet.InsertNode(data, InsertPos);
}
@@ -327,8 +318,7 @@ const UnarySymExpr *SymbolManager::getUnarySymExpr(const SymExpr *Operand,
void *InsertPos;
SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos);
if (!data) {
- data = (UnarySymExpr *)BPAlloc.Allocate<UnarySymExpr>();
- new (data) UnarySymExpr(Operand, Opc, T);
+ data = new (BPAlloc) UnarySymExpr(Operand, Opc, T);
DataSet.InsertNode(data, InsertPos);
}
@@ -398,7 +388,7 @@ void SymbolReaper::markDependentsLive(SymbolRef sym) {
if (const SymbolRefSmallVectorTy *Deps = SymMgr.getDependentSymbols(sym)) {
for (const auto I : *Deps) {
- if (TheLiving.find(I) != TheLiving.end())
+ if (TheLiving.contains(I))
continue;
markLive(I);
}
@@ -424,8 +414,8 @@ void SymbolReaper::markElementIndicesLive(const MemRegion *region) {
SR = dyn_cast<SubRegion>(SR->getSuperRegion())) {
if (const auto ER = dyn_cast<ElementRegion>(SR)) {
SVal Idx = ER->getIndex();
- for (auto SI = Idx.symbol_begin(), SE = Idx.symbol_end(); SI != SE; ++SI)
- markLive(*SI);
+ for (SymbolRef Sym : Idx.symbols())
+ markLive(Sym);
}
}
}
diff --git a/clang/lib/StaticAnalyzer/Core/TextDiagnostics.cpp b/clang/lib/StaticAnalyzer/Core/TextDiagnostics.cpp
index 05f4d19ebda0..71268af22e24 100644
--- a/clang/lib/StaticAnalyzer/Core/TextDiagnostics.cpp
+++ b/clang/lib/StaticAnalyzer/Core/TextDiagnostics.cpp
@@ -86,10 +86,7 @@ public:
}
};
- for (std::vector<const PathDiagnostic *>::iterator I = Diags.begin(),
- E = Diags.end();
- I != E; ++I) {
- const PathDiagnostic *PD = *I;
+ for (const PathDiagnostic *PD : Diags) {
std::string WarningMsg = (DiagOpts.ShouldDisplayDiagnosticName
? " [" + PD->getCheckerName() + "]"
: "")