29 #include "llvm/ADT/DenseMap.h"
30 #include "llvm/ADT/IntrusiveRefCntPtr.h"
31 #include "llvm/ADT/STLExtras.h"
32 #include "llvm/ADT/SmallString.h"
33 #include "llvm/ADT/Statistic.h"
34 #include "llvm/Support/raw_ostream.h"
38 using namespace clang;
41 #define DEBUG_TYPE "BugReporter"
44 "The maximum number of bug reports in the same equivalence class");
46 "The maximum number of bug reports in the same equivalence class "
47 "where at least one report is valid (not suppressed)");
51 void BugReporterContext::anchor() {}
65 static inline const Stmt*
88 if (X->
getTag() == tagPreferred && Y->
getTag() == tagLesser)
91 if (Y->
getTag() == tagPreferred && X->
getTag() == tagLesser)
103 unsigned N = path.size();
110 for (
unsigned i = 0; i < N; ++i) {
114 switch (piece->getKind()) {
128 dyn_cast<PathDiagnosticEventPiece>(path.front().get())) {
130 cast<PathDiagnosticEventPiece>(piece);
144 path.push_back(piece);
150 typedef llvm::DenseMap<const PathPieces *, const LocationContext *>
158 bool containsSomethingInteresting =
false;
159 const unsigned N = pieces.size();
161 for (
unsigned i = 0 ; i < N ; ++i) {
167 switch (piece->getKind()) {
171 assert(LCM.count(&call->
path));
173 containsSomethingInteresting =
true;
180 containsSomethingInteresting =
true;
187 containsSomethingInteresting =
true;
195 containsSomethingInteresting |= !
event->
isPrunable();
202 pieces.push_back(piece);
205 return containsSomethingInteresting;
212 return D->isImplicit() || !D->hasBody();
224 assert((*I)->getLocation().asLocation().isValid());
228 if (LastCallLocation) {
245 assert(ThisCallLocation &&
"Outermost call has an invalid location");
262 dyn_cast<PathDiagnosticControlFlowPiece>(*
I)) {
263 const Stmt *Start = CF->getStartLocation().asStmt();
264 const Stmt *
End = CF->getEndLocation().asStmt();
265 if (Start && isa<CXXDefaultInitExpr>(Start)) {
268 }
else if (End && isa<CXXDefaultInitExpr>(End)) {
272 dyn_cast<PathDiagnosticControlFlowPiece>(*Next)) {
273 NextCF->setStartLocation(CF->getStartLocation());
296 if (!(*I)->getLocation().isValid() ||
297 !(*I)->getLocation().asLocation().isValid()) {
331 R(r), PDC(pdc), NMC(Backmap), LC(r->getErrorNode()->getLocationContext())
341 Decl const &getCodeDecl() {
return R->getErrorNode()->getCodeDecl(); }
343 ParentMap& getParentMap() {
return LC->getParentMap(); }
346 return getParentMap().getParent(S);
349 NodeMapClosure& getNodeResolver()
override {
return NMC; }
357 bool supportsLogicalOpControlFlow()
const {
358 return PDC ? PDC->supportsLogicalOpControlFlow() :
true;
364 PathDiagnosticBuilder::ExecutionContinues(
const ExplodedNode *N) {
373 PathDiagnosticBuilder::ExecutionContinues(llvm::raw_string_ostream &os,
377 if (os.str().empty())
383 os <<
"Execution continues on line "
384 << getSourceManager().getExpansionLineNumber(Loc.
asLocation())
387 os <<
"Execution jumps to the end of the ";
389 if (isa<ObjCMethodDecl>(D))
391 else if (isa<FunctionDecl>(D))
394 assert(isa<BlockDecl>(D));
395 os <<
"anonymous block";
411 switch (Parent->getStmtClass()) {
412 case Stmt::ForStmtClass:
413 case Stmt::DoStmtClass:
414 case Stmt::WhileStmtClass:
415 case Stmt::ObjCForCollectionStmtClass:
416 case Stmt::CXXForRangeStmtClass:
432 switch (Parent->getStmtClass()) {
433 case Stmt::BinaryOperatorClass: {
439 case Stmt::CompoundStmtClass:
440 case Stmt::StmtExprClass:
442 case Stmt::ChooseExprClass:
445 if (allowNestedContexts || cast<ChooseExpr>(Parent)->getCond() == S)
449 case Stmt::BinaryConditionalOperatorClass:
450 case Stmt::ConditionalOperatorClass:
453 if (allowNestedContexts ||
454 cast<AbstractConditionalOperator>(Parent)->getCond() == S)
458 case Stmt::CXXForRangeStmtClass:
459 if (cast<CXXForRangeStmt>(Parent)->getBody() == S)
462 case Stmt::DoStmtClass:
464 case Stmt::ForStmtClass:
465 if (cast<ForStmt>(Parent)->getBody() == S)
468 case Stmt::IfStmtClass:
469 if (cast<IfStmt>(Parent)->getCond() != S)
472 case Stmt::ObjCForCollectionStmtClass:
473 if (cast<ObjCForCollectionStmt>(Parent)->getBody() == S)
476 case Stmt::WhileStmtClass:
477 if (cast<WhileStmt>(Parent)->getCond() != S)
487 assert(S &&
"Cannot have null Stmt for PathDiagnosticLocation");
494 assert(S &&
"Null Stmt passed to getEnclosingStmtLocation");
504 ArrayRef<std::unique_ptr<BugReporterVisitor>> visitors) {
513 for (
auto &V : visitors) {
528 typedef std::pair<PathDiagnosticCallPiece*, const ExplodedNode*>
StackDiagPair;
536 dyn_cast<PathDiagnosticEventPiece>(P)) {
538 if (ep->hasCallStackHint())
540 E = CallStack.end();
I !=
E; ++
I) {
543 std::string stackMsg = ep->getCallStackMessage(N);
559 ArrayRef<std::unique_ptr<BugReporterVisitor>> visitors) {
580 LCM[&C->
path] = CE->getCalleeContext();
598 if (VisitedEntireCall) {
599 C = cast<PathDiagnosticCallPiece>(PD.
getActivePath().front());
601 const Decl *Caller = CE->getLocationContext()->getDecl();
604 LCM[&C->
path] = CE->getCalleeContext();
608 if (!CallStack.empty()) {
609 assert(CallStack.back().first == C);
610 CallStack.pop_back();
627 switch (T->getStmtClass()) {
631 case Stmt::GotoStmtClass:
632 case Stmt::IndirectGotoStmtClass: {
639 llvm::raw_string_ostream os(sbuf);
642 os <<
"Control jumps to line "
645 Start, End, os.str()));
649 case Stmt::SwitchStmtClass: {
652 llvm::raw_string_ostream os(sbuf);
657 switch (S->getStmtClass()) {
659 os <<
"No cases match in the switch statement. "
660 "Control jumps to line "
663 case Stmt::DefaultStmtClass:
664 os <<
"Control jumps to the 'default' case at line "
668 case Stmt::CaseStmtClass: {
669 os <<
"Control jumps to 'case ";
670 const CaseStmt *Case = cast<CaseStmt>(
S);
674 bool GetRawInt =
true;
676 if (
const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(LHS)) {
689 os << LHS->EvaluateKnownConstInt(PDB.getASTContext());
697 Start, End, os.str()));
700 os <<
"'Default' branch taken. ";
703 Start, End, os.str()));
709 case Stmt::BreakStmtClass:
710 case Stmt::ContinueStmtClass: {
712 llvm::raw_string_ostream os(sbuf);
715 Start, End, os.str()));
720 case Stmt::BinaryConditionalOperatorClass:
721 case Stmt::ConditionalOperatorClass: {
723 llvm::raw_string_ostream os(sbuf);
724 os <<
"'?' condition is ";
734 End = PDB.getEnclosingStmtLocation(S);
737 Start, End, os.str()));
742 case Stmt::BinaryOperatorClass: {
743 if (!PDB.supportsLogicalOpControlFlow())
748 llvm::raw_string_ostream os(sbuf);
749 os <<
"Left side of '";
752 os <<
"&&" <<
"' is ";
760 Start,
End, os.str()));
767 Start, End, os.str()));
772 os <<
"||" <<
"' is ";
779 Start, End, os.str()));
787 Start,
End, os.str()));
794 case Stmt::DoStmtClass: {
797 llvm::raw_string_ostream os(sbuf);
799 os <<
"Loop condition is true. ";
803 End = PDB.getEnclosingStmtLocation(S);
806 Start, End, os.str()));
812 End = PDB.getEnclosingStmtLocation(S);
815 Start, End,
"Loop condition is false. Exiting loop"));
821 case Stmt::WhileStmtClass:
822 case Stmt::ForStmtClass: {
825 llvm::raw_string_ostream os(sbuf);
827 os <<
"Loop condition is false. ";
830 End = PDB.getEnclosingStmtLocation(S);
833 Start, End, os.str()));
838 End = PDB.getEnclosingStmtLocation(S);
841 Start, End,
"Loop condition is true. Entering loop body"));
847 case Stmt::IfStmtClass: {
851 End = PDB.getEnclosingStmtLocation(S);
855 Start, End,
"Taking false branch"));
858 Start, End,
"Taking true branch"));
869 for (
auto &V : visitors) {
878 if (!PDB.getBugReport()->isValid())
899 if (isa<AbstractConditionalOperator>(E))
903 if (B->isLogicalOp())
916 void markDead() { IsDead =
true; }
917 bool isDead()
const {
return IsDead; }
922 bool firstCharOnly =
false) {
924 const Stmt *Original =
S;
928 switch (S->getStmtClass()) {
931 case Stmt::ParenExprClass:
932 case Stmt::GenericSelectionExprClass:
933 S = cast<Expr>(
S)->IgnoreParens();
934 firstCharOnly =
true;
936 case Stmt::BinaryConditionalOperatorClass:
937 case Stmt::ConditionalOperatorClass:
938 S = cast<AbstractConditionalOperator>(
S)->getCond();
939 firstCharOnly =
true;
941 case Stmt::ChooseExprClass:
942 S = cast<ChooseExpr>(
S)->getCond();
943 firstCharOnly =
true;
945 case Stmt::BinaryOperatorClass:
946 S = cast<BinaryOperator>(
S)->getLHS();
947 firstCharOnly =
true;
965 std::vector<ContextLocation> CLocs;
968 PathDiagnosticBuilder &PDB;
981 if (!CLocs.back().isDead() && CLocs.back().asLocation().isFileID()) {
983 rawAddEdge(cleanUpLocation(CLocs.back(), PDB.LC,
true));
994 if (!PD.path.empty()) {
995 PrevLoc = (*PD.path.begin())->getLocation();
997 if (
const Stmt *S = PrevLoc.asStmt())
998 addExtendedContext(PDB.getEnclosingStmtLocation(S).asStmt());
1003 while (!CLocs.empty()) popLocation();
1009 PDB.getSourceManager());
1014 void flushLocations() {
1015 while (!CLocs.empty())
1021 bool IsPostJump =
false);
1025 void addContext(
const Stmt *S);
1027 void addExtendedContext(
const Stmt *S);
1038 return PDB.getEnclosingStmtLocation(S);
1047 if (Container == Containee)
1054 if (
const Stmt *ContainerS = Container.
asStmt()) {
1056 if (S == ContainerS)
1058 S = PDB.getParent(S);
1078 assert(ContainerBegLine <= ContainerEndLine);
1079 assert(ContaineeBegLine <= ContaineeEndLine);
1081 return (ContainerBegLine <= ContaineeBegLine &&
1082 ContainerEndLine >= ContaineeEndLine &&
1083 (ContainerBegLine != ContaineeBegLine ||
1086 (ContainerEndLine != ContaineeEndLine ||
1092 if (!PrevLoc.isValid()) {
1125 while (!CLocs.empty()) {
1126 ContextLocation &TopContextLoc = CLocs.back();
1129 if (TopContextLoc == CLoc) {
1131 if (IsConsumedExpr(TopContextLoc))
1132 TopContextLoc.markDead();
1138 TopContextLoc.markDead();
1142 if (containsLocation(TopContextLoc, CLoc)) {
1146 if (IsConsumedExpr(CLoc)) {
1147 CLocs.push_back(ContextLocation(CLoc,
true));
1152 CLocs.push_back(ContextLocation(CLoc, IsPostJump));
1165 if (
const Expr *
X = dyn_cast_or_null<Expr>(L.
asStmt()))
1171 void EdgeBuilder::addExtendedContext(
const Stmt *S) {
1175 const Stmt *Parent = PDB.getParent(S);
1177 if (isa<CompoundStmt>(Parent))
1178 Parent = PDB.getParent(Parent);
1184 switch (Parent->getStmtClass()) {
1185 case Stmt::DoStmtClass:
1186 case Stmt::ObjCAtSynchronizedStmtClass:
1196 void EdgeBuilder::addContext(
const Stmt *S) {
1205 while (!CLocs.empty()) {
1209 if (TopContextLoc == L)
1212 if (containsLocation(TopContextLoc, L)) {
1246 switch (Ex->getStmtClass()) {
1248 if (!isa<CastExpr>(Ex))
1251 case Stmt::BinaryOperatorClass:
1252 case Stmt::UnaryOperatorClass: {
1253 for (
const Stmt *SubStmt : Ex->children()) {
1254 if (
const Expr *child = dyn_cast_or_null<Expr>(SubStmt)) {
1276 if (
const CallExpr *CE = dyn_cast_or_null<CallExpr>(CallSite)) {
1279 PE = FD->param_end();
1281 for (; AI != AE && PI != PE; ++AI, ++PI) {
1282 if (
const Expr *ArgE = *AI) {
1284 Loc LV = State->
getLValue(PD, CalleeCtx);
1299 switch (Term->getStmtClass()) {
1300 case Stmt::ForStmtClass:
1301 case Stmt::WhileStmtClass:
1302 case Stmt::ObjCForCollectionStmtClass:
1303 case Stmt::CXXForRangeStmtClass:
1341 const Stmt *S = SP->getStmt();
1351 const Stmt *LoopBody =
nullptr;
1352 switch (Term->getStmtClass()) {
1353 case Stmt::CXXForRangeStmtClass: {
1362 case Stmt::ForStmtClass: {
1363 const ForStmt *FS = cast<ForStmt>(Term);
1369 case Stmt::ObjCForCollectionStmtClass: {
1374 case Stmt::WhileStmtClass:
1375 LoopBody = cast<WhileStmt>(Term)->getBody();
1390 ArrayRef<std::unique_ptr<BugReporterVisitor>> visitors) {
1391 EdgeBuilder EB(PD, PDB);
1404 if (
const Expr *Ex = PS->getStmtAs<
Expr>())
1411 const Stmt *S = CE->getCalleeContext()->getCallSite();
1412 if (
const Expr *Ex = dyn_cast_or_null<Expr>(S)) {
1420 LCM[&C->
path] = CE->getCalleeContext();
1423 EB.flushLocations();
1435 const Decl *D = CE->getCalleeContext()->getDecl();
1442 EB.flushLocations();
1452 if (VisitedEntireCall) {
1453 C = cast<PathDiagnosticCallPiece>(PD.
getActivePath().front());
1455 const Decl *Caller = CE->getLocationContext()->getDecl();
1457 LCM[&C->
path] = CE->getCalleeContext();
1463 if (!CallStack.empty()) {
1464 assert(CallStack.back().first == C);
1465 CallStack.pop_back();
1483 if (CallerCtx != CalleeCtx) {
1486 CalleeCtx, CallerCtx);
1491 if (
const Stmt *Loop = BE->getSrc()->getLoopTarget()) {
1495 if (
const ForStmt *FS = dyn_cast<ForStmt>(Loop))
1497 else if (
const WhileStmt *WS = dyn_cast<WhileStmt>(Loop))
1498 CS = dyn_cast<CompoundStmt>(WS->getBody());
1502 "Looping back to the head of the loop");
1515 const CFGBlock *BSrc = BE->getSrc();
1538 EB.addContext(Term);
1550 EB.addContext(stmt);
1553 EB.addExtendedContext(PDB.getEnclosingStmtLocation(stmt).asStmt());
1567 for (
auto &V : visitors) {
1570 EB.addEdge(Loc,
true);
1575 EB.addExtendedContext(PDB.getEnclosingStmtLocation(S).asStmt());
1580 return PDB.getBugReport()->isValid();
1615 dyn_cast_or_null<ObjCForCollectionStmt>(S))
1616 return FS->getElement();
1623 "Loop body skipped when range is empty";
1625 "Loop body skipped when collection is empty";
1630 ArrayRef<std::unique_ptr<BugReporterVisitor>> visitors) {
1663 if (VisitedEntireCall) {
1665 C = cast<PathDiagnosticCallPiece>(
P);
1667 const Decl *Caller = CE->getLocationContext()->getDecl();
1678 assert(LCM[&C->
path] ==
nullptr ||
1679 LCM[&C->
path] == CE->getCalleeContext());
1680 LCM[&C->
path] = CE->getCalleeContext();
1695 if (!CallStack.empty()) {
1696 assert(CallStack.back().first == C);
1697 CallStack.pop_back();
1714 const Stmt *S = CE->getCalleeContext()->getCallSite();
1716 if (
const Expr *Ex = dyn_cast_or_null<Expr>(S)) {
1728 LCM[&C->
path] = CE->getCalleeContext();
1744 if (
const Expr *Ex = PS->getStmtAs<
Expr>())
1752 if (!isa<ObjCForCollectionStmt>(PS->getStmt())) {
1767 if (CallerCtx != CalleeCtx) {
1770 CalleeCtx, CallerCtx);
1775 if (
const Stmt *Loop = BE->getSrc()->getLoopTarget()) {
1777 const Stmt *Body =
nullptr;
1779 if (
const ForStmt *FS = dyn_cast<ForStmt>(Loop))
1780 Body = FS->getBody();
1781 else if (
const WhileStmt *WS = dyn_cast<WhileStmt>(Loop))
1782 Body = WS->getBody();
1784 dyn_cast<ObjCForCollectionStmt>(Loop)) {
1785 Body = OFS->getBody();
1787 dyn_cast<CXXForRangeStmt>(Loop)) {
1788 Body = FRS->getBody();
1800 if (
const CompoundStmt *CS = dyn_cast_or_null<CompoundStmt>(Body)) {
1807 const CFGBlock *BSrc = BE->getSrc();
1818 const char *str =
nullptr;
1821 if (!IsInLoopBody) {
1822 if (isa<ObjCForCollectionStmt>(Term)) {
1824 }
else if (isa<CXXForRangeStmt>(Term)) {
1843 }
else if (isa<BreakStmt>(Term) || isa<ContinueStmt>(Term) ||
1844 isa<GotoStmt>(Term)) {
1857 for (
auto &V : visitors) {
1893 if (isa<ExprWithCleanups>(S) ||
1894 isa<CXXBindTemporaryExpr>(S) ||
1895 isa<SubstNonTypeTemplateParmExpr>(S))
1905 switch (S->getStmtClass()) {
1906 case Stmt::BinaryOperatorClass: {
1912 case Stmt::IfStmtClass:
1913 return cast<IfStmt>(
S)->getCond() == Cond;
1914 case Stmt::ForStmtClass:
1915 return cast<ForStmt>(
S)->getCond() == Cond;
1916 case Stmt::WhileStmtClass:
1917 return cast<WhileStmt>(
S)->getCond() == Cond;
1918 case Stmt::DoStmtClass:
1919 return cast<DoStmt>(
S)->getCond() == Cond;
1920 case Stmt::ChooseExprClass:
1921 return cast<ChooseExpr>(
S)->getCond() == Cond;
1922 case Stmt::IndirectGotoStmtClass:
1923 return cast<IndirectGotoStmt>(
S)->getTarget() == Cond;
1924 case Stmt::SwitchStmtClass:
1925 return cast<SwitchStmt>(
S)->getCond() == Cond;
1926 case Stmt::BinaryConditionalOperatorClass:
1927 return cast<BinaryConditionalOperator>(
S)->getCond() == Cond;
1928 case Stmt::ConditionalOperatorClass: {
1930 return CO->
getCond() == Cond ||
1934 case Stmt::ObjCForCollectionStmtClass:
1935 return cast<ObjCForCollectionStmt>(
S)->getElement() == Cond;
1936 case Stmt::CXXForRangeStmtClass: {
1946 if (
const ForStmt *FS = dyn_cast<ForStmt>(FL))
1947 return FS->getInc() == S || FS->getInit() ==
S;
1949 return FRS->getInc() == S || FRS->getRangeStmt() == S ||
1950 FRS->getLoopVarStmt() || FRS->getRangeInit() ==
S;
1977 const Stmt *InnerStmt =
nullptr;
1978 while (NextSrcContext.
isValid() && NextSrcContext.
asStmt() != InnerStmt) {
1979 SrcContexts.push_back(NextSrcContext);
1980 InnerStmt = NextSrcContext.
asStmt();
1995 if (!DstContext.isValid() || DstContext.asStmt() == Dst)
1999 if (std::find(SrcContexts.begin(), SrcContexts.end(), DstContext) !=
2027 I = pieces.insert(I, Piece);
2055 if (!s1Start || !s1End)
2089 if (!s2Start || !s2End || s1End != s2Start)
2094 if (!(isa<ForStmt>(s1Start) || isa<WhileStmt>(s1Start) ||
2095 isa<IfStmt>(s1Start) || isa<ObjCForCollectionStmt>(s1Start) ||
2096 isa<CXXForRangeStmt>(s1Start)))
2106 I = pieces.erase(I);
2131 StringRef Snippet = Buffer->getBuffer().slice(BeginOffset, EndOffset);
2137 if (Snippet.find_first_of(
"\r\n") != StringRef::npos)
2141 return Snippet.size();
2189 if (isa<PathDiagnosticEventPiece>(*NextI)) {
2205 if (s1Start && s2Start && s1Start == s2End && s2Start == s1End) {
2206 const size_t MAX_SHORT_LINE_LENGTH = 80;
2208 if (s1Length && *s1Length <= MAX_SHORT_LINE_LENGTH) {
2210 if (s2Length && *s2Length <= MAX_SHORT_LINE_LENGTH) {
2212 I = Path.erase(NextI);
2239 bool erased =
false;
2271 std::swap(SecondLoc, FirstLoc);
2280 const size_t MAX_PUNY_EDGE_LENGTH = 2;
2281 if (*ByteWidth <= MAX_PUNY_EDGE_LENGTH) {
2320 bool hasChanges =
false;
2330 if (!OCS.count(CallI)) {
2384 if (level1 && level1 == level2 && level1 == level3 && level1 == level4) {
2399 if (s1End && s1End == s2Start && level2) {
2400 bool removeEdge =
false;
2426 else if (s1Start && s2End &&
2439 else if (s1Start && s2End &&
2463 if (s1End == s2Start) {
2465 dyn_cast_or_null<ObjCForCollectionStmt>(level3);
2511 const Decl *D = LCM[&Path]->getDecl();
2523 void BugType::anchor() { }
2527 void BuiltinBug::anchor() {}
2533 void BugReport::NodeResolver::anchor() {}
2539 llvm::FoldingSetNodeID
ID;
2540 visitor->Profile(ID);
2547 Callbacks.push_back(std::move(visitor));
2553 popInterestingSymbolsAndRegions();
2570 hash.AddPointer(&
BT);
2583 if (!range.isValid())
2585 hash.AddInteger(range.getBegin().getRawEncoding());
2586 hash.AddInteger(range.getEnd().getRawEncoding());
2595 if (getInterestingSymbols().insert(sym).second)
2599 getInterestingRegions().insert(meta->getRegion());
2608 if (getInterestingRegions().insert(R).second)
2612 getInterestingSymbols().insert(SR->getSymbol());
2635 return getInterestingSymbols().count(sym);
2642 bool b = getInterestingRegions().count(R);
2646 return getInterestingSymbols().count(SR->getSymbol());
2656 void BugReport::lazyInitializeInterestingSets() {
2664 lazyInitializeInterestingSets();
2669 lazyInitializeInterestingSets();
2673 void BugReport::pushInterestingSymbolsAndRegions() {
2678 void BugReport::popInterestingSymbolsAndRegions() {
2688 const Stmt *S =
nullptr;
2692 if (BE->getBlock() == &Exit)
2721 "Either Location or ErrorNode should be specified but not both.");
2746 typedef std::vector<BugReportEquivClass *> ContTy;
2754 if (BugTypes.isEmpty())
2763 I = bugTypes.begin(),
E = bugTypes.end();
I !=
E; ++
I)
2764 const_cast<BugType*>(*I)->FlushReports(*
this);
2768 typedef std::vector<BugReportEquivClass *> ContVecTy;
2779 llvm::DeleteContainerSeconds(StrBugTypes);
2782 BugTypes = F.getEmptySet();
2795 std::unique_ptr<ExplodedGraph> Graph;
2801 class TrimmedGraph {
2804 typedef llvm::DenseMap<const ExplodedNode *, unsigned> PriorityMapTy;
2805 PriorityMapTy PriorityMap;
2807 typedef std::pair<const ExplodedNode *, size_t> NodeIndexPair;
2810 std::unique_ptr<ExplodedGraph> G;
2813 template <
bool Descending>
2814 class PriorityCompare {
2815 const PriorityMapTy &PriorityMap;
2818 PriorityCompare(
const PriorityMapTy &M) : PriorityMap(M) {}
2821 PriorityMapTy::const_iterator LI = PriorityMap.find(LHS);
2822 PriorityMapTy::const_iterator RI = PriorityMap.find(RHS);
2823 PriorityMapTy::const_iterator
E = PriorityMap.end();
2830 return Descending ? LI->second > RI->second
2831 : LI->second < RI->second;
2834 bool operator()(
const NodeIndexPair &LHS,
const NodeIndexPair &RHS)
const {
2835 return (*
this)(LHS.first, RHS.first);
2843 bool popNextReportGraph(ReportGraph &GraphWrapper);
2847 TrimmedGraph::TrimmedGraph(
const ExplodedGraph *OriginalGraph,
2852 G = OriginalGraph->
trim(Nodes, &ForwardMap, &InverseMap);
2857 llvm::SmallPtrSet<const ExplodedNode *, 32> RemainingNodes;
2859 for (
unsigned i = 0, count = Nodes.size(); i < count; ++i) {
2860 if (
const ExplodedNode *NewNode = ForwardMap.lookup(Nodes[i])) {
2861 ReportNodes.push_back(std::make_pair(NewNode, i));
2862 RemainingNodes.insert(NewNode);
2866 assert(!RemainingNodes.empty() &&
"No error node found in the trimmed graph");
2869 std::queue<const ExplodedNode *> WS;
2871 assert(G->num_roots() == 1);
2872 WS.push(*G->roots_begin());
2873 unsigned Priority = 0;
2875 while (!WS.empty()) {
2881 std::tie(PriorityEntry, IsNew) =
2882 PriorityMap.insert(std::make_pair(Node, Priority));
2886 assert(PriorityEntry->second <= Priority);
2890 if (RemainingNodes.erase(Node))
2891 if (RemainingNodes.empty())
2901 std::sort(ReportNodes.begin(), ReportNodes.end(),
2902 PriorityCompare<true>(PriorityMap));
2905 bool TrimmedGraph::popNextReportGraph(ReportGraph &GraphWrapper) {
2906 if (ReportNodes.empty())
2910 std::tie(OrigN, GraphWrapper.Index) = ReportNodes.pop_back_val();
2911 assert(PriorityMap.find(OrigN) != PriorityMap.end() &&
2912 "error node not accessible from root");
2916 auto GNew = llvm::make_unique<ExplodedGraph>();
2917 GraphWrapper.BackMap.clear();
2929 InterExplodedGraphMap::const_iterator IMitr = InverseMap.find(OrigN);
2930 assert(IMitr != InverseMap.end() &&
"No mapping to original node.");
2931 GraphWrapper.BackMap[NewN] = IMitr->second;
2937 GraphWrapper.ErrorNode = NewN;
2943 GNew->addRoot(NewN);
2950 PriorityCompare<false>(PriorityMap));
2953 GraphWrapper.Graph = std::move(GNew);
2962 typedef std::vector<std::pair<IntrusiveRefCntPtr<PathDiagnosticMacroPiece>,
2965 typedef std::vector<IntrusiveRefCntPtr<PathDiagnosticPiece> >
2968 MacroStackTy MacroStack;
2971 for (PathPieces::const_iterator
I = path.begin(), E = path.end();
2992 Pieces.push_back(piece);
2999 if (!MacroStack.empty() && InstantiationLoc == MacroStack.back().second) {
3000 MacroStack.back().first->subPieces.push_back(piece);
3013 while (!MacroStack.empty()) {
3014 if (InstantiationLoc == MacroStack.back().second) {
3015 MacroGroup = MacroStack.back().first;
3019 if (ParentInstantiationLoc == MacroStack.back().second) {
3020 MacroGroup = MacroStack.back().first;
3024 MacroStack.pop_back();
3027 if (!MacroGroup || ParentInstantiationLoc == MacroStack.back().second) {
3034 MacroGroup->subPieces.push_back(NewGroup);
3036 assert(InstantiationLoc.
isFileID());
3037 Pieces.push_back(NewGroup);
3040 MacroGroup = NewGroup;
3041 MacroStack.push_back(std::make_pair(MacroGroup, InstantiationLoc));
3045 MacroGroup->subPieces.push_back(piece);
3051 path.insert(path.end(), Pieces.begin(), Pieces.end());
3057 assert(!bugReports.empty());
3059 bool HasValid =
false;
3060 bool HasInvalid =
false;
3063 E = bugReports.end();
I !=
E; ++
I) {
3064 if ((*I)->isValid()) {
3066 errorNodes.push_back((*I)->getErrorNode());
3070 errorNodes.push_back(
nullptr);
3089 TrimmedGraph TrimG(&getGraph(), errorNodes);
3090 ReportGraph ErrorGraph;
3092 while (TrimG.popNextReportGraph(ErrorGraph)) {
3094 assert(ErrorGraph.Index < bugReports.size());
3095 BugReport *R = bugReports[ErrorGraph.Index];
3096 assert(R &&
"No original report found for sliced graph.");
3097 assert(R->isValid() &&
"Report selected by trimmed graph marked invalid.");
3100 PathDiagnosticBuilder PDB(*
this, R, ErrorGraph.BackMap, &PC);
3104 R->addVisitor(llvm::make_unique<NilReceiverBRVisitor>());
3105 R->addVisitor(llvm::make_unique<ConditionBRVisitor>());
3106 R->addVisitor(llvm::make_unique<LikelyFalsePositiveSuppressionBRVisitor>());
3109 unsigned origReportConfigToken, finalReportConfigToken;
3119 E = R->visitor_end();
I !=
E; ++
I)
3120 visitors.push_back((*I)->clone());
3124 origReportConfigToken = R->getConfigurationChangeToken();
3128 std::unique_ptr<PathDiagnosticPiece> LastPiece;
3131 if (std::unique_ptr<PathDiagnosticPiece> Piece =
3132 (*I)->getEndPath(PDB, N, *R)) {
3133 assert (!LastPiece &&
3134 "There can only be one final piece in a diagnostic.");
3135 LastPiece = std::move(Piece);
3150 switch (ActiveScheme) {
3169 finalReportConfigToken = R->getConfigurationChangeToken();
3170 }
while (finalReportConfigToken != origReportConfigToken);
3176 if (!PD.
path.empty()) {
3177 if (R->shouldPrunePath() && getAnalyzerOptions().shouldPrunePaths()) {
3179 assert(stillHasNotes);
3180 (void)stillHasNotes;
3213 assert(!HasInvalid &&
"Inconsistent suppression");
3219 BugTypes = F.add(BugTypes, BT);
3226 assert((E->isSink() || E->getLocation().getTag()) &&
3227 "Error node must either be a sink or have a tag");
3230 E->getLocationContext()->getAnalysisDeclContext();
3240 bool ValidSourceLoc = R->getLocation(getSourceManager()).isValid();
3241 assert(ValidSourceLoc);
3244 if (!ValidSourceLoc)
3248 llvm::FoldingSetNodeID
ID;
3259 EQClasses.InsertNode(EQ, InsertPos);
3260 EQClassesVector.push_back(EQ);
3262 EQ->AddReport(std::move(R));
3271 struct FRIEC_WLItem {
3276 : N(n),
I(N->succ_begin()), E(N->succ_end()) {}
3297 bugReports.push_back(R);
3311 for (; I !=
E; ++
I) {
3316 if (errorNode->
isSink()) {
3318 "BugType::isSuppressSink() should not be 'true' for sink end nodes");
3322 bugReports.push_back(&*I);
3324 exampleReport = &*
I;
3330 typedef FRIEC_WLItem WLItem;
3332 llvm::DenseMap<const ExplodedNode *, unsigned> Visited;
3335 WL.push_back(errorNode);
3336 Visited[errorNode] = 1;
3338 while (!WL.empty()) {
3339 WLItem &WI = WL.back();
3340 assert(!WI.N->succ_empty());
3342 for (; WI.I != WI.E; ++WI.I) {
3348 bugReports.push_back(&*I);
3350 exampleReport = &*
I;
3359 unsigned &mark = Visited[Succ];
3369 if (!WL.empty() && &WL.back() == &WI)
3376 return exampleReport;
3382 if (exampleReport) {
3384 FlushReport(exampleReport, *PDC, bugReports);
3389 void BugReporter::FlushReport(
BugReport *exampleReport,
3405 MaxBugClassSize =
std::max(bugReports.size(),
3406 static_cast<size_t>(MaxBugClassSize));
3412 if (!bugReports.empty())
3413 if (!generatePathDiagnostic(*D.get(), PD, bugReports))
3416 MaxValidBugClassSize =
std::max(bugReports.size(),
3417 static_cast<size_t>(MaxValidBugClassSize));
3423 D->resetDiagnosticLocationToMainFile();
3427 if (D->path.empty()) {
3429 auto piece = llvm::make_unique<PathDiagnosticEventPiece>(
3432 piece->addRange(Range);
3433 D->setEndOfPath(std::move(piece));
3438 for (BugReport::ExtraTextList::const_iterator i = Meta.begin(),
3439 e = Meta.end(); i != e; ++i) {
3456 StringRef name, StringRef category,
3461 BugType *BT = getBugTypeForName(CheckName, name, category);
3462 auto R = llvm::make_unique<BugReport>(*
BT, str, Loc);
3463 R->setDeclWithIssue(DeclWithIssue);
3467 emitReport(std::move(R));
3471 StringRef category) {
3473 llvm::raw_svector_ostream(fullDesc) << CheckName.
getName() <<
":" << name
3475 BugType *&BT = StrBugTypes[fullDesc];
3477 BT =
new BugType(CheckName, name, category);
3483 for (PathPieces::const_iterator
I =
begin(), E =
end();
I !=
E; ++
I) {
3484 llvm::errs() <<
"[" << index++ <<
"] ";
3486 llvm::errs() <<
"\n";
3491 llvm::errs() <<
"CALL\n--------------\n";
3495 else if (
const NamedDecl *ND = dyn_cast<NamedDecl>(getCallee()))
3496 llvm::errs() << *ND <<
"\n";
3502 llvm::errs() <<
"EVENT\n--------------\n";
3503 llvm::errs() << getString() <<
"\n";
3504 llvm::errs() <<
" ---- at ----\n";
3509 llvm::errs() <<
"CONTROL\n--------------\n";
3510 getStartLocation().dump();
3511 llvm::errs() <<
" ---- to ----\n";
3512 getEndLocation().dump();
3516 llvm::errs() <<
"MACRO\n--------------\n";
3522 llvm::errs() <<
"<INVALID>\n";
3529 llvm::errs() <<
"<range>\n";
3532 asLocation().dump();
3533 llvm::errs() <<
"\n";
3539 llvm::errs() <<
"<NULL STMT>\n";
3542 if (
const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(D))
3543 llvm::errs() << *ND <<
"\n";
3544 else if (isa<BlockDecl>(D))
3546 llvm::errs() <<
"<block>\n";
3548 llvm::errs() <<
"<unknown decl>\n";
3550 llvm::errs() <<
"<NULL DECL>\n";
VisitorList::iterator visitor_iterator
Defines the clang::ASTContext interface.
static void removeEdgesToDefaultInitializers(PathPieces &Pieces)
Remove edges in and out of C++ default initializer expressions.
SourceLocation getEnd() const
static bool isLoopJumpPastBody(const Stmt *Term, const BlockEdge *BE)
Return true if the terminator is a loop and the destination is the false branch.
static bool removeUnneededCalls(PathPieces &pieces, BugReport *R, LocationContextMap &LCM)
Recursively scan through a path and prune out calls and macros pieces that aren't needed...
FunctionDecl - An instance of this class is created to represent a function declaration or definition...
const Decl * getDeclWithIssue() const
Return the canonical declaration, be it a method or class, where this issue semantically occurred...
static void removeRedundantMsgs(PathPieces &path)
An optimization pass over PathPieces that removes redundant diagnostics generated by both ConditionBR...
static bool isContainedByStmt(ParentMap &PM, const Stmt *S, const Stmt *SubS)
static Optional< size_t > getLengthOnSingleLine(SourceManager &SM, SourceRange Range)
Returns the number of bytes in the given (character-based) SourceRange.
const SourceRange * ranges_iterator
MemRegion - The root abstract class for all memory regions.
bool hasCallStackMessage()
StringRef getCategory() const
bool isInteresting(SymbolRef sym)
PathDiagnosticLocation getLocation() const override
llvm::DenseSet< SymbolRef > Symbols
succ_iterator succ_begin()
const ExplodedNode * getErrorNode() const
virtual PathDiagnosticLocation getLocation(const SourceManager &SM) const
Return the "definitive" location of the reported bug.
const internal::VariadicAllOfMatcher< Stmt > stmt
Matches statements.
EnumConstantDecl - An instance of this object exists for each enum constant that is defined...
SVal getRawSVal(Loc LV, QualType T=QualType()) const
Returns the "raw" SVal bound to LV before any value simplfication.
Defines the SourceManager interface.
ProgramPoint getLocation() const
getLocation - Returns the edge associated with the given node.
Represents a point when we begin processing an inlined call.
llvm::MemoryBuffer * getBuffer(FileID FID, SourceLocation Loc, bool *Invalid=nullptr) const
Return the buffer for the specified FileID.
std::unique_ptr< llvm::MemoryBuffer > Buffer
SmallVector< StackDiagPair, 6 > StackDiagVector
static void adjustCallLocations(PathPieces &Pieces, PathDiagnosticLocation *LastCallLocation=nullptr)
Recursively scan through a path and make sure that all call pieces have valid locations.
StringRef getName() const
void setPrunable(bool isPrunable, bool override=false)
Mark the diagnostic piece as being potentially prunable.
void dump() const override
static PathDiagnosticLocation createEndBrace(const CompoundStmt *CS, const SourceManager &SM)
Create a location for the end of the compound statement.
static bool optimizeEdges(PathPieces &path, SourceManager &SM, OptimizedCallsSet &OCS, LocationContextMap &LCM)
PathDiagnosticLocation getLocation() const
unsigned succ_size() const
static const Stmt * GetCurrentOrPreviousStmt(const ExplodedNode *N)
SmallVector< SourceRange, 4 > Ranges
static bool isConditionForTerminator(const Stmt *S, const Stmt *Cond)
const MemRegion * getBaseRegion() const
Defines the Objective-C statement AST node classes.
static PathDiagnosticLocation createDeclEnd(const LocationContext *LC, const SourceManager &SM)
Constructs a location for the end of the enclosing declaration body.
ParmVarDecl - Represents a parameter to a function.
Defines the clang::Expr interface and subclasses for C++ expressions.
static PathDiagnosticLocation createSingleLocation(const PathDiagnosticLocation &PDL)
Convert the given location into a single kind location.
static void removePiecesWithInvalidLocations(PathPieces &Pieces)
Remove all pieces with invalid locations as these cannot be serialized.
BoundNodesTreeBuilder Nodes
static void updateStackPiecesWithMessage(PathDiagnosticPiece *P, StackDiagVector &CallStack)
FullSourceLoc asLocation() const
PathDiagnostic - PathDiagnostic objects represent a single path-sensitive diagnostic.
const Decl * getUniqueingDecl() const
Get the declaration containing the uniqueing location.
void setStartLocation(const PathDiagnosticLocation &L)
unsigned getExpansionLineNumber(bool *Invalid=nullptr) const
class LLVM_ALIGNAS(8) DependentTemplateSpecializationType const IdentifierInfo * Name
Represents a template specialization type whose template cannot be resolved, e.g. ...
void addRange(SourceRange R)
Add a range to a bug report.
std::pair< SourceLocation, SourceLocation > getExpansionRange(SourceLocation Loc) const
Given a SourceLocation object, return the range of tokens covered by the expansion in the ultimate fi...
bool isBodyAutosynthesized() const
Checks if the body of the Decl is generated by the BodyFarm.
friend class BugReportEquivClass
succ_iterator succ_begin()
static PathDiagnosticLocation getEnclosingStmtLocation(const Stmt *S, SourceManager &SMgr, const ParentMap &P, const LocationContext *LC, bool allowNestedContexts)
AnalysisDeclContext contains the context data for the function or method under analysis.
static void removeIdenticalEvents(PathPieces &path)
static const char StrLoopBodyZero[]
StringRef getString() const
const BugType & getBugType() const
void pushActivePath(PathPieces *p)
const Stmt * getStmt() const
void addPredecessor(ExplodedNode *V, ExplodedGraph &G)
addPredeccessor - Adds a predecessor to the current node, and in tandem add this node as a successor ...
SmallVector< Regions *, 2 > interestingRegions
A (stack of) set of regions that are registered with this report as being "interesting", and thus used to help decide which diagnostics to include when constructing the final path diagnostic.
PathPieces & getMutablePieces()
Return a mutable version of 'path'.
bool isPrunable() const
Return true if the diagnostic piece is prunable.
unsigned getExpansionColumnNumber(SourceLocation Loc, bool *Invalid=nullptr) const
virtual llvm::iterator_range< ranges_iterator > getRanges()
Get the SourceRanges associated with the report.
static bool IsControlFlowExpr(const Stmt *S)
llvm::FoldingSet< BugReporterVisitor > CallbacksSet
Used for ensuring the visitors are only added once.
virtual void FlushReports(BugReporter &BR)
llvm::SmallSet< const LocationContext *, 2 > InterestingLocationContexts
A set of location contexts that correspoind to call sites which should be considered "interesting"...
ForStmt - This represents a 'for (init;cond;inc)' stmt.
static void addEdgeToPath(PathPieces &path, PathDiagnosticLocation &PrevLoc, PathDiagnosticLocation NewLoc, const LocationContext *LC)
Adds a sanitized control-flow diagnostic edge to a path.
virtual ~BugReporterVisitor()
STATISTIC(MaxBugClassSize,"The maximum number of bug reports in the same equivalence class")
static bool isJumpToFalseBranch(const BlockEdge *BE)
const Decl * asDecl() const
A builtin binary operation expression such as "x + y" or "x <= y".
const Stmt * getCallSite() const
void dump() const override
CXXForRangeStmt - This represents C++0x [stmt.ranged]'s ranged for statement, represented as 'for (ra...
Expr * IgnoreParenCasts() LLVM_READONLY
IgnoreParenCasts - Ignore parentheses and casts.
static PathDiagnosticCallPiece * construct(const ExplodedNode *N, const CallExitEnd &CE, const SourceManager &SM)
const void * getTag() const
Return the opaque tag (if any) on the PathDiagnosticPiece.
static const Stmt * getStmtBeforeCond(ParentMap &PM, const Stmt *Term, const ExplodedNode *N)
StringRef getDescription() const
ExplodedNode * getFirstPred()
StringRef getShortDescription(bool UseFallback=true) const
PathDiagnosticLocation callEnter
static void reversePropagateIntererstingSymbols(BugReport &R, InterestingExprs &IE, const ProgramState *State, const Expr *Ex, const LocationContext *LCtx)
detail::InMemoryDirectory::const_iterator I
virtual PathDiagnosticLocation getLocation() const =0
void addVisitor(std::unique_ptr< BugReporterVisitor > visitor)
Add custom or predefined bug report visitors to this report.
const Stmt * asStmt() const
llvm::DenseSet< const Expr * > InterestingExprs
bool isSuppressOnSink() const
isSuppressOnSink - Returns true if bug reports associated with this bug type should be suppressed if ...
const LocationContext * getLocationContext() const
ArrayRef< ParmVarDecl * >::const_iterator param_const_iterator
const CFGBlock * getSrc() const
StringRef getName() const
ConditionalOperator - The ?: ternary operator.
CompoundStmt - This represents a group of statements like { stmt stmt }.
FileID getFileID(SourceLocation SpellingLoc) const
Return the FileID for a SourceLocation.
static BugReport * FindReportInEquivalenceClass(BugReportEquivClass &EQ, SmallVectorImpl< BugReport * > &bugReports)
llvm::DenseSet< const PathDiagnosticCallPiece * > OptimizedCallsSet
void HandlePathDiagnostic(std::unique_ptr< PathDiagnostic > D)
CFGBlock - Represents a single basic block in a source-level CFG.
llvm::DenseMap< const ExplodedNode *, const ExplodedNode * > InterExplodedGraphMap
static const char * getTag()
Return the tag associated with this visitor.
Represents a point when we finish the call exit sequence (for inlined call).
SymbolicRegion - A special, "non-concrete" region.
const CFGBlock * getDst() const
virtual const ExtraTextList & getExtraText()
bool isWrittenInSameFile(SourceLocation Loc1, SourceLocation Loc2) const
Returns true if the spelling locations for both SourceLocations are part of the same file buffer...
ProgramState - This class encapsulates:
const Decl * getCallee() const
Expr - This represents one expression.
const ProgramStateRef & getState() const
Stmt * getTerminatorCondition(bool StripParens=true)
bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const
Determines the order of 2 source locations in the translation unit.
~GRBugReporter() override
const SourceManager & getManager() const
ParentMap & getParentMap() const
SVal getSVal(const Stmt *S, const LocationContext *LCtx) const
Returns the SVal bound to the statement 'S' in the state's environment.
static bool lexicalContains(ParentMap &PM, const Stmt *X, const Stmt *Y)
Return true if X is contained by Y.
static void reversePropagateInterestingSymbols(BugReport &R, InterestingExprs &IE, const ProgramState *State, const LocationContext *CalleeCtx, const LocationContext *CallerCtx)
PathDiagnosticLocation getEndLocation() const
unsigned getExpansionLineNumber(SourceLocation Loc, bool *Invalid=nullptr) const
void Register(BugType *BT)
static const Stmt * getNextStmt(const ExplodedNode *N)
Retrieve the statement corresponding to the successor node.
unsigned ConfigurationChangeToken
Used for clients to tell if the report's configuration has changed since the last time they checked...
void FlushReports()
Generate and flush diagnostics for all bug reports.
static void dropFunctionEntryEdge(PathPieces &Path, LocationContextMap &LCM, SourceManager &SM)
Drop the very first edge in a path, which should be a function entry edge.
void markInteresting(SymbolRef sym)
static const Stmt * GetPreviousStmt(const ExplodedNode *N)
bool getBooleanOption(StringRef Name, bool DefaultVal, const ento::CheckerBase *C=nullptr, bool SearchInParents=false)
Interprets an option's string value as a boolean.
PathDiagnosticLocation getStartLocation() const
CheckName getCheckName() const
static bool GenerateVisitorsOnlyPathDiagnostic(PathDiagnostic &PD, PathDiagnosticBuilder &PDB, const ExplodedNode *N, ArrayRef< std::unique_ptr< BugReporterVisitor >> visitors)
llvm::ilist< BugReport >::iterator iterator
BugReporter is a utility class for generating PathDiagnostics for analysis.
static const Stmt * getStmt(const ExplodedNode *N)
Given an exploded node, retrieve the statement that should be used for the diagnostic location...
bool isConsumedExpr(Expr *E) const
static PathDiagnosticLocation createDeclBegin(const LocationContext *LC, const SourceManager &SM)
Create a location for the beginning of the enclosing declaration body.
CFGTerminator getTerminator()
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
static PathDiagnosticEventPiece * eventsDescribeSameCondition(PathDiagnosticEventPiece *X, PathDiagnosticEventPiece *Y)
llvm::DenseSet< const MemRegion * > Regions
static std::unique_ptr< PathDiagnosticPiece > getDefaultEndPath(BugReporterContext &BRC, const ExplodedNode *N, BugReport &BR)
Generates the default final diagnostic piece.
ConstExprIterator const_arg_iterator
Stmt * getParent(Stmt *) const
static void simplifySimpleBranches(PathPieces &pieces)
Move edges from a branch condition to a branch target when the condition is simple.
Encodes a location in the source.
void EmitBasicReport(const Decl *DeclWithIssue, const CheckerBase *Checker, StringRef BugName, StringRef BugCategory, StringRef BugStr, PathDiagnosticLocation Loc, ArrayRef< SourceRange > Ranges=None)
const TemplateArgument * iterator
const ExplodedNode * ErrorNode
const StackFrameContext * getCurrentStackFrame() const
virtual PathGenerationScheme getGenerationScheme() const
Stmt * getParentIgnoreParens(Stmt *) const
StringRef getCheckName() const
const ExplodedNode *const * const_succ_iterator
bool isValid() const
Return true if this is a valid SourceLocation object.
ExplodedGraph & getGraph()
getGraph - Get the exploded graph created by the analysis engine for the analyzed method or function...
void emitReport(std::unique_ptr< BugReport > R)
Add the given report to the set of reports tracked by BugReporter.
static bool isIncrementOrInitInForLoop(const Stmt *S, const Stmt *FL)
PathDiagnosticLocation callReturn
void Profile(llvm::FoldingSetNodeID &ID) const
void setCallee(const CallEnter &CE, const SourceManager &SM)
SVal - This represents a symbolic expression, which can be either an L-value or an R-value...
bool generatePathDiagnostic(PathDiagnostic &PD, PathDiagnosticConsumer &PC, ArrayRef< BugReport * > &bugReports) override
Generates a path corresponding to one of the given bug reports.
PathDiagnosticLocation Location
const Decl * getDecl() const
SourceLocation getBegin() const
const Decl * DeclWithIssue
PathDiagnosticLocation getLocation() const override
static const Stmt * getEnclosingParent(const Stmt *S, const ParentMap &PM)
static bool isLogicalOp(Opcode Opc)
void dump() const override
static void removePunyEdges(PathPieces &path, SourceManager &SM, ParentMap &PM)
VisitorList Callbacks
A set of custom visitors which generate "event" diagnostics at interesting points in the path...
static bool hasImplicitBody(const Decl *D)
Returns true if the given decl has been implicitly given a body, either by the analyzer or by the com...
SmallVector< Symbols *, 2 > interestingSymbols
A (stack of) a set of symbols that are registered with this report as being "interesting", and thus used to help decide which diagnostics to include when constructing the final path diagnostic.
std::unique_ptr< ExplodedGraph > trim(ArrayRef< const NodeTy * > Nodes, InterExplodedGraphMap *ForwardMap=nullptr, InterExplodedGraphMap *InverseMap=nullptr) const
Creates a trimmed version of the graph that only contains paths leading to the given nodes...
ast_type_traits::DynTypedNode Node
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
if(T->getSizeExpr()) TRY_TO(TraverseStmt(T-> getSizeExpr()))
virtual void Profile(llvm::FoldingSetNodeID &hash) const
Profile to identify equivalent bug reports for error report coalescing.
static const char StrLoopCollectionEmpty[]
static const Stmt * getLocStmt(PathDiagnosticLocation L)
const LocationContext * getLocationContext() const
virtual ~BugReporterData()
PathDiagnosticLocation getUniqueingLocation() const
Get the location on which the report should be uniqued.
static bool GenerateMinimalPathDiagnostic(PathDiagnostic &PD, PathDiagnosticBuilder &PDB, const ExplodedNode *N, LocationContextMap &LCM, ArrayRef< std::unique_ptr< BugReporterVisitor >> visitors)
detail::InMemoryDirectory::const_iterator E
const MemRegion * getAsRegion() const
static const Stmt * getTerminatorCondition(const CFGBlock *B)
A customized wrapper for CFGBlock::getTerminatorCondition() which returns the element for ObjCForColl...
bool isBodyAutosynthesizedFromModelFile() const
Checks if the body of the Decl is generated by the BodyFarm from a model file.
Optional< T > getAs() const
Convert to the specified ProgramPoint type, returning None if this ProgramPoint is not of the desired...
void setEndLocation(const PathDiagnosticLocation &L)
static bool isLoop(const Stmt *Term)
const ExplodedNode *const * const_pred_iterator
Represents Objective-C's collection statement.
void setEndOfPath(std::unique_ptr< PathDiagnosticPiece > EndPiece)
void setCallStackMessage(StringRef st)
const Decl * getCaller() const
char __ovld __cnfn max(char x, char y)
Returns y if x < y, otherwise it returns x.
static PathDiagnosticLocation createOperatorLoc(const BinaryOperator *BO, const SourceManager &SM)
Create the location for the operator of the binary expression.
X
Add a minimal nested name specifier fixit hint to allow lookup of a tag name from an outer enclosing ...
PathDiagnosticRange asRange() const
ProgramStateManager & getStateManager()
getStateManager - Return the state manager used by the analysis engine.
static void CompactPathDiagnostic(PathPieces &path, const SourceManager &SM)
CompactPathDiagnostic - This function postprocesses a PathDiagnostic object and collapses PathDiagost...
PathPieces & getActivePath()
Return the path currently used by builders for constructing the PathDiagnostic.
void dump() const override
pred_iterator pred_begin()
static const Stmt * getStmtParent(const Stmt *S, const ParentMap &PM)
WhileStmt - This represents a 'while' stmt.
static PathDiagnosticLocation createEndOfPath(const ExplodedNode *N, const SourceManager &SM)
Create a location corresponding to the next valid ExplodedNode as end of path location.
llvm::DenseMap< const PathPieces *, const LocationContext * > LocationContextMap
A map from PathDiagnosticPiece to the LocationContext of the inlined function call it represents...
static void removeContextCycles(PathPieces &Path, SourceManager &SM, ParentMap &PM)
Eliminate two-edge cycles created by addContextEdges().
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
Loc getLValue(const VarDecl *D, const LocationContext *LC) const
Get the lvalue for a variable reference.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
static bool GenerateAlternateExtensivePathDiagnostic(PathDiagnostic &PD, PathDiagnosticBuilder &PDB, const ExplodedNode *N, LocationContextMap &LCM, ArrayRef< std::unique_ptr< BugReporterVisitor >> visitors)
A SourceLocation and its associated SourceManager.
PathDiagnosticLocation callEnterWithin
A reference to a declared variable, function, enum, etc.
FullSourceLoc getExpansionLoc() const
static bool GenerateExtensivePathDiagnostic(PathDiagnostic &PD, PathDiagnosticBuilder &PDB, const ExplodedNode *N, LocationContextMap &LCM, ArrayRef< std::unique_ptr< BugReporterVisitor >> visitors)
unsigned getFileOffset(SourceLocation SpellingLoc) const
Returns the offset from the start of the file that the specified SourceLocation represents.
DeclStmt * getLoopVarStmt()
A trivial tuple used to represent a source range.
static void addContextEdges(PathPieces &pieces, SourceManager &SM, const ParentMap &PM, const LocationContext *LCtx)
Adds synthetic edges from top-level statements to their subexpressions.
NamedDecl - This represents a decl with a name.
This class provides an interface through which checkers can create individual bug reports...
SourceLocation getExpansionLoc(SourceLocation Loc) const
Given a SourceLocation object Loc, return the expansion location referenced by the ID...
bool isWithinCall() const
bool shouldReportIssuesInMainSourceFile()
Returns whether or not the diagnostic report should be always reported in the main source file and no...
bool isValid() const
Returns whether or not this report should be considered valid.
static const char StrEnteringLoop[]
std::pair< PathDiagnosticCallPiece *, const ExplodedNode * > StackDiagPair
static const char StrLoopRangeEmpty[]
This class handles loading and caching of source files into memory.
Expr * IgnoreParens() LLVM_READONLY
IgnoreParens - Ignore parentheses.
static const char * getTag()
Return the tag associated with this visitor.
static bool isInLoopBody(ParentMap &PM, const Stmt *S, const Stmt *Term)