30 #include "llvm/ADT/DenseMap.h" 31 #include "llvm/ADT/IntrusiveRefCntPtr.h" 32 #include "llvm/ADT/STLExtras.h" 33 #include "llvm/ADT/SmallString.h" 34 #include "llvm/ADT/Statistic.h" 35 #include "llvm/Support/raw_ostream.h" 39 using namespace clang;
42 #define DEBUG_TYPE "BugReporter" 45 "The maximum number of bug reports in the same equivalence class");
47 "The maximum number of bug reports in the same equivalence class " 48 "where at least one report is valid (not suppressed)");
52 void BugReporterContext::anchor() {}
66 static inline const Stmt*
91 if (X->
getTag() == tagPreferred && Y->
getTag() == tagLesser)
94 if (Y->
getTag() == tagPreferred && X->
getTag() == tagLesser)
106 unsigned N = path.size();
113 for (
unsigned i = 0; i < N; ++i) {
114 auto piece = std::move(path.front());
117 switch (piece->getKind()) {
131 dyn_cast<PathDiagnosticEventPiece>(path.front().get())) {
133 cast<PathDiagnosticEventPiece>(piece.get());
137 if (
auto *pieceToKeep =
139 piece = std::move(pieceToKeep == event ? piece : path.front());
149 path.push_back(std::move(piece));
155 typedef llvm::DenseMap<const PathPieces *, const LocationContext *>
163 bool containsSomethingInteresting =
false;
164 const unsigned N = pieces.size();
166 for (
unsigned i = 0 ; i < N ; ++i) {
169 auto piece = std::move(pieces.front());
172 switch (piece->getKind()) {
174 auto &call = cast<PathDiagnosticCallPiece>(*piece);
176 assert(LCM.count(&call.path));
178 containsSomethingInteresting =
true;
185 containsSomethingInteresting =
true;
189 auto ¯o = cast<PathDiagnosticMacroPiece>(*piece);
192 containsSomethingInteresting =
true;
196 auto &
event = cast<PathDiagnosticEventPiece>(*piece);
200 containsSomethingInteresting |= !
event.isPrunable();
210 pieces.push_back(std::move(piece));
213 return containsSomethingInteresting;
228 for (PathPieces::iterator I = Pieces.begin(), E = Pieces.end(); I != E; ++I) {
235 if (LastCallLocation) {
252 assert(ThisCallLocation &&
"Outermost call has an invalid location");
261 for (PathPieces::iterator I = Pieces.begin(), E = Pieces.end(); I != E;) {
262 if (
auto *C = dyn_cast<PathDiagnosticCallPiece>(I->get()))
265 if (
auto *M = dyn_cast<PathDiagnosticMacroPiece>(I->get()))
268 if (
auto *CF = dyn_cast<PathDiagnosticControlFlowPiece>(I->get())) {
269 const Stmt *Start = CF->getStartLocation().asStmt();
270 const Stmt *
End = CF->getEndLocation().asStmt();
271 if (Start && isa<CXXDefaultInitExpr>(Start)) {
274 }
else if (End && isa<CXXDefaultInitExpr>(End)) {
275 PathPieces::iterator Next = std::next(I);
278 dyn_cast<PathDiagnosticControlFlowPiece>(Next->get())) {
279 NextCF->setStartLocation(CF->getStartLocation());
295 for (PathPieces::iterator I = Pieces.begin(), E = Pieces.end(); I != E;) {
296 if (
auto *C = dyn_cast<PathDiagnosticCallPiece>(I->get()))
299 if (
auto *M = dyn_cast<PathDiagnosticMacroPiece>(I->get()))
302 if (!(*I)->getLocation().isValid() ||
303 !(*I)->getLocation().asLocation().isValid()) {
351 const Stmt *getParent(
const Stmt *S) {
352 return getParentMap().getParent(S);
355 NodeMapClosure& getNodeResolver()
override {
return NMC; }
363 bool supportsLogicalOpControlFlow()
const {
370 PathDiagnosticBuilder::ExecutionContinues(
const ExplodedNode *N) {
379 PathDiagnosticBuilder::ExecutionContinues(llvm::raw_string_ostream &os,
383 if (os.str().empty())
389 os <<
"Execution continues on line " 390 << getSourceManager().getExpansionLineNumber(Loc.
asLocation())
393 os <<
"Execution jumps to the end of the ";
395 if (isa<ObjCMethodDecl>(D))
397 else if (isa<FunctionDecl>(D))
400 assert(isa<BlockDecl>(D));
401 os <<
"anonymous block";
418 case Stmt::ForStmtClass:
419 case Stmt::DoStmtClass:
420 case Stmt::WhileStmtClass:
421 case Stmt::ObjCForCollectionStmtClass:
422 case Stmt::CXXForRangeStmtClass:
438 switch (
Parent->getStmtClass()) {
439 case Stmt::BinaryOperatorClass: {
445 case Stmt::CompoundStmtClass:
446 case Stmt::StmtExprClass:
448 case Stmt::ChooseExprClass:
451 if (allowNestedContexts || cast<ChooseExpr>(
Parent)->getCond() == S)
455 case Stmt::BinaryConditionalOperatorClass:
456 case Stmt::ConditionalOperatorClass:
459 if (allowNestedContexts ||
460 cast<AbstractConditionalOperator>(
Parent)->getCond() == S)
464 case Stmt::CXXForRangeStmtClass:
465 if (cast<CXXForRangeStmt>(
Parent)->getBody() == S)
468 case Stmt::DoStmtClass:
470 case Stmt::ForStmtClass:
471 if (cast<ForStmt>(
Parent)->getBody() == S)
474 case Stmt::IfStmtClass:
475 if (cast<IfStmt>(
Parent)->getCond() != S)
478 case Stmt::ObjCForCollectionStmtClass:
479 if (cast<ObjCForCollectionStmt>(
Parent)->getBody() == S)
482 case Stmt::WhileStmtClass:
483 if (cast<WhileStmt>(
Parent)->getCond() != S)
493 assert(S &&
"Cannot have null Stmt for PathDiagnosticLocation");
500 assert(S &&
"Null Stmt passed to getEnclosingStmtLocation");
510 ArrayRef<std::unique_ptr<BugReporterVisitor>> visitors) {
519 for (
auto &V : visitors)
521 V->VisitNode(N, Pred, PDB, *R);
532 typedef std::pair<PathDiagnosticCallPiece*, const ExplodedNode*>
StackDiagPair;
541 if (ep->hasCallStackHint())
542 for (StackDiagVector::iterator I = CallStack.begin(),
543 E = CallStack.end(); I != E; ++I) {
546 std::string stackMsg = ep->getCallStackMessage(N);
562 ArrayRef<std::unique_ptr<BugReporterVisitor>> visitors) {
582 LCM[&C->path] = CE->getCalleeContext();
601 if (VisitedEntireCall) {
602 C = cast<PathDiagnosticCallPiece>(PD.
getActivePath().front().get());
604 const Decl *Caller = CE->getLocationContext()->getDecl();
607 LCM[&C->
path] = CE->getCalleeContext();
611 if (!CallStack.empty()) {
612 assert(CallStack.back().first == C);
613 CallStack.pop_back();
634 case Stmt::GotoStmtClass:
635 case Stmt::IndirectGotoStmtClass: {
642 llvm::raw_string_ostream os(sbuf);
645 os <<
"Control jumps to line " 648 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
653 case Stmt::SwitchStmtClass: {
656 llvm::raw_string_ostream os(sbuf);
663 os <<
"No cases match in the switch statement. " 664 "Control jumps to line " 667 case Stmt::DefaultStmtClass:
668 os <<
"Control jumps to the 'default' case at line " 672 case Stmt::CaseStmtClass: {
673 os <<
"Control jumps to 'case ";
674 const CaseStmt *Case = cast<CaseStmt>(S);
678 bool GetRawInt =
true;
680 if (
const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(LHS)) {
693 os << LHS->EvaluateKnownConstInt(PDB.getASTContext());
701 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
705 os <<
"'Default' branch taken. ";
708 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
715 case Stmt::BreakStmtClass:
716 case Stmt::ContinueStmtClass: {
718 llvm::raw_string_ostream os(sbuf);
721 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
727 case Stmt::BinaryConditionalOperatorClass:
728 case Stmt::ConditionalOperatorClass: {
730 llvm::raw_string_ostream os(sbuf);
731 os <<
"'?' condition is ";
741 End = PDB.getEnclosingStmtLocation(S);
744 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
750 case Stmt::BinaryOperatorClass: {
751 if (!PDB.supportsLogicalOpControlFlow())
756 llvm::raw_string_ostream os(sbuf);
757 os <<
"Left side of '";
760 os <<
"&&" <<
"' is ";
768 std::make_shared<PathDiagnosticControlFlowPiece>(Start,
End,
776 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
782 os <<
"||" <<
"' is ";
789 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
798 std::make_shared<PathDiagnosticControlFlowPiece>(Start,
End,
806 case Stmt::DoStmtClass: {
809 llvm::raw_string_ostream os(sbuf);
811 os <<
"Loop condition is true. ";
815 End = PDB.getEnclosingStmtLocation(S);
818 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
825 End = PDB.getEnclosingStmtLocation(S);
828 std::make_shared<PathDiagnosticControlFlowPiece>(
829 Start, End,
"Loop condition is false. Exiting loop"));
835 case Stmt::WhileStmtClass:
836 case Stmt::ForStmtClass: {
839 llvm::raw_string_ostream os(sbuf);
841 os <<
"Loop condition is false. ";
844 End = PDB.getEnclosingStmtLocation(S);
847 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
853 End = PDB.getEnclosingStmtLocation(S);
856 std::make_shared<PathDiagnosticControlFlowPiece>(
857 Start, End,
"Loop condition is true. Entering loop body"));
863 case Stmt::IfStmtClass: {
867 End = PDB.getEnclosingStmtLocation(S);
871 std::make_shared<PathDiagnosticControlFlowPiece>(
872 Start, End,
"Taking false branch"));
875 std::make_shared<PathDiagnosticControlFlowPiece>(
876 Start, End,
"Taking true branch"));
887 llvm::FoldingSet<PathDiagnosticPiece> DeduplicationSet;
888 for (
auto &V : visitors) {
889 if (
auto p = V->VisitNode(N, NextNode, PDB, *R)) {
890 if (DeduplicationSet.GetOrInsertNode(p.get()) != p.get())
900 if (!PDB.getBugReport()->isValid())
921 if (isa<AbstractConditionalOperator>(E))
925 if (B->isLogicalOp())
938 void markDead() { IsDead =
true; }
939 bool isDead()
const {
return IsDead; }
944 bool firstCharOnly =
false) {
946 const Stmt *Original = S;
953 case Stmt::ParenExprClass:
954 case Stmt::GenericSelectionExprClass:
955 S = cast<Expr>(S)->IgnoreParens();
956 firstCharOnly =
true;
958 case Stmt::BinaryConditionalOperatorClass:
959 case Stmt::ConditionalOperatorClass:
960 S = cast<AbstractConditionalOperator>(S)->getCond();
961 firstCharOnly =
true;
963 case Stmt::ChooseExprClass:
964 S = cast<ChooseExpr>(S)->getCond();
965 firstCharOnly =
true;
967 case Stmt::BinaryOperatorClass:
968 S = cast<BinaryOperator>(S)->getLHS();
969 firstCharOnly =
true;
987 std::vector<ContextLocation> CLocs;
988 typedef std::vector<ContextLocation>::iterator iterator;
990 PathDiagnosticBuilder &PDB;
1002 void popLocation() {
1003 if (!CLocs.back().isDead() && CLocs.back().asLocation().isFileID()) {
1005 rawAddEdge(cleanUpLocation(CLocs.back(), PDB.LC,
true));
1012 : PD(pd), PDB(pdb) {
1016 if (!PD.
path.empty()) {
1017 PrevLoc = (*PD.
path.begin())->getLocation();
1020 addExtendedContext(PDB.getEnclosingStmtLocation(S).asStmt());
1025 while (!CLocs.empty()) popLocation();
1031 PDB.getSourceManager());
1036 void flushLocations() {
1037 while (!CLocs.empty())
1043 bool IsPostJump =
false);
1047 void addContext(
const Stmt *S);
1049 void addExtendedContext(
const Stmt *S);
1060 return PDB.getEnclosingStmtLocation(S);
1069 if (Container == Containee)
1076 if (
const Stmt *ContainerS = Container.
asStmt()) {
1078 if (S == ContainerS)
1080 S = PDB.getParent(S);
1100 assert(ContainerBegLine <= ContainerEndLine);
1101 assert(ContaineeBegLine <= ContaineeEndLine);
1103 return (ContainerBegLine <= ContaineeBegLine &&
1104 ContainerEndLine >= ContaineeEndLine &&
1105 (ContainerBegLine != ContaineeBegLine ||
1108 (ContainerEndLine != ContaineeEndLine ||
1114 if (!PrevLoc.isValid()) {
1135 PD.getActivePath().push_front(
1136 std::make_shared<PathDiagnosticControlFlowPiece>(NewLocClean,
1149 while (!CLocs.empty()) {
1150 ContextLocation &TopContextLoc = CLocs.back();
1153 if (TopContextLoc == CLoc) {
1155 if (IsConsumedExpr(TopContextLoc))
1156 TopContextLoc.markDead();
1162 TopContextLoc.markDead();
1166 if (containsLocation(TopContextLoc, CLoc)) {
1170 if (IsConsumedExpr(CLoc)) {
1171 CLocs.push_back(ContextLocation(CLoc,
true));
1176 CLocs.push_back(ContextLocation(CLoc, IsPostJump));
1189 if (
const Expr *
X = dyn_cast_or_null<Expr>(L.
asStmt()))
1195 void EdgeBuilder::addExtendedContext(
const Stmt *S) {
1201 if (isa<CompoundStmt>(Parent))
1202 Parent = PDB.getParent(Parent);
1209 case Stmt::DoStmtClass:
1210 case Stmt::ObjCAtSynchronizedStmtClass:
1220 void EdgeBuilder::addContext(
const Stmt *S) {
1229 while (!CLocs.empty()) {
1233 if (TopContextLoc == L)
1236 if (containsLocation(TopContextLoc, L)) {
1272 if (!isa<CastExpr>(Ex))
1275 case Stmt::BinaryOperatorClass:
1276 case Stmt::UnaryOperatorClass: {
1278 if (
const Expr *child = dyn_cast_or_null<Expr>(SubStmt)) {
1300 if (
const CallExpr *CE = dyn_cast_or_null<CallExpr>(CallSite)) {
1303 PE = FD->param_end();
1305 for (; AI != AE && PI != PE; ++AI, ++PI) {
1306 if (
const Expr *ArgE = *AI) {
1324 case Stmt::ForStmtClass:
1325 case Stmt::WhileStmtClass:
1326 case Stmt::ObjCForCollectionStmtClass:
1327 case Stmt::CXXForRangeStmtClass:
1365 const Stmt *S = SP->getStmt();
1375 const Stmt *LoopBody =
nullptr;
1377 case Stmt::CXXForRangeStmtClass: {
1386 case Stmt::ForStmtClass: {
1387 const ForStmt *FS = cast<ForStmt>(Term);
1393 case Stmt::ObjCForCollectionStmtClass: {
1398 case Stmt::WhileStmtClass:
1399 LoopBody = cast<WhileStmt>(Term)->getBody();
1414 ArrayRef<std::unique_ptr<BugReporterVisitor>> visitors) {
1415 EdgeBuilder EB(PD, PDB);
1428 if (
const Expr *Ex = PS->getStmtAs<
Expr>())
1435 const Stmt *S = CE->getCalleeContext()->getCallSite();
1436 if (
const Expr *Ex = dyn_cast_or_null<Expr>(S)) {
1443 LCM[&C->path] = CE->getCalleeContext();
1445 EB.addEdge(C->callReturn,
true,
true);
1446 EB.flushLocations();
1459 const Decl *D = CE->getCalleeContext()->getDecl();
1466 EB.flushLocations();
1476 if (VisitedEntireCall) {
1477 C = cast<PathDiagnosticCallPiece>(PD.
getActivePath().front().get());
1479 const Decl *Caller = CE->getLocationContext()->getDecl();
1481 LCM[&C->
path] = CE->getCalleeContext();
1487 if (!CallStack.empty()) {
1488 assert(CallStack.back().first == C);
1489 CallStack.pop_back();
1507 if (CallerCtx != CalleeCtx) {
1510 CalleeCtx, CallerCtx);
1515 if (
const Stmt *Loop = BE->getSrc()->getLoopTarget()) {
1519 if (
const ForStmt *FS = dyn_cast<ForStmt>(Loop))
1521 else if (
const WhileStmt *WS = dyn_cast<WhileStmt>(Loop))
1522 CS = dyn_cast<CompoundStmt>(WS->getBody());
1524 auto p = std::make_shared<PathDiagnosticEventPiece>(
1525 L,
"Looping back to the head of the loop");
1526 p->setPrunable(
true);
1528 EB.addEdge(p->getLocation(),
true);
1538 const CFGBlock *BSrc = BE->getSrc();
1551 auto PE = std::make_shared<PathDiagnosticEventPiece>(
1552 L,
"Loop body executed 0 times");
1553 PE->setPrunable(
true);
1555 EB.addEdge(PE->getLocation(),
true);
1561 EB.addContext(Term);
1573 EB.addContext(stmt);
1576 EB.addExtendedContext(PDB.getEnclosingStmtLocation(stmt).asStmt());
1590 llvm::FoldingSet<PathDiagnosticPiece> DeduplicationSet;
1591 for (
auto &V : visitors) {
1592 if (
auto p = V->VisitNode(N, NextNode, PDB, *R)) {
1593 if (DeduplicationSet.GetOrInsertNode(p.get()) != p.get())
1597 EB.addEdge(Loc,
true);
1602 EB.addExtendedContext(PDB.getEnclosingStmtLocation(S).asStmt());
1607 return PDB.getBugReport()->isValid();
1633 std::make_shared<PathDiagnosticControlFlowPiece>(NewLoc, PrevLoc));
1642 dyn_cast_or_null<ObjCForCollectionStmt>(S))
1643 return FS->getElement();
1650 "Loop body skipped when range is empty";
1652 "Loop body skipped when collection is empty";
1657 ArrayRef<std::unique_ptr<BugReporterVisitor>> visitors) {
1696 if (VisitedEntireCall) {
1698 C = cast<PathDiagnosticCallPiece>(
P);
1700 const Decl *Caller = CE->getLocationContext()->getDecl();
1711 assert(LCM[&C->
path] ==
nullptr ||
1712 LCM[&C->
path] == CE->getCalleeContext());
1713 LCM[&C->
path] = CE->getCalleeContext();
1728 if (!CallStack.empty()) {
1729 assert(CallStack.back().first == C);
1730 CallStack.pop_back();
1747 const Stmt *S = CE->getCalleeContext()->getCallSite();
1749 if (
const Expr *Ex = dyn_cast_or_null<Expr>(S)) {
1760 LCM[&C->path] = CE->getCalleeContext();
1777 if (
const Expr *Ex = PS->getStmtAs<
Expr>())
1785 if (!isa<ObjCForCollectionStmt>(PS->getStmt())) {
1800 if (CallerCtx != CalleeCtx) {
1803 CalleeCtx, CallerCtx);
1808 if (
const Stmt *Loop = BE->getSrc()->getLoopTarget()) {
1810 const Stmt *Body =
nullptr;
1812 if (
const ForStmt *FS = dyn_cast<ForStmt>(Loop))
1813 Body = FS->getBody();
1814 else if (
const WhileStmt *WS = dyn_cast<WhileStmt>(Loop))
1815 Body = WS->getBody();
1817 dyn_cast<ObjCForCollectionStmt>(Loop)) {
1818 Body = OFS->getBody();
1820 dyn_cast<CXXForRangeStmt>(Loop)) {
1821 Body = FRS->getBody();
1825 auto p = std::make_shared<PathDiagnosticEventPiece>(
1826 L,
"Looping back to the head " 1828 p->setPrunable(
true);
1833 if (
const CompoundStmt *CS = dyn_cast_or_null<CompoundStmt>(Body)) {
1840 const CFGBlock *BSrc = BE->getSrc();
1843 if (
const Stmt *Term = BSrc->getTerminator()) {
1851 const char *str =
nullptr;
1854 if (!IsInLoopBody) {
1855 if (isa<ObjCForCollectionStmt>(Term)) {
1857 }
else if (isa<CXXForRangeStmt>(Term)) {
1869 auto PE = std::make_shared<PathDiagnosticEventPiece>(L, str);
1870 PE->setPrunable(
true);
1872 PE->getLocation(), PDB.LC);
1875 }
else if (isa<BreakStmt>(Term) || isa<ContinueStmt>(Term) ||
1876 isa<GotoStmt>(Term)) {
1889 llvm::FoldingSet<PathDiagnosticPiece> DeduplicationSet;
1890 for (
auto &V : visitors) {
1891 if (
auto p = V->VisitNode(N, NextNode, PDB, *report)) {
1892 if (DeduplicationSet.GetOrInsertNode(p.get()) != p.get())
1929 if (isa<ExprWithCleanups>(S) ||
1930 isa<CXXBindTemporaryExpr>(S) ||
1931 isa<SubstNonTypeTemplateParmExpr>(S))
1942 case Stmt::BinaryOperatorClass: {
1948 case Stmt::IfStmtClass:
1949 return cast<IfStmt>(S)->getCond() == Cond;
1950 case Stmt::ForStmtClass:
1951 return cast<ForStmt>(S)->getCond() == Cond;
1952 case Stmt::WhileStmtClass:
1953 return cast<WhileStmt>(S)->getCond() == Cond;
1954 case Stmt::DoStmtClass:
1955 return cast<DoStmt>(S)->getCond() == Cond;
1956 case Stmt::ChooseExprClass:
1957 return cast<ChooseExpr>(S)->getCond() == Cond;
1958 case Stmt::IndirectGotoStmtClass:
1959 return cast<IndirectGotoStmt>(S)->getTarget() == Cond;
1960 case Stmt::SwitchStmtClass:
1961 return cast<SwitchStmt>(S)->getCond() == Cond;
1962 case Stmt::BinaryConditionalOperatorClass:
1963 return cast<BinaryConditionalOperator>(S)->getCond() == Cond;
1964 case Stmt::ConditionalOperatorClass: {
1966 return CO->
getCond() == Cond ||
1970 case Stmt::ObjCForCollectionStmtClass:
1971 return cast<ObjCForCollectionStmt>(S)->getElement() == Cond;
1972 case Stmt::CXXForRangeStmtClass: {
1982 if (
const ForStmt *FS = dyn_cast<ForStmt>(FL))
1983 return FS->getInc() == S || FS->getInit() == S;
1985 return FRS->getInc() == S || FRS->getRangeStmt() == S ||
1986 FRS->getLoopVarStmt() || FRS->getRangeInit() == S;
2000 PathPieces::iterator Prev = pieces.end();
2001 for (PathPieces::iterator I = pieces.begin(), E = Prev; I != E;
2013 const Stmt *InnerStmt =
nullptr;
2014 while (NextSrcContext.
isValid() && NextSrcContext.
asStmt() != InnerStmt) {
2015 SrcContexts.push_back(NextSrcContext);
2016 InnerStmt = NextSrcContext.
asStmt();
2031 if (!DstContext.isValid() || DstContext.asStmt() == Dst)
2035 if (std::find(SrcContexts.begin(), SrcContexts.end(), DstContext) !=
2048 if (
const Stmt *PrevSrc =
getLocStmt(PrevPiece->getStartLocation())) {
2051 PrevPiece->setEndLocation(DstContext);
2062 std::make_shared<PathDiagnosticControlFlowPiece>(SrcLoc, DstContext);
2064 I = pieces.insert(I, std::move(
P));
2081 for (PathPieces::iterator I = pieces.begin(), E = pieces.end(); I != E; ++I) {
2091 if (!s1Start || !s1End)
2094 PathPieces::iterator NextI = I; ++NextI;
2106 StringRef S = EV->getString();
2125 if (!s2Start || !s2End || s1End != s2Start)
2130 if (!(isa<ForStmt>(s1Start) || isa<WhileStmt>(s1Start) ||
2131 isa<IfStmt>(s1Start) || isa<ObjCForCollectionStmt>(s1Start) ||
2132 isa<CXXForRangeStmt>(s1Start)))
2142 I = pieces.erase(I);
2161 const llvm::MemoryBuffer *Buffer = SM.
getBuffer(FID, &Invalid);
2167 StringRef Snippet = Buffer->getBuffer().slice(BeginOffset, EndOffset);
2173 if (Snippet.find_first_of(
"\r\n") != StringRef::npos)
2177 return Snippet.size();
2204 for (PathPieces::iterator I = Path.begin(), E = Path.end(); I != E; ) {
2217 PathPieces::iterator NextI = I; ++NextI;
2225 if (isa<PathDiagnosticEventPiece>(NextI->get())) {
2241 if (s1Start && s2Start && s1Start == s2End && s2Start == s1End) {
2242 const size_t MAX_SHORT_LINE_LENGTH = 80;
2244 if (s1Length && *s1Length <= MAX_SHORT_LINE_LENGTH) {
2246 if (s2Length && *s2Length <= MAX_SHORT_LINE_LENGTH) {
2248 I = Path.erase(NextI);
2275 bool erased =
false;
2277 for (PathPieces::iterator I = path.begin(), E = path.end(); I != E;
2306 std::swap(SecondLoc, FirstLoc);
2315 const size_t MAX_PUNY_EDGE_LENGTH = 2;
2316 if (*ByteWidth <= MAX_PUNY_EDGE_LENGTH) {
2328 for (PathPieces::iterator I = path.begin(), E = path.end(); I != E; ++I) {
2334 PathPieces::iterator NextI = I; ++NextI;
2344 if (PieceI->getString() == PieceNextI->getString()) {
2353 bool hasChanges =
false;
2358 for (PathPieces::iterator I = path.begin(), E = path.end(); I != E; ) {
2360 if (
auto *CallI = dyn_cast<PathDiagnosticCallPiece>(I->get())) {
2363 if (!OCS.count(CallI)) {
2384 PathPieces::iterator NextI = I; ++NextI;
2395 const Stmt *s2Start =
getLocStmt(PieceNextI->getStartLocation());
2415 if (level1 && level1 == level2 && level1 == level3 && level1 == level4) {
2416 PieceI->setEndLocation(PieceNextI->getEndLocation());
2430 if (s1End && s1End == s2Start && level2) {
2431 bool removeEdge =
false;
2457 else if (s1Start && s2End &&
2470 else if (s1Start && s2End &&
2472 SourceRange EdgeRange(PieceI->getEndLocation().asLocation(),
2473 PieceI->getStartLocation().asLocation());
2480 PieceI->setEndLocation(PieceNextI->getEndLocation());
2494 if (s1End == s2Start) {
2496 dyn_cast_or_null<ObjCForCollectionStmt>(level3);
2499 PieceI->setEndLocation(PieceNextI->getEndLocation());
2537 const auto *FirstEdge =
2542 const Decl *D = LCM[&Path]->getDecl();
2544 if (FirstEdge->getStartLocation() != EntryLoc)
2554 void BugType::anchor() { }
2558 void BuiltinBug::anchor() {}
2564 void BugReport::NodeResolver::anchor() {}
2570 llvm::FoldingSetNodeID
ID;
2571 visitor->Profile(ID);
2574 if (CallbacksSet.FindNodeOrInsertPos(ID, InsertPos))
2577 CallbacksSet.InsertNode(visitor.get(), InsertPos);
2578 Callbacks.push_back(std::move(visitor));
2579 ++ConfigurationChangeToken;
2583 while (!interestingSymbols.empty()) {
2584 popInterestingSymbolsAndRegions();
2590 return DeclWithIssue;
2601 hash.AddPointer(&BT);
2602 hash.AddString(Description);
2606 }
else if (Location.isValid()) {
2607 Location.Profile(hash);
2614 if (!range.isValid())
2616 hash.AddInteger(range.getBegin().getRawEncoding());
2617 hash.AddInteger(range.getEnd().getRawEncoding());
2626 if (getInterestingSymbols().insert(sym).second)
2627 ++ConfigurationChangeToken;
2630 getInterestingRegions().insert(meta->getRegion());
2639 if (getInterestingRegions().insert(R).second)
2640 ++ConfigurationChangeToken;
2643 getInterestingSymbols().insert(SR->getSymbol());
2654 InterestingLocationContexts.insert(LC);
2666 return getInterestingSymbols().count(sym);
2673 bool b = getInterestingRegions().count(R);
2677 return getInterestingSymbols().count(SR->getSymbol());
2684 return InterestingLocationContexts.count(LC);
2687 void BugReport::lazyInitializeInterestingSets() {
2688 if (interestingSymbols.empty()) {
2689 interestingSymbols.push_back(
new Symbols());
2690 interestingRegions.push_back(
new Regions());
2695 lazyInitializeInterestingSets();
2696 return *interestingSymbols.back();
2700 lazyInitializeInterestingSets();
2701 return *interestingRegions.back();
2704 void BugReport::pushInterestingSymbolsAndRegions() {
2705 interestingSymbols.push_back(
new Symbols(getInterestingSymbols()));
2706 interestingRegions.push_back(
new Regions(getInterestingRegions()));
2709 void BugReport::popInterestingSymbolsAndRegions() {
2710 delete interestingSymbols.pop_back_val();
2711 delete interestingRegions.pop_back_val();
2719 const Stmt *S =
nullptr;
2723 if (BE->getBlock() == &Exit)
2735 if (Ranges.empty()) {
2736 if (
const Expr *E = dyn_cast_or_null<Expr>(getStmt()))
2737 addRange(E->getSourceRange());
2743 if (Ranges.size() == 1 && !Ranges.begin()->isValid())
2746 return llvm::make_range(Ranges.begin(), Ranges.end());
2751 assert(!Location.isValid() &&
2752 "Either Location or ErrorNode should be specified but not both.");
2756 assert(Location.isValid());
2777 typedef std::vector<BugReportEquivClass *> ContTy;
2778 for (ContTy::iterator I = EQClassesVector.begin(), E = EQClassesVector.end();
2785 if (BugTypes.isEmpty())
2794 I = bugTypes.begin(), E = bugTypes.end(); I != E; ++I)
2795 const_cast<BugType*>(*I)->FlushReports(*
this);
2799 typedef std::vector<BugReportEquivClass *> ContVecTy;
2800 for (ContVecTy::iterator EI=EQClassesVector.begin(), EE=EQClassesVector.end();
2810 llvm::DeleteContainerSeconds(StrBugTypes);
2813 BugTypes = F.getEmptySet();
2826 std::unique_ptr<ExplodedGraph> Graph;
2832 class TrimmedGraph {
2835 typedef llvm::DenseMap<const ExplodedNode *, unsigned> PriorityMapTy;
2836 PriorityMapTy PriorityMap;
2838 typedef std::pair<const ExplodedNode *, size_t> NodeIndexPair;
2841 std::unique_ptr<ExplodedGraph> G;
2844 template <
bool Descending>
2845 class PriorityCompare {
2846 const PriorityMapTy &PriorityMap;
2849 PriorityCompare(
const PriorityMapTy &M) : PriorityMap(M) {}
2852 PriorityMapTy::const_iterator LI = PriorityMap.find(LHS);
2853 PriorityMapTy::const_iterator RI = PriorityMap.find(RHS);
2854 PriorityMapTy::const_iterator E = PriorityMap.end();
2861 return Descending ? LI->second > RI->second
2862 : LI->second < RI->second;
2865 bool operator()(
const NodeIndexPair &LHS,
const NodeIndexPair &RHS)
const {
2866 return (*
this)(LHS.first, RHS.first);
2874 bool popNextReportGraph(ReportGraph &GraphWrapper);
2878 TrimmedGraph::TrimmedGraph(
const ExplodedGraph *OriginalGraph,
2883 G = OriginalGraph->
trim(Nodes, &ForwardMap, &InverseMap);
2888 llvm::SmallPtrSet<const ExplodedNode *, 32> RemainingNodes;
2890 for (
unsigned i = 0, count = Nodes.size(); i < count; ++i) {
2891 if (
const ExplodedNode *NewNode = ForwardMap.lookup(Nodes[i])) {
2892 ReportNodes.push_back(std::make_pair(NewNode, i));
2893 RemainingNodes.insert(NewNode);
2897 assert(!RemainingNodes.empty() &&
"No error node found in the trimmed graph");
2900 std::queue<const ExplodedNode *> WS;
2902 assert(G->num_roots() == 1);
2903 WS.push(*G->roots_begin());
2904 unsigned Priority = 0;
2906 while (!WS.empty()) {
2910 PriorityMapTy::iterator PriorityEntry;
2912 std::tie(PriorityEntry, IsNew) =
2913 PriorityMap.insert(std::make_pair(Node, Priority));
2917 assert(PriorityEntry->second <= Priority);
2921 if (RemainingNodes.erase(Node))
2922 if (RemainingNodes.empty())
2932 std::sort(ReportNodes.begin(), ReportNodes.end(),
2933 PriorityCompare<true>(PriorityMap));
2936 bool TrimmedGraph::popNextReportGraph(ReportGraph &GraphWrapper) {
2937 if (ReportNodes.empty())
2941 std::tie(OrigN, GraphWrapper.Index) = ReportNodes.pop_back_val();
2942 assert(PriorityMap.find(OrigN) != PriorityMap.end() &&
2943 "error node not accessible from root");
2947 auto GNew = llvm::make_unique<ExplodedGraph>();
2948 GraphWrapper.BackMap.clear();
2960 InterExplodedGraphMap::const_iterator IMitr = InverseMap.find(OrigN);
2961 assert(IMitr != InverseMap.end() &&
"No mapping to original node.");
2962 GraphWrapper.BackMap[NewN] = IMitr->second;
2968 GraphWrapper.ErrorNode = NewN;
2974 GNew->addRoot(NewN);
2981 PriorityCompare<false>(PriorityMap));
2984 GraphWrapper.Graph = std::move(GNew);
2993 typedef std::vector<
2994 std::pair<std::shared_ptr<PathDiagnosticMacroPiece>,
SourceLocation>>
2997 typedef std::vector<std::shared_ptr<PathDiagnosticPiece>> PiecesTy;
2999 MacroStackTy MacroStack;
3002 for (PathPieces::const_iterator I = path.begin(), E = path.end();
3008 if (
auto *call = dyn_cast<PathDiagnosticCallPiece>(&*piece)) {
3023 Pieces.push_back(piece);
3030 if (!MacroStack.empty() && InstantiationLoc == MacroStack.back().second) {
3031 MacroStack.back().first->subPieces.push_back(piece);
3037 std::shared_ptr<PathDiagnosticMacroPiece> MacroGroup;
3044 while (!MacroStack.empty()) {
3045 if (InstantiationLoc == MacroStack.back().second) {
3046 MacroGroup = MacroStack.back().first;
3050 if (ParentInstantiationLoc == MacroStack.back().second) {
3051 MacroGroup = MacroStack.back().first;
3055 MacroStack.pop_back();
3058 if (!MacroGroup || ParentInstantiationLoc == MacroStack.back().second) {
3060 auto NewGroup = std::make_shared<PathDiagnosticMacroPiece>(
3064 MacroGroup->subPieces.push_back(NewGroup);
3066 assert(InstantiationLoc.
isFileID());
3067 Pieces.push_back(NewGroup);
3070 MacroGroup = NewGroup;
3071 MacroStack.push_back(std::make_pair(MacroGroup, InstantiationLoc));
3075 MacroGroup->subPieces.push_back(piece);
3081 path.insert(path.end(), Pieces.begin(), Pieces.end());
3087 assert(!bugReports.empty());
3089 bool HasValid =
false;
3090 bool HasInvalid =
false;
3093 E = bugReports.end(); I != E; ++I) {
3094 if ((*I)->isValid()) {
3096 errorNodes.push_back((*I)->getErrorNode());
3100 errorNodes.push_back(
nullptr);
3119 TrimmedGraph TrimG(&getGraph(), errorNodes);
3120 ReportGraph ErrorGraph;
3122 while (TrimG.popNextReportGraph(ErrorGraph)) {
3124 assert(ErrorGraph.Index < bugReports.size());
3125 BugReport *R = bugReports[ErrorGraph.Index];
3126 assert(R &&
"No original report found for sliced graph.");
3127 assert(R->isValid() &&
"Report selected by trimmed graph marked invalid.");
3130 PathDiagnosticBuilder PDB(*
this, R, ErrorGraph.BackMap, &PC);
3134 R->addVisitor(llvm::make_unique<NilReceiverBRVisitor>());
3135 R->addVisitor(llvm::make_unique<ConditionBRVisitor>());
3136 R->addVisitor(llvm::make_unique<LikelyFalsePositiveSuppressionBRVisitor>());
3137 R->addVisitor(llvm::make_unique<CXXSelfAssignmentBRVisitor>());
3140 unsigned origReportConfigToken, finalReportConfigToken;
3150 E = R->visitor_end(); I != E; ++I)
3151 visitors.push_back((*I)->clone());
3155 origReportConfigToken = R->getConfigurationChangeToken();
3159 std::unique_ptr<PathDiagnosticPiece> LastPiece;
3162 if (std::unique_ptr<PathDiagnosticPiece> Piece =
3163 (*I)->getEndPath(PDB, N, *R)) {
3164 assert (!LastPiece &&
3165 "There can only be one final piece in a diagnostic.");
3166 LastPiece = std::move(Piece);
3181 switch (ActiveScheme) {
3200 finalReportConfigToken = R->getConfigurationChangeToken();
3201 }
while (finalReportConfigToken != origReportConfigToken);
3207 if (!PD.
path.empty()) {
3208 if (R->shouldPrunePath() && getAnalyzerOptions().shouldPrunePaths()) {
3210 assert(stillHasNotes);
3211 (void)stillHasNotes;
3244 assert(!HasInvalid &&
"Inconsistent suppression");
3250 BugTypes = F.add(BugTypes, BT);
3257 assert((E->isSink() || E->getLocation().getTag()) &&
3258 "Error node must either be a sink or have a tag");
3261 E->getLocationContext()->getAnalysisDeclContext();
3271 bool ValidSourceLoc = R->getLocation(getSourceManager()).isValid();
3272 assert(ValidSourceLoc);
3275 if (!ValidSourceLoc)
3279 llvm::FoldingSetNodeID
ID;
3283 BugType& BT = R->getBugType();
3290 EQClasses.InsertNode(EQ, InsertPos);
3291 EQClassesVector.push_back(EQ);
3293 EQ->AddReport(std::move(R));
3302 struct FRIEC_WLItem {
3314 return BEP->getBlock();
3342 if (isa<CXXThrowExpr>(StmtElm->getStmt()))
3365 llvm::SmallPtrSet<const CFGBlock *, 32> Visited;
3367 DFSWorkList.push_back(StartBlk);
3368 while (!DFSWorkList.empty()) {
3369 const CFGBlock *Blk = DFSWorkList.back();
3370 DFSWorkList.pop_back();
3371 Visited.insert(Blk);
3373 for (
const auto &Succ : Blk->
succs()) {
3374 if (
const CFGBlock *SuccBlk = Succ.getReachableBlock()) {
3375 if (SuccBlk == &Cfg.
getExit()) {
3386 DFSWorkList.push_back(SuccBlk);
3402 BugType& BT = I->getBugType();
3413 bugReports.push_back(R);
3427 for (; I != E; ++I) {
3432 if (errorNode->
isSink()) {
3434 "BugType::isSuppressSink() should not be 'true' for sink end nodes");
3438 bugReports.push_back(&*I);
3440 exampleReport = &*I;
3453 typedef FRIEC_WLItem WLItem;
3455 llvm::DenseMap<const ExplodedNode *, unsigned> Visited;
3458 WL.push_back(errorNode);
3459 Visited[errorNode] = 1;
3461 while (!WL.empty()) {
3462 WLItem &WI = WL.back();
3463 assert(!WI.N->succ_empty());
3465 for (; WI.I != WI.E; ++WI.I) {
3471 bugReports.push_back(&*I);
3473 exampleReport = &*I;
3482 unsigned &mark = Visited[Succ];
3492 if (!WL.empty() && &WL.back() == &WI)
3499 return exampleReport;
3505 if (exampleReport) {
3507 FlushReport(exampleReport, *PDC, bugReports);
3512 void BugReporter::FlushReport(
BugReport *exampleReport,
3533 assert(!bugReports.empty());
3535 MaxBugClassSize.updateMax(bugReports.size());
3537 if (!generatePathDiagnostic(*D.get(), PD, bugReports))
3540 MaxValidBugClassSize.updateMax(bugReports.size());
3546 D->resetDiagnosticLocationToMainFile();
3551 if (D->path.empty()) {
3553 auto piece = llvm::make_unique<PathDiagnosticEventPiece>(
3556 piece->addRange(Range);
3557 D->setEndOfPath(std::move(piece));
3561 if (getAnalyzerOptions().shouldDisplayNotesAsEvents()) {
3564 for (
auto I = exampleReport->
getNotes().rbegin(),
3565 E = exampleReport->
getNotes().rend(); I != E; ++I) {
3567 auto ConvertedPiece = std::make_shared<PathDiagnosticEventPiece>(
3570 ConvertedPiece->addRange(R);
3572 Pieces.push_front(std::move(ConvertedPiece));
3575 for (
auto I = exampleReport->
getNotes().rbegin(),
3576 E = exampleReport->
getNotes().rend(); I != E; ++I)
3577 Pieces.push_front(*I);
3582 for (BugReport::ExtraTextList::const_iterator i = Meta.begin(),
3583 e = Meta.end(); i != e; ++i) {
3592 StringRef Name, StringRef
Category,
3600 StringRef name, StringRef category,
3605 BugType *BT = getBugTypeForName(CheckName, name, category);
3606 auto R = llvm::make_unique<BugReport>(*BT, str, Loc);
3607 R->setDeclWithIssue(DeclWithIssue);
3611 emitReport(std::move(R));
3615 StringRef category) {
3617 llvm::raw_svector_ostream(fullDesc) << CheckName.
getName() <<
":" << name
3619 BugType *&BT = StrBugTypes[fullDesc];
3621 BT =
new BugType(CheckName, name, category);
3627 for (PathPieces::const_iterator I = begin(), E = end(); I != E; ++I) {
3628 llvm::errs() <<
"[" << index++ <<
"] ";
3630 llvm::errs() <<
"\n";
3635 llvm::errs() <<
"CALL\n--------------\n";
3639 else if (
const NamedDecl *ND = dyn_cast<NamedDecl>(getCallee()))
3640 llvm::errs() << *ND <<
"\n";
3642 getLocation().dump();
3646 llvm::errs() <<
"EVENT\n--------------\n";
3647 llvm::errs() << getString() <<
"\n";
3648 llvm::errs() <<
" ---- at ----\n";
3649 getLocation().dump();
3653 llvm::errs() <<
"CONTROL\n--------------\n";
3654 getStartLocation().dump();
3655 llvm::errs() <<
" ---- to ----\n";
3656 getEndLocation().dump();
3660 llvm::errs() <<
"MACRO\n--------------\n";
3665 llvm::errs() <<
"NOTE\n--------------\n";
3666 llvm::errs() << getString() <<
"\n";
3667 llvm::errs() <<
" ---- at ----\n";
3668 getLocation().dump();
3673 llvm::errs() <<
"<INVALID>\n";
3680 llvm::errs() <<
"<range>\n";
3683 asLocation().dump();
3684 llvm::errs() <<
"\n";
3690 llvm::errs() <<
"<NULL STMT>\n";
3693 if (
const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(D))
3694 llvm::errs() << *ND <<
"\n";
3695 else if (isa<BlockDecl>(D))
3697 llvm::errs() <<
"<block>\n";
3699 llvm::errs() <<
"<unknown decl>\n";
3701 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.
bool isWrittenInSameFile(SourceLocation Loc1, SourceLocation Loc2) const
Returns true if the spelling locations for both SourceLocations are part of the same file buffer...
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...
An instance of this class is created to represent a function declaration or definition.
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.
if(T->getSizeExpr()) TRY_TO(TraverseStmt(T -> getSizeExpr()))
MemRegion - The root abstract class for all memory regions.
PathDiagnosticLocation getUniqueingLocation() const
Get the location on which the report should be uniqued.
bool hasCallStackMessage()
bool isInteresting(SymbolRef sym)
PathDiagnosticLocation getLocation() const override
const internal::VariadicAllOfMatcher< Stmt > stmt
Matches statements.
succ_iterator succ_begin()
CFGStmtMap * getCFGStmtMap()
FullSourceLoc getExpansionLoc() const
Stmt - This represents one statement.
EnumConstantDecl - An instance of this object exists for each enum constant that is defined...
Defines the SourceManager interface.
CheckName getCheckName() const
const CFGBlock * getSrc() const
Decl - This represents one declaration (or definition), e.g.
Represents a point when we begin processing an inlined call.
StringRef getDescription() const
bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const
Determines the order of 2 source locations in the translation unit.
Stmt * getParent(Stmt *) const
void Profile(llvm::FoldingSetNodeID &ID) const
SmallVector< StackDiagPair, 6 > StackDiagVector
Loc getLValue(const VarDecl *D, const LocationContext *LC) const
Get the lvalue for a variable reference.
static void adjustCallLocations(PathPieces &Pieces, PathDiagnosticLocation *LastCallLocation=nullptr)
Recursively scan through a path and make sure that all call pieces have valid locations.
const ProgramStateRef & getState() const
static std::shared_ptr< PathDiagnosticCallPiece > construct(const ExplodedNode *N, const CallExitEnd &CE, const SourceManager &SM)
ArrayRef< ParmVarDecl * >::const_iterator param_const_iterator
void dump() const override
PathDiagnosticLocation getStartLocation() const
virtual PathDiagnosticLocation getLocation(const SourceManager &SM) const
Return the "definitive" location of the reported bug.
static PathDiagnosticLocation createEndBrace(const CompoundStmt *CS, const SourceManager &SM)
Create a location for the end of the compound statement.
unsigned succ_size() const
static bool optimizeEdges(PathPieces &path, SourceManager &SM, OptimizedCallsSet &OCS, LocationContextMap &LCM)
bool isConsumedExpr(Expr *E) const
static const Stmt * GetCurrentOrPreviousStmt(const ExplodedNode *N)
const Decl & getCodeDecl() const
static bool isConditionForTerminator(const Stmt *S, const Stmt *Cond)
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
PathDiagnosticLocation getLocation() const
PathDiagnostic - PathDiagnostic objects represent a single path-sensitive diagnostic.
void setStartLocation(const PathDiagnosticLocation &L)
bool isValid() const
Returns whether or not this report should be considered valid.
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)
StringRef getName() const
static const char StrLoopBodyZero[]
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...
void dump() const override
static const CFGBlock * findBlockForNode(const ExplodedNode *N)
void pushActivePath(PathPieces *p)
void addPredecessor(ExplodedNode *V, ExplodedGraph &G)
addPredeccessor - Adds a predecessor to the current node, and in tandem add this node as a successor ...
virtual bool supportsLogicalOpControlFlow() const
PathPieces & getMutablePieces()
Return a mutable version of 'path'.
virtual llvm::iterator_range< ranges_iterator > getRanges()
Get the SourceRanges associated with the report.
const Decl * asDecl() const
static bool IsControlFlowExpr(const Stmt *S)
StringRef getCategory() const
const Stmt * getStmt() const
virtual void FlushReports(BugReporter &BR)
const BugType & getBugType() const
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()
const Stmt * asStmt() const
static bool isJumpToFalseBranch(const BlockEdge *BE)
SourceLocation getExpansionLoc(SourceLocation Loc) const
Given a SourceLocation object Loc, return the expansion location referenced by the ID...
const StackFrameContext * getCurrentStackFrame() const
const LocationContext * getLocationContext() const
A builtin binary operation expression such as "x + y" or "x <= y".
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.
bool generatePathDiagnostic(PathDiagnostic &PD, PathDiagnosticConsumer &PC, ArrayRef< BugReport *> &bugReports) override
Generates a path corresponding to one of the given bug reports.
const Decl * getDeclWithIssue() const
Return the canonical declaration, be it a method or class, where this issue semantically occurred...
static const Stmt * getStmtBeforeCond(ParentMap &PM, const Stmt *Term, const ExplodedNode *N)
ExplodedNode * getFirstPred()
PathDiagnosticLocation callEnter
static void reversePropagateIntererstingSymbols(BugReport &R, InterestingExprs &IE, const ProgramState *State, const Expr *Ex, const LocationContext *LCtx)
static BugReport * FindReportInEquivalenceClass(BugReportEquivClass &EQ, SmallVectorImpl< BugReport *> &bugReports)
void addVisitor(std::unique_ptr< BugReporterVisitor > visitor)
Add custom or predefined bug report visitors to this report.
SVal getSVal(const Stmt *S, const LocationContext *LCtx) const
Returns the SVal bound to the statement 'S' in the state's environment.
PathDiagnosticLocation getEndLocation() const
virtual const NoteList & getNotes()
llvm::DenseSet< const Expr * > InterestingExprs
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
ConditionalOperator - The ?: ternary operator.
Const iterator for iterating over Stmt * arrays that contain only Expr *.
CompoundStmt - This represents a group of statements like { stmt stmt }.
const Stmt * getCallSite() const
StringRef getName() const
const void * getTag() const
Return the opaque tag (if any) on the PathDiagnosticPiece.
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.
bool isBodyAutosynthesizedFromModelFile() const
Checks if the body of the Decl is generated by the BodyFarm from a model file.
virtual const ExtraTextList & getExtraText()
STATISTIC(MaxBugClassSize, "The maximum number of bug reports in the same equivalence class")
ProgramState - This class encapsulates:
Expr - This represents one expression.
Stmt * getTerminatorCondition(bool StripParens=true)
CFG - Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt...
const FunctionProtoType * T
static bool isPieceMessageGeneric(const PathDiagnosticPiece *Piece)
CFGBlock * getBlock(Stmt *S)
Returns the CFGBlock the specified Stmt* appears in.
~GRBugReporter() override
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
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)
const SourceManager & getManager() const
const Decl * getUniqueingDecl() const
Get the declaration containing the uniqueing location.
void Register(BugType *BT)
static const Stmt * getNextStmt(const ExplodedNode *N)
Retrieve the statement corresponding to the successor node.
void FlushReports()
Generate and flush diagnostics for all bug reports.
const CFGBlock * getDst() const
static void dropFunctionEntryEdge(PathPieces &Path, LocationContextMap &LCM, SourceManager &SM)
Drop the very first edge in a path, which should be a function entry edge.
bool isBodyAutosynthesized() const
Checks if the body of the Decl is generated by the BodyFarm.
SourceLocation getEnd() const
void markInteresting(SymbolRef sym)
static const Stmt * GetPreviousStmt(const ExplodedNode *N)
unsigned getExpansionLineNumber(SourceLocation Loc, bool *Invalid=nullptr) const
bool getBooleanOption(StringRef Name, bool DefaultVal, const ento::CheckerBase *C=nullptr, bool SearchInParents=false)
Interprets an option's string value as a boolean.
ParentMap & getParentMap() const
static bool GenerateVisitorsOnlyPathDiagnostic(PathDiagnostic &PD, PathDiagnosticBuilder &PDB, const ExplodedNode *N, ArrayRef< std::unique_ptr< BugReporterVisitor >> visitors)
llvm::ilist< BugReport >::iterator iterator
virtual bool hasBody() const
Returns true if this Decl represents a declaration for a body of code, such as a function or method d...
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...
unsigned getFileOffset(SourceLocation SpellingLoc) const
Returns the offset from the start of the file that the specified SourceLocation represents.
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)
static std::unique_ptr< PathDiagnosticPiece > getDefaultEndPath(BugReporterContext &BRC, const ExplodedNode *N, BugReport &BR)
Generates the default final diagnostic piece.
const Decl * getCallee() const
llvm::MemoryBuffer * getBuffer(FileID FID, SourceLocation Loc, bool *Invalid=nullptr) const
Return the buffer for the specified FileID.
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)
Stmt * getParentIgnoreParens(Stmt *) const
const ExplodedNode *const * const_succ_iterator
const MemRegion * getAsRegion() const
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 setCallee(const CallEnter &CE, const SourceManager &SM)
ProgramPoint getLocation() const
getLocation - Returns the edge associated with the given node.
SVal - This represents a symbolic expression, which can be either an L-value or an R-value...
FullSourceLoc asLocation() const
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)
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...
ast_type_traits::DynTypedNode Node
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
unsigned getExpansionColumnNumber(SourceLocation Loc, bool *Invalid=nullptr) const
ArrayRef< SourceRange > getRanges() const
Return the SourceRanges associated with this PathDiagnosticPiece.
Dataflow Directional Tag Classes.
static const char StrLoopCollectionEmpty[]
bool isValid() const
Return true if this is a valid SourceLocation object.
static const Stmt * getLocStmt(PathDiagnosticLocation L)
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...
PathDiagnosticRange asRange() const
virtual ~BugReporterData()
StmtClass getStmtClass() const
static void updateStackPiecesWithMessage(PathDiagnosticPiece &P, StackDiagVector &CallStack)
StringRef getCheckName() const
static bool GenerateMinimalPathDiagnostic(PathDiagnostic &PD, PathDiagnosticBuilder &PDB, const ExplodedNode *N, LocationContextMap &LCM, ArrayRef< std::unique_ptr< BugReporterVisitor >> visitors)
static const Stmt * getTerminatorCondition(const CFGBlock *B)
A customized wrapper for CFGBlock::getTerminatorCondition() which returns the element for ObjCForColl...
bool isWithinCall() const
const Decl * getDecl() const
unsigned getExpansionLineNumber(bool *Invalid=nullptr) const
static bool isLoop(const Stmt *Term)
FileID getFileID(SourceLocation SpellingLoc) const
Return the FileID for a SourceLocation.
virtual PathGenerationScheme getGenerationScheme() const
void dump() const
Dumps the specified AST fragment and all subtrees to llvm::errs().
const ExplodedNode *const * const_pred_iterator
Represents Objective-C's collection statement.
void setEndOfPath(std::unique_ptr< PathDiagnosticPiece > EndPiece)
const ExplodedNode * getErrorNode() const
const LocationContext * getLocationContext() const
void setCallStackMessage(StringRef st)
virtual void Profile(llvm::FoldingSetNodeID &hash) const
Profile to identify equivalent bug reports for error report coalescing.
SVal getRawSVal(Loc LV, QualType T=QualType()) const
Returns the "raw" SVal bound to LV before any value simplfication.
StringRef getShortDescription(bool UseFallback=true) const
static bool isInevitablySinking(const ExplodedNode *N)
bool hasNoReturnElement() const
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 ...
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()
const Decl * getCaller() const
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...
CFGElement - Represents a top-level expression in a basic block.
static void removeContextCycles(PathPieces &Path, SourceManager &SM, ParentMap &PM)
Eliminate two-edge cycles created by addContextEdges().
const MemRegion * getBaseRegion() const
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
static bool isImmediateSinkBlock(const CFGBlock *Blk)
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.
bool isSuppressOnSink() const
isSuppressOnSink - Returns true if bug reports associated with this bug type should be suppressed if ...
static bool GenerateExtensivePathDiagnostic(PathDiagnostic &PD, PathDiagnosticBuilder &PDB, const ExplodedNode *N, LocationContextMap &LCM, ArrayRef< std::unique_ptr< BugReporterVisitor >> visitors)
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.
Optional< T > getAs() const
Convert to the specified ProgramPoint type, returning None if this ProgramPoint is not of the desired...
This class provides an interface through which checkers can create individual bug reports...
AnalysisDeclContext * getAnalysisDeclContext() const
bool shouldReportIssuesInMainSourceFile()
Returns whether or not the diagnostic report should be always reported in the main source file and no...
StringRef getString() const
static const char StrEnteringLoop[]
SourceLocation getLocStart() const LLVM_READONLY
SourceLocation getBegin() const
std::pair< PathDiagnosticCallPiece *, const ExplodedNode * > StackDiagPair
static const char StrLoopRangeEmpty[]
This class handles loading and caching of source files into memory.
bool isPathSensitive() const
True when the report has an execution path associated with it.
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)