44 #include "llvm/ADT/ArrayRef.h" 45 #include "llvm/ADT/DenseMap.h" 46 #include "llvm/ADT/DenseSet.h" 47 #include "llvm/ADT/FoldingSet.h" 48 #include "llvm/ADT/None.h" 49 #include "llvm/ADT/Optional.h" 50 #include "llvm/ADT/STLExtras.h" 51 #include "llvm/ADT/SmallPtrSet.h" 52 #include "llvm/ADT/SmallString.h" 53 #include "llvm/ADT/SmallVector.h" 54 #include "llvm/ADT/Statistic.h" 55 #include "llvm/ADT/StringRef.h" 56 #include "llvm/ADT/iterator_range.h" 57 #include "llvm/Support/Casting.h" 58 #include "llvm/Support/Compiler.h" 59 #include "llvm/Support/ErrorHandling.h" 60 #include "llvm/Support/MemoryBuffer.h" 61 #include "llvm/Support/raw_ostream.h" 73 using namespace clang;
76 #define DEBUG_TYPE "BugReporter" 79 "The maximum number of bug reports in the same equivalence class");
81 "The maximum number of bug reports in the same equivalence class " 82 "where at least one report is valid (not suppressed)");
84 BugReporterVisitor::~BugReporterVisitor() =
default;
86 void BugReporterContext::anchor() {}
100 static inline const Stmt*
119 const void *tagPreferred = ConditionBRVisitor::getTag();
120 const void *tagLesser = TrackConstraintBRVisitor::getTag();
125 if (X->
getTag() == tagPreferred && Y->
getTag() == tagLesser)
126 return ConditionBRVisitor::isPieceMessageGeneric(X) ? Y :
X;
128 if (Y->
getTag() == tagPreferred && X->
getTag() == tagLesser)
129 return ConditionBRVisitor::isPieceMessageGeneric(Y) ?
X : Y;
140 unsigned N = path.size();
147 for (
unsigned i = 0; i < N; ++i) {
148 auto piece = std::move(path.front());
151 switch (piece->getKind()) {
164 if (
auto *nextEvent =
165 dyn_cast<PathDiagnosticEventPiece>(path.front().get())) {
166 auto *
event = cast<PathDiagnosticEventPiece>(piece.get());
170 if (
auto *pieceToKeep =
172 piece = std::move(pieceToKeep == event ? piece : path.front());
182 path.push_back(std::move(piece));
189 llvm::DenseMap<const PathPieces *, const LocationContext *>;
196 bool IsInteresting =
false) {
197 bool containsSomethingInteresting = IsInteresting;
198 const unsigned N = pieces.size();
200 for (
unsigned i = 0 ; i < N ; ++i) {
203 auto piece = std::move(pieces.front());
206 switch (piece->getKind()) {
208 auto &call = cast<PathDiagnosticCallPiece>(*piece);
210 assert(LCM.count(&call.path));
215 containsSomethingInteresting =
true;
219 auto ¯o = cast<PathDiagnosticMacroPiece>(*piece);
222 containsSomethingInteresting =
true;
226 auto &
event = cast<PathDiagnosticEventPiece>(*piece);
230 containsSomethingInteresting |= !
event.isPrunable();
240 pieces.push_back(std::move(piece));
243 return containsSomethingInteresting;
258 for (
const auto &I : Pieces) {
264 if (LastCallLocation) {
266 if (CallerIsImplicit || !Call->callEnter.asLocation().isValid())
267 Call->callEnter = *LastCallLocation;
268 if (CallerIsImplicit || !Call->callReturn.asLocation().isValid())
269 Call->callReturn = *LastCallLocation;
275 if (Call->callEnterWithin.asLocation().isValid() &&
277 ThisCallLocation = &Call->callEnterWithin;
279 ThisCallLocation = &Call->callEnter;
281 assert(ThisCallLocation &&
"Outermost call has an invalid location");
290 for (PathPieces::iterator I = Pieces.begin(), E = Pieces.end(); I != E;) {
291 if (
auto *C = dyn_cast<PathDiagnosticCallPiece>(I->get()))
294 if (
auto *M = dyn_cast<PathDiagnosticMacroPiece>(I->get()))
297 if (
auto *CF = dyn_cast<PathDiagnosticControlFlowPiece>(I->get())) {
298 const Stmt *Start = CF->getStartLocation().asStmt();
299 const Stmt *
End = CF->getEndLocation().asStmt();
300 if (Start && isa<CXXDefaultInitExpr>(Start)) {
303 }
else if (End && isa<CXXDefaultInitExpr>(End)) {
304 PathPieces::iterator Next = std::next(I);
307 dyn_cast<PathDiagnosticControlFlowPiece>(Next->get())) {
308 NextCF->setStartLocation(CF->getStartLocation());
324 for (PathPieces::iterator I = Pieces.begin(), E = Pieces.end(); I != E;) {
325 if (
auto *C = dyn_cast<PathDiagnosticCallPiece>(I->get()))
328 if (
auto *M = dyn_cast<PathDiagnosticMacroPiece>(I->get()))
331 if (!(*I)->getLocation().isValid() ||
332 !(*I)->getLocation().asLocation().isValid()) {
370 const Stmt *getParent(
const Stmt *S) {
371 return getParentMap().getParent(S);
380 bool supportsLogicalOpControlFlow()
const {
388 PathDiagnosticBuilder::ExecutionContinues(
const ExplodedNode *N) {
397 PathDiagnosticBuilder::ExecutionContinues(llvm::raw_string_ostream &os,
400 if (os.str().empty())
406 os <<
"Execution continues on line " 410 os <<
"Execution jumps to the end of the ";
412 if (isa<ObjCMethodDecl>(D))
414 else if (isa<FunctionDecl>(D))
417 assert(isa<BlockDecl>(D));
418 os <<
"anonymous block";
435 case Stmt::ForStmtClass:
436 case Stmt::DoStmtClass:
437 case Stmt::WhileStmtClass:
438 case Stmt::ObjCForCollectionStmtClass:
439 case Stmt::CXXForRangeStmtClass:
455 switch (
Parent->getStmtClass()) {
456 case Stmt::BinaryOperatorClass: {
457 const auto *B = cast<BinaryOperator>(
Parent);
458 if (B->isLogicalOp())
462 case Stmt::CompoundStmtClass:
463 case Stmt::StmtExprClass:
465 case Stmt::ChooseExprClass:
468 if (allowNestedContexts || cast<ChooseExpr>(
Parent)->getCond() == S)
472 case Stmt::BinaryConditionalOperatorClass:
473 case Stmt::ConditionalOperatorClass:
476 if (allowNestedContexts ||
477 cast<AbstractConditionalOperator>(
Parent)->getCond() == S)
481 case Stmt::CXXForRangeStmtClass:
482 if (cast<CXXForRangeStmt>(
Parent)->getBody() == S)
485 case Stmt::DoStmtClass:
487 case Stmt::ForStmtClass:
488 if (cast<ForStmt>(
Parent)->getBody() == S)
491 case Stmt::IfStmtClass:
492 if (cast<IfStmt>(
Parent)->getCond() != S)
495 case Stmt::ObjCForCollectionStmtClass:
496 if (cast<ObjCForCollectionStmt>(
Parent)->getBody() == S)
499 case Stmt::WhileStmtClass:
500 if (cast<WhileStmt>(
Parent)->getCond() != S)
510 assert(S &&
"Cannot have null Stmt for PathDiagnosticLocation");
517 assert(S &&
"Null Stmt passed to getEnclosingStmtLocation");
526 std::pair<PathDiagnosticCallPiece *, const ExplodedNode *>;
533 if (
auto *ep = dyn_cast<PathDiagnosticEventPiece>(&P)) {
534 if (ep->hasCallStackHint())
535 for (
const auto &I : CallStack) {
538 std::string stackMsg = ep->getCallStackMessage(N);
557 PathDiagnosticBuilder &PDB,
562 llvm::raw_string_ostream os(sbuf);
570 os <<
"No cases match in the switch statement. " 571 "Control jumps to line " 574 case Stmt::DefaultStmtClass:
575 os <<
"Control jumps to the 'default' case at line " 579 case Stmt::CaseStmtClass: {
580 os <<
"Control jumps to 'case ";
581 const auto *Case = cast<CaseStmt>(S);
585 bool GetRawInt =
true;
587 if (
const auto *DR = dyn_cast<DeclRefExpr>(LHS)) {
599 os << LHS->EvaluateKnownConstInt(PDB.getASTContext());
606 os <<
"'Default' branch taken. ";
607 End = PDB.ExecutionContinues(os, N);
609 return std::make_shared<PathDiagnosticControlFlowPiece>(Start,
End,
616 PathDiagnosticBuilder &PDB,
619 llvm::raw_string_ostream os(sbuf);
622 return std::make_shared<PathDiagnosticControlFlowPiece>(Start,
End, os.str());
632 PathDiagnosticBuilder &PDB,
634 const auto *B = cast<BinaryOperator>(T);
636 llvm::raw_string_ostream os(sbuf);
637 os <<
"Left side of '";
640 if (B->getOpcode() == BO_LAnd) {
652 End = PDB.ExecutionContinues(N);
655 assert(B->getOpcode() == BO_LOr);
662 End = PDB.ExecutionContinues(N);
670 return std::make_shared<PathDiagnosticControlFlowPiece>(Start,
End,
676 PathDiagnosticBuilder &PDB,
690 case Stmt::GotoStmtClass:
691 case Stmt::IndirectGotoStmtClass: {
697 case Stmt::SwitchStmtClass: {
703 case Stmt::BreakStmtClass:
704 case Stmt::ContinueStmtClass: {
706 llvm::raw_string_ostream os(sbuf);
709 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, os.str()));
714 case Stmt::BinaryConditionalOperatorClass:
715 case Stmt::ConditionalOperatorClass: {
717 llvm::raw_string_ostream os(sbuf);
718 os <<
"'?' condition is ";
728 End = PDB.getEnclosingStmtLocation(S);
731 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, os.str()));
736 case Stmt::BinaryOperatorClass: {
737 if (!PDB.supportsLogicalOpControlFlow())
740 std::shared_ptr<PathDiagnosticControlFlowPiece>
Diag =
746 case Stmt::DoStmtClass:
749 llvm::raw_string_ostream os(sbuf);
751 os <<
"Loop condition is true. ";
755 End = PDB.getEnclosingStmtLocation(S);
758 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
764 End = PDB.getEnclosingStmtLocation(S);
767 std::make_shared<PathDiagnosticControlFlowPiece>(
768 Start, End,
"Loop condition is false. Exiting loop"));
772 case Stmt::WhileStmtClass:
773 case Stmt::ForStmtClass:
776 llvm::raw_string_ostream os(sbuf);
778 os <<
"Loop condition is false. ";
781 End = PDB.getEnclosingStmtLocation(S);
784 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
789 End = PDB.getEnclosingStmtLocation(S);
792 std::make_shared<PathDiagnosticControlFlowPiece>(
793 Start, End,
"Loop condition is true. Entering loop body"));
798 case Stmt::IfStmtClass: {
802 End = PDB.getEnclosingStmtLocation(S);
806 std::make_shared<PathDiagnosticControlFlowPiece>(
807 Start, End,
"Taking false branch"));
810 std::make_shared<PathDiagnosticControlFlowPiece>(
811 Start, End,
"Taking true branch"));
842 if (!isa<CastExpr>(Ex))
845 case Stmt::BinaryOperatorClass:
846 case Stmt::UnaryOperatorClass: {
848 if (
const auto *child = dyn_cast_or_null<Expr>(SubStmt)) {
870 if (
const auto *CE = dyn_cast_or_null<CallExpr>(CallSite)) {
871 if (
const auto *FD = dyn_cast<FunctionDecl>(CalleeCtx->
getDecl())) {
873 PE = FD->param_end();
875 for (; AI != AE && PI != PE; ++AI, ++PI) {
876 if (
const Expr *ArgE = *AI) {
894 case Stmt::ForStmtClass:
895 case Stmt::WhileStmtClass:
896 case Stmt::ObjCForCollectionStmtClass:
897 case Stmt::CXXForRangeStmtClass:
925 const Stmt *S = SP->getStmt();
935 const Stmt *LoopBody =
nullptr;
937 case Stmt::CXXForRangeStmtClass: {
938 const auto *FR = cast<CXXForRangeStmt>(Term);
943 LoopBody = FR->getBody();
946 case Stmt::ForStmtClass: {
947 const auto *FS = cast<ForStmt>(Term);
950 LoopBody = FS->getBody();
953 case Stmt::ObjCForCollectionStmtClass: {
954 const auto *FC = cast<ObjCForCollectionStmt>(Term);
955 LoopBody = FC->getBody();
958 case Stmt::WhileStmtClass:
959 LoopBody = cast<WhileStmt>(Term)->getBody();
990 std::make_shared<PathDiagnosticControlFlowPiece>(NewLoc, PrevLoc));
998 if (
const auto *FS = dyn_cast_or_null<ObjCForCollectionStmt>(S))
999 return FS->getElement();
1006 "Loop body skipped when range is empty";
1008 "Loop body skipped when collection is empty";
1010 static std::unique_ptr<FilesToLineNumsMap>
1020 PathDiagnosticBuilder &PDB,
1024 bool AddPathEdges) {
1054 if (VisitedEntireCall) {
1055 C = cast<PathDiagnosticCallPiece>(PD.
getActivePath().front().get());
1057 const Decl *Caller = CE->getLocationContext()->getDecl();
1070 assert(LCM[&C->
path] ==
nullptr ||
1071 LCM[&C->
path] == CE->getCalleeContext());
1072 LCM[&C->
path] = CE->getCalleeContext();
1087 if (!CallStack.empty()) {
1088 assert(CallStack.back().first == C);
1089 CallStack.pop_back();
1113 LCM[&C->path] = CE->getCalleeContext();
1116 const Stmt *S = CE->getCalleeContext()->getCallSite();
1118 if (
const auto *Ex = dyn_cast_or_null<Expr>(S)) {
1143 if (
const Expr *Ex = PS->getStmtAs<
Expr>())
1151 if (!isa<ObjCForCollectionStmt>(PS->getStmt())) {
1159 if (!AddPathEdges) {
1169 if (CallerCtx != CalleeCtx && AddPathEdges) {
1172 CalleeCtx, CallerCtx);
1177 if (
const Stmt *Loop = BE->getSrc()->getLoopTarget()) {
1179 const Stmt *Body =
nullptr;
1181 if (
const auto *FS = dyn_cast<ForStmt>(Loop))
1182 Body = FS->getBody();
1183 else if (
const auto *WS = dyn_cast<WhileStmt>(Loop))
1184 Body = WS->getBody();
1185 else if (
const auto *OFS = dyn_cast<ObjCForCollectionStmt>(Loop)) {
1186 Body = OFS->getBody();
1187 }
else if (
const auto *FRS = dyn_cast<CXXForRangeStmt>(Loop)) {
1188 Body = FRS->getBody();
1192 auto p = std::make_shared<PathDiagnosticEventPiece>(
1193 L,
"Looping back to the head " 1195 p->setPrunable(
true);
1200 if (
const auto *CS = dyn_cast_or_null<CompoundStmt>(Body)) {
1207 const CFGBlock *BSrc = BE->getSrc();
1210 if (
const Stmt *Term = BSrc->getTerminator()) {
1218 const char *str =
nullptr;
1221 if (!IsInLoopBody) {
1222 if (isa<ObjCForCollectionStmt>(Term)) {
1224 }
else if (isa<CXXForRangeStmt>(Term)) {
1236 auto PE = std::make_shared<PathDiagnosticEventPiece>(L, str);
1237 PE->setPrunable(
true);
1239 PE->getLocation(), PDB.LC);
1242 }
else if (isa<BreakStmt>(Term) || isa<ContinueStmt>(Term) ||
1243 isa<GotoStmt>(Term)) {
1251 static std::unique_ptr<PathDiagnostic>
1254 return llvm::make_unique<PathDiagnostic>(
1272 if (isa<ExprWithCleanups>(S) ||
1273 isa<CXXBindTemporaryExpr>(S) ||
1274 isa<SubstNonTypeTemplateParmExpr>(S))
1285 case Stmt::BinaryOperatorClass: {
1286 const auto *BO = cast<BinaryOperator>(S);
1287 if (!BO->isLogicalOp())
1289 return BO->getLHS() == Cond || BO->getRHS() == Cond;
1291 case Stmt::IfStmtClass:
1292 return cast<IfStmt>(S)->getCond() == Cond;
1293 case Stmt::ForStmtClass:
1294 return cast<ForStmt>(S)->getCond() == Cond;
1295 case Stmt::WhileStmtClass:
1296 return cast<WhileStmt>(S)->getCond() == Cond;
1297 case Stmt::DoStmtClass:
1298 return cast<DoStmt>(S)->getCond() == Cond;
1299 case Stmt::ChooseExprClass:
1300 return cast<ChooseExpr>(S)->getCond() == Cond;
1301 case Stmt::IndirectGotoStmtClass:
1302 return cast<IndirectGotoStmt>(S)->getTarget() == Cond;
1303 case Stmt::SwitchStmtClass:
1304 return cast<SwitchStmt>(S)->getCond() == Cond;
1305 case Stmt::BinaryConditionalOperatorClass:
1306 return cast<BinaryConditionalOperator>(S)->getCond() == Cond;
1307 case Stmt::ConditionalOperatorClass: {
1308 const auto *CO = cast<ConditionalOperator>(S);
1309 return CO->getCond() == Cond ||
1310 CO->getLHS() == Cond ||
1311 CO->getRHS() == Cond;
1313 case Stmt::ObjCForCollectionStmtClass:
1314 return cast<ObjCForCollectionStmt>(S)->getElement() == Cond;
1315 case Stmt::CXXForRangeStmtClass: {
1316 const auto *FRS = cast<CXXForRangeStmt>(S);
1317 return FRS->getCond() == Cond || FRS->getRangeInit() == Cond;
1325 if (
const auto *FS = dyn_cast<ForStmt>(FL))
1326 return FS->getInc() == S || FS->getInit() == S;
1327 if (
const auto *FRS = dyn_cast<CXXForRangeStmt>(FL))
1328 return FRS->getInc() == S || FRS->getRangeStmt() == S ||
1329 FRS->getLoopVarStmt() || FRS->getRangeInit() == S;
1342 PathPieces::iterator Prev = pieces.end();
1343 for (PathPieces::iterator I = pieces.begin(), E = Prev; I != E;
1354 const Stmt *InnerStmt =
nullptr;
1355 while (NextSrcContext.
isValid() && NextSrcContext.
asStmt() != InnerStmt) {
1356 SrcContexts.push_back(NextSrcContext);
1357 InnerStmt = NextSrcContext.
asStmt();
1366 const Stmt *Dst = Piece->getEndLocation().getStmtOrNull();
1376 if (std::find(SrcContexts.begin(), SrcContexts.end(), DstContext) !=
1381 Piece->setStartLocation(DstContext);
1389 if (
const Stmt *PrevSrc =
1390 PrevPiece->getStartLocation().getStmtOrNull()) {
1392 if (PrevSrcParent ==
1394 PrevPiece->setEndLocation(DstContext);
1405 std::make_shared<PathDiagnosticControlFlowPiece>(SrcLoc, DstContext);
1407 I = pieces.insert(I, std::move(
P));
1423 for (PathPieces::iterator I = pieces.begin(), E = pieces.end(); I != E; ++I) {
1429 const Stmt *s1Start = PieceI->getStartLocation().getStmtOrNull();
1430 const Stmt *s1End = PieceI->getEndLocation().getStmtOrNull();
1432 if (!s1Start || !s1End)
1435 PathPieces::iterator NextI = I; ++NextI;
1447 StringRef S = EV->getString();
1466 if (!s2Start || !s2End || s1End != s2Start)
1471 if (!(isa<ForStmt>(s1Start) || isa<WhileStmt>(s1Start) ||
1472 isa<IfStmt>(s1Start) || isa<ObjCForCollectionStmt>(s1Start) ||
1473 isa<CXXForRangeStmt>(s1Start)))
1483 I = pieces.erase(I);
1498 if (FID != SM.
getFileID(ExpansionRange.getEnd()))
1502 const llvm::MemoryBuffer *Buffer = SM.
getBuffer(FID, &Invalid);
1506 unsigned BeginOffset = SM.
getFileOffset(ExpansionRange.getBegin());
1507 unsigned EndOffset = SM.
getFileOffset(ExpansionRange.getEnd());
1508 StringRef Snippet = Buffer->getBuffer().slice(BeginOffset, EndOffset);
1514 if (Snippet.find_first_of(
"\r\n") != StringRef::npos)
1518 return Snippet.size();
1545 for (PathPieces::iterator I = Path.begin(), E = Path.end(); I != E; ) {
1554 const Stmt *s1Start = PieceI->getStartLocation().getStmtOrNull();
1555 const Stmt *s1End = PieceI->getEndLocation().getStmtOrNull();
1557 PathPieces::iterator NextI = I; ++NextI;
1561 const auto *PieceNextI =
1565 if (isa<PathDiagnosticEventPiece>(NextI->get())) {
1578 const Stmt *s2Start = PieceNextI->getStartLocation().getStmtOrNull();
1579 const Stmt *s2End = PieceNextI->getEndLocation().getStmtOrNull();
1581 if (s1Start && s2Start && s1Start == s2End && s2Start == s1End) {
1582 const size_t MAX_SHORT_LINE_LENGTH = 80;
1584 if (s1Length && *s1Length <= MAX_SHORT_LINE_LENGTH) {
1586 if (s2Length && *s2Length <= MAX_SHORT_LINE_LENGTH) {
1588 I = Path.erase(NextI);
1611 bool erased =
false;
1613 for (PathPieces::iterator I = path.begin(), E = path.end(); I != E;
1622 const Stmt *start = PieceI->getStartLocation().getStmtOrNull();
1623 const Stmt *end = PieceI->getEndLocation().getStmtOrNull();
1641 std::swap(SecondLoc, FirstLoc);
1650 const size_t MAX_PUNY_EDGE_LENGTH = 2;
1651 if (*ByteWidth <= MAX_PUNY_EDGE_LENGTH) {
1663 for (PathPieces::iterator I = path.begin(), E = path.end(); I != E; ++I) {
1669 PathPieces::iterator NextI = I; ++NextI;
1679 if (PieceI->getString() == PieceNextI->getString()) {
1688 bool hasChanges =
false;
1693 for (PathPieces::iterator I = path.begin(), E = path.end(); I != E; ) {
1695 if (
auto *CallI = dyn_cast<PathDiagnosticCallPiece>(I->get())) {
1698 if (!OCS.count(CallI)) {
1714 const Stmt *s1Start = PieceI->getStartLocation().getStmtOrNull();
1715 const Stmt *s1End = PieceI->getEndLocation().getStmtOrNull();
1719 PathPieces::iterator NextI = I; ++NextI;
1730 const Stmt *s2Start = PieceNextI->getStartLocation().getStmtOrNull();
1731 const Stmt *s2End = PieceNextI->getEndLocation().getStmtOrNull();
1749 if (level1 && level1 == level2 && level1 == level3 && level1 == level4) {
1750 PieceI->setEndLocation(PieceNextI->getEndLocation());
1763 if (s1End && s1End == s2Start && level2) {
1764 bool removeEdge =
false;
1790 else if (s1Start && s2End &&
1803 else if (s1Start && s2End &&
1805 SourceRange EdgeRange(PieceI->getEndLocation().asLocation(),
1806 PieceI->getStartLocation().asLocation());
1813 PieceI->setEndLocation(PieceNextI->getEndLocation());
1827 if (s1End == s2Start) {
1828 const auto *FS = dyn_cast_or_null<ObjCForCollectionStmt>(level3);
1829 if (FS && FS->getCollection()->IgnoreParens() == s2Start &&
1830 s2End == FS->getElement()) {
1831 PieceI->setEndLocation(PieceNextI->getEndLocation());
1868 const auto *FirstEdge =
1873 const Decl *D = LCM[&Path]->getDecl();
1875 if (FirstEdge->getStartLocation() != EntryLoc)
1882 std::vector<std::shared_ptr<PathDiagnosticPiece>>>;
1898 PathDiagnosticBuilder &PDB,
1912 if (GenerateDiagnostics) {
1913 auto EndNotes = VisitorsDiagnostics.find(ErrorNode);
1914 std::shared_ptr<PathDiagnosticPiece> LastPiece;
1915 if (EndNotes != VisitorsDiagnostics.end()) {
1916 assert(!EndNotes->second.empty());
1917 LastPiece = EndNotes->second[0];
1919 LastPiece = BugReporterVisitor::getDefaultEndPath(PDB, ErrorNode, *R);
1921 PD->setEndOfPath(LastPiece);
1927 if (GenerateDiagnostics)
1929 NextNode, *PD, PrevLoc, PDB, LCM, CallStack, IE, AddPathEdges);
1931 auto VisitorNotes = VisitorsDiagnostics.find(NextNode);
1933 if (!GenerateDiagnostics || VisitorNotes == VisitorsDiagnostics.end())
1938 std::set<llvm::FoldingSetNodeID> DeduplicationSet;
1941 for (
const auto &Note : VisitorNotes->second) {
1942 llvm::FoldingSetNodeID
ID;
1944 auto P = DeduplicationSet.insert(ID);
1949 addEdgeToPath(PD->getActivePath(), PrevLoc, Note->getLocation(),
1952 PD->getActivePath().push_front(Note);
1965 if (!AddPathEdges && GenerateDiagnostics)
1969 if (!PD->path.empty()) {
1971 bool stillHasNotes =
1973 assert(stillHasNotes);
1974 (void)stillHasNotes;
2008 void BugType::anchor() {}
2012 void BuiltinBug::anchor() {}
2018 void BugReport::NodeResolver::anchor() {}
2024 llvm::FoldingSetNodeID
ID;
2025 visitor->Profile(ID);
2027 void *InsertPos =
nullptr;
2028 if (CallbacksSet.FindNodeOrInsertPos(ID, InsertPos)) {
2032 Callbacks.push_back(std::move(visitor));
2040 while (!interestingSymbols.empty()) {
2041 popInterestingSymbolsAndRegions();
2047 return DeclWithIssue;
2058 hash.AddPointer(&BT);
2059 hash.AddString(Description);
2063 }
else if (Location.isValid()) {
2064 Location.Profile(hash);
2071 if (!range.isValid())
2073 hash.AddInteger(range.getBegin().getRawEncoding());
2074 hash.AddInteger(range.getEnd().getRawEncoding());
2082 getInterestingSymbols().insert(sym);
2084 if (
const auto *meta = dyn_cast<SymbolMetadata>(sym))
2085 getInterestingRegions().insert(meta->getRegion());
2093 getInterestingRegions().insert(R);
2095 if (
const auto *SR = dyn_cast<SymbolicRegion>(R))
2096 getInterestingSymbols().insert(SR->getSymbol());
2107 InterestingLocationContexts.insert(LC);
2119 return getInterestingSymbols().count(sym);
2126 bool b = getInterestingRegions().count(R);
2129 if (
const auto *SR = dyn_cast<SymbolicRegion>(R))
2130 return getInterestingSymbols().count(SR->getSymbol());
2137 return InterestingLocationContexts.count(LC);
2140 void BugReport::lazyInitializeInterestingSets() {
2141 if (interestingSymbols.empty()) {
2142 interestingSymbols.push_back(
new Symbols());
2143 interestingRegions.push_back(
new Regions());
2148 lazyInitializeInterestingSets();
2149 return *interestingSymbols.back();
2153 lazyInitializeInterestingSets();
2154 return *interestingRegions.back();
2157 void BugReport::pushInterestingSymbolsAndRegions() {
2158 interestingSymbols.push_back(
new Symbols(getInterestingSymbols()));
2159 interestingRegions.push_back(
new Regions(getInterestingRegions()));
2162 void BugReport::popInterestingSymbolsAndRegions() {
2163 delete interestingSymbols.pop_back_val();
2164 delete interestingRegions.pop_back_val();
2172 const Stmt *S =
nullptr;
2176 if (BE->getBlock() == &Exit)
2188 if (Ranges.empty()) {
2189 if (
const auto *E = dyn_cast_or_null<Expr>(getStmt()))
2190 addRange(E->getSourceRange());
2196 if (Ranges.size() == 1 && !Ranges.begin()->isValid())
2199 return llvm::make_range(Ranges.begin(), Ranges.end());
2204 assert(!Location.isValid() &&
2205 "Either Location or ErrorNode should be specified but not both.");
2209 assert(Location.isValid());
2232 for (
const auto I : EQClassesVector)
2237 if (BugTypes.isEmpty())
2245 for (
const auto I : bugTypes)
2246 const_cast<BugType*
>(I)->FlushReports(*
this);
2250 for (
const auto EQ : EQClassesVector)
2257 llvm::DeleteContainerSeconds(StrBugTypes);
2260 BugTypes = F.getEmptySet();
2274 std::unique_ptr<ExplodedGraph> Graph;
2280 class TrimmedGraph {
2283 using PriorityMapTy = llvm::DenseMap<const ExplodedNode *, unsigned>;
2285 PriorityMapTy PriorityMap;
2287 using NodeIndexPair = std::pair<const ExplodedNode *, size_t>;
2291 std::unique_ptr<ExplodedGraph> G;
2294 template <
bool Descending>
2295 class PriorityCompare {
2296 const PriorityMapTy &PriorityMap;
2299 PriorityCompare(
const PriorityMapTy &M) : PriorityMap(M) {}
2302 PriorityMapTy::const_iterator LI = PriorityMap.find(LHS);
2303 PriorityMapTy::const_iterator RI = PriorityMap.find(RHS);
2304 PriorityMapTy::const_iterator E = PriorityMap.end();
2311 return Descending ? LI->second > RI->second
2312 : LI->second < RI->second;
2315 bool operator()(
const NodeIndexPair &LHS,
const NodeIndexPair &RHS)
const {
2316 return (*
this)(LHS.first, RHS.first);
2324 bool popNextReportGraph(ReportGraph &GraphWrapper);
2329 TrimmedGraph::TrimmedGraph(
const ExplodedGraph *OriginalGraph,
2334 G = OriginalGraph->
trim(Nodes, &ForwardMap, &InverseMap);
2339 llvm::SmallPtrSet<const ExplodedNode *, 32> RemainingNodes;
2341 for (
unsigned i = 0, count = Nodes.size(); i < count; ++i) {
2342 if (
const ExplodedNode *NewNode = ForwardMap.lookup(Nodes[i])) {
2343 ReportNodes.push_back(std::make_pair(NewNode, i));
2344 RemainingNodes.insert(NewNode);
2348 assert(!RemainingNodes.empty() &&
"No error node found in the trimmed graph");
2351 std::queue<const ExplodedNode *> WS;
2353 assert(G->num_roots() == 1);
2354 WS.push(*G->roots_begin());
2355 unsigned Priority = 0;
2357 while (!WS.empty()) {
2361 PriorityMapTy::iterator PriorityEntry;
2363 std::tie(PriorityEntry, IsNew) =
2364 PriorityMap.insert(std::make_pair(Node, Priority));
2368 assert(PriorityEntry->second <= Priority);
2372 if (RemainingNodes.erase(Node))
2373 if (RemainingNodes.empty())
2383 llvm::sort(ReportNodes.begin(), ReportNodes.end(),
2384 PriorityCompare<true>(PriorityMap));
2387 bool TrimmedGraph::popNextReportGraph(ReportGraph &GraphWrapper) {
2388 if (ReportNodes.empty())
2392 std::tie(OrigN, GraphWrapper.Index) = ReportNodes.pop_back_val();
2393 assert(PriorityMap.find(OrigN) != PriorityMap.end() &&
2394 "error node not accessible from root");
2398 auto GNew = llvm::make_unique<ExplodedGraph>();
2399 GraphWrapper.BackMap.clear();
2411 InterExplodedGraphMap::const_iterator IMitr = InverseMap.find(OrigN);
2412 assert(IMitr != InverseMap.end() &&
"No mapping to original node.");
2413 GraphWrapper.BackMap[NewN] = IMitr->second;
2419 GraphWrapper.ErrorNode = NewN;
2425 GNew->addRoot(NewN);
2432 PriorityCompare<false>(PriorityMap));
2435 GraphWrapper.Graph = std::move(GNew);
2443 using MacroStackTy =
2445 std::pair<std::shared_ptr<PathDiagnosticMacroPiece>,
SourceLocation>>;
2447 using PiecesTy = std::vector<std::shared_ptr<PathDiagnosticPiece>>;
2449 MacroStackTy MacroStack;
2452 for (PathPieces::const_iterator I = path.begin(), E = path.end();
2454 const auto &piece = *I;
2457 if (
auto *call = dyn_cast<PathDiagnosticCallPiece>(&*piece)) {
2466 SourceLocation InstantiationLoc = Loc.
isMacroID() ?
2472 Pieces.push_back(piece);
2479 if (!MacroStack.empty() && InstantiationLoc == MacroStack.back().second) {
2480 MacroStack.back().first->subPieces.push_back(piece);
2486 std::shared_ptr<PathDiagnosticMacroPiece> MacroGroup;
2488 SourceLocation ParentInstantiationLoc = InstantiationLoc.
isMacroID() ?
2493 while (!MacroStack.empty()) {
2494 if (InstantiationLoc == MacroStack.back().second) {
2495 MacroGroup = MacroStack.back().first;
2499 if (ParentInstantiationLoc == MacroStack.back().second) {
2500 MacroGroup = MacroStack.back().first;
2504 MacroStack.pop_back();
2507 if (!MacroGroup || ParentInstantiationLoc == MacroStack.back().second) {
2509 auto NewGroup = std::make_shared<PathDiagnosticMacroPiece>(
2513 MacroGroup->subPieces.push_back(NewGroup);
2515 assert(InstantiationLoc.
isFileID());
2516 Pieces.push_back(NewGroup);
2519 MacroGroup = NewGroup;
2520 MacroStack.push_back(std::make_pair(MacroGroup, InstantiationLoc));
2524 MacroGroup->subPieces.push_back(piece);
2530 path.insert(path.end(), Pieces.begin(), Pieces.end());
2536 static std::unique_ptr<VisitorsDiagnosticsTy>
2539 auto Notes = llvm::make_unique<VisitorsDiagnosticsTy>();
2551 visitors.push_back(std::move(*I));
2557 std::shared_ptr<PathDiagnosticPiece> LastPiece;
2558 for (
auto &V : visitors) {
2559 V->finalizeVisitor(BRC, ErrorNode, *R);
2561 if (
auto Piece = V->getEndPath(BRC, ErrorNode, *R)) {
2562 assert(!LastPiece &&
2563 "There can only be one final piece in a diagnostic.");
2564 LastPiece = std::move(Piece);
2565 (*Notes)[ErrorNode].push_back(LastPiece);
2571 for (
auto &V : visitors) {
2572 auto P = V->VisitNode(NextNode, Pred, BRC, *R);
2574 (*Notes)[NextNode].push_back(std::move(
P));
2590 std::pair<BugReport*, std::unique_ptr<VisitorsDiagnosticsTy>> findValidReport(
2591 TrimmedGraph &TrimG,
2592 ReportGraph &ErrorGraph,
2597 while (TrimG.popNextReportGraph(ErrorGraph)) {
2599 assert(ErrorGraph.Index < bugReports.size());
2600 BugReport *R = bugReports[ErrorGraph.Index];
2601 assert(R &&
"No original report found for sliced graph.");
2602 assert(R->isValid() &&
"Report selected by trimmed graph marked invalid.");
2607 R->addVisitor(llvm::make_unique<LikelyFalsePositiveSuppressionBRVisitor>());
2610 R->addVisitor(llvm::make_unique<NilReceiverBRVisitor>());
2611 R->addVisitor(llvm::make_unique<ConditionBRVisitor>());
2612 R->addVisitor(llvm::make_unique<CXXSelfAssignmentBRVisitor>());
2617 std::unique_ptr<VisitorsDiagnosticsTy> visitorNotes =
2618 generateVisitorsDiagnostics(R, ErrorNode, BRC);
2625 R->addVisitor(llvm::make_unique<FalsePositiveRefutationBRVisitor>());
2629 generateVisitorsDiagnostics(R, ErrorGraph.ErrorNode, BRC);
2634 return std::make_pair(R, std::move(visitorNotes));
2638 return std::make_pair(
nullptr, llvm::make_unique<VisitorsDiagnosticsTy>());
2641 std::unique_ptr<DiagnosticForConsumerMapTy>
2645 assert(!bugReports.empty());
2647 auto Out = llvm::make_unique<DiagnosticForConsumerMapTy>();
2648 bool HasValid =
false;
2650 for (
const auto I : bugReports) {
2653 errorNodes.push_back(I->getErrorNode());
2656 errorNodes.push_back(
nullptr);
2665 TrimmedGraph TrimG(&
getGraph(), errorNodes);
2666 ReportGraph ErrorGraph;
2667 auto ReportInfo = findValidReport(TrimG, ErrorGraph, bugReports,
2674 PathDiagnosticBuilder PDB(*
this, R, ErrorGraph.BackMap, PC);
2676 PC->getGenerationScheme(), PDB, ErrorNode, *ReportInfo.second);
2677 (*Out)[PC] = std::move(PD);
2685 BugTypes = F.add(BugTypes, BT);
2692 assert((E->isSink() || E->getLocation().getTag()) &&
2693 "Error node must either be a sink or have a tag");
2696 E->getLocationContext()->getAnalysisDeclContext();
2707 assert(ValidSourceLoc);
2710 if (!ValidSourceLoc)
2714 llvm::FoldingSetNodeID
ID;
2718 BugType& BT = R->getBugType();
2725 EQClasses.InsertNode(EQ, InsertPos);
2726 EQClassesVector.push_back(EQ);
2728 EQ->AddReport(std::move(R));
2737 struct FRIEC_WLItem {
2750 return BEP->getBlock();
2766 static bool isImmediateSinkBlock(
const CFGBlock *Blk) {
2778 if (isa<CXXThrowExpr>(StmtElm->getStmt()))
2791 static bool isInevitablySinking(
const ExplodedNode *N) {
2794 const CFGBlock *StartBlk = findBlockForNode(N);
2797 if (isImmediateSinkBlock(StartBlk))
2801 llvm::SmallPtrSet<const CFGBlock *, 32> Visited;
2803 DFSWorkList.push_back(StartBlk);
2804 while (!DFSWorkList.empty()) {
2805 const CFGBlock *Blk = DFSWorkList.back();
2806 DFSWorkList.pop_back();
2807 Visited.insert(Blk);
2809 for (
const auto &Succ : Blk->
succs()) {
2810 if (
const CFGBlock *SuccBlk = Succ.getReachableBlock()) {
2811 if (SuccBlk == &Cfg.
getExit()) {
2819 if (!isImmediateSinkBlock(SuccBlk) && !Visited.count(SuccBlk)) {
2822 DFSWorkList.push_back(SuccBlk);
2837 BugType& BT = I->getBugType();
2844 for (
auto &I : EQ) {
2848 bugReports.push_back(R);
2862 for (; I != E; ++I) {
2867 if (errorNode->
isSink()) {
2869 "BugType::isSuppressSink() should not be 'true' for sink end nodes");
2873 bugReports.push_back(&*I);
2875 exampleReport = &*I;
2883 if (isInevitablySinking(errorNode))
2888 using WLItem = FRIEC_WLItem;
2891 llvm::DenseMap<const ExplodedNode *, unsigned> Visited;
2894 WL.push_back(errorNode);
2895 Visited[errorNode] = 1;
2897 while (!WL.empty()) {
2898 WLItem &WI = WL.back();
2899 assert(!WI.N->succ_empty());
2901 for (; WI.I != WI.E; ++WI.I) {
2907 bugReports.push_back(&*I);
2909 exampleReport = &*I;
2918 unsigned &mark = Visited[Succ];
2928 if (!WL.empty() && &WL.back() == &WI)
2935 return exampleReport;
2940 BugReport *report = FindReportInEquivalenceClass(EQ, bugReports);
2945 std::unique_ptr<DiagnosticForConsumerMapTy> Diagnostics =
2946 generateDiagnosticForConsumerMap(report, Consumers, bugReports);
2948 for (
auto &
P : *Diagnostics) {
2950 std::unique_ptr<PathDiagnostic> &PD =
P.second;
2954 if (PD->path.empty()) {
2956 auto piece = llvm::make_unique<PathDiagnosticEventPiece>(
2959 piece->addRange(
Range);
2960 PD->setEndOfPath(std::move(piece));
2967 for (
auto I = report->
getNotes().rbegin(),
2968 E = report->
getNotes().rend(); I != E; ++I) {
2970 auto ConvertedPiece = std::make_shared<PathDiagnosticEventPiece>(
2973 ConvertedPiece->addRange(R);
2975 Pieces.push_front(std::move(ConvertedPiece));
2978 for (
auto I = report->
getNotes().rbegin(),
2979 E = report->
getNotes().rend(); I != E; ++I)
2980 Pieces.push_front(*I);
2985 for (
const auto &i : Meta)
2994 static void populateExecutedLinesWithFunctionSignature(
2996 std::unique_ptr<FilesToLineNumsMap> &ExecutedLines) {
2999 if (
const auto FD = dyn_cast<FunctionDecl>(Signature)) {
3000 SignatureSourceRange = FD->getSourceRange();
3001 }
else if (
const auto OD = dyn_cast<ObjCMethodDecl>(Signature)) {
3002 SignatureSourceRange = OD->getSourceRange();
3008 : SignatureSourceRange.
getEnd();
3013 for (
unsigned Line = StartLine;
Line <= EndLine;
Line++)
3017 static void populateExecutedLinesWithStmt(
3019 std::unique_ptr<FilesToLineNumsMap> &ExecutedLines) {
3024 ExecutedLines->operator[](FID.
getHashValue()).insert(LineNo);
3029 static std::unique_ptr<FilesToLineNumsMap>
3031 auto ExecutedLines = llvm::make_unique<FilesToLineNumsMap>();
3037 populateExecutedLinesWithFunctionSignature(D, SM, ExecutedLines);
3040 const Decl* D = CE->getCalleeContext()->getDecl();
3041 populateExecutedLinesWithFunctionSignature(D, SM, ExecutedLines);
3043 populateExecutedLinesWithStmt(S, SM, ExecutedLines);
3051 if (
const auto *RS = dyn_cast_or_null<ReturnStmt>(P)) {
3052 populateExecutedLinesWithStmt(RS, SM, ExecutedLines);
3056 if (P && (isa<SwitchCase>(P) || isa<LabelStmt>(P)))
3057 populateExecutedLinesWithStmt(P, SM, ExecutedLines);
3062 return ExecutedLines;
3065 std::unique_ptr<DiagnosticForConsumerMapTy>
3066 BugReporter::generateDiagnosticForConsumerMap(
3071 auto Out = llvm::make_unique<DiagnosticForConsumerMapTy>();
3072 for (
auto *Consumer : consumers)
3082 assert(!bugReports.empty());
3083 MaxBugClassSize.updateMax(bugReports.size());
3084 std::unique_ptr<DiagnosticForConsumerMapTy> Out =
3085 generatePathDiagnostics(consumers, bugReports);
3090 MaxValidBugClassSize.updateMax(bugReports.size());
3095 for (
auto const &
P : *Out)
3097 P.second->resetDiagnosticLocationToMainFile();
3104 StringRef Name, StringRef
Category,
3113 StringRef name, StringRef category,
3117 BugType *BT = getBugTypeForName(CheckName, name, category);
3118 auto R = llvm::make_unique<BugReport>(*BT, str, Loc);
3123 emitReport(std::move(R));
3126 BugType *BugReporter::getBugTypeForName(CheckName CheckName, StringRef name,
3127 StringRef category) {
3129 llvm::raw_svector_ostream(fullDesc) << CheckName.
getName() <<
":" << name
3131 BugType *&BT = StrBugTypes[fullDesc];
3133 BT =
new BugType(CheckName, name, category);
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...
bool shouldPrunePath() const
Indicates whether or not any path pruning should take place when generating a PathDiagnostic from thi...
static DiagnosticBuilder Diag(DiagnosticsEngine *Diags, const LangOptions &Features, FullSourceLoc TokLoc, const char *TokBegin, const char *TokRangeBegin, const char *TokRangeEnd, unsigned DiagID)
Produce a diagnostic highlighting some portion of a literal.
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.
static bool removeUnneededCalls(PathPieces &pieces, BugReport *R, LocationContextMap &LCM, bool IsInteresting=false)
Recursively scan through a path and prune out calls and macros pieces that aren't needed...
PathDiagnosticLocation getUniqueingLocation() const
Get the location on which the report should be uniqued.
bool hasCallStackMessage()
bool isInteresting(SymbolRef sym)
PathDiagnosticLocation getLocation() const override
succ_iterator succ_begin()
CFGStmtMap * getCFGStmtMap()
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
AnalyzerOptions & getAnalyzerOptions()
Stmt - This represents one statement.
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.
bool shouldPrunePaths()
Returns whether irrelevant parts of a bug report path should be pruned out of the final output...
Stmt * getParent(Stmt *) const
void Profile(llvm::FoldingSetNodeID &ID) const
A Range represents the closed range [from, to].
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
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.
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
void clearVisitors()
Remove all visitors attached to this bug report.
PathDiagnostic - PathDiagnostic objects represent a single path-sensitive diagnostic.
void setStartLocation(const PathDiagnosticLocation &L)
void addRange(SourceRange R)
Add a range to a bug report.
static std::unique_ptr< PathDiagnostic > generateEmptyDiagnosticForReport(BugReport *R, SourceManager &SM)
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.
unsigned getHashValue() const
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...
static std::unique_ptr< PathDiagnostic > generatePathDiagnosticForConsumer(PathDiagnosticConsumer::PathGenerationScheme ActiveScheme, PathDiagnosticBuilder &PDB, const ExplodedNode *ErrorNode, const VisitorsDiagnosticsTy &VisitorsDiagnostics)
This function is responsible for generating diagnostic pieces that are not provided by bug report vis...
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
Optional< T > getLocationAs() const LLVM_LVALUE_FUNCTION
virtual llvm::iterator_range< ranges_iterator > getRanges()
Get the SourceRanges associated with the report.
StringRef getCategory() const
const Stmt * getStmt() const
llvm::DenseMap< const ExplodedNode *, std::vector< std::shared_ptr< PathDiagnosticPiece > >> VisitorsDiagnosticsTy
llvm::DenseMap< const PathPieces *, const LocationContext * > LocationContextMap
A map from PathDiagnosticPiece to the LocationContext of the inlined function call it represents...
virtual void FlushReports(BugReporter &BR)
const BugType & getBugType() const
void emitReport(std::unique_ptr< BugReport > R)
Add the given report to the set of reports tracked by BugReporter.
static void addEdgeToPath(PathPieces &path, PathDiagnosticLocation &PrevLoc, PathDiagnosticLocation NewLoc, const LocationContext *LC)
Adds a sanitized control-flow diagnostic edge to a path.
const Stmt * asStmt() const
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified...
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 LocationContext * getLocationContext() const
ExplodedGraph & getGraph()
Expr * IgnoreParenCasts() LLVM_READONLY
IgnoreParenCasts - Ignore parentheses and casts.
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()
static void reversePropagateIntererstingSymbols(BugReport &R, InterestingExprs &IE, const ProgramState *State, const Expr *Ex, const LocationContext *LCtx)
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()
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
const ExplodedNode *const * const_succ_iterator
Const iterator for iterating over Stmt * arrays that contain only Expr *.
const Stmt * getCallSite() const
StringRef getName() const
const void * getTag() const
Return the opaque tag (if any) on the PathDiagnosticPiece.
VisitorList::iterator visitor_iterator
const Stmt * getStmtOrNull() const
void HandlePathDiagnostic(std::unique_ptr< PathDiagnostic > D)
Represents a single basic block in a source-level CFG.
Represents a point when we finish the call exit sequence (for inlined call).
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)
Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt...
visitor_iterator visitor_end()
const AnnotatedLine * Line
CFGBlock * getBlock(Stmt *S)
Returns the CFGBlock the specified Stmt* appears in.
~GRBugReporter() override
visitor_iterator visitor_begin()
Iterators through the custom diagnostic visitors.
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)
Loc getLValue(const CXXBaseSpecifier &BaseSpec, const SubRegion *Super) const
Get the lvalue for a base class object reference.
const Decl * getUniqueingDecl() const
Get the declaration containing the uniqueing location.
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
BugReporterContext(GRBugReporter &br, InterExplodedGraphMap &Backmap)
void markInteresting(SymbolRef sym)
static const Stmt * GetPreviousStmt(const ExplodedNode *N)
unsigned getExpansionLineNumber(SourceLocation Loc, bool *Invalid=nullptr) const
ParentMap & getParentMap() const
virtual bool hasBody() const
Returns true if this Decl represents a declaration for a body of code, such as a function or method d...
Only runs visitors, no output generated.
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.
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::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.
Stmt * getParentIgnoreParens(Stmt *) const
const MemRegion * getAsRegion() const
ExplodedGraph & getGraph()
getGraph - Get the exploded graph created by the analysis engine for the analyzed method or function...
static bool isIncrementOrInitInForLoop(const Stmt *S, const Stmt *FL)
SourceLocation getLocStart() const LLVM_READONLY
void setCallee(const CallEnter &CE, const SourceManager &SM)
std::shared_ptr< PathDiagnosticControlFlowPiece > generateDiagForGotoOP(const Stmt *S, PathDiagnosticBuilder &PDB, PathDiagnosticLocation &Start)
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...
std::shared_ptr< PathDiagnosticControlFlowPiece > generateDiagForSwitchOP(const ExplodedNode *N, const CFGBlock *Dst, const SourceManager &SM, const LocationContext *LC, PathDiagnosticBuilder &PDB, PathDiagnosticLocation &Start)
FullSourceLoc asLocation() const
ParentMap & getParentMap() const
PathDiagnosticLocation getLocation() const override
static const Stmt * getEnclosingParent(const Stmt *S, const ParentMap &PM)
Used for plist output, used for "arrows" generation.
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...
std::unique_ptr< DiagnosticForConsumerMapTy > generatePathDiagnostics(ArrayRef< PathDiagnosticConsumer *> consumers, ArrayRef< BugReport *> &bugReports) override
bugReports A set of bug reports within a single equivalence class
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.
std::pair< PathDiagnosticCallPiece *, const ExplodedNode * > StackDiagPair
virtual ~BugReporterData()
StmtClass getStmtClass() const
static void updateStackPiecesWithMessage(PathDiagnosticPiece &P, StackDiagVector &CallStack)
StringRef getCheckName() const
static const Stmt * getTerminatorCondition(const CFGBlock *B)
A customized wrapper for CFGBlock::getTerminatorCondition() which returns the element for ObjCForColl...
static std::unique_ptr< FilesToLineNumsMap > findExecutedLines(SourceManager &SM, const ExplodedNode *N)
bool isWithinCall() const
const Decl * getDecl() const
unsigned getExpansionLineNumber(bool *Invalid=nullptr) const
llvm::DenseMap< const ExplodedNode *, const ExplodedNode * > InterExplodedGraphMap
static bool isLoop(const Stmt *Term)
FileID getFileID(SourceLocation SpellingLoc) const
Return the FileID for a SourceLocation.
virtual PathGenerationScheme getGenerationScheme() const
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.
const StackFrameContext * getStackFrame() const
StringRef getShortDescription(bool UseFallback=true) const
CharSourceRange getExpansionRange(SourceLocation Loc) const
Given a SourceLocation object, return the range of tokens covered by the expansion in the ultimate fi...
void generateMinimalDiagForBlockEdge(const ExplodedNode *N, BlockEdge BE, const SourceManager &SM, PathDiagnosticBuilder &PDB, PathDiagnostic &PD)
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 ...
llvm::ilist< BugReport >::iterator iterator
ProgramStateManager & getStateManager()
getStateManager - Return the state manager used by the analysis engine.
Used for HTML and text output.
static void CompactPathDiagnostic(PathPieces &path, const SourceManager &SM)
CompactPathDiagnostic - This function postprocesses a PathDiagnostic object and collapses PathDiagost...
Defines the clang::SourceLocation class and associated facilities.
PathPieces & getActivePath()
Return the path currently used by builders for constructing the PathDiagnostic.
bool shouldCrosscheckWithZ3()
Returns whether bug reports should be crosschecked with the Z3 constraint manager backend...
pred_iterator pred_begin()
static const Stmt * getStmtParent(const Stmt *S, const ParentMap &PM)
static PathDiagnosticLocation createEndOfPath(const ExplodedNode *N, const SourceManager &SM)
Create a location corresponding to the next valid ExplodedNode as end of path location.
void Register(BugType *BT)
Represents a top-level expression in a basic block.
GRBugReporter is used for generating path-sensitive reports.
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...
A SourceLocation and its associated SourceManager.
static void generatePathDiagnosticsForNode(const ExplodedNode *N, PathDiagnostic &PD, PathDiagnosticLocation &PrevLoc, PathDiagnosticBuilder &PDB, LocationContextMap &LCM, StackDiagVector &CallStack, InterestingExprs &IE, bool AddPathEdges)
Generate diagnostics for the node N, and write it into PD.
bool isSuppressOnSink() const
isSuppressOnSink - Returns true if bug reports associated with this bug type should be suppressed if ...
const ExplodedNode *const * const_pred_iterator
std::shared_ptr< PathDiagnosticControlFlowPiece > generateDiagForBinaryOP(const ExplodedNode *N, const Stmt *T, const CFGBlock *Src, const CFGBlock *Dst, const SourceManager &SM, PathDiagnosticBuilder &PDB, const LocationContext *LC)
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.
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...
void EmitBasicReport(const Decl *DeclWithIssue, const CheckerBase *Checker, StringRef BugName, StringRef BugCategory, StringRef BugStr, PathDiagnosticLocation Loc, ArrayRef< SourceRange > Ranges=None)
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 getBegin() const
static const char StrLoopRangeEmpty[]
This class handles loading and caching of source files into memory.
SourceManager & getSourceManager()
void setDeclWithIssue(const Decl *declWithIssue)
Specifically set the Decl where an issue occurred.
bool isPathSensitive() const
True when the report has an execution path associated with it.
static bool isInLoopBody(ParentMap &PM, const Stmt *S, const Stmt *Term)