aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp')
-rw-r--r--clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp334
1 files changed, 255 insertions, 79 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index 3a90c37a36da..2b461acf9a73 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -46,8 +46,6 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/None.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
@@ -60,6 +58,7 @@
#include <cassert>
#include <deque>
#include <memory>
+#include <optional>
#include <string>
#include <utility>
@@ -206,8 +205,8 @@ static bool hasVisibleUpdate(const ExplodedNode *LeftNode, SVal LeftVal,
RLCV->getStore() == RightNode->getState()->getStore();
}
-static Optional<SVal> getSValForVar(const Expr *CondVarExpr,
- const ExplodedNode *N) {
+static std::optional<SVal> getSValForVar(const Expr *CondVarExpr,
+ const ExplodedNode *N) {
ProgramStateRef State = N->getState();
const LocationContext *LCtx = N->getLocationContext();
@@ -227,16 +226,16 @@ static Optional<SVal> getSValForVar(const Expr *CondVarExpr,
if (auto FieldL = State->getSVal(ME, LCtx).getAs<Loc>())
return State->getRawSVal(*FieldL, FD->getType());
- return None;
+ return std::nullopt;
}
-static Optional<const llvm::APSInt *>
+static std::optional<const llvm::APSInt *>
getConcreteIntegerValue(const Expr *CondVarExpr, const ExplodedNode *N) {
- if (Optional<SVal> V = getSValForVar(CondVarExpr, N))
+ if (std::optional<SVal> V = getSValForVar(CondVarExpr, N))
if (auto CI = V->getAs<nonloc::ConcreteInt>())
return &CI->getValue();
- return None;
+ return std::nullopt;
}
static bool isVarAnInterestingCondition(const Expr *CondVarExpr,
@@ -248,8 +247,9 @@ static bool isVarAnInterestingCondition(const Expr *CondVarExpr,
if (!B->getErrorNode()->getStackFrame()->isParentOf(N->getStackFrame()))
return false;
- if (Optional<SVal> V = getSValForVar(CondVarExpr, N))
- if (Optional<bugreporter::TrackingKind> K = B->getInterestingnessKind(*V))
+ if (std::optional<SVal> V = getSValForVar(CondVarExpr, N))
+ if (std::optional<bugreporter::TrackingKind> K =
+ B->getInterestingnessKind(*V))
return *K == bugreporter::TrackingKind::Condition;
return false;
@@ -257,7 +257,7 @@ static bool isVarAnInterestingCondition(const Expr *CondVarExpr,
static bool isInterestingExpr(const Expr *E, const ExplodedNode *N,
const PathSensitiveBugReport *B) {
- if (Optional<SVal> V = getSValForVar(E, N))
+ if (std::optional<SVal> V = getSValForVar(E, N))
return B->getInterestingnessKind(*V).has_value();
return false;
}
@@ -538,8 +538,8 @@ private:
/// Dereferences fields up to a given recursion limit.
/// Note that \p Vec is passed by value, leading to quadratic copying cost,
/// but it's OK in practice since its length is limited to DEREFERENCE_LIMIT.
- /// \return A chain fields leading to the region of interest or None.
- const Optional<RegionVector>
+ /// \return A chain fields leading to the region of interest or std::nullopt.
+ const std::optional<RegionVector>
findRegionOfInterestInRecord(const RecordDecl *RD, ProgramStateRef State,
const MemRegion *R, const RegionVector &Vec = {},
int depth = 0);
@@ -619,26 +619,26 @@ static bool potentiallyWritesIntoIvar(const Decl *Parent,
/// Dereferences fields up to a given recursion limit.
/// Note that \p Vec is passed by value, leading to quadratic copying cost,
/// but it's OK in practice since its length is limited to DEREFERENCE_LIMIT.
-/// \return A chain fields leading to the region of interest or None.
-const Optional<NoStoreFuncVisitor::RegionVector>
+/// \return A chain fields leading to the region of interest or std::nullopt.
+const std::optional<NoStoreFuncVisitor::RegionVector>
NoStoreFuncVisitor::findRegionOfInterestInRecord(
const RecordDecl *RD, ProgramStateRef State, const MemRegion *R,
const NoStoreFuncVisitor::RegionVector &Vec /* = {} */,
int depth /* = 0 */) {
if (depth == DEREFERENCE_LIMIT) // Limit the recursion depth.
- return None;
+ return std::nullopt;
if (const auto *RDX = dyn_cast<CXXRecordDecl>(RD))
if (!RDX->hasDefinition())
- return None;
+ return std::nullopt;
// Recursively examine the base classes.
// Note that following base classes does not increase the recursion depth.
if (const auto *RDX = dyn_cast<CXXRecordDecl>(RD))
for (const auto &II : RDX->bases())
if (const RecordDecl *RRD = II.getType()->getAsRecordDecl())
- if (Optional<RegionVector> Out =
+ if (std::optional<RegionVector> Out =
findRegionOfInterestInRecord(RRD, State, R, Vec, depth))
return Out;
@@ -664,12 +664,12 @@ NoStoreFuncVisitor::findRegionOfInterestInRecord(
continue;
if (const RecordDecl *RRD = PT->getAsRecordDecl())
- if (Optional<RegionVector> Out =
+ if (std::optional<RegionVector> Out =
findRegionOfInterestInRecord(RRD, State, VR, VecF, depth + 1))
return Out;
}
- return None;
+ return std::nullopt;
}
PathDiagnosticPieceRef
@@ -730,7 +730,7 @@ PathDiagnosticPieceRef NoStoreFuncVisitor::maybeEmitNoteForParameters(
ProgramStateRef State = N->getState();
if (const RecordDecl *RD = PT->getAsRecordDecl())
- if (Optional<RegionVector> P =
+ if (std::optional<RegionVector> P =
findRegionOfInterestInRecord(RD, State, MR))
return maybeEmitNote(R, Call, N, *P, RegionOfInterest, ParamName,
ParamIsReferenceType, IndirectionLevel);
@@ -928,12 +928,12 @@ public:
private:
/// \return Source location of right hand side of an assignment
/// into \c RegionOfInterest, empty optional if none found.
- Optional<SourceLocation> matchAssignment(const ExplodedNode *N) {
+ std::optional<SourceLocation> matchAssignment(const ExplodedNode *N) {
const Stmt *S = N->getStmtForDiagnostics();
ProgramStateRef State = N->getState();
auto *LCtx = N->getLocationContext();
if (!S)
- return None;
+ return std::nullopt;
if (const auto *DS = dyn_cast<DeclStmt>(S)) {
if (const auto *VD = dyn_cast<VarDecl>(DS->getSingleDecl()))
@@ -948,7 +948,7 @@ private:
return RHS->getBeginLoc();
}
}
- return None;
+ return std::nullopt;
}
};
@@ -1001,7 +1001,7 @@ public:
if (N->getLocationContext() != CalleeSFC)
return nullptr;
- Optional<StmtPoint> SP = N->getLocationAs<StmtPoint>();
+ std::optional<StmtPoint> SP = N->getLocationAs<StmtPoint>();
if (!SP)
return nullptr;
@@ -1023,7 +1023,7 @@ public:
assert(RetE && "Tracking a return value for a void function");
// Handle cases where a reference is returned and then immediately used.
- Optional<Loc> LValue;
+ std::optional<Loc> LValue;
if (RetE->isGLValue()) {
if ((LValue = V.getAs<Loc>())) {
SVal RValue = State->getRawSVal(*LValue, RetE->getType());
@@ -1122,7 +1122,7 @@ public:
assert(Options.ShouldAvoidSuppressingNullArgumentPaths);
// Are we at the entry node for this call?
- Optional<CallEnter> CE = N->getLocationAs<CallEnter>();
+ std::optional<CallEnter> CE = N->getLocationAs<CallEnter>();
if (!CE)
return nullptr;
@@ -1140,7 +1140,7 @@ public:
ProgramStateRef State = N->getState();
CallEventRef<> Call = CallMgr.getCaller(CalleeSFC, State);
for (unsigned I = 0, E = Call->getNumArgs(); I != E; ++I) {
- Optional<Loc> ArgV = Call->getArgSVal(I).getAs<Loc>();
+ std::optional<Loc> ArgV = Call->getArgSVal(I).getAs<Loc>();
if (!ArgV)
continue;
@@ -1187,8 +1187,6 @@ public:
}
};
-} // end of anonymous namespace
-
//===----------------------------------------------------------------------===//
// StoreSiteFinder
//===----------------------------------------------------------------------===//
@@ -1228,6 +1226,7 @@ public:
BugReporterContext &BRC,
PathSensitiveBugReport &BR) override;
};
+} // namespace
void StoreSiteFinder::Profile(llvm::FoldingSetNodeID &ID) const {
static int tag = 0;
@@ -1241,7 +1240,7 @@ void StoreSiteFinder::Profile(llvm::FoldingSetNodeID &ID) const {
/// Returns true if \p N represents the DeclStmt declaring and initializing
/// \p VR.
static bool isInitializationOfVar(const ExplodedNode *N, const VarRegion *VR) {
- Optional<PostStmt> P = N->getLocationAs<PostStmt>();
+ std::optional<PostStmt> P = N->getLocationAs<PostStmt>();
if (!P)
return false;
@@ -1340,13 +1339,12 @@ static void showBRDiagnostics(llvm::raw_svector_ostream &OS, StoreInfo SI) {
static void showBRParamDiagnostics(llvm::raw_svector_ostream &OS,
StoreInfo SI) {
const auto *VR = cast<VarRegion>(SI.Dest);
- const auto *Param = cast<ParmVarDecl>(VR->getDecl());
+ const auto *D = VR->getDecl();
OS << "Passing ";
if (isa<loc::ConcreteInt>(SI.Value)) {
- OS << (isObjCPointer(Param) ? "nil object reference"
- : "null pointer value");
+ OS << (isObjCPointer(D) ? "nil object reference" : "null pointer value");
} else if (SI.Value.isUndef()) {
OS << "uninitialized value";
@@ -1361,12 +1359,19 @@ static void showBRParamDiagnostics(llvm::raw_svector_ostream &OS,
OS << "value";
}
- // Printed parameter indexes are 1-based, not 0-based.
- unsigned Idx = Param->getFunctionScopeIndex() + 1;
- OS << " via " << Idx << llvm::getOrdinalSuffix(Idx) << " parameter";
- if (VR->canPrintPretty()) {
- OS << " ";
- VR->printPretty(OS);
+ if (const auto *Param = dyn_cast<ParmVarDecl>(VR->getDecl())) {
+ // Printed parameter indexes are 1-based, not 0-based.
+ unsigned Idx = Param->getFunctionScopeIndex() + 1;
+ OS << " via " << Idx << llvm::getOrdinalSuffix(Idx) << " parameter";
+ if (VR->canPrintPretty()) {
+ OS << " ";
+ VR->printPretty(OS);
+ }
+ } else if (const auto *ImplParam = dyn_cast<ImplicitParamDecl>(D)) {
+ if (ImplParam->getParameterKind() ==
+ ImplicitParamDecl::ImplicitParamKind::ObjCSelf) {
+ OS << " via implicit parameter 'self'";
+ }
}
}
@@ -1410,6 +1415,83 @@ static void showBRDefaultDiagnostics(llvm::raw_svector_ostream &OS,
}
}
+static bool isTrivialCopyOrMoveCtor(const CXXConstructExpr *CE) {
+ if (!CE)
+ return false;
+
+ const auto *CtorDecl = CE->getConstructor();
+
+ return CtorDecl->isCopyOrMoveConstructor() && CtorDecl->isTrivial();
+}
+
+static const Expr *tryExtractInitializerFromList(const InitListExpr *ILE,
+ const MemRegion *R) {
+
+ const auto *TVR = dyn_cast_or_null<TypedValueRegion>(R);
+
+ if (!TVR)
+ return nullptr;
+
+ const auto ITy = ILE->getType().getCanonicalType();
+
+ // Push each sub-region onto the stack.
+ std::stack<const TypedValueRegion *> TVRStack;
+ while (isa<FieldRegion>(TVR) || isa<ElementRegion>(TVR)) {
+ // We found a region that matches the type of the init list,
+ // so we assume this is the outer-most region. This can happen
+ // if the initializer list is inside a class. If our assumption
+ // is wrong, we return a nullptr in the end.
+ if (ITy == TVR->getValueType().getCanonicalType())
+ break;
+
+ TVRStack.push(TVR);
+ TVR = cast<TypedValueRegion>(TVR->getSuperRegion());
+ }
+
+ // If the type of the outer most region doesn't match the type
+ // of the ILE, we can't match the ILE and the region.
+ if (ITy != TVR->getValueType().getCanonicalType())
+ return nullptr;
+
+ const Expr *Init = ILE;
+ while (!TVRStack.empty()) {
+ TVR = TVRStack.top();
+ TVRStack.pop();
+
+ // We hit something that's not an init list before
+ // running out of regions, so we most likely failed.
+ if (!isa<InitListExpr>(Init))
+ return nullptr;
+
+ ILE = cast<InitListExpr>(Init);
+ auto NumInits = ILE->getNumInits();
+
+ if (const auto *FR = dyn_cast<FieldRegion>(TVR)) {
+ const auto *FD = FR->getDecl();
+
+ if (FD->getFieldIndex() >= NumInits)
+ return nullptr;
+
+ Init = ILE->getInit(FD->getFieldIndex());
+ } else if (const auto *ER = dyn_cast<ElementRegion>(TVR)) {
+ const auto Ind = ER->getIndex();
+
+ // If index is symbolic, we can't figure out which expression
+ // belongs to the region.
+ if (!Ind.isConstant())
+ return nullptr;
+
+ const auto IndVal = Ind.getAsInteger()->getLimitedValue();
+ if (IndVal >= NumInits)
+ return nullptr;
+
+ Init = ILE->getInit(IndVal);
+ }
+ }
+
+ return Init;
+}
+
PathDiagnosticPieceRef StoreSiteFinder::VisitNode(const ExplodedNode *Succ,
BugReporterContext &BRC,
PathSensitiveBugReport &BR) {
@@ -1431,7 +1513,8 @@ PathDiagnosticPieceRef StoreSiteFinder::VisitNode(const ExplodedNode *Succ,
// If this is a post initializer expression, initializing the region, we
// should track the initializer expression.
- if (Optional<PostInitializer> PIP = Pred->getLocationAs<PostInitializer>()) {
+ if (std::optional<PostInitializer> PIP =
+ Pred->getLocationAs<PostInitializer>()) {
const MemRegion *FieldReg = (const MemRegion *)PIP->getLocationValue();
if (FieldReg == R) {
StoreSite = Pred;
@@ -1449,25 +1532,101 @@ PathDiagnosticPieceRef StoreSiteFinder::VisitNode(const ExplodedNode *Succ,
return nullptr;
if (hasVisibleUpdate(Pred, Pred->getState()->getSVal(R), Succ, V)) {
- Optional<PostStore> PS = Succ->getLocationAs<PostStore>();
+ std::optional<PostStore> PS = Succ->getLocationAs<PostStore>();
if (!PS || PS->getLocationValue() != R)
return nullptr;
}
StoreSite = Succ;
- // If this is an assignment expression, we can track the value
- // being assigned.
- if (Optional<PostStmt> P = Succ->getLocationAs<PostStmt>())
- if (const BinaryOperator *BO = P->getStmtAs<BinaryOperator>())
+ if (std::optional<PostStmt> P = Succ->getLocationAs<PostStmt>()) {
+ // If this is an assignment expression, we can track the value
+ // being assigned.
+ if (const BinaryOperator *BO = P->getStmtAs<BinaryOperator>()) {
if (BO->isAssignmentOp())
InitE = BO->getRHS();
+ }
+ // If we have a declaration like 'S s{1,2}' that needs special
+ // handling, we handle it here.
+ else if (const auto *DS = P->getStmtAs<DeclStmt>()) {
+ const auto *Decl = DS->getSingleDecl();
+ if (isa<VarDecl>(Decl)) {
+ const auto *VD = cast<VarDecl>(Decl);
+
+ // FIXME: Here we only track the inner most region, so we lose
+ // information, but it's still better than a crash or no information
+ // at all.
+ //
+ // E.g.: The region we have is 's.s2.s3.s4.y' and we only track 'y',
+ // and throw away the rest.
+ if (const auto *ILE = dyn_cast<InitListExpr>(VD->getInit()))
+ InitE = tryExtractInitializerFromList(ILE, R);
+ }
+ } else if (const auto *CE = P->getStmtAs<CXXConstructExpr>()) {
+
+ const auto State = Succ->getState();
+
+ if (isTrivialCopyOrMoveCtor(CE) && isa<SubRegion>(R)) {
+ // Migrate the field regions from the current object to
+ // the parent object. If we track 'a.y.e' and encounter
+ // 'S a = b' then we need to track 'b.y.e'.
+
+ // Push the regions to a stack, from last to first, so
+ // considering the example above the stack will look like
+ // (bottom) 'e' -> 'y' (top).
+
+ std::stack<const SubRegion *> SRStack;
+ const SubRegion *SR = cast<SubRegion>(R);
+ while (isa<FieldRegion>(SR) || isa<ElementRegion>(SR)) {
+ SRStack.push(SR);
+ SR = cast<SubRegion>(SR->getSuperRegion());
+ }
+
+ // Get the region for the object we copied/moved from.
+ const auto *OriginEx = CE->getArg(0);
+ const auto OriginVal =
+ State->getSVal(OriginEx, Succ->getLocationContext());
+
+ // Pop the stored field regions and apply them to the origin
+ // object in the same order we had them on the copy.
+ // OriginField will evolve like 'b' -> 'b.y' -> 'b.y.e'.
+ SVal OriginField = OriginVal;
+ while (!SRStack.empty()) {
+ const auto *TopR = SRStack.top();
+ SRStack.pop();
+
+ if (const auto *FR = dyn_cast<FieldRegion>(TopR)) {
+ OriginField = State->getLValue(FR->getDecl(), OriginField);
+ } else if (const auto *ER = dyn_cast<ElementRegion>(TopR)) {
+ OriginField = State->getLValue(ER->getElementType(),
+ ER->getIndex(), OriginField);
+ } else {
+ // FIXME: handle other region type
+ }
+ }
+
+ // Track 'b.y.e'.
+ getParentTracker().track(V, OriginField.getAsRegion(), Options);
+ InitE = OriginEx;
+ }
+ }
+ // This branch can occur in cases like `Ctor() : field{ x, y } {}'.
+ else if (const auto *ILE = P->getStmtAs<InitListExpr>()) {
+ // FIXME: Here we only track the top level region, so we lose
+ // information, but it's still better than a crash or no information
+ // at all.
+ //
+ // E.g.: The region we have is 's.s2.s3.s4.y' and we only track 'y', and
+ // throw away the rest.
+ InitE = tryExtractInitializerFromList(ILE, R);
+ }
+ }
// If this is a call entry, the variable should be a parameter.
// FIXME: Handle CXXThisRegion as well. (This is not a priority because
// 'this' should never be NULL, but this visitor isn't just for NULL and
// UndefinedVal.)
- if (Optional<CallEnter> CE = Succ->getLocationAs<CallEnter>()) {
+ if (std::optional<CallEnter> CE = Succ->getLocationAs<CallEnter>()) {
if (const auto *VR = dyn_cast<VarRegion>(R)) {
if (const auto *Param = dyn_cast<ParmVarDecl>(VR->getDecl())) {
@@ -1590,7 +1749,7 @@ PathDiagnosticPieceRef StoreSiteFinder::VisitNode(const ExplodedNode *Succ,
R,
OldRegion};
- if (Optional<PostStmt> PS = StoreSite->getLocationAs<PostStmt>()) {
+ if (std::optional<PostStmt> PS = StoreSite->getLocationAs<PostStmt>()) {
const Stmt *S = PS->getStmt();
const auto *DS = dyn_cast<DeclStmt>(S);
const auto *VR = dyn_cast<VarRegion>(R);
@@ -1983,7 +2142,7 @@ static const Expr *peelOffOuterExpr(const Expr *Ex, const ExplodedNode *N) {
const ExplodedNode *NI = N;
do {
ProgramPoint ProgPoint = NI->getLocation();
- if (Optional<BlockEdge> BE = ProgPoint.getAs<BlockEdge>()) {
+ if (std::optional<BlockEdge> BE = ProgPoint.getAs<BlockEdge>()) {
const CFGBlock *srcBlk = BE->getSrc();
if (const Stmt *term = srcBlk->getTerminatorStmt()) {
if (term == CO) {
@@ -2058,6 +2217,7 @@ PathDiagnosticPieceRef StoreHandler::constructNote(StoreInfo SI,
return std::make_shared<PathDiagnosticEventPiece>(L, NodeText);
}
+namespace {
class DefaultStoreHandler final : public StoreHandler {
public:
using StoreHandler::StoreHandler;
@@ -2255,7 +2415,8 @@ class InlinedFunctionCallHandler final : public ExpressionHandler {
do {
// If that is satisfied we found our statement as an inlined call.
- if (Optional<CallExitEnd> CEE = ExprNode->getLocationAs<CallExitEnd>())
+ if (std::optional<CallExitEnd> CEE =
+ ExprNode->getLocationAs<CallExitEnd>())
if (CEE->getCalleeContext()->getCallSite() == E)
break;
@@ -2270,7 +2431,7 @@ class InlinedFunctionCallHandler final : public ExpressionHandler {
// FIXME: This code currently bypasses the call site for the
// conservatively evaluated allocator.
if (!BypassCXXNewExprEval)
- if (Optional<StmtPoint> SP = ExprNode->getLocationAs<StmtPoint>())
+ if (std::optional<StmtPoint> SP = ExprNode->getLocationAs<StmtPoint>())
// See if we do not enter into another context.
if (SP->getStmt() == E && CurrentSFC == PredSFC)
break;
@@ -2285,7 +2446,7 @@ class InlinedFunctionCallHandler final : public ExpressionHandler {
return {};
// Finally, see if we inlined the call.
- Optional<CallExitEnd> CEE = ExprNode->getLocationAs<CallExitEnd>();
+ std::optional<CallExitEnd> CEE = ExprNode->getLocationAs<CallExitEnd>();
if (!CEE)
return {};
@@ -2299,7 +2460,7 @@ class InlinedFunctionCallHandler final : public ExpressionHandler {
// Handle cases where a reference is returned and then immediately used.
if (cast<Expr>(E)->isGLValue())
- if (Optional<Loc> LValue = RetVal.getAs<Loc>())
+ if (std::optional<Loc> LValue = RetVal.getAs<Loc>())
RetVal = State->getSVal(*LValue);
// See if the return value is NULL. If so, suppress the report.
@@ -2307,7 +2468,7 @@ class InlinedFunctionCallHandler final : public ExpressionHandler {
bool EnableNullFPSuppression = false;
if (Opts.EnableNullFPSuppression && Options.ShouldSuppressNullReturnPaths)
- if (Optional<Loc> RetLoc = RetVal.getAs<Loc>())
+ if (std::optional<Loc> RetLoc = RetVal.getAs<Loc>())
EnableNullFPSuppression = State->isNull(*RetLoc).isConstrainedTrue();
PathSensitiveBugReport &Report = getParentTracker().getReport();
@@ -2342,7 +2503,7 @@ public:
// what is written inside the pointer.
bool CanDereference = true;
if (const auto *SR = L->getRegionAs<SymbolicRegion>()) {
- if (SR->getSymbol()->getType()->getPointeeType()->isVoidType())
+ if (SR->getPointeeStaticType()->isVoidType())
CanDereference = false;
} else if (L->getRegionAs<AllocaRegion>())
CanDereference = false;
@@ -2395,6 +2556,29 @@ public:
if (!RVNode)
return {};
+ Tracker::Result CombinedResult;
+ Tracker &Parent = getParentTracker();
+
+ const auto track = [&CombinedResult, &Parent, ExprNode,
+ Opts](const Expr *Inner) {
+ CombinedResult.combineWith(Parent.track(Inner, ExprNode, Opts));
+ };
+
+ // FIXME: Initializer lists can appear in many different contexts
+ // and most of them needs a special handling. For now let's handle
+ // what we can. If the initializer list only has 1 element, we track
+ // that.
+ // This snippet even handles nesting, e.g.: int *x{{{{{y}}}}};
+ if (const auto *ILE = dyn_cast<InitListExpr>(E)) {
+ if (ILE->getNumInits() == 1) {
+ track(ILE->getInit(0));
+
+ return CombinedResult;
+ }
+
+ return {};
+ }
+
ProgramStateRef RVState = RVNode->getState();
SVal V = RVState->getSValAsScalarOrLoc(E, RVNode->getLocationContext());
const auto *BO = dyn_cast<BinaryOperator>(E);
@@ -2406,13 +2590,6 @@ public:
SVal LHSV = RVState->getSVal(BO->getLHS(), RVNode->getLocationContext());
// Track both LHS and RHS of a multiplication.
- Tracker::Result CombinedResult;
- Tracker &Parent = getParentTracker();
-
- const auto track = [&CombinedResult, &Parent, ExprNode, Opts](Expr *Inner) {
- CombinedResult.combineWith(Parent.track(Inner, ExprNode, Opts));
- };
-
if (BO->getOpcode() == BO_Mul) {
if (LHSV.isZeroConstant())
track(BO->getLHS());
@@ -2426,6 +2603,7 @@ public:
return CombinedResult;
}
};
+} // namespace
Tracker::Tracker(PathSensitiveBugReport &Report) : Report(Report) {
// Default expression handlers.
@@ -2524,7 +2702,7 @@ const Expr *NilReceiverBRVisitor::getNilReceiver(const Stmt *S,
PathDiagnosticPieceRef
NilReceiverBRVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
PathSensitiveBugReport &BR) {
- Optional<PreStmt> P = N->getLocationAs<PreStmt>();
+ std::optional<PreStmt> P = N->getLocationAs<PreStmt>();
if (!P)
return nullptr;
@@ -2588,7 +2766,7 @@ ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N,
// If an assumption was made on a branch, it should be caught
// here by looking at the state transition.
- if (Optional<BlockEdge> BE = ProgPoint.getAs<BlockEdge>()) {
+ if (std::optional<BlockEdge> BE = ProgPoint.getAs<BlockEdge>()) {
const CFGBlock *SrcBlock = BE->getSrc();
if (const Stmt *Term = SrcBlock->getTerminatorStmt()) {
// If the tag of the previous node is 'Eagerly Assume...' the current
@@ -2605,7 +2783,7 @@ ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N,
return nullptr;
}
- if (Optional<PostStmt> PS = ProgPoint.getAs<PostStmt>()) {
+ if (std::optional<PostStmt> PS = ProgPoint.getAs<PostStmt>()) {
const ProgramPointTag *CurrentNodeTag = PS->getTag();
if (CurrentNodeTag != Tags.first && CurrentNodeTag != Tags.second)
return nullptr;
@@ -2744,13 +2922,11 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond, BugReporterContext &BRC,
Loc, TookTrue ? GenericTrueMessage : GenericFalseMessage);
}
-bool ConditionBRVisitor::patternMatch(const Expr *Ex,
- const Expr *ParentEx,
- raw_ostream &Out,
- BugReporterContext &BRC,
+bool ConditionBRVisitor::patternMatch(const Expr *Ex, const Expr *ParentEx,
+ raw_ostream &Out, BugReporterContext &BRC,
PathSensitiveBugReport &report,
const ExplodedNode *N,
- Optional<bool> &prunable,
+ std::optional<bool> &prunable,
bool IsSameFieldName) {
const Expr *OriginalExpr = Ex;
Ex = Ex->IgnoreParenCasts();
@@ -2836,7 +3012,7 @@ PathDiagnosticPieceRef ConditionBRVisitor::VisitTrueTest(
PathSensitiveBugReport &R, const ExplodedNode *N, bool TookTrue,
bool IsAssuming) {
bool shouldInvert = false;
- Optional<bool> shouldPrune;
+ std::optional<bool> shouldPrune;
// Check if the field name of the MemberExprs is ambiguous. Example:
// " 'a.d' is equal to 'h.d' " in 'test/Analysis/null-deref-path-notes.cpp'.
@@ -2947,7 +3123,7 @@ PathDiagnosticPieceRef ConditionBRVisitor::VisitTrueTest(
PathDiagnosticLocation Loc(Cond, SM, LCtx);
auto event = std::make_shared<PathDiagnosticEventPiece>(Loc, Message);
if (shouldPrune)
- event->setPrunable(shouldPrune.value());
+ event->setPrunable(*shouldPrune);
return event;
}
@@ -3070,7 +3246,7 @@ bool ConditionBRVisitor::printValue(const Expr *CondVarExpr, raw_ostream &Out,
if (!Ty->isIntegralOrEnumerationType())
return false;
- Optional<const llvm::APSInt *> IntValue;
+ std::optional<const llvm::APSInt *> IntValue;
if (!IsAssuming)
IntValue = getConcreteIntegerValue(CondVarExpr, N);
@@ -3081,9 +3257,9 @@ bool ConditionBRVisitor::printValue(const Expr *CondVarExpr, raw_ostream &Out,
Out << (TookTrue ? "not equal to 0" : "0");
} else {
if (Ty->isBooleanType())
- Out << (IntValue.value()->getBoolValue() ? "true" : "false");
+ Out << ((*IntValue)->getBoolValue() ? "true" : "false");
else
- Out << *IntValue.value();
+ Out << **IntValue;
}
return true;
@@ -3196,7 +3372,7 @@ UndefOrNullArgVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
ProgramPoint ProgLoc = N->getLocation();
// We are only interested in visiting CallEnter nodes.
- Optional<CallEnter> CEnter = ProgLoc.getAs<CallEnter>();
+ std::optional<CallEnter> CEnter = ProgLoc.getAs<CallEnter>();
if (!CEnter)
return nullptr;
@@ -3275,11 +3451,11 @@ void FalsePositiveRefutationBRVisitor::finalizeVisitor(
}
// And check for satisfiability
- Optional<bool> IsSAT = RefutationSolver->check();
+ std::optional<bool> IsSAT = RefutationSolver->check();
if (!IsSAT)
return;
- if (!IsSAT.value())
+ if (!*IsSAT)
BR.markInvalid("Infeasible constraints", EndPathNode->getLocationContext());
}
@@ -3334,7 +3510,7 @@ PathDiagnosticPieceRef TagVisitor::VisitNode(const ExplodedNode *N,
if (!T)
return nullptr;
- if (Optional<std::string> Msg = T->generateMessage(BRC, R)) {
+ if (std::optional<std::string> Msg = T->generateMessage(BRC, R)) {
PathDiagnosticLocation Loc =
PathDiagnosticLocation::create(PP, BRC.getSourceManager());
auto Piece = std::make_shared<PathDiagnosticEventPiece>(Loc, *Msg);