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) {
232 assert((*I)->getLocation().asLocation().isValid());
236 if (LastCallLocation) {
253 assert(ThisCallLocation &&
"Outermost call has an invalid location");
262 for (PathPieces::iterator
I = Pieces.begin(),
E = Pieces.end();
I !=
E;) {
263 if (
auto *C = dyn_cast<PathDiagnosticCallPiece>(
I->get()))
266 if (
auto *M = dyn_cast<PathDiagnosticMacroPiece>(
I->get()))
269 if (
auto *CF = dyn_cast<PathDiagnosticControlFlowPiece>(
I->get())) {
270 const Stmt *Start = CF->getStartLocation().asStmt();
271 const Stmt *
End = CF->getEndLocation().asStmt();
272 if (Start && isa<CXXDefaultInitExpr>(Start)) {
275 }
else if (End && isa<CXXDefaultInitExpr>(End)) {
276 PathPieces::iterator
Next = std::next(
I);
279 dyn_cast<PathDiagnosticControlFlowPiece>(Next->get())) {
280 NextCF->setStartLocation(CF->getStartLocation());
296 for (PathPieces::iterator
I = Pieces.begin(),
E = Pieces.end();
I !=
E;) {
297 if (
auto *C = dyn_cast<PathDiagnosticCallPiece>(
I->get()))
300 if (
auto *M = dyn_cast<PathDiagnosticMacroPiece>(
I->get()))
303 if (!(*I)->getLocation().isValid() ||
304 !(*I)->getLocation().asLocation().isValid()) {
338 R(r), PDC(pdc), NMC(Backmap), LC(r->getErrorNode()->getLocationContext())
348 Decl const &getCodeDecl() {
return R->getErrorNode()->getCodeDecl(); }
350 ParentMap& getParentMap() {
return LC->getParentMap(); }
353 return getParentMap().getParent(S);
356 NodeMapClosure& getNodeResolver()
override {
return NMC; }
364 bool supportsLogicalOpControlFlow()
const {
365 return PDC ? PDC->supportsLogicalOpControlFlow() :
true;
371 PathDiagnosticBuilder::ExecutionContinues(
const ExplodedNode *N) {
380 PathDiagnosticBuilder::ExecutionContinues(llvm::raw_string_ostream &os,
384 if (os.str().empty())
390 os <<
"Execution continues on line "
391 << getSourceManager().getExpansionLineNumber(Loc.
asLocation())
394 os <<
"Execution jumps to the end of the ";
396 if (isa<ObjCMethodDecl>(D))
398 else if (isa<FunctionDecl>(D))
401 assert(isa<BlockDecl>(D));
402 os <<
"anonymous block";
419 case Stmt::ForStmtClass:
420 case Stmt::DoStmtClass:
421 case Stmt::WhileStmtClass:
422 case Stmt::ObjCForCollectionStmtClass:
423 case Stmt::CXXForRangeStmtClass:
439 switch (Parent->getStmtClass()) {
440 case Stmt::BinaryOperatorClass: {
446 case Stmt::CompoundStmtClass:
447 case Stmt::StmtExprClass:
449 case Stmt::ChooseExprClass:
452 if (allowNestedContexts || cast<ChooseExpr>(Parent)->getCond() == S)
456 case Stmt::BinaryConditionalOperatorClass:
457 case Stmt::ConditionalOperatorClass:
460 if (allowNestedContexts ||
461 cast<AbstractConditionalOperator>(Parent)->getCond() == S)
465 case Stmt::CXXForRangeStmtClass:
466 if (cast<CXXForRangeStmt>(Parent)->getBody() == S)
469 case Stmt::DoStmtClass:
471 case Stmt::ForStmtClass:
472 if (cast<ForStmt>(Parent)->getBody() == S)
475 case Stmt::IfStmtClass:
476 if (cast<IfStmt>(Parent)->getCond() != S)
479 case Stmt::ObjCForCollectionStmtClass:
480 if (cast<ObjCForCollectionStmt>(Parent)->getBody() == S)
483 case Stmt::WhileStmtClass:
484 if (cast<WhileStmt>(Parent)->getCond() != S)
494 assert(S &&
"Cannot have null Stmt for PathDiagnosticLocation");
501 assert(S &&
"Null Stmt passed to getEnclosingStmtLocation");
511 ArrayRef<std::unique_ptr<BugReporterVisitor>> visitors) {
520 for (
auto &V : visitors)
522 V->VisitNode(N, Pred, PDB, *R);
533 typedef std::pair<PathDiagnosticCallPiece*, const ExplodedNode*>
StackDiagPair;
542 if (ep->hasCallStackHint())
543 for (StackDiagVector::iterator
I = CallStack.begin(),
544 E = CallStack.end();
I !=
E; ++
I) {
547 std::string stackMsg = ep->getCallStackMessage(N);
563 ArrayRef<std::unique_ptr<BugReporterVisitor>> visitors) {
583 LCM[&C->path] = CE->getCalleeContext();
602 if (VisitedEntireCall) {
603 C = cast<PathDiagnosticCallPiece>(PD.
getActivePath().front().get());
605 const Decl *Caller = CE->getLocationContext()->getDecl();
608 LCM[&C->
path] = CE->getCalleeContext();
612 if (!CallStack.empty()) {
613 assert(CallStack.back().first == C);
614 CallStack.pop_back();
635 case Stmt::GotoStmtClass:
636 case Stmt::IndirectGotoStmtClass: {
643 llvm::raw_string_ostream os(sbuf);
646 os <<
"Control jumps to line "
649 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
654 case Stmt::SwitchStmtClass: {
657 llvm::raw_string_ostream os(sbuf);
664 os <<
"No cases match in the switch statement. "
665 "Control jumps to line "
668 case Stmt::DefaultStmtClass:
669 os <<
"Control jumps to the 'default' case at line "
673 case Stmt::CaseStmtClass: {
674 os <<
"Control jumps to 'case ";
675 const CaseStmt *Case = cast<CaseStmt>(
S);
679 bool GetRawInt =
true;
681 if (
const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(LHS)) {
694 os << LHS->EvaluateKnownConstInt(PDB.getASTContext());
702 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
706 os <<
"'Default' branch taken. ";
709 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
716 case Stmt::BreakStmtClass:
717 case Stmt::ContinueStmtClass: {
719 llvm::raw_string_ostream os(sbuf);
722 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
728 case Stmt::BinaryConditionalOperatorClass:
729 case Stmt::ConditionalOperatorClass: {
731 llvm::raw_string_ostream os(sbuf);
732 os <<
"'?' condition is ";
742 End = PDB.getEnclosingStmtLocation(S);
745 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
751 case Stmt::BinaryOperatorClass: {
752 if (!PDB.supportsLogicalOpControlFlow())
757 llvm::raw_string_ostream os(sbuf);
758 os <<
"Left side of '";
761 os <<
"&&" <<
"' is ";
769 std::make_shared<PathDiagnosticControlFlowPiece>(Start,
End,
777 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
783 os <<
"||" <<
"' is ";
790 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
799 std::make_shared<PathDiagnosticControlFlowPiece>(Start,
End,
807 case Stmt::DoStmtClass: {
810 llvm::raw_string_ostream os(sbuf);
812 os <<
"Loop condition is true. ";
816 End = PDB.getEnclosingStmtLocation(S);
819 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
826 End = PDB.getEnclosingStmtLocation(S);
829 std::make_shared<PathDiagnosticControlFlowPiece>(
830 Start, End,
"Loop condition is false. Exiting loop"));
836 case Stmt::WhileStmtClass:
837 case Stmt::ForStmtClass: {
840 llvm::raw_string_ostream os(sbuf);
842 os <<
"Loop condition is false. ";
845 End = PDB.getEnclosingStmtLocation(S);
848 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
854 End = PDB.getEnclosingStmtLocation(S);
857 std::make_shared<PathDiagnosticControlFlowPiece>(
858 Start, End,
"Loop condition is true. Entering loop body"));
864 case Stmt::IfStmtClass: {
868 End = PDB.getEnclosingStmtLocation(S);
872 std::make_shared<PathDiagnosticControlFlowPiece>(
873 Start, End,
"Taking false branch"));
876 std::make_shared<PathDiagnosticControlFlowPiece>(
877 Start, End,
"Taking true branch"));
888 for (
auto &V : visitors) {
889 if (
auto p = V->VisitNode(N, NextNode, PDB, *R)) {
897 if (!PDB.getBugReport()->isValid())
918 if (isa<AbstractConditionalOperator>(E))
922 if (B->isLogicalOp())
935 void markDead() { IsDead =
true; }
936 bool isDead()
const {
return IsDead; }
941 bool firstCharOnly =
false) {
943 const Stmt *Original =
S;
950 case Stmt::ParenExprClass:
951 case Stmt::GenericSelectionExprClass:
952 S = cast<Expr>(
S)->IgnoreParens();
953 firstCharOnly =
true;
955 case Stmt::BinaryConditionalOperatorClass:
956 case Stmt::ConditionalOperatorClass:
957 S = cast<AbstractConditionalOperator>(
S)->getCond();
958 firstCharOnly =
true;
960 case Stmt::ChooseExprClass:
961 S = cast<ChooseExpr>(
S)->getCond();
962 firstCharOnly =
true;
964 case Stmt::BinaryOperatorClass:
965 S = cast<BinaryOperator>(
S)->getLHS();
966 firstCharOnly =
true;
984 std::vector<ContextLocation> CLocs;
985 typedef std::vector<ContextLocation>::iterator iterator;
987 PathDiagnosticBuilder &PDB;
1000 if (!CLocs.back().isDead() && CLocs.back().asLocation().isFileID()) {
1002 rawAddEdge(cleanUpLocation(CLocs.back(), PDB.LC,
true));
1009 : PD(pd), PDB(pdb) {
1013 if (!PD.path.empty()) {
1014 PrevLoc = (*PD.path.begin())->getLocation();
1016 if (
const Stmt *S = PrevLoc.asStmt())
1017 addExtendedContext(PDB.getEnclosingStmtLocation(S).asStmt());
1022 while (!CLocs.empty()) popLocation();
1028 PDB.getSourceManager());
1033 void flushLocations() {
1034 while (!CLocs.empty())
1040 bool IsPostJump =
false);
1044 void addContext(
const Stmt *S);
1046 void addExtendedContext(
const Stmt *S);
1057 return PDB.getEnclosingStmtLocation(S);
1066 if (Container == Containee)
1073 if (
const Stmt *ContainerS = Container.
asStmt()) {
1075 if (S == ContainerS)
1077 S = PDB.getParent(S);
1097 assert(ContainerBegLine <= ContainerEndLine);
1098 assert(ContaineeBegLine <= ContaineeEndLine);
1100 return (ContainerBegLine <= ContaineeBegLine &&
1101 ContainerEndLine >= ContaineeEndLine &&
1102 (ContainerBegLine != ContaineeBegLine ||
1105 (ContainerEndLine != ContaineeEndLine ||
1111 if (!PrevLoc.isValid()) {
1132 PD.getActivePath().push_front(
1133 std::make_shared<PathDiagnosticControlFlowPiece>(NewLocClean,
1146 while (!CLocs.empty()) {
1147 ContextLocation &TopContextLoc = CLocs.back();
1150 if (TopContextLoc == CLoc) {
1152 if (IsConsumedExpr(TopContextLoc))
1153 TopContextLoc.markDead();
1159 TopContextLoc.markDead();
1163 if (containsLocation(TopContextLoc, CLoc)) {
1167 if (IsConsumedExpr(CLoc)) {
1168 CLocs.push_back(ContextLocation(CLoc,
true));
1173 CLocs.push_back(ContextLocation(CLoc, IsPostJump));
1186 if (
const Expr *
X = dyn_cast_or_null<Expr>(L.
asStmt()))
1192 void EdgeBuilder::addExtendedContext(
const Stmt *S) {
1196 const Stmt *Parent = PDB.getParent(S);
1198 if (isa<CompoundStmt>(Parent))
1199 Parent = PDB.getParent(Parent);
1206 case Stmt::DoStmtClass:
1207 case Stmt::ObjCAtSynchronizedStmtClass:
1217 void EdgeBuilder::addContext(
const Stmt *S) {
1226 while (!CLocs.empty()) {
1230 if (TopContextLoc == L)
1233 if (containsLocation(TopContextLoc, L)) {
1269 if (!isa<CastExpr>(Ex))
1272 case Stmt::BinaryOperatorClass:
1273 case Stmt::UnaryOperatorClass: {
1275 if (
const Expr *child = dyn_cast_or_null<Expr>(SubStmt)) {
1297 if (
const CallExpr *CE = dyn_cast_or_null<CallExpr>(CallSite)) {
1300 PE = FD->param_end();
1302 for (; AI != AE && PI != PE; ++AI, ++PI) {
1303 if (
const Expr *ArgE = *AI) {
1305 Loc LV = State->
getLValue(PD, CalleeCtx);
1321 case Stmt::ForStmtClass:
1322 case Stmt::WhileStmtClass:
1323 case Stmt::ObjCForCollectionStmtClass:
1324 case Stmt::CXXForRangeStmtClass:
1362 const Stmt *S = SP->getStmt();
1372 const Stmt *LoopBody =
nullptr;
1374 case Stmt::CXXForRangeStmtClass: {
1383 case Stmt::ForStmtClass: {
1384 const ForStmt *FS = cast<ForStmt>(Term);
1390 case Stmt::ObjCForCollectionStmtClass: {
1395 case Stmt::WhileStmtClass:
1396 LoopBody = cast<WhileStmt>(Term)->getBody();
1411 ArrayRef<std::unique_ptr<BugReporterVisitor>> visitors) {
1412 EdgeBuilder EB(PD, PDB);
1425 if (
const Expr *Ex = PS->getStmtAs<
Expr>())
1432 const Stmt *S = CE->getCalleeContext()->getCallSite();
1433 if (
const Expr *Ex = dyn_cast_or_null<Expr>(S)) {
1440 LCM[&C->path] = CE->getCalleeContext();
1442 EB.addEdge(C->callReturn,
true,
true);
1443 EB.flushLocations();
1456 const Decl *D = CE->getCalleeContext()->getDecl();
1463 EB.flushLocations();
1473 if (VisitedEntireCall) {
1474 C = cast<PathDiagnosticCallPiece>(PD.
getActivePath().front().get());
1476 const Decl *Caller = CE->getLocationContext()->getDecl();
1478 LCM[&C->
path] = CE->getCalleeContext();
1484 if (!CallStack.empty()) {
1485 assert(CallStack.back().first == C);
1486 CallStack.pop_back();
1504 if (CallerCtx != CalleeCtx) {
1507 CalleeCtx, CallerCtx);
1512 if (
const Stmt *Loop = BE->getSrc()->getLoopTarget()) {
1516 if (
const ForStmt *FS = dyn_cast<ForStmt>(Loop))
1518 else if (
const WhileStmt *WS = dyn_cast<WhileStmt>(Loop))
1519 CS = dyn_cast<CompoundStmt>(WS->getBody());
1521 auto p = std::make_shared<PathDiagnosticEventPiece>(
1522 L,
"Looping back to the head of the loop");
1523 p->setPrunable(
true);
1525 EB.addEdge(p->getLocation(),
true);
1535 const CFGBlock *BSrc = BE->getSrc();
1548 auto PE = std::make_shared<PathDiagnosticEventPiece>(
1549 L,
"Loop body executed 0 times");
1550 PE->setPrunable(
true);
1552 EB.addEdge(PE->getLocation(),
true);
1558 EB.addContext(Term);
1570 EB.addContext(stmt);
1573 EB.addExtendedContext(PDB.getEnclosingStmtLocation(stmt).asStmt());
1587 for (
auto &V : visitors) {
1588 if (
auto p = V->VisitNode(N, NextNode, PDB, *R)) {
1590 EB.addEdge(Loc,
true);
1595 EB.addExtendedContext(PDB.getEnclosingStmtLocation(S).asStmt());
1600 return PDB.getBugReport()->isValid();
1626 std::make_shared<PathDiagnosticControlFlowPiece>(NewLoc, PrevLoc));
1635 dyn_cast_or_null<ObjCForCollectionStmt>(S))
1636 return FS->getElement();
1643 "Loop body skipped when range is empty";
1645 "Loop body skipped when collection is empty";
1650 ArrayRef<std::unique_ptr<BugReporterVisitor>> visitors) {
1689 if (VisitedEntireCall) {
1691 C = cast<PathDiagnosticCallPiece>(
P);
1693 const Decl *Caller = CE->getLocationContext()->getDecl();
1704 assert(LCM[&C->
path] ==
nullptr ||
1705 LCM[&C->
path] == CE->getCalleeContext());
1706 LCM[&C->
path] = CE->getCalleeContext();
1721 if (!CallStack.empty()) {
1722 assert(CallStack.back().first == C);
1723 CallStack.pop_back();
1740 const Stmt *S = CE->getCalleeContext()->getCallSite();
1742 if (
const Expr *Ex = dyn_cast_or_null<Expr>(S)) {
1753 LCM[&C->path] = CE->getCalleeContext();
1770 if (
const Expr *Ex = PS->getStmtAs<
Expr>())
1778 if (!isa<ObjCForCollectionStmt>(PS->getStmt())) {
1793 if (CallerCtx != CalleeCtx) {
1796 CalleeCtx, CallerCtx);
1801 if (
const Stmt *Loop = BE->getSrc()->getLoopTarget()) {
1803 const Stmt *Body =
nullptr;
1805 if (
const ForStmt *FS = dyn_cast<ForStmt>(Loop))
1806 Body = FS->getBody();
1807 else if (
const WhileStmt *WS = dyn_cast<WhileStmt>(Loop))
1808 Body = WS->getBody();
1810 dyn_cast<ObjCForCollectionStmt>(Loop)) {
1811 Body = OFS->getBody();
1813 dyn_cast<CXXForRangeStmt>(Loop)) {
1814 Body = FRS->getBody();
1818 auto p = std::make_shared<PathDiagnosticEventPiece>(
1819 L,
"Looping back to the head "
1821 p->setPrunable(
true);
1826 if (
const CompoundStmt *CS = dyn_cast_or_null<CompoundStmt>(Body)) {
1833 const CFGBlock *BSrc = BE->getSrc();
1844 const char *str =
nullptr;
1847 if (!IsInLoopBody) {
1848 if (isa<ObjCForCollectionStmt>(Term)) {
1850 }
else if (isa<CXXForRangeStmt>(Term)) {
1862 auto PE = std::make_shared<PathDiagnosticEventPiece>(L, str);
1863 PE->setPrunable(
true);
1865 PE->getLocation(), PDB.LC);
1868 }
else if (isa<BreakStmt>(Term) || isa<ContinueStmt>(Term) ||
1869 isa<GotoStmt>(Term)) {
1882 for (
auto &V : visitors) {
1883 if (
auto p = V->VisitNode(N, NextNode, PDB, *report)) {
1918 if (isa<ExprWithCleanups>(S) ||
1919 isa<CXXBindTemporaryExpr>(S) ||
1920 isa<SubstNonTypeTemplateParmExpr>(S))
1931 case Stmt::BinaryOperatorClass: {
1937 case Stmt::IfStmtClass:
1938 return cast<IfStmt>(
S)->getCond() == Cond;
1939 case Stmt::ForStmtClass:
1940 return cast<ForStmt>(
S)->getCond() == Cond;
1941 case Stmt::WhileStmtClass:
1942 return cast<WhileStmt>(
S)->getCond() == Cond;
1943 case Stmt::DoStmtClass:
1944 return cast<DoStmt>(
S)->getCond() == Cond;
1945 case Stmt::ChooseExprClass:
1946 return cast<ChooseExpr>(
S)->getCond() == Cond;
1947 case Stmt::IndirectGotoStmtClass:
1948 return cast<IndirectGotoStmt>(
S)->getTarget() == Cond;
1949 case Stmt::SwitchStmtClass:
1950 return cast<SwitchStmt>(
S)->getCond() == Cond;
1951 case Stmt::BinaryConditionalOperatorClass:
1952 return cast<BinaryConditionalOperator>(
S)->getCond() == Cond;
1953 case Stmt::ConditionalOperatorClass: {
1955 return CO->
getCond() == Cond ||
1959 case Stmt::ObjCForCollectionStmtClass:
1960 return cast<ObjCForCollectionStmt>(
S)->getElement() == Cond;
1961 case Stmt::CXXForRangeStmtClass: {
1971 if (
const ForStmt *FS = dyn_cast<ForStmt>(FL))
1972 return FS->getInc() == S || FS->getInit() ==
S;
1974 return FRS->getInc() == S || FRS->getRangeStmt() == S ||
1975 FRS->getLoopVarStmt() || FRS->getRangeInit() ==
S;
1989 PathPieces::iterator Prev = pieces.end();
1990 for (PathPieces::iterator
I = pieces.begin(),
E = Prev;
I !=
E;
2002 const Stmt *InnerStmt =
nullptr;
2003 while (NextSrcContext.
isValid() && NextSrcContext.
asStmt() != InnerStmt) {
2004 SrcContexts.push_back(NextSrcContext);
2005 InnerStmt = NextSrcContext.
asStmt();
2020 if (!DstContext.isValid() || DstContext.asStmt() == Dst)
2024 if (std::find(SrcContexts.begin(), SrcContexts.end(), DstContext) !=
2037 if (
const Stmt *PrevSrc =
getLocStmt(PrevPiece->getStartLocation())) {
2040 PrevPiece->setEndLocation(DstContext);
2051 std::make_shared<PathDiagnosticControlFlowPiece>(SrcLoc, DstContext);
2053 I = pieces.insert(
I, std::move(
P));
2070 for (PathPieces::iterator
I = pieces.begin(),
E = pieces.end();
I !=
E; ++
I) {
2080 if (!s1Start || !s1End)
2083 PathPieces::iterator NextI =
I; ++NextI;
2095 StringRef S = EV->getString();
2114 if (!s2Start || !s2End || s1End != s2Start)
2119 if (!(isa<ForStmt>(s1Start) || isa<WhileStmt>(s1Start) ||
2120 isa<IfStmt>(s1Start) || isa<ObjCForCollectionStmt>(s1Start) ||
2121 isa<CXXForRangeStmt>(s1Start)))
2131 I = pieces.erase(
I);
2156 StringRef Snippet = Buffer->getBuffer().slice(BeginOffset, EndOffset);
2162 if (Snippet.find_first_of(
"\r\n") != StringRef::npos)
2166 return Snippet.size();
2193 for (PathPieces::iterator
I = Path.begin(),
E = Path.end();
I !=
E; ) {
2206 PathPieces::iterator NextI =
I; ++NextI;
2214 if (isa<PathDiagnosticEventPiece>(NextI->get())) {
2230 if (s1Start && s2Start && s1Start == s2End && s2Start == s1End) {
2231 const size_t MAX_SHORT_LINE_LENGTH = 80;
2233 if (s1Length && *s1Length <= MAX_SHORT_LINE_LENGTH) {
2235 if (s2Length && *s2Length <= MAX_SHORT_LINE_LENGTH) {
2237 I = Path.erase(NextI);
2264 bool erased =
false;
2266 for (PathPieces::iterator
I = path.begin(),
E = path.end();
I !=
E;
2295 std::swap(SecondLoc, FirstLoc);
2304 const size_t MAX_PUNY_EDGE_LENGTH = 2;
2305 if (*ByteWidth <= MAX_PUNY_EDGE_LENGTH) {
2317 for (PathPieces::iterator
I = path.begin(),
E = path.end();
I !=
E; ++
I) {
2323 PathPieces::iterator NextI =
I; ++NextI;
2333 if (PieceI->getString() == PieceNextI->getString()) {
2342 bool hasChanges =
false;
2347 for (PathPieces::iterator
I = path.begin(),
E = path.end();
I !=
E; ) {
2349 if (
auto *CallI = dyn_cast<PathDiagnosticCallPiece>(
I->get())) {
2352 if (!OCS.count(CallI)) {
2373 PathPieces::iterator NextI =
I; ++NextI;
2384 const Stmt *s2Start =
getLocStmt(PieceNextI->getStartLocation());
2404 if (level1 && level1 == level2 && level1 == level3 && level1 == level4) {
2405 PieceI->setEndLocation(PieceNextI->getEndLocation());
2419 if (s1End && s1End == s2Start && level2) {
2420 bool removeEdge =
false;
2446 else if (s1Start && s2End &&
2459 else if (s1Start && s2End &&
2461 SourceRange EdgeRange(PieceI->getEndLocation().asLocation(),
2462 PieceI->getStartLocation().asLocation());
2469 PieceI->setEndLocation(PieceNextI->getEndLocation());
2483 if (s1End == s2Start) {
2485 dyn_cast_or_null<ObjCForCollectionStmt>(level3);
2488 PieceI->setEndLocation(PieceNextI->getEndLocation());
2526 const auto *FirstEdge =
2531 const Decl *D = LCM[&Path]->getDecl();
2533 if (FirstEdge->getStartLocation() != EntryLoc)
2543 void BugType::anchor() { }
2547 void BuiltinBug::anchor() {}
2553 void BugReport::NodeResolver::anchor() {}
2559 llvm::FoldingSetNodeID
ID;
2560 visitor->Profile(ID);
2567 Callbacks.push_back(std::move(visitor));
2573 popInterestingSymbolsAndRegions();
2590 hash.AddPointer(&
BT);
2603 if (!range.isValid())
2605 hash.AddInteger(range.getBegin().getRawEncoding());
2606 hash.AddInteger(range.getEnd().getRawEncoding());
2615 if (getInterestingSymbols().insert(sym).second)
2619 getInterestingRegions().insert(meta->getRegion());
2628 if (getInterestingRegions().insert(R).second)
2632 getInterestingSymbols().insert(SR->getSymbol());
2655 return getInterestingSymbols().count(sym);
2662 bool b = getInterestingRegions().count(R);
2666 return getInterestingSymbols().count(SR->getSymbol());
2676 void BugReport::lazyInitializeInterestingSets() {
2684 lazyInitializeInterestingSets();
2689 lazyInitializeInterestingSets();
2693 void BugReport::pushInterestingSymbolsAndRegions() {
2698 void BugReport::popInterestingSymbolsAndRegions() {
2708 const Stmt *S =
nullptr;
2712 if (BE->getBlock() == &Exit)
2741 "Either Location or ErrorNode should be specified but not both.");
2766 typedef std::vector<BugReportEquivClass *> ContTy;
2767 for (ContTy::iterator
I = EQClassesVector.begin(),
E = EQClassesVector.end();
2774 if (BugTypes.isEmpty())
2783 I = bugTypes.begin(),
E = bugTypes.end();
I !=
E; ++
I)
2784 const_cast<BugType*>(*I)->FlushReports(*
this);
2788 typedef std::vector<BugReportEquivClass *> ContVecTy;
2789 for (ContVecTy::iterator EI=EQClassesVector.begin(), EE=EQClassesVector.end();
2799 llvm::DeleteContainerSeconds(StrBugTypes);
2802 BugTypes = F.getEmptySet();
2815 std::unique_ptr<ExplodedGraph> Graph;
2821 class TrimmedGraph {
2824 typedef llvm::DenseMap<const ExplodedNode *, unsigned> PriorityMapTy;
2825 PriorityMapTy PriorityMap;
2827 typedef std::pair<const ExplodedNode *, size_t> NodeIndexPair;
2830 std::unique_ptr<ExplodedGraph> G;
2833 template <
bool Descending>
2834 class PriorityCompare {
2835 const PriorityMapTy &PriorityMap;
2838 PriorityCompare(
const PriorityMapTy &M) : PriorityMap(M) {}
2841 PriorityMapTy::const_iterator LI = PriorityMap.find(LHS);
2842 PriorityMapTy::const_iterator RI = PriorityMap.find(RHS);
2843 PriorityMapTy::const_iterator
E = PriorityMap.end();
2850 return Descending ? LI->second > RI->second
2851 : LI->second < RI->second;
2854 bool operator()(
const NodeIndexPair &LHS,
const NodeIndexPair &RHS)
const {
2855 return (*
this)(LHS.first, RHS.first);
2863 bool popNextReportGraph(ReportGraph &GraphWrapper);
2867 TrimmedGraph::TrimmedGraph(
const ExplodedGraph *OriginalGraph,
2872 G = OriginalGraph->
trim(Nodes, &ForwardMap, &InverseMap);
2877 llvm::SmallPtrSet<const ExplodedNode *, 32> RemainingNodes;
2879 for (
unsigned i = 0, count = Nodes.size(); i < count; ++i) {
2880 if (
const ExplodedNode *NewNode = ForwardMap.lookup(Nodes[i])) {
2881 ReportNodes.push_back(std::make_pair(NewNode, i));
2882 RemainingNodes.insert(NewNode);
2886 assert(!RemainingNodes.empty() &&
"No error node found in the trimmed graph");
2889 std::queue<const ExplodedNode *> WS;
2891 assert(G->num_roots() == 1);
2892 WS.push(*G->roots_begin());
2893 unsigned Priority = 0;
2895 while (!WS.empty()) {
2899 PriorityMapTy::iterator PriorityEntry;
2901 std::tie(PriorityEntry, IsNew) =
2902 PriorityMap.insert(std::make_pair(Node, Priority));
2906 assert(PriorityEntry->second <= Priority);
2910 if (RemainingNodes.erase(Node))
2911 if (RemainingNodes.empty())
2921 std::sort(ReportNodes.begin(), ReportNodes.end(),
2922 PriorityCompare<true>(PriorityMap));
2925 bool TrimmedGraph::popNextReportGraph(ReportGraph &GraphWrapper) {
2926 if (ReportNodes.empty())
2930 std::tie(OrigN, GraphWrapper.Index) = ReportNodes.pop_back_val();
2931 assert(PriorityMap.find(OrigN) != PriorityMap.end() &&
2932 "error node not accessible from root");
2936 auto GNew = llvm::make_unique<ExplodedGraph>();
2937 GraphWrapper.BackMap.clear();
2949 InterExplodedGraphMap::const_iterator IMitr = InverseMap.find(OrigN);
2950 assert(IMitr != InverseMap.end() &&
"No mapping to original node.");
2951 GraphWrapper.BackMap[NewN] = IMitr->second;
2957 GraphWrapper.ErrorNode = NewN;
2963 GNew->addRoot(NewN);
2970 PriorityCompare<false>(PriorityMap));
2973 GraphWrapper.Graph = std::move(GNew);
2982 typedef std::vector<
2983 std::pair<std::shared_ptr<PathDiagnosticMacroPiece>,
SourceLocation>>
2986 typedef std::vector<std::shared_ptr<PathDiagnosticPiece>> PiecesTy;
2988 MacroStackTy MacroStack;
2991 for (PathPieces::const_iterator
I = path.begin(), E = path.end();
2997 if (
auto *call = dyn_cast<PathDiagnosticCallPiece>(&*piece)) {
3012 Pieces.push_back(piece);
3019 if (!MacroStack.empty() && InstantiationLoc == MacroStack.back().second) {
3020 MacroStack.back().first->subPieces.push_back(piece);
3026 std::shared_ptr<PathDiagnosticMacroPiece> MacroGroup;
3033 while (!MacroStack.empty()) {
3034 if (InstantiationLoc == MacroStack.back().second) {
3035 MacroGroup = MacroStack.back().first;
3039 if (ParentInstantiationLoc == MacroStack.back().second) {
3040 MacroGroup = MacroStack.back().first;
3044 MacroStack.pop_back();
3047 if (!MacroGroup || ParentInstantiationLoc == MacroStack.back().second) {
3049 auto NewGroup = std::make_shared<PathDiagnosticMacroPiece>(
3053 MacroGroup->subPieces.push_back(NewGroup);
3055 assert(InstantiationLoc.
isFileID());
3056 Pieces.push_back(NewGroup);
3059 MacroGroup = NewGroup;
3060 MacroStack.push_back(std::make_pair(MacroGroup, InstantiationLoc));
3064 MacroGroup->subPieces.push_back(piece);
3070 path.insert(path.end(), Pieces.begin(), Pieces.end());
3076 assert(!bugReports.empty());
3078 bool HasValid =
false;
3079 bool HasInvalid =
false;
3082 E = bugReports.end();
I !=
E; ++
I) {
3083 if ((*I)->isValid()) {
3085 errorNodes.push_back((*I)->getErrorNode());
3089 errorNodes.push_back(
nullptr);
3108 TrimmedGraph TrimG(&getGraph(), errorNodes);
3109 ReportGraph ErrorGraph;
3111 while (TrimG.popNextReportGraph(ErrorGraph)) {
3113 assert(ErrorGraph.Index < bugReports.size());
3114 BugReport *R = bugReports[ErrorGraph.Index];
3115 assert(R &&
"No original report found for sliced graph.");
3116 assert(R->isValid() &&
"Report selected by trimmed graph marked invalid.");
3119 PathDiagnosticBuilder PDB(*
this, R, ErrorGraph.BackMap, &PC);
3123 R->addVisitor(llvm::make_unique<NilReceiverBRVisitor>());
3124 R->addVisitor(llvm::make_unique<ConditionBRVisitor>());
3125 R->addVisitor(llvm::make_unique<LikelyFalsePositiveSuppressionBRVisitor>());
3126 R->addVisitor(llvm::make_unique<CXXSelfAssignmentBRVisitor>());
3129 unsigned origReportConfigToken, finalReportConfigToken;
3139 E = R->visitor_end();
I !=
E; ++
I)
3140 visitors.push_back((*I)->clone());
3144 origReportConfigToken = R->getConfigurationChangeToken();
3148 std::unique_ptr<PathDiagnosticPiece> LastPiece;
3151 if (std::unique_ptr<PathDiagnosticPiece> Piece =
3152 (*I)->getEndPath(PDB, N, *R)) {
3153 assert (!LastPiece &&
3154 "There can only be one final piece in a diagnostic.");
3155 LastPiece = std::move(Piece);
3170 switch (ActiveScheme) {
3189 finalReportConfigToken = R->getConfigurationChangeToken();
3190 }
while (finalReportConfigToken != origReportConfigToken);
3196 if (!PD.
path.empty()) {
3197 if (R->shouldPrunePath() && getAnalyzerOptions().shouldPrunePaths()) {
3199 assert(stillHasNotes);
3200 (void)stillHasNotes;
3233 assert(!HasInvalid &&
"Inconsistent suppression");
3239 BugTypes = F.add(BugTypes, BT);
3246 assert((E->isSink() || E->getLocation().getTag()) &&
3247 "Error node must either be a sink or have a tag");
3250 E->getLocationContext()->getAnalysisDeclContext();
3260 bool ValidSourceLoc = R->getLocation(getSourceManager()).isValid();
3261 assert(ValidSourceLoc);
3264 if (!ValidSourceLoc)
3268 llvm::FoldingSetNodeID
ID;
3279 EQClasses.InsertNode(EQ, InsertPos);
3280 EQClassesVector.push_back(EQ);
3282 EQ->AddReport(std::move(R));
3291 struct FRIEC_WLItem {
3296 : N(n),
I(N->succ_begin()), E(N->succ_end()) {}
3303 return BEP->getBlock();
3330 bugReports.push_back(R);
3344 for (; I !=
E; ++
I) {
3349 if (errorNode->
isSink()) {
3351 "BugType::isSuppressSink() should not be 'true' for sink end nodes");
3355 bugReports.push_back(&*I);
3357 exampleReport = &*
I;
3370 if (B->hasNoReturnElement())
3375 typedef FRIEC_WLItem WLItem;
3377 llvm::DenseMap<const ExplodedNode *, unsigned> Visited;
3380 WL.push_back(errorNode);
3381 Visited[errorNode] = 1;
3383 while (!WL.empty()) {
3384 WLItem &WI = WL.back();
3385 assert(!WI.N->succ_empty());
3387 for (; WI.I != WI.E; ++WI.I) {
3393 bugReports.push_back(&*I);
3395 exampleReport = &*
I;
3404 unsigned &mark = Visited[Succ];
3414 if (!WL.empty() && &WL.back() == &WI)
3421 return exampleReport;
3427 if (exampleReport) {
3429 FlushReport(exampleReport, *PDC, bugReports);
3434 void BugReporter::FlushReport(
BugReport *exampleReport,
3455 assert(!bugReports.empty());
3457 MaxBugClassSize.updateMax(bugReports.size());
3459 if (!generatePathDiagnostic(*D.get(), PD, bugReports))
3462 MaxValidBugClassSize.updateMax(bugReports.size());
3468 D->resetDiagnosticLocationToMainFile();
3473 if (D->path.empty()) {
3475 auto piece = llvm::make_unique<PathDiagnosticEventPiece>(
3478 piece->addRange(Range);
3479 D->setEndOfPath(std::move(piece));
3483 if (getAnalyzerOptions().shouldDisplayNotesAsEvents()) {
3486 for (
auto I = exampleReport->
getNotes().rbegin(),
3487 E = exampleReport->
getNotes().rend();
I !=
E; ++
I) {
3489 auto ConvertedPiece = std::make_shared<PathDiagnosticEventPiece>(
3492 ConvertedPiece->addRange(R);
3494 Pieces.push_front(std::move(ConvertedPiece));
3497 for (
auto I = exampleReport->
getNotes().rbegin(),
3498 E = exampleReport->
getNotes().rend();
I !=
E; ++
I)
3499 Pieces.push_front(*
I);
3504 for (BugReport::ExtraTextList::const_iterator i = Meta.begin(),
3505 e = Meta.end(); i != e; ++i) {
3522 StringRef name, StringRef category,
3527 BugType *BT = getBugTypeForName(CheckName, name, category);
3528 auto R = llvm::make_unique<BugReport>(*
BT, str, Loc);
3529 R->setDeclWithIssue(DeclWithIssue);
3533 emitReport(std::move(R));
3537 StringRef category) {
3539 llvm::raw_svector_ostream(fullDesc) << CheckName.
getName() <<
":" << name
3541 BugType *&BT = StrBugTypes[fullDesc];
3543 BT =
new BugType(CheckName, name, category);
3549 for (PathPieces::const_iterator
I = begin(), E = end();
I !=
E; ++
I) {
3550 llvm::errs() <<
"[" << index++ <<
"] ";
3552 llvm::errs() <<
"\n";
3557 llvm::errs() <<
"CALL\n--------------\n";
3561 else if (
const NamedDecl *ND = dyn_cast<NamedDecl>(getCallee()))
3562 llvm::errs() << *ND <<
"\n";
3568 llvm::errs() <<
"EVENT\n--------------\n";
3569 llvm::errs() << getString() <<
"\n";
3570 llvm::errs() <<
" ---- at ----\n";
3575 llvm::errs() <<
"CONTROL\n--------------\n";
3576 getStartLocation().dump();
3577 llvm::errs() <<
" ---- to ----\n";
3578 getEndLocation().dump();
3582 llvm::errs() <<
"MACRO\n--------------\n";
3587 llvm::errs() <<
"NOTE\n--------------\n";
3588 llvm::errs() << getString() <<
"\n";
3589 llvm::errs() <<
" ---- at ----\n";
3595 llvm::errs() <<
"<INVALID>\n";
3602 llvm::errs() <<
"<range>\n";
3605 asLocation().dump();
3606 llvm::errs() <<
"\n";
3612 llvm::errs() <<
"<NULL STMT>\n";
3615 if (
const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(D))
3616 llvm::errs() << *ND <<
"\n";
3617 else if (isa<BlockDecl>(D))
3619 llvm::errs() <<
"<block>\n";
3621 llvm::errs() <<
"<unknown decl>\n";
3623 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
StmtClass getStmtClass() 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()
CFGStmtMap * getCFGStmtMap()
const ExplodedNode * getErrorNode() const
Stmt - This represents one statement.
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.
Decl - This represents one declaration (or definition), e.g.
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
static std::shared_ptr< PathDiagnosticCallPiece > construct(const ExplodedNode *N, const CallExitEnd &CE, const SourceManager &SM)
void dump() const override
static PathDiagnosticLocation createEndBrace(const CompoundStmt *CS, const SourceManager &SM)
Create a location for the end of the compound statement.
ArrayRef< SourceRange > getRanges() const
Return the SourceRanges associated with this PathDiagnosticPiece.
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
FullSourceLoc asLocation() const
PathDiagnostic - PathDiagnostic objects represent a single path-sensitive diagnostic.
const Decl * getUniqueingDecl() const
Get the declaration containing the uniqueing location.
bool isPathSensitive() const
True when the report has an execution path associated with it.
void setStartLocation(const PathDiagnosticLocation &L)
unsigned getExpansionLineNumber(bool *Invalid=nullptr) const
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)
AnalysisDeclContext * getAnalysisDeclContext() const
static const char StrLoopBodyZero[]
StringRef getString() const
const BugType & getBugType() const
void dump() const override
static const CFGBlock * findBlockForNode(const ExplodedNode *N)
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'.
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")
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
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.
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
void addVisitor(std::unique_ptr< BugReporterVisitor > visitor)
Add custom or predefined bug report visitors to this report.
const Stmt * asStmt() const
virtual const NoteList & getNotes()
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.
Const iterator for iterating over Stmt * arrays that contain only Expr *.
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.
static bool isPieceMessageGeneric(const PathDiagnosticPiece *Piece)
CFGBlock * getBlock(Stmt *S)
Returns the CFGBlock the specified Stmt* appears in.
~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 dump() const
Dumps the specified AST fragment and all subtrees to llvm::errs().
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.
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 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()
static void updateStackPiecesWithMessage(PathDiagnosticPiece &P, StackDiagVector &CallStack)
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...
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
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.
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 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[]
SourceLocation getLocStart() const LLVM_READONLY
std::pair< PathDiagnosticCallPiece *, const ExplodedNode * > StackDiagPair
virtual bool hasBody() const
Returns true if this Decl represents a declaration for a body of code, such as a function or method d...
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)