43 #include "llvm/ADT/ArrayRef.h" 44 #include "llvm/ADT/DenseMap.h" 45 #include "llvm/ADT/DenseSet.h" 46 #include "llvm/ADT/FoldingSet.h" 47 #include "llvm/ADT/None.h" 48 #include "llvm/ADT/Optional.h" 49 #include "llvm/ADT/STLExtras.h" 50 #include "llvm/ADT/SmallPtrSet.h" 51 #include "llvm/ADT/SmallString.h" 52 #include "llvm/ADT/SmallVector.h" 53 #include "llvm/ADT/Statistic.h" 54 #include "llvm/ADT/StringRef.h" 55 #include "llvm/ADT/iterator_range.h" 56 #include "llvm/Support/Casting.h" 57 #include "llvm/Support/Compiler.h" 58 #include "llvm/Support/ErrorHandling.h" 59 #include "llvm/Support/MemoryBuffer.h" 60 #include "llvm/Support/raw_ostream.h" 72 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() {}
96 std::pair<PathDiagnosticCallPiece *, const ExplodedNode *>;
100 using VisitorsDiagnosticsTy =
101 llvm::DenseMap<const ExplodedNode *, std::vector<PathDiagnosticPieceRef>>;
105 using LocationContextMap =
106 llvm::DenseMap<const PathPieces *, const LocationContext *>;
111 class PathDiagnosticConstruct {
113 const PathDiagnosticConsumer *Consumer;
116 const ExplodedNode *CurrentNode;
120 LocationContextMap LCM;
127 CallWithEntryStack CallStack;
131 std::unique_ptr<PathDiagnostic> PD;
134 PathDiagnosticConstruct(
const PathDiagnosticConsumer *PDC,
135 const ExplodedNode *ErrorNode,
136 const PathSensitiveBugReport *R);
141 assert(CurrentNode &&
"Already reached the root!");
142 return CurrentNode->getLocationContext();
149 return LCM.find(&PD->getActivePath())->getSecond();
152 const ExplodedNode *getCurrentNode()
const {
return CurrentNode; }
156 bool ascendToPrevNode() {
157 CurrentNode = CurrentNode->getFirstPred();
158 return static_cast<bool>(CurrentNode);
162 return getCurrLocationContext()->getParentMap();
167 const Stmt *getParent(
const Stmt *S)
const {
168 return getParentMap().getParent(S);
171 void updateLocCtxMap(
const PathPieces *Path,
const LocationContext *LC) {
176 const LocationContext *getLocationContextFor(
const PathPieces *Path)
const {
177 assert(LCM.count(Path) &&
178 "Failed to find the context associated with these pieces!");
179 return LCM.find(Path)->getSecond();
182 bool isInLocCtxMap(
const PathPieces *Path)
const {
return LCM.count(Path); }
184 PathPieces &getActivePath() {
return PD->getActivePath(); }
185 PathPieces &getMutablePieces() {
return PD->getMutablePieces(); }
187 bool shouldAddPathEdges()
const {
return Consumer->shouldAddPathEdges(); }
188 bool shouldGenerateDiagnostics()
const {
189 return Consumer->shouldGenerateDiagnostics();
191 bool supportsLogicalOpControlFlow()
const {
192 return Consumer->supportsLogicalOpControlFlow();
200 class PathDiagnosticBuilder :
public BugReporterContext {
202 std::unique_ptr<const ExplodedGraph> BugPath;
207 const PathSensitiveBugReport *R;
210 const ExplodedNode *
const ErrorNode;
213 std::unique_ptr<const VisitorsDiagnosticsTy> VisitorsDiagnostics;
221 PathSensitiveBugReporter &Reporter);
223 PathDiagnosticBuilder(
224 BugReporterContext BRC, std::unique_ptr<ExplodedGraph> BugPath,
225 PathSensitiveBugReport *r,
const ExplodedNode *ErrorNode,
226 std::unique_ptr<VisitorsDiagnosticsTy> VisitorsDiagnostics);
238 std::unique_ptr<PathDiagnostic>
239 generate(
const PathDiagnosticConsumer *PDC)
const;
243 const CallWithEntryStack &CallStack)
const;
244 void generatePathDiagnosticsForNode(PathDiagnosticConstruct &C,
245 PathDiagnosticLocation &PrevLoc)
const;
247 void generateMinimalDiagForBlockEdge(PathDiagnosticConstruct &C,
251 generateDiagForGotoOP(
const PathDiagnosticConstruct &C,
const Stmt *S,
252 PathDiagnosticLocation &Start)
const;
255 generateDiagForSwitchOP(
const PathDiagnosticConstruct &C,
const CFGBlock *Dst,
256 PathDiagnosticLocation &Start)
const;
259 generateDiagForBinaryOP(
const PathDiagnosticConstruct &C,
const Stmt *T,
262 PathDiagnosticLocation
263 ExecutionContinues(
const PathDiagnosticConstruct &C)
const;
265 PathDiagnosticLocation
266 ExecutionContinues(llvm::raw_string_ostream &os,
267 const PathDiagnosticConstruct &C)
const;
269 const PathSensitiveBugReport *getBugReport()
const {
return R; }
282 return getMessageForSymbolNotFound();
289 const auto *CE = dyn_cast_or_null<CallExpr>(CallSite);
294 unsigned ArgIndex = 0;
296 E = CE->arg_end(); I != E; ++I, ++ArgIndex){
302 return getMessageForArg(*I, ArgIndex);
308 if ((*I)->getType()->isVoidPointerType())
313 return getMessageForArg(*I, ArgIndex);
322 return getMessageForReturn(CE);
325 return getMessageForSymbolNotFound();
333 return (llvm::Twine(Msg) +
" via " + std::to_string(ArgIndex) +
334 llvm::getOrdinalSuffix(ArgIndex) +
" parameter").str();
343 PathDiagnosticEventPiece *Y) {
348 const void *tagPreferred = ConditionBRVisitor::getTag();
349 const void *tagLesser = TrackConstraintBRVisitor::getTag();
351 if (X->getLocation() != Y->getLocation())
354 if (X->getTag() == tagPreferred && Y->getTag() == tagLesser)
355 return ConditionBRVisitor::isPieceMessageGeneric(X) ? Y :
X;
357 if (Y->getTag() == tagPreferred && X->getTag() == tagLesser)
358 return ConditionBRVisitor::isPieceMessageGeneric(Y) ?
X : Y;
369 unsigned N = path.size();
376 for (
unsigned i = 0; i < N; ++i) {
377 auto piece = std::move(path.front());
380 switch (piece->getKind()) {
391 if (
auto *nextEvent =
392 dyn_cast<PathDiagnosticEventPiece>(path.front().get())) {
393 auto *
event = cast<PathDiagnosticEventPiece>(piece.get());
397 if (
auto *pieceToKeep =
399 piece = std::move(pieceToKeep == event ? piece : path.front());
411 path.push_back(std::move(piece));
420 const PathSensitiveBugReport *R,
421 bool IsInteresting =
false) {
422 bool containsSomethingInteresting = IsInteresting;
423 const unsigned N = pieces.size();
425 for (
unsigned i = 0 ; i < N ; ++i) {
428 auto piece = std::move(pieces.front());
431 switch (piece->getKind()) {
433 auto &call = cast<PathDiagnosticCallPiece>(*piece);
437 R->isInteresting(C.getLocationContextFor(&call.path))))
440 containsSomethingInteresting =
true;
444 auto ¯o = cast<PathDiagnosticMacroPiece>(*piece);
447 containsSomethingInteresting =
true;
451 auto &
event = cast<PathDiagnosticEventPiece>(*piece);
455 containsSomethingInteresting |= !
event.isPrunable();
464 pieces.push_back(std::move(piece));
467 return containsSomethingInteresting;
472 for (
unsigned int i = 0; i < Path.size(); ++i) {
473 auto Piece = std::move(Path.front());
475 if (!isa<PathDiagnosticPopUpPiece>(*Piece))
476 Path.push_back(std::move(Piece));
491 PathDiagnosticLocation *LastCallLocation =
nullptr) {
492 for (
const auto &I : Pieces) {
493 auto *Call = dyn_cast<PathDiagnosticCallPiece>(I.get());
498 if (LastCallLocation) {
500 if (CallerIsImplicit || !Call->callEnter.asLocation().isValid())
501 Call->callEnter = *LastCallLocation;
502 if (CallerIsImplicit || !Call->callReturn.asLocation().isValid())
503 Call->callReturn = *LastCallLocation;
508 PathDiagnosticLocation *ThisCallLocation;
509 if (Call->callEnterWithin.asLocation().isValid() &&
511 ThisCallLocation = &Call->callEnterWithin;
513 ThisCallLocation = &Call->callEnter;
515 assert(ThisCallLocation &&
"Outermost call has an invalid location");
524 for (PathPieces::iterator I = Pieces.begin(), E = Pieces.end(); I != E;) {
525 if (
auto *C = dyn_cast<PathDiagnosticCallPiece>(I->get()))
528 if (
auto *M = dyn_cast<PathDiagnosticMacroPiece>(I->get()))
531 if (
auto *
CF = dyn_cast<PathDiagnosticControlFlowPiece>(I->get())) {
532 const Stmt *Start =
CF->getStartLocation().asStmt();
533 const Stmt *
End =
CF->getEndLocation().asStmt();
534 if (Start && isa<CXXDefaultInitExpr>(Start)) {
537 }
else if (End && isa<CXXDefaultInitExpr>(End)) {
538 PathPieces::iterator Next = std::next(I);
541 dyn_cast<PathDiagnosticControlFlowPiece>(Next->get())) {
542 NextCF->setStartLocation(
CF->getStartLocation());
558 for (PathPieces::iterator I = Pieces.begin(), E = Pieces.end(); I != E;) {
559 if (
auto *C = dyn_cast<PathDiagnosticCallPiece>(I->get()))
562 if (
auto *M = dyn_cast<PathDiagnosticMacroPiece>(I->get()))
565 if (!(*I)->getLocation().isValid() ||
566 !(*I)->getLocation().asLocation().isValid()) {
574 PathDiagnosticLocation PathDiagnosticBuilder::ExecutionContinues(
575 const PathDiagnosticConstruct &C)
const {
576 if (
const Stmt *S = C.getCurrentNode()->getNextStmtForDiagnostics())
577 return PathDiagnosticLocation(S, getSourceManager(),
578 C.getCurrLocationContext());
584 PathDiagnosticLocation PathDiagnosticBuilder::ExecutionContinues(
585 llvm::raw_string_ostream &os,
const PathDiagnosticConstruct &C)
const {
587 if (os.str().empty())
590 const PathDiagnosticLocation &Loc = ExecutionContinues(C);
593 os <<
"Execution continues on line " 594 << getSourceManager().getExpansionLineNumber(Loc.asLocation())
597 os <<
"Execution jumps to the end of the ";
598 const Decl *D = C.getCurrLocationContext()->getDecl();
599 if (isa<ObjCMethodDecl>(D))
601 else if (isa<FunctionDecl>(D))
604 assert(isa<BlockDecl>(D));
605 os <<
"anonymous block";
622 case Stmt::ForStmtClass:
623 case Stmt::DoStmtClass:
624 case Stmt::WhileStmtClass:
625 case Stmt::ObjCForCollectionStmtClass:
626 case Stmt::CXXForRangeStmtClass:
635 static PathDiagnosticLocation
637 bool allowNestedContexts =
false) {
644 switch (
Parent->getStmtClass()) {
645 case Stmt::BinaryOperatorClass: {
646 const auto *B = cast<BinaryOperator>(
Parent);
647 if (B->isLogicalOp())
648 return PathDiagnosticLocation(allowNestedContexts ? B : S, SMgr, LC);
651 case Stmt::CompoundStmtClass:
652 case Stmt::StmtExprClass:
653 return PathDiagnosticLocation(S, SMgr, LC);
654 case Stmt::ChooseExprClass:
657 if (allowNestedContexts || cast<ChooseExpr>(
Parent)->getCond() == S)
658 return PathDiagnosticLocation(
Parent, SMgr, LC);
660 return PathDiagnosticLocation(S, SMgr, LC);
661 case Stmt::BinaryConditionalOperatorClass:
662 case Stmt::ConditionalOperatorClass:
665 if (allowNestedContexts ||
666 cast<AbstractConditionalOperator>(
Parent)->getCond() == S)
667 return PathDiagnosticLocation(
Parent, SMgr, LC);
669 return PathDiagnosticLocation(S, SMgr, LC);
670 case Stmt::CXXForRangeStmtClass:
671 if (cast<CXXForRangeStmt>(
Parent)->getBody() == S)
672 return PathDiagnosticLocation(S, SMgr, LC);
674 case Stmt::DoStmtClass:
675 return PathDiagnosticLocation(S, SMgr, LC);
676 case Stmt::ForStmtClass:
677 if (cast<ForStmt>(
Parent)->getBody() == S)
678 return PathDiagnosticLocation(S, SMgr, LC);
680 case Stmt::IfStmtClass:
681 if (cast<IfStmt>(
Parent)->getCond() != S)
682 return PathDiagnosticLocation(S, SMgr, LC);
684 case Stmt::ObjCForCollectionStmtClass:
685 if (cast<ObjCForCollectionStmt>(
Parent)->getBody() == S)
686 return PathDiagnosticLocation(S, SMgr, LC);
688 case Stmt::WhileStmtClass:
689 if (cast<WhileStmt>(
Parent)->getCond() != S)
690 return PathDiagnosticLocation(S, SMgr, LC);
699 assert(S &&
"Cannot have null Stmt for PathDiagnosticLocation");
701 return PathDiagnosticLocation(S, SMgr, LC);
718 void PathDiagnosticBuilder::updateStackPiecesWithMessage(
720 if (R->hasCallStackHint(P))
721 for (
const auto &I : CallStack) {
722 PathDiagnosticCallPiece *CP = I.first;
723 const ExplodedNode *N = I.second;
724 std::string stackMsg = R->getCallStackMessage(P, N);
729 if (!CP->hasCallStackMessage())
730 CP->setCallStackMessage(stackMsg);
738 const PathDiagnosticConstruct &C,
const CFGBlock *Dst,
739 PathDiagnosticLocation &Start)
const {
744 llvm::raw_string_ostream os(sbuf);
745 PathDiagnosticLocation
End;
748 End = PathDiagnosticLocation(S, SM, C.getCurrLocationContext());
752 os <<
"No cases match in the switch statement. " 753 "Control jumps to line " 754 << End.asLocation().getExpansionLineNumber();
756 case Stmt::DefaultStmtClass:
757 os <<
"Control jumps to the 'default' case at line " 758 << End.asLocation().getExpansionLineNumber();
761 case Stmt::CaseStmtClass: {
762 os <<
"Control jumps to 'case ";
763 const auto *Case = cast<CaseStmt>(S);
767 bool GetRawInt =
true;
769 if (
const auto *DR = dyn_cast<DeclRefExpr>(LHS)) {
781 os << LHS->EvaluateKnownConstInt(getASTContext());
783 os <<
":' at line " << End.asLocation().getExpansionLineNumber();
788 os <<
"'Default' branch taken. ";
789 End = ExecutionContinues(os, C);
791 return std::make_shared<PathDiagnosticControlFlowPiece>(Start,
End,
796 const PathDiagnosticConstruct &C,
const Stmt *S,
797 PathDiagnosticLocation &Start)
const {
799 llvm::raw_string_ostream os(sbuf);
800 const PathDiagnosticLocation &
End =
802 os <<
"Control jumps to line " << End.asLocation().getExpansionLineNumber();
803 return std::make_shared<PathDiagnosticControlFlowPiece>(Start,
End, os.str());
807 const PathDiagnosticConstruct &C,
const Stmt *T,
const CFGBlock *Src,
812 const auto *B = cast<BinaryOperator>(T);
814 llvm::raw_string_ostream os(sbuf);
815 os <<
"Left side of '";
816 PathDiagnosticLocation Start,
End;
818 if (B->getOpcode() == BO_LAnd) {
824 End = PathDiagnosticLocation(B->getLHS(),
SM, C.getCurrLocationContext());
830 PathDiagnosticLocation(B->getLHS(),
SM, C.getCurrLocationContext());
831 End = ExecutionContinues(C);
834 assert(B->getOpcode() == BO_LOr);
841 PathDiagnosticLocation(B->getLHS(),
SM, C.getCurrLocationContext());
842 End = ExecutionContinues(C);
845 End = PathDiagnosticLocation(B->getLHS(),
SM, C.getCurrLocationContext());
850 return std::make_shared<PathDiagnosticControlFlowPiece>(Start,
End,
854 void PathDiagnosticBuilder::generateMinimalDiagForBlockEdge(
855 PathDiagnosticConstruct &C,
BlockEdge BE)
const {
869 case Stmt::GotoStmtClass:
870 case Stmt::IndirectGotoStmtClass: {
871 if (
const Stmt *S = C.getCurrentNode()->getNextStmtForDiagnostics())
872 C.getActivePath().push_front(generateDiagForGotoOP(C, S, Start));
876 case Stmt::SwitchStmtClass: {
877 C.getActivePath().push_front(generateDiagForSwitchOP(C, Dst, Start));
881 case Stmt::BreakStmtClass:
882 case Stmt::ContinueStmtClass: {
884 llvm::raw_string_ostream os(sbuf);
885 PathDiagnosticLocation
End = ExecutionContinues(os, C);
886 C.getActivePath().push_front(
887 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, os.str()));
892 case Stmt::BinaryConditionalOperatorClass:
893 case Stmt::ConditionalOperatorClass: {
895 llvm::raw_string_ostream os(sbuf);
896 os <<
"'?' condition is ";
903 PathDiagnosticLocation
End = ExecutionContinues(C);
905 if (
const Stmt *S = End.asStmt())
908 C.getActivePath().push_front(
909 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, os.str()));
914 case Stmt::BinaryOperatorClass: {
915 if (!C.supportsLogicalOpControlFlow())
918 C.getActivePath().push_front(generateDiagForBinaryOP(C, T, Src, Dst));
922 case Stmt::DoStmtClass:
925 llvm::raw_string_ostream os(sbuf);
927 os <<
"Loop condition is true. ";
928 PathDiagnosticLocation
End = ExecutionContinues(os, C);
930 if (
const Stmt *S = End.asStmt())
933 C.getActivePath().push_front(
934 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
937 PathDiagnosticLocation
End = ExecutionContinues(C);
939 if (
const Stmt *S = End.asStmt())
942 C.getActivePath().push_front(
943 std::make_shared<PathDiagnosticControlFlowPiece>(
944 Start, End,
"Loop condition is false. Exiting loop"));
948 case Stmt::WhileStmtClass:
949 case Stmt::ForStmtClass:
952 llvm::raw_string_ostream os(sbuf);
954 os <<
"Loop condition is false. ";
955 PathDiagnosticLocation
End = ExecutionContinues(os, C);
956 if (
const Stmt *S = End.asStmt())
959 C.getActivePath().push_front(
960 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
963 PathDiagnosticLocation
End = ExecutionContinues(C);
964 if (
const Stmt *S = End.asStmt())
967 C.getActivePath().push_front(
968 std::make_shared<PathDiagnosticControlFlowPiece>(
969 Start, End,
"Loop condition is true. Entering loop body"));
974 case Stmt::IfStmtClass: {
975 PathDiagnosticLocation
End = ExecutionContinues(C);
977 if (
const Stmt *S = End.asStmt())
981 C.getActivePath().push_front(
982 std::make_shared<PathDiagnosticControlFlowPiece>(
983 Start, End,
"Taking false branch"));
985 C.getActivePath().push_front(
986 std::make_shared<PathDiagnosticControlFlowPiece>(
987 Start, End,
"Taking true branch"));
1000 case Stmt::ForStmtClass:
1001 case Stmt::WhileStmtClass:
1002 case Stmt::ObjCForCollectionStmtClass:
1003 case Stmt::CXXForRangeStmtClass:
1028 const ExplodedNode *N) {
1032 const Stmt *S = SP->getStmt();
1036 N = N->getFirstPred();
1042 const Stmt *LoopBody =
nullptr;
1044 case Stmt::CXXForRangeStmtClass: {
1045 const auto *FR = cast<CXXForRangeStmt>(Term);
1050 LoopBody = FR->getBody();
1053 case Stmt::ForStmtClass: {
1054 const auto *FS = cast<ForStmt>(Term);
1057 LoopBody = FS->getBody();
1060 case Stmt::ObjCForCollectionStmtClass: {
1061 const auto *FC = cast<ObjCForCollectionStmt>(Term);
1062 LoopBody = FC->getBody();
1065 case Stmt::WhileStmtClass:
1066 LoopBody = cast<WhileStmt>(Term)->getBody();
1076 PathDiagnosticLocation &PrevLoc,
1077 PathDiagnosticLocation NewLoc) {
1078 if (!NewLoc.isValid())
1085 if (!PrevLoc.isValid() || !PrevLoc.asLocation().isValid()) {
1092 if (NewLoc.asStmt() && NewLoc.asStmt() == PrevLoc.asStmt())
1096 std::make_shared<PathDiagnosticControlFlowPiece>(NewLoc, PrevLoc));
1104 if (
const auto *FS = dyn_cast_or_null<ObjCForCollectionStmt>(S))
1105 return FS->getElement();
1112 "Loop body skipped when range is empty";
1114 "Loop body skipped when collection is empty";
1116 static std::unique_ptr<FilesToLineNumsMap>
1119 void PathDiagnosticBuilder::generatePathDiagnosticsForNode(
1120 PathDiagnosticConstruct &C, PathDiagnosticLocation &PrevLoc)
const {
1130 if (C.shouldAddPathEdges()) {
1146 bool VisitedEntireCall = C.PD->isWithinCall();
1147 C.PD->popActivePath();
1149 PathDiagnosticCallPiece *Call;
1150 if (VisitedEntireCall) {
1151 Call = cast<PathDiagnosticCallPiece>(C.getActivePath().front().get());
1155 const Decl *Caller = CE->getLocationContext()->getDecl();
1157 assert(C.getActivePath().size() == 1 &&
1158 C.getActivePath().front().get() == Call);
1162 assert(C.isInLocCtxMap(&C.getActivePath()) &&
1163 "When we ascend to a previously unvisited call, the active path's " 1164 "address shouldn't change, but rather should be compacted into " 1165 "a single CallEvent!");
1166 C.updateLocCtxMap(&C.getActivePath(), C.getCurrLocationContext());
1169 assert(!C.isInLocCtxMap(&Call->path) &&
1170 "When we ascend to a previously unvisited call, this must be the " 1171 "first time we encounter the caller context!");
1172 C.updateLocCtxMap(&Call->path, CE->getCalleeContext());
1174 Call->setCallee(*CE, SM);
1177 PrevLoc = Call->getLocation();
1179 if (!C.CallStack.empty()) {
1180 assert(C.CallStack.back().first == Call);
1181 C.CallStack.pop_back();
1186 assert(C.getCurrLocationContext() == C.getLocationContextForActivePath() &&
1187 "The current position in the bug path is out of sync with the " 1188 "location context associated with the active path!");
1197 assert(!C.isInLocCtxMap(&Call->path) &&
1198 "We just entered a call, this must've been the first time we " 1199 "encounter its context!");
1200 C.updateLocCtxMap(&Call->path, CE->getCalleeContext());
1202 if (C.shouldAddPathEdges()) {
1204 addEdgeToPath(C.getActivePath(), PrevLoc, Call->callReturn);
1205 PrevLoc.invalidate();
1208 auto *P = Call.get();
1209 C.getActivePath().push_front(std::move(Call));
1212 C.PD->pushActivePath(&P->path);
1213 C.CallStack.push_back(CallWithEntry(P, C.getCurrentNode()));
1218 if (!C.shouldAddPathEdges())
1224 if (!isa<ObjCForCollectionStmt>(PS->getStmt())) {
1225 PathDiagnosticLocation L =
1226 PathDiagnosticLocation(PS->getStmt(),
SM, C.getCurrLocationContext());
1232 if (!C.shouldAddPathEdges()) {
1233 generateMinimalDiagForBlockEdge(C, *BE);
1239 PathDiagnosticLocation L(Loop, SM, C.getCurrLocationContext());
1240 const Stmt *Body =
nullptr;
1242 if (
const auto *FS = dyn_cast<ForStmt>(Loop))
1243 Body = FS->getBody();
1244 else if (
const auto *WS = dyn_cast<WhileStmt>(Loop))
1245 Body = WS->getBody();
1246 else if (
const auto *OFS = dyn_cast<ObjCForCollectionStmt>(Loop)) {
1247 Body = OFS->getBody();
1248 }
else if (
const auto *FRS = dyn_cast<CXXForRangeStmt>(Loop)) {
1249 Body = FRS->getBody();
1253 auto p = std::make_shared<PathDiagnosticEventPiece>(
1254 L,
"Looping back to the head " 1256 p->setPrunable(
true);
1258 addEdgeToPath(C.getActivePath(), PrevLoc, p->getLocation());
1259 C.getActivePath().push_front(std::move(p));
1261 if (
const auto *CS = dyn_cast_or_null<CompoundStmt>(Body)) {
1270 if (
const Stmt *Term = BSrc->getTerminatorStmt()) {
1281 if (!IsInLoopBody) {
1282 if (isa<ObjCForCollectionStmt>(Term)) {
1284 }
else if (isa<CXXForRangeStmt>(Term)) {
1295 PathDiagnosticLocation L(TermCond ? TermCond : Term, SM,
1296 C.getCurrLocationContext());
1297 auto PE = std::make_shared<PathDiagnosticEventPiece>(L, str);
1298 PE->setPrunable(
true);
1299 addEdgeToPath(C.getActivePath(), PrevLoc, PE->getLocation());
1300 C.getActivePath().push_front(std::move(PE));
1302 }
else if (isa<BreakStmt>(Term) || isa<ContinueStmt>(Term) ||
1303 isa<GotoStmt>(Term)) {
1304 PathDiagnosticLocation L(Term, SM, C.getCurrLocationContext());
1311 static std::unique_ptr<PathDiagnostic>
1313 const BugType &BT = R->getBugType();
1314 return std::make_unique<PathDiagnostic>(
1315 BT.getCheckerName(), R->getDeclWithIssue(), BT.getDescription(),
1316 R->getDescription(), R->getShortDescription(
false),
1317 BT.getCategory(), R->getUniqueingLocation(), R->getUniqueingDecl(),
1318 std::make_unique<FilesToLineNumsMap>());
1321 static std::unique_ptr<PathDiagnostic>
1324 const BugType &BT = R->getBugType();
1325 return std::make_unique<PathDiagnostic>(
1326 BT.getCheckerName(), R->getDeclWithIssue(), BT.getDescription(),
1327 R->getDescription(), R->getShortDescription(
false),
1328 BT.getCategory(), R->getUniqueingLocation(), R->getUniqueingDecl(),
1342 if (isa<FullExpr>(S) ||
1343 isa<CXXBindTemporaryExpr>(S) ||
1344 isa<SubstNonTypeTemplateParmExpr>(S))
1355 case Stmt::BinaryOperatorClass: {
1356 const auto *BO = cast<BinaryOperator>(S);
1357 if (!BO->isLogicalOp())
1359 return BO->getLHS() == Cond || BO->getRHS() == Cond;
1361 case Stmt::IfStmtClass:
1362 return cast<IfStmt>(S)->getCond() == Cond;
1363 case Stmt::ForStmtClass:
1364 return cast<ForStmt>(S)->getCond() == Cond;
1365 case Stmt::WhileStmtClass:
1366 return cast<WhileStmt>(S)->getCond() == Cond;
1367 case Stmt::DoStmtClass:
1368 return cast<DoStmt>(S)->getCond() == Cond;
1369 case Stmt::ChooseExprClass:
1370 return cast<ChooseExpr>(S)->getCond() == Cond;
1371 case Stmt::IndirectGotoStmtClass:
1372 return cast<IndirectGotoStmt>(S)->getTarget() == Cond;
1373 case Stmt::SwitchStmtClass:
1374 return cast<SwitchStmt>(S)->getCond() == Cond;
1375 case Stmt::BinaryConditionalOperatorClass:
1376 return cast<BinaryConditionalOperator>(S)->getCond() == Cond;
1377 case Stmt::ConditionalOperatorClass: {
1378 const auto *CO = cast<ConditionalOperator>(S);
1379 return CO->getCond() == Cond ||
1380 CO->getLHS() == Cond ||
1381 CO->getRHS() == Cond;
1383 case Stmt::ObjCForCollectionStmtClass:
1384 return cast<ObjCForCollectionStmt>(S)->getElement() == Cond;
1385 case Stmt::CXXForRangeStmtClass: {
1386 const auto *FRS = cast<CXXForRangeStmt>(S);
1387 return FRS->getCond() == Cond || FRS->getRangeInit() == Cond;
1395 if (
const auto *FS = dyn_cast<ForStmt>(FL))
1396 return FS->getInc() == S || FS->getInit() == S;
1397 if (
const auto *FRS = dyn_cast<CXXForRangeStmt>(FL))
1398 return FRS->getInc() == S || FRS->getRangeStmt() == S ||
1399 FRS->getLoopVarStmt() || FRS->getRangeInit() == S;
1412 PathPieces::iterator Prev = pieces.end();
1413 for (PathPieces::iterator I = pieces.begin(), E = Prev; I != E;
1415 auto *Piece = dyn_cast<PathDiagnosticControlFlowPiece>(I->get());
1420 PathDiagnosticLocation SrcLoc = Piece->getStartLocation();
1423 PathDiagnosticLocation NextSrcContext = SrcLoc;
1424 const Stmt *InnerStmt =
nullptr;
1425 while (NextSrcContext.isValid() && NextSrcContext.asStmt() != InnerStmt) {
1426 SrcContexts.push_back(NextSrcContext);
1427 InnerStmt = NextSrcContext.asStmt();
1436 const Stmt *Dst = Piece->getEndLocation().getStmtOrNull();
1440 PathDiagnosticLocation DstContext =
1442 if (!DstContext.isValid() || DstContext.asStmt() == Dst)
1446 if (llvm::find(SrcContexts, DstContext) != SrcContexts.end())
1450 Piece->setStartLocation(DstContext);
1455 auto *PrevPiece = dyn_cast<PathDiagnosticControlFlowPiece>(Prev->get());
1458 if (
const Stmt *PrevSrc =
1459 PrevPiece->getStartLocation().getStmtOrNull()) {
1461 if (PrevSrcParent ==
1463 PrevPiece->setEndLocation(DstContext);
1474 std::make_shared<PathDiagnosticControlFlowPiece>(SrcLoc, DstContext);
1476 I = pieces.insert(I, std::move(P));
1492 for (PathPieces::iterator I = pieces.begin(), E = pieces.end(); I != E; ++I) {
1493 const auto *PieceI = dyn_cast<PathDiagnosticControlFlowPiece>(I->get());
1498 const Stmt *s1Start = PieceI->getStartLocation().getStmtOrNull();
1499 const Stmt *s1End = PieceI->getEndLocation().getStmtOrNull();
1501 if (!s1Start || !s1End)
1504 PathPieces::iterator NextI = I; ++NextI;
1508 PathDiagnosticControlFlowPiece *PieceNextI =
nullptr;
1514 const auto *EV = dyn_cast<PathDiagnosticEventPiece>(NextI->get());
1516 StringRef S = EV->getString();
1517 if (S == StrEnteringLoop || S == StrLoopBodyZero ||
1518 S == StrLoopCollectionEmpty || S == StrLoopRangeEmpty) {
1525 PieceNextI = dyn_cast<PathDiagnosticControlFlowPiece>(NextI->get());
1532 const Stmt *s2Start = PieceNextI->getStartLocation().getStmtOrNull();
1533 const Stmt *s2End = PieceNextI->getEndLocation().getStmtOrNull();
1535 if (!s2Start || !s2End || s1End != s2Start)
1540 if (!(isa<ForStmt>(s1Start) || isa<WhileStmt>(s1Start) ||
1541 isa<IfStmt>(s1Start) || isa<ObjCForCollectionStmt>(s1Start) ||
1542 isa<CXXForRangeStmt>(s1Start)))
1551 PieceNextI->setStartLocation(PieceI->getStartLocation());
1552 I = pieces.erase(I);
1567 if (FID != SM.
getFileID(ExpansionRange.getEnd()))
1571 const llvm::MemoryBuffer *Buffer = SM.
getBuffer(FID, &Invalid);
1575 unsigned BeginOffset = SM.
getFileOffset(ExpansionRange.getBegin());
1576 unsigned EndOffset = SM.
getFileOffset(ExpansionRange.getEnd());
1577 StringRef Snippet = Buffer->getBuffer().slice(BeginOffset, EndOffset);
1583 if (Snippet.find_first_of(
"\r\n") != StringRef::npos)
1587 return Snippet.size();
1613 for (PathPieces::iterator I = Path.begin(), E = Path.end(); I != E; ) {
1615 const auto *PieceI = dyn_cast<PathDiagnosticControlFlowPiece>(I->get());
1622 const Stmt *s1Start = PieceI->getStartLocation().getStmtOrNull();
1623 const Stmt *s1End = PieceI->getEndLocation().getStmtOrNull();
1625 PathPieces::iterator NextI = I; ++NextI;
1629 const auto *PieceNextI =
1630 dyn_cast<PathDiagnosticControlFlowPiece>(NextI->get());
1633 if (isa<PathDiagnosticEventPiece>(NextI->get())) {
1637 PieceNextI = dyn_cast<PathDiagnosticControlFlowPiece>(NextI->get());
1646 const Stmt *s2Start = PieceNextI->getStartLocation().getStmtOrNull();
1647 const Stmt *s2End = PieceNextI->getEndLocation().getStmtOrNull();
1649 if (s1Start && s2Start && s1Start == s2End && s2Start == s1End) {
1650 const size_t MAX_SHORT_LINE_LENGTH = 80;
1652 if (s1Length && *s1Length <= MAX_SHORT_LINE_LENGTH) {
1654 if (s2Length && *s2Length <= MAX_SHORT_LINE_LENGTH) {
1656 I = Path.erase(NextI);
1679 bool erased =
false;
1681 for (PathPieces::iterator I = path.begin(), E = path.end(); I != E;
1685 const auto *PieceI = dyn_cast<PathDiagnosticControlFlowPiece>(I->get());
1690 const Stmt *start = PieceI->getStartLocation().getStmtOrNull();
1691 const Stmt *end = PieceI->getEndLocation().getStmtOrNull();
1709 std::swap(SecondLoc, FirstLoc);
1718 const size_t MAX_PUNY_EDGE_LENGTH = 2;
1719 if (*ByteWidth <= MAX_PUNY_EDGE_LENGTH) {
1731 for (PathPieces::iterator I = path.begin(), E = path.end(); I != E; ++I) {
1732 const auto *PieceI = dyn_cast<PathDiagnosticEventPiece>(I->get());
1737 PathPieces::iterator NextI = I; ++NextI;
1741 const auto *PieceNextI = dyn_cast<PathDiagnosticEventPiece>(NextI->get());
1747 if (PieceI->getString() == PieceNextI->getString()) {
1755 bool hasChanges =
false;
1761 for (PathPieces::iterator I = path.begin(), E = path.end(); I != E; ) {
1763 if (
auto *CallI = dyn_cast<PathDiagnosticCallPiece>(I->get())) {
1766 if (!OCS.count(CallI)) {
1776 auto *PieceI = dyn_cast<PathDiagnosticControlFlowPiece>(I->get());
1783 const Stmt *s1Start = PieceI->getStartLocation().getStmtOrNull();
1784 const Stmt *s1End = PieceI->getEndLocation().getStmtOrNull();
1788 PathPieces::iterator NextI = I; ++NextI;
1792 const auto *PieceNextI = dyn_cast<PathDiagnosticControlFlowPiece>(NextI->get());
1799 const Stmt *s2Start = PieceNextI->getStartLocation().getStmtOrNull();
1800 const Stmt *s2End = PieceNextI->getEndLocation().getStmtOrNull();
1818 if (level1 && level1 == level2 && level1 == level3 && level1 == level4) {
1819 PieceI->setEndLocation(PieceNextI->getEndLocation());
1832 if (s1End && s1End == s2Start && level2) {
1833 bool removeEdge =
false;
1859 else if (s1Start && s2End &&
1872 else if (s1Start && s2End &&
1874 SourceRange EdgeRange(PieceI->getEndLocation().asLocation(),
1875 PieceI->getStartLocation().asLocation());
1882 PieceI->setEndLocation(PieceNextI->getEndLocation());
1896 if (s1End == s2Start) {
1897 const auto *FS = dyn_cast_or_null<ObjCForCollectionStmt>(level3);
1898 if (FS && FS->getCollection()->IgnoreParens() == s2Start &&
1899 s2End == FS->getElement()) {
1900 PieceI->setEndLocation(PieceNextI->getEndLocation());
1937 const auto *FirstEdge =
1938 dyn_cast<PathDiagnosticControlFlowPiece>(Path.front().get());
1942 const Decl *D = C.getLocationContextFor(&Path)->getDecl();
1943 PathDiagnosticLocation EntryLoc =
1945 if (FirstEdge->getStartLocation() != EntryLoc)
1954 PathPieces path = PD.path.flatten(
true);
1957 for (
const auto &P : path) {
1958 FullSourceLoc Loc = P->getLocation().asLocation().getExpansionLoc();
1962 ExecutedLines[FID].insert(LineNo);
1966 PathDiagnosticConstruct::PathDiagnosticConstruct(
1967 const PathDiagnosticConsumer *PDC,
const ExplodedNode *ErrorNode,
1968 const PathSensitiveBugReport *R)
1969 : Consumer(PDC), CurrentNode(ErrorNode),
1970 SM(CurrentNode->getCodeDecl().getASTContext().getSourceManager()),
1972 LCM[&PD->getActivePath()] = ErrorNode->getLocationContext();
1975 PathDiagnosticBuilder::PathDiagnosticBuilder(
1976 BugReporterContext BRC, std::unique_ptr<ExplodedGraph> BugPath,
1977 PathSensitiveBugReport *r,
const ExplodedNode *ErrorNode,
1978 std::unique_ptr<VisitorsDiagnosticsTy> VisitorsDiagnostics)
1979 : BugReporterContext(BRC), BugPath(std::move(BugPath)), R(r),
1980 ErrorNode(ErrorNode),
1981 VisitorsDiagnostics(std::move(VisitorsDiagnostics)) {}
1983 std::unique_ptr<PathDiagnostic>
1984 PathDiagnosticBuilder::generate(
const PathDiagnosticConsumer *PDC)
const {
1985 PathDiagnosticConstruct Construct(PDC, ErrorNode, R);
1989 StringRef ErrorTag = ErrorNode->getLocation().getTag()->getTagDescription();
1994 if (ErrorTag.startswith(CheckerOrPackage))
1998 if (!PDC->shouldGenerateDiagnostics())
2002 auto EndNotes = VisitorsDiagnostics->find(ErrorNode);
2004 if (EndNotes != VisitorsDiagnostics->end()) {
2005 assert(!EndNotes->second.empty());
2006 LastPiece = EndNotes->second[0];
2008 LastPiece = BugReporterVisitor::getDefaultEndPath(*
this, ErrorNode,
2011 Construct.PD->setEndOfPath(LastPiece);
2013 PathDiagnosticLocation PrevLoc = Construct.PD->getLocation();
2016 while (Construct.ascendToPrevNode()) {
2017 generatePathDiagnosticsForNode(Construct, PrevLoc);
2019 auto VisitorNotes = VisitorsDiagnostics->find(Construct.getCurrentNode());
2020 if (VisitorNotes == VisitorsDiagnostics->end())
2025 std::set<llvm::FoldingSetNodeID> DeduplicationSet;
2029 llvm::FoldingSetNodeID
ID;
2031 if (!DeduplicationSet.insert(ID).second)
2034 if (PDC->shouldAddPathEdges())
2035 addEdgeToPath(Construct.getActivePath(), PrevLoc, Note->getLocation());
2036 updateStackPiecesWithMessage(Note, Construct.CallStack);
2037 Construct.getActivePath().push_front(Note);
2041 if (PDC->shouldAddPathEdges()) {
2045 Construct.getLocationContextForActivePath()->getStackFrame();
2053 if (!Construct.PD->path.empty()) {
2054 if (R->shouldPrunePath() && Opts.ShouldPrunePaths) {
2055 bool stillHasNotes =
2057 assert(stillHasNotes);
2058 (void)stillHasNotes;
2062 if (!Opts.ShouldAddPopUpNotes)
2069 if (PDC->shouldAddPathEdges()) {
2075 while (
optimizeEdges(Construct, Construct.getMutablePieces(), OCS)) {
2090 if (Opts.ShouldDisplayMacroExpansions)
2093 return std::move(Construct.PD);
2100 void BugType::anchor() {}
2102 void BuiltinBug::anchor() {}
2109 std::unique_ptr<BugReporterVisitor> visitor) {
2113 llvm::FoldingSetNodeID
ID;
2114 visitor->Profile(ID);
2116 void *InsertPos =
nullptr;
2117 if (CallbacksSet.FindNodeOrInsertPos(ID, InsertPos)) {
2121 Callbacks.push_back(std::move(visitor));
2138 hash.AddInteger(static_cast<int>(
getKind()));
2139 hash.AddPointer(&BT);
2140 hash.AddString(Description);
2141 assert(Location.isValid());
2142 Location.Profile(hash);
2145 if (!
range.isValid())
2147 hash.AddInteger(
range.getBegin().getRawEncoding());
2148 hash.AddInteger(
range.getEnd().getRawEncoding());
2153 hash.AddInteger(static_cast<int>(
getKind()));
2154 hash.AddPointer(&BT);
2155 hash.AddString(Description);
2164 hash.AddPointer(ErrorNode->getCurrentOrPreviousStmtForDiagnostics());
2168 if (!
range.isValid())
2170 hash.AddInteger(
range.getBegin().getRawEncoding());
2171 hash.AddInteger(
range.getEnd().getRawEncoding());
2177 llvm::DenseMap<T, bugreporter::TrackingKind> &InterestingnessMap, T Val,
2178 bugreporter::TrackingKind TKind) {
2179 auto Result = InterestingnessMap.insert({Val, TKind});
2191 case bugreporter::TrackingKind::Thorough:
2192 Result.first->getSecond() = bugreporter::TrackingKind::Thorough;
2194 case bugreporter::TrackingKind::Condition:
2199 "BugReport::markInteresting currently can only handle 2 different " 2200 "tracking kinds! Please define what tracking kind should this entitiy" 2201 "have, if it was already marked as interesting with a different kind!");
2205 bugreporter::TrackingKind TKind) {
2211 if (
const auto *meta = dyn_cast<SymbolMetadata>(sym))
2212 markInteresting(meta->getRegion(), TKind);
2216 bugreporter::TrackingKind TKind) {
2220 R = R->getBaseRegion();
2223 if (
const auto *SR = dyn_cast<SymbolicRegion>(R))
2224 markInteresting(SR->getSymbol(), TKind);
2228 bugreporter::TrackingKind TKind) {
2229 markInteresting(V.getAsRegion(), TKind);
2230 markInteresting(V.getAsSymbol(), TKind);
2236 InterestingLocationContexts.insert(LC);
2241 auto RKind = getInterestingnessKind(V.
getAsRegion());
2242 auto SKind = getInterestingnessKind(V.
getAsSymbol());
2251 case bugreporter::TrackingKind::Thorough:
2253 case bugreporter::TrackingKind::Condition:
2258 "BugReport::getInterestingnessKind currently can only handle 2 different " 2259 "tracking kinds! Please define what tracking kind should we return here " 2260 "when the kind of getAsRegion() and getAsSymbol() is different!");
2270 auto It = InterestingSymbols.find(sym);
2271 if (It == InterestingSymbols.end())
2273 return It->getSecond();
2282 auto It = InterestingRegions.find(R);
2283 if (It != InterestingRegions.end())
2284 return It->getSecond();
2286 if (
const auto *SR = dyn_cast<SymbolicRegion>(R))
2287 return getInterestingnessKind(SR->getSymbol());
2292 return getInterestingnessKind(V).hasValue();
2296 return getInterestingnessKind(sym).hasValue();
2300 return getInterestingnessKind(R).hasValue();
2306 return InterestingLocationContexts.count(LC);
2314 const Stmt *S =
nullptr;
2318 if (BE->getBlock() == &Exit)
2319 S = ErrorNode->getPreviousStmtForDiagnostics();
2322 S = ErrorNode->getStmtForDiagnostics();
2331 if (Ranges.empty() && isa_and_nonnull<Expr>(getStmt()))
2332 return ErrorNodeRange;
2339 assert(ErrorNode &&
"Cannot create a location with a null node.");
2340 const Stmt *S = ErrorNode->getStmtForDiagnostics();
2344 ErrorNode->getState()->getStateManager().getContext().getSourceManager();
2354 S = ErrorNode->getNextStmtForDiagnostics();
2359 if (
const auto *ME = dyn_cast<MemberExpr>(S))
2363 if (
const auto *B = dyn_cast<BinaryOperator>(S))
2385 return Eng.getGraph();
2389 return Eng.getStateManager();
2394 assert(StrBugTypes.empty() &&
2395 "Destroying BugReporter before diagnostics are emitted!");
2398 for (
const auto I : EQClassesVector)
2405 for (
const auto EQ : EQClassesVector)
2412 llvm::DeleteContainerSeconds(StrBugTypes);
2425 std::unique_ptr<ExplodedGraph> BugPath;
2432 class BugPathGetter {
2433 std::unique_ptr<ExplodedGraph> TrimmedGraph;
2435 using PriorityMapTy = llvm::DenseMap<const ExplodedNode *, unsigned>;
2438 PriorityMapTy PriorityMap;
2442 using ReportNewNodePair =
2443 std::pair<PathSensitiveBugReport *, const ExplodedNode *>;
2446 BugPathInfo CurrentBugPath;
2449 template <
bool Descending>
2450 class PriorityCompare {
2451 const PriorityMapTy &PriorityMap;
2454 PriorityCompare(
const PriorityMapTy &M) : PriorityMap(M) {}
2457 PriorityMapTy::const_iterator LI = PriorityMap.find(LHS);
2458 PriorityMapTy::const_iterator RI = PriorityMap.find(RHS);
2459 PriorityMapTy::const_iterator E = PriorityMap.end();
2466 return Descending ? LI->second > RI->second
2467 : LI->second < RI->second;
2470 bool operator()(
const ReportNewNodePair &LHS,
2471 const ReportNewNodePair &RHS)
const {
2472 return (*
this)(LHS.second, RHS.second);
2480 BugPathInfo *getNextBugPath();
2485 BugPathGetter::BugPathGetter(
const ExplodedGraph *OriginalGraph,
2488 for (
const auto I : bugReports) {
2489 assert(I->isValid() &&
2490 "We only allow BugReporterVisitors and BugReporter itself to " 2491 "invalidate reports!");
2492 Nodes.emplace_back(I->getErrorNode());
2498 TrimmedGraph = OriginalGraph->
trim(Nodes, &ForwardMap);
2503 llvm::SmallPtrSet<const ExplodedNode *, 32> RemainingNodes;
2506 const ExplodedNode *NewNode = ForwardMap.lookup(Report->getErrorNode());
2508 "Failed to construct a trimmed graph that contains this error " 2510 ReportNodes.emplace_back(Report, NewNode);
2511 RemainingNodes.insert(NewNode);
2514 assert(!RemainingNodes.empty() &&
"No error node found in the trimmed graph");
2517 std::queue<const ExplodedNode *> WS;
2519 assert(TrimmedGraph->num_roots() == 1);
2520 WS.push(*TrimmedGraph->roots_begin());
2523 while (!WS.empty()) {
2527 PriorityMapTy::iterator PriorityEntry;
2529 std::tie(PriorityEntry, IsNew) = PriorityMap.insert({
Node, Priority});
2533 assert(PriorityEntry->second <= Priority);
2537 if (RemainingNodes.erase(Node))
2538 if (RemainingNodes.empty())
2546 llvm::sort(ReportNodes, PriorityCompare<true>(PriorityMap));
2549 BugPathInfo *BugPathGetter::getNextBugPath() {
2550 if (ReportNodes.empty())
2554 std::tie(CurrentBugPath.Report, OrigN) = ReportNodes.pop_back_val();
2555 assert(PriorityMap.find(OrigN) != PriorityMap.end() &&
2556 "error node not accessible from root");
2560 auto GNew = std::make_unique<ExplodedGraph>();
2576 CurrentBugPath.ErrorNode = NewN;
2582 GNew->addRoot(NewN);
2589 PriorityCompare<false>(PriorityMap));
2592 CurrentBugPath.BugPath = std::move(GNew);
2594 return &CurrentBugPath;
2601 using MacroStackTy = std::vector<
2602 std::pair<std::shared_ptr<PathDiagnosticMacroPiece>,
SourceLocation>>;
2604 using PiecesTy = std::vector<PathDiagnosticPieceRef>;
2606 MacroStackTy MacroStack;
2609 for (PathPieces::const_iterator I = path.begin(), E = path.end();
2611 const auto &piece = *I;
2614 if (
auto *call = dyn_cast<PathDiagnosticCallPiece>(&*piece)) {
2619 const FullSourceLoc Loc = piece->getLocation().asLocation();
2623 SourceLocation InstantiationLoc = Loc.
isMacroID() ?
2629 Pieces.push_back(piece);
2636 if (!MacroStack.empty() && InstantiationLoc == MacroStack.back().second) {
2637 MacroStack.back().first->subPieces.push_back(piece);
2643 std::shared_ptr<PathDiagnosticMacroPiece> MacroGroup;
2645 SourceLocation ParentInstantiationLoc = InstantiationLoc.
isMacroID() ?
2650 while (!MacroStack.empty()) {
2651 if (InstantiationLoc == MacroStack.back().second) {
2652 MacroGroup = MacroStack.back().first;
2656 if (ParentInstantiationLoc == MacroStack.back().second) {
2657 MacroGroup = MacroStack.back().first;
2661 MacroStack.pop_back();
2664 if (!MacroGroup || ParentInstantiationLoc == MacroStack.back().second) {
2666 auto NewGroup = std::make_shared<PathDiagnosticMacroPiece>(
2670 MacroGroup->subPieces.push_back(NewGroup);
2672 assert(InstantiationLoc.
isFileID());
2673 Pieces.push_back(NewGroup);
2676 MacroGroup = NewGroup;
2677 MacroStack.push_back(std::make_pair(MacroGroup, InstantiationLoc));
2681 MacroGroup->subPieces.push_back(piece);
2687 path.insert(path.end(), Pieces.begin(), Pieces.end());
2693 static std::unique_ptr<VisitorsDiagnosticsTy>
2694 generateVisitorsDiagnostics(PathSensitiveBugReport *R,
2695 const ExplodedNode *ErrorNode,
2696 BugReporterContext &BRC) {
2697 std::unique_ptr<VisitorsDiagnosticsTy> Notes =
2698 std::make_unique<VisitorsDiagnosticsTy>();
2703 const ExplodedNode *NextNode = ErrorNode->getFirstPred();
2711 for (std::unique_ptr<BugReporterVisitor> &Visitor : R->visitors())
2712 visitors.push_back(std::move(Visitor));
2716 const ExplodedNode *Pred = NextNode->getFirstPred();
2719 for (
auto &V : visitors) {
2720 V->finalizeVisitor(BRC, ErrorNode, *R);
2722 if (
auto Piece = V->getEndPath(BRC, ErrorNode, *R)) {
2723 assert(!LastPiece &&
2724 "There can only be one final piece in a diagnostic.");
2725 assert(Piece->getKind() == PathDiagnosticPiece::Kind::Event &&
2726 "The final piece must contain a message!");
2727 LastPiece = std::move(Piece);
2728 (*Notes)[ErrorNode].push_back(LastPiece);
2734 for (
auto &V : visitors) {
2735 auto P = V->VisitNode(NextNode, BRC, *R);
2737 (*Notes)[NextNode].push_back(std::move(P));
2751 PathSensitiveBugReporter &Reporter) {
2753 BugPathGetter BugGraph(&Reporter.getGraph(), bugReports);
2755 while (BugPathInfo *BugPath = BugGraph.getNextBugPath()) {
2757 PathSensitiveBugReport *R = BugPath->Report;
2758 assert(R &&
"No original report found for sliced graph.");
2759 assert(R->isValid() &&
"Report selected by trimmed graph marked invalid.");
2760 const ExplodedNode *ErrorNode = BugPath->ErrorNode;
2764 R->addVisitor(std::make_unique<LikelyFalsePositiveSuppressionBRVisitor>());
2767 R->addVisitor(std::make_unique<NilReceiverBRVisitor>());
2768 R->addVisitor(std::make_unique<ConditionBRVisitor>());
2769 R->addVisitor(std::make_unique<TagVisitor>());
2771 BugReporterContext BRC(Reporter);
2774 std::unique_ptr<VisitorsDiagnosticsTy> visitorNotes =
2775 generateVisitorsDiagnostics(R, ErrorNode, BRC);
2778 if (Reporter.getAnalyzerOptions().ShouldCrosscheckWithZ3) {
2782 R->addVisitor(std::make_unique<FalsePositiveRefutationBRVisitor>());
2786 generateVisitorsDiagnostics(R, BugPath->ErrorNode, BRC);
2791 return PathDiagnosticBuilder(
2792 std::move(BRC), std::move(BugPath->BugPath), BugPath->Report,
2793 BugPath->ErrorNode, std::move(visitorNotes));
2800 std::unique_ptr<DiagnosticForConsumerMapTy>
2804 assert(!bugReports.empty());
2806 auto Out = std::make_unique<DiagnosticForConsumerMapTy>();
2809 PathDiagnosticBuilder::findValidReport(bugReports, *
this);
2812 for (PathDiagnosticConsumer *PC : consumers) {
2813 if (std::unique_ptr<PathDiagnostic> PD = PDB->generate(PC)) {
2814 (*Out)[PC] = std::move(PD);
2823 bool ValidSourceLoc = R->getLocation().isValid();
2824 assert(ValidSourceLoc);
2827 if (!ValidSourceLoc)
2831 llvm::FoldingSetNodeID
ID;
2836 BugReportEquivClass*
EQ = EQClasses.FindNodeOrInsertPos(ID, InsertPos);
2839 EQ =
new BugReportEquivClass(std::move(R));
2840 EQClasses.InsertNode(EQ, InsertPos);
2841 EQClassesVector.push_back(EQ);
2843 EQ->AddReport(std::move(R));
2847 if (
auto PR = dyn_cast<PathSensitiveBugReport>(R.get()))
2848 if (
const ExplodedNode *E = PR->getErrorNode()) {
2851 assert((E->isSink() || E->getLocation().getTag()) &&
2852 "Error node must either be a sink or have a tag");
2855 E->getLocationContext()->getAnalysisDeclContext();
2874 struct FRIEC_WLItem {
2875 const ExplodedNode *N;
2878 FRIEC_WLItem(
const ExplodedNode *n)
2879 : N(n), I(N->succ_begin()), E(N->succ_end()) {}
2884 BugReport *PathSensitiveBugReporter::findReportInEquivalenceClass(
2889 assert(EQ.getReports().size() > 0);
2890 const BugType& BT = EQ.getReports()[0]->getBugType();
2891 if (!BT.isSuppressOnSink()) {
2892 BugReport *R = EQ.getReports()[0].get();
2893 for (
auto &J : EQ.getReports()) {
2894 if (
auto *PR = dyn_cast<PathSensitiveBugReport>(J.get())) {
2896 bugReports.push_back(PR);
2908 BugReport *exampleReport =
nullptr;
2910 for (
const auto &I: EQ.getReports()) {
2911 auto *R = dyn_cast<PathSensitiveBugReport>(I.get());
2915 const ExplodedNode *errorNode = R->getErrorNode();
2916 if (errorNode->isSink()) {
2918 "BugType::isSuppressSink() should not be 'true' for sink end nodes");
2921 if (errorNode->succ_empty()) {
2922 bugReports.push_back(R);
2932 if (
const CFGBlock *ErrorB = errorNode->getCFGBlock())
2933 if (ErrorB->isInevitablySinking())
2938 using WLItem = FRIEC_WLItem;
2941 llvm::DenseMap<const ExplodedNode *, unsigned> Visited;
2944 WL.push_back(errorNode);
2945 Visited[errorNode] = 1;
2947 while (!WL.empty()) {
2948 WLItem &WI = WL.back();
2949 assert(!WI.N->succ_empty());
2951 for (; WI.I != WI.E; ++WI.I) {
2952 const ExplodedNode *Succ = *WI.I;
2954 if (Succ->succ_empty()) {
2956 if (!Succ->isSink()) {
2957 bugReports.push_back(R);
2968 unsigned &mark = Visited[Succ];
2978 if (!WL.empty() && &WL.back() == &WI)
2985 return exampleReport;
2988 void BugReporter::FlushReport(BugReportEquivClass& EQ) {
2990 BugReport *report = findReportInEquivalenceClass(EQ, bugReports);
2995 std::unique_ptr<DiagnosticForConsumerMapTy> Diagnostics =
2996 generateDiagnosticForConsumerMap(report, Consumers, bugReports);
2998 for (
auto &P : *Diagnostics) {
2999 PathDiagnosticConsumer *Consumer = P.first;
3000 std::unique_ptr<PathDiagnostic> &PD = P.second;
3004 if (PD->path.empty()) {
3005 PathDiagnosticLocation L = report->getLocation();
3006 auto piece = std::make_unique<PathDiagnosticEventPiece>(
3007 L, report->getDescription());
3009 piece->addRange(Range);
3010 PD->setEndOfPath(std::move(piece));
3013 PathPieces &Pieces = PD->getMutablePieces();
3014 if (getAnalyzerOptions().ShouldDisplayNotesAsEvents) {
3017 for (
auto I = report->getNotes().rbegin(),
3018 E = report->getNotes().rend(); I != E; ++I) {
3019 PathDiagnosticNotePiece *Piece = I->get();
3020 auto ConvertedPiece = std::make_shared<PathDiagnosticEventPiece>(
3021 Piece->getLocation(), Piece->getString());
3022 for (
const auto &R: Piece->getRanges())
3023 ConvertedPiece->addRange(R);
3025 Pieces.push_front(std::move(ConvertedPiece));
3028 for (
auto I = report->getNotes().rbegin(),
3029 E = report->getNotes().rend(); I != E; ++I)
3030 Pieces.push_front(*I);
3033 for (
const auto &I : report->getFixits())
3034 Pieces.back()->addFixit(I);
3037 Consumer->HandlePathDiagnostic(std::move(PD));
3043 static void populateExecutedLinesWithFunctionSignature(
3048 if (
const auto FD = dyn_cast<FunctionDecl>(Signature)) {
3049 SignatureSourceRange = FD->getSourceRange();
3050 }
else if (
const auto OD = dyn_cast<ObjCMethodDecl>(Signature)) {
3051 SignatureSourceRange = OD->getSourceRange();
3057 : SignatureSourceRange.
getEnd();
3064 for (
unsigned Line = StartLine;
Line <= EndLine;
Line++)
3065 ExecutedLines[FID].insert(
Line);
3068 static void populateExecutedLinesWithStmt(
3077 ExecutedLines[FID].insert(LineNo);
3082 static std::unique_ptr<FilesToLineNumsMap>
3084 auto ExecutedLines = std::make_unique<FilesToLineNumsMap>();
3087 if (N->getFirstPred() ==
nullptr) {
3089 const Decl *D = N->getLocationContext()->getDecl();
3090 populateExecutedLinesWithFunctionSignature(D, SM, *ExecutedLines);
3091 }
else if (
auto CE = N->getLocationAs<
CallEnter>()) {
3093 const Decl* D = CE->getCalleeContext()->getDecl();
3094 populateExecutedLinesWithFunctionSignature(D, SM, *ExecutedLines);
3095 }
else if (
const Stmt *S = N->getStmtForDiagnostics()) {
3096 populateExecutedLinesWithStmt(S, SM, *ExecutedLines);
3099 const Stmt *P = N->getParentMap().getParent(S);
3104 if (
const auto *RS = dyn_cast_or_null<ReturnStmt>(P)) {
3105 populateExecutedLinesWithStmt(RS, SM, *ExecutedLines);
3106 P = N->getParentMap().getParent(RS);
3109 if (P && (isa<SwitchCase>(P) || isa<LabelStmt>(P)))
3110 populateExecutedLinesWithStmt(P, SM, *ExecutedLines);
3113 N = N->getFirstPred();
3115 return ExecutedLines;
3118 std::unique_ptr<DiagnosticForConsumerMapTy>
3122 auto *basicReport = cast<BasicBugReport>(exampleReport);
3123 auto Out = std::make_unique<DiagnosticForConsumerMapTy>();
3124 for (
auto *Consumer : consumers)
3129 static PathDiagnosticCallPiece *
3130 getFirstStackedCallToHeaderFile(PathDiagnosticCallPiece *CP,
3139 "The call piece should not be in a header file.");
3145 const PathPieces &Path = CP->path;
3151 if (
auto *CPInner = dyn_cast<PathDiagnosticCallPiece>(Path.back().get()))
3152 return getFirstStackedCallToHeaderFile(CPInner, SMgr);
3158 static void resetDiagnosticLocationToMainFile(PathDiagnostic &PD) {
3159 if (PD.path.empty())
3162 PathDiagnosticPiece *LastP = PD.path.back().get();
3164 const SourceManager &SMgr = LastP->getLocation().getManager();
3168 if (
auto *CP = dyn_cast<PathDiagnosticCallPiece>(LastP)) {
3169 CP = getFirstStackedCallToHeaderFile(CP, SMgr);
3172 CP->setAsLastInMainSourceFile();
3175 const auto *ND = dyn_cast<
NamedDecl>(CP->getCallee());
3178 llvm::raw_svector_ostream os(buf);
3179 os <<
" (within a call to '" << ND->getDeclName() <<
"')";
3180 PD.appendToDesc(os.str());
3184 PD.setDeclWithIssue(CP->getCaller());
3185 PD.setLocation(CP->getLocation());
3194 std::unique_ptr<DiagnosticForConsumerMapTy>
3195 PathSensitiveBugReporter::generateDiagnosticForConsumerMap(
3198 std::vector<BasicBugReport *> BasicBugReports;
3199 std::vector<PathSensitiveBugReport *> PathSensitiveBugReports;
3200 if (isa<BasicBugReport>(exampleReport))
3202 consumers, bugReports);
3208 assert(!bugReports.empty());
3209 MaxBugClassSize.updateMax(bugReports.size());
3213 reinterpret_cast<PathSensitiveBugReport *const *>(&*bugReports.begin()),
3214 reinterpret_cast<PathSensitiveBugReport *const *>(&*bugReports.end()));
3215 std::unique_ptr<DiagnosticForConsumerMapTy> Out = generatePathDiagnostics(
3216 consumers, convertedArrayOfReports);
3221 MaxValidBugClassSize.updateMax(bugReports.size());
3226 for (
auto const &P : *Out)
3227 if (Opts.ShouldReportIssuesInMainSourceFile && !Opts.
AnalyzeAll)
3228 resetDiagnosticLocationToMainFile(*P.second);
3234 const CheckerBase *Checker, StringRef Name,
3236 PathDiagnosticLocation Loc,
3239 EmitBasicReport(DeclWithIssue, Checker->getCheckerName(), Name,
Category, Str,
3240 Loc, Ranges, Fixits);
3244 CheckerNameRef CheckName,
3245 StringRef
name, StringRef category,
3246 StringRef str, PathDiagnosticLocation Loc,
3250 BugType *BT = getBugTypeForName(CheckName, name, category);
3251 auto R = std::make_unique<BasicBugReport>(*BT, str, Loc);
3252 R->setDeclWithIssue(DeclWithIssue);
3253 for (
const auto &SR : Ranges)
3255 for (
const auto &FH : Fixits)
3256 R->addFixItHint(FH);
3257 emitReport(std::move(R));
3260 BugType *BugReporter::getBugTypeForName(CheckerNameRef CheckName,
3261 StringRef name, StringRef category) {
3263 llvm::raw_svector_ostream(fullDesc) << CheckName.getName() <<
":" << name
3265 BugType *&BT = StrBugTypes[fullDesc];
3267 BT =
new BugType(CheckName, name, category);
Indicates that the tracked object is a CF object.
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...
ProgramStateManager & getStateManager() const
getStateManager - Return the state manager used by the analysis engine.
static void removeRedundantMsgs(PathPieces &path)
An optimization pass over PathPieces that removes redundant diagnostics generated by both ConditionBR...
if(T->getSizeExpr()) TRY_TO(TraverseStmt(T -> getSizeExpr()))
MemRegion - The root abstract class for all memory regions.
succ_iterator succ_begin()
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
Specialize PointerLikeTypeTraits to allow LazyGenerationalUpdatePtr to be placed into a PointerUnion...
Stmt - This represents one statement.
std::unique_ptr< DiagnosticForConsumerMapTy > generatePathDiagnostics(ArrayRef< PathDiagnosticConsumer *> consumers, ArrayRef< PathSensitiveBugReport *> &bugReports)
bugReports A set of bug reports within a single equivalence class
An instance of this object exists for each enum constant that is defined.
Defines the SourceManager interface.
const CFGBlock * getSrc() const
Decl - This represents one declaration (or definition), e.g.
Represents a point when we begin processing an inlined call.
bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const
Determines the order of 2 source locations in the translation unit.
static bool isInLoopBody(const ParentMap &PM, const Stmt *S, const Stmt *Term)
static void updateExecutedLinesWithDiagnosticPieces(PathDiagnostic &PD)
Populate executes lines with lines containing at least one diagnostics.
const Stmt * getLoopTarget() const
Stmt * getParent(Stmt *) const
virtual std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex)
Produces the message of the following form: 'Msg via Nth parameter'.
void Profile(llvm::FoldingSetNodeID &ID) const
Represents a program point just before an implicit call event.
virtual ~StackHintGenerator()=0
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 PathDiagnosticLocation createEndBrace(const CompoundStmt *CS, const SourceManager &SM)
Create a location for the end of the compound statement.
unsigned succ_size() const
bool isConsumedExpr(Expr *E) const
SymbolRef getAsLocSymbol(bool IncludeBaseRegions=false) const
If this SVal is a location and wraps a symbol, return that SymbolRef.
ArrayRef< SourceRange > getRanges() const override
Get the SourceRanges associated with the report.
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.
Defines the clang::Expr interface and subclasses for C++ expressions.
static PathDiagnosticLocation createSingleLocation(const PathDiagnosticLocation &PDL)
Convert the given location into a single kind location.
static void removePiecesWithInvalidLocations(PathPieces &Pieces)
Remove all pieces with invalid locations as these cannot be serialized.
BoundNodesTreeBuilder Nodes
static const Stmt * getStmtBeforeCond(const ParentMap &PM, const Stmt *Term, const ExplodedNode *N)
static PathDiagnosticLocation getEnclosingStmtLocation(const Stmt *S, const LocationContext *LC, bool allowNestedContexts=false)
static Optional< size_t > getLengthOnSingleLine(const SourceManager &SM, SourceRange Range)
Returns the number of bytes in the given (character-based) SourceRange.
virtual void emitReport(std::unique_ptr< BugReport > R)
Add the given report to the set of reports tracked by BugReporter.
const SymExpr * SymbolRef
void markInteresting(SymbolRef sym, bugreporter::TrackingKind TKind=bugreporter::TrackingKind::Thorough)
Marks a symbol as interesting.
SourceLocation getBeginLoc() const LLVM_READONLY
AnalysisDeclContext contains the context data for the function or method under analysis.
static void removeIdenticalEvents(PathPieces &path)
std::unique_ptr< ExplodedGraph > trim(ArrayRef< const NodeTy *> Nodes, InterExplodedGraphMap *ForwardMap=nullptr, InterExplodedGraphMap *InverseMap=nullptr) const
Creates a trimmed version of the graph that only contains paths leading to the given nodes...
void EmitBasicReport(const Decl *DeclWithIssue, const CheckerBase *Checker, StringRef BugName, StringRef BugCategory, StringRef BugStr, PathDiagnosticLocation Loc, ArrayRef< SourceRange > Ranges=None, ArrayRef< FixItHint > Fixits=None)
static bool isInCodeFile(SourceLocation SL, const SourceManager &SM)
void addPredecessor(ExplodedNode *V, ExplodedGraph &G)
addPredeccessor - Adds a predecessor to the current node, and in tandem add this node as a successor ...
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
static bool lexicalContains(const ParentMap &PM, const Stmt *X, const Stmt *Y)
Return true if X is contained by Y.
static void insertToInterestingnessMap(llvm::DenseMap< T, bugreporter::TrackingKind > &InterestingnessMap, T Val, bugreporter::TrackingKind TKind)
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
std::string getMessage(const ExplodedNode *N) override
Search the call expression for the symbol Sym and dispatch the 'getMessageForX()' methods to construc...
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Represents a point after we ran remove dead bindings AFTER processing the given statement.
bool isInteresting(SymbolRef sym) const
static PathDiagnosticLocation createMemberLoc(const MemberExpr *ME, const SourceManager &SM)
For member expressions, return the location of the '.
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
const ExplodedNode *const * const_succ_iterator
const Stmt * getCallSite() const
static SourceLocation getValidSourceLocation(const Stmt *S, LocationOrAnalysisDeclContext LAC, bool UseEndOfStatement=false)
Construct a source location that corresponds to either the beginning or the end of the given statemen...
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.
STATISTIC(MaxBugClassSize, "The maximum number of bug reports in the same equivalence class")
This represents one expression.
Stmt * getTerminatorCondition(bool StripParens=true)
const AnnotatedLine * Line
std::vector< std::string > SilencedCheckersAndPackages
Vector of checker/package names which will not emit warnings.
unsigned getLineNumber(bool *Invalid=nullptr) const
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
static void dropFunctionEntryEdge(const PathDiagnosticConstruct &C, PathPieces &Path)
Drop the very first edge in a path, which should be a function entry edge.
static std::unique_ptr< PathDiagnostic > generateEmptyDiagnosticForReport(const PathSensitiveBugReport *R, const SourceManager &SM)
void FlushReports()
Generate and flush diagnostics for all bug reports.
const CFGBlock * getDst() const
ReturnStmt - This represents a return, optionally of an expression: return; return 4;...
bool isBodyAutosynthesized() const
Checks if the body of the Decl is generated by the BodyFarm.
SourceLocation getEnd() const
std::map< FileID, std::set< unsigned > > FilesToLineNumsMap
File IDs mapped to sets of line numbers.
unsigned getExpansionLineNumber(SourceLocation Loc, bool *Invalid=nullptr) const
static void removePopUpNotes(PathPieces &Path)
Same logic as above to remove extra pieces.
Optional< T > getAs() const
Convert to the specified SVal type, returning None if this SVal is not of the desired type...
void emitReport(std::unique_ptr< BugReport > R) override
Add the given report to the set of reports tracked by BugReporter.
virtual bool hasBody() const
Returns true if this Decl represents a declaration for a body of code, such as a function or method d...
constexpr llvm::StringLiteral StrLoopCollectionEmpty
unsigned getFileOffset(SourceLocation SpellingLoc) const
Returns the offset from the start of the file that the specified SourceLocation represents.
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
static PathDiagnosticEventPiece * eventsDescribeSameCondition(PathDiagnosticEventPiece *X, PathDiagnosticEventPiece *Y)
static void simplifySimpleBranches(PathPieces &pieces)
Move edges from a branch condition to a branch target when the condition is simple.
constexpr llvm::StringLiteral StrLoopRangeEmpty
Encodes a location in the source.
virtual std::unique_ptr< DiagnosticForConsumerMapTy > generateDiagnosticForConsumerMap(BugReport *exampleReport, ArrayRef< PathDiagnosticConsumer *> consumers, ArrayRef< BugReport *> bugReports)
Generate the diagnostics for the given bug report.
Stmt * getParentIgnoreParens(Stmt *) const
T castAs() const
Convert to the specified ProgramPoint type, asserting that this ProgramPoint is of the desired type...
const MemRegion * getAsRegion() const
static bool isIncrementOrInitInForLoop(const Stmt *S, const Stmt *FL)
static void removeContextCycles(PathPieces &Path, const SourceManager &SM)
Eliminate two-edge cycles created by addContextEdges().
static void addContextEdges(PathPieces &pieces, const LocationContext *LC)
Adds synthetic edges from top-level statements to their subexpressions.
ASTContext & getASTContext() const LLVM_READONLY
static void removePunyEdges(PathPieces &path, const SourceManager &SM, const ParentMap &PM)
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...
static PathDiagnosticLocation createEnd(const Stmt *S, const SourceManager &SM, const LocationOrAnalysisDeclContext LAC)
Create a location for the end of the statement.
const Stmt * getStmt() const
SVal getSVal(const Stmt *S) const
Get the value of an arbitrary expression at this node.
static const Stmt * getEnclosingParent(const Stmt *S, const ParentMap &PM)
PathDiagnosticLocation getLocation() const override
The primary location of the bug report that points at the undesirable behavior in the code...
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...
Optional< bugreporter::TrackingKind > getInterestingnessKind(SymbolRef sym) const
ast_type_traits::DynTypedNode Node
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
const llvm::MemoryBuffer * getBuffer(FileID FID, SourceLocation Loc, bool *Invalid=nullptr) const
Return the buffer for the specified FileID.
constexpr llvm::StringLiteral StrLoopBodyZero
void clearVisitors()
Remove all visitors attached to this bug report.
Dataflow Directional Tag Classes.
bool isValid() const
Return true if this is a valid SourceLocation object.
static void addEdgeToPath(PathPieces &path, PathDiagnosticLocation &PrevLoc, PathDiagnosticLocation NewLoc)
Adds a sanitized control-flow diagnostic edge to a path.
const StackFrameContext * getCalleeContext() const
void Profile(llvm::FoldingSetNodeID &hash) const override
Reports are uniqued to ensure that we do not emit multiple diagnostics for each bug.
StmtClass getStmtClass() const
static std::unique_ptr< PathDiagnostic > generateDiagnosticForBasicReport(const BasicBugReport *R)
Stmt * getTerminatorStmt()
static const Stmt * getTerminatorCondition(const CFGBlock *B)
A customized wrapper for CFGBlock::getTerminatorCondition() which returns the element for ObjCForColl...
const Decl * getDecl() const
llvm::DenseMap< const ExplodedNode *, const ExplodedNode * > InterExplodedGraphMap
constexpr llvm::StringLiteral StrEnteringLoop
static bool isLoop(const Stmt *Term)
FileID getFileID(SourceLocation SpellingLoc) const
Return the FileID for a SourceLocation.
Iterator for iterating over Stmt * arrays that contain only T *.
static std::unique_ptr< FilesToLineNumsMap > findExecutedLines(const SourceManager &SM, const ExplodedNode *N)
const LocationContext * getLocationContext() const
void Profile(llvm::FoldingSetNodeID &hash) const override
Profile to identify equivalent bug reports for error report coalescing.
const ExplodedGraph & getGraph() const
getGraph - Get the exploded graph created by the analysis engine for the analyzed method or function...
const StackFrameContext * getStackFrame() const
CharSourceRange getExpansionRange(SourceLocation Loc) const
Given a SourceLocation object, return the range of tokens covered by the expansion in the ultimate fi...
Stores options for the analyzer from the command line.
SourceManager & getSourceManager()
static std::shared_ptr< PathDiagnosticCallPiece > construct(const CallExitEnd &CE, const SourceManager &SM)
static bool optimizeEdges(const PathDiagnosticConstruct &C, PathPieces &path, OptimizedCallsSet &OCS)
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 ...
static bool removeUnneededCalls(const PathDiagnosticConstruct &C, PathPieces &pieces, const PathSensitiveBugReport *R, bool IsInteresting=false)
Recursively scan through a path and prune out calls and macros pieces that aren't needed...
Defines the clang::SourceLocation class and associated facilities.
const ParentMap & getParentMap() const
pred_iterator pred_begin()
static bool isContainedByStmt(const ParentMap &PM, const Stmt *S, const Stmt *SubS)
static const Stmt * getStmtParent(const Stmt *S, const ParentMap &PM)
void addVisitor(std::unique_ptr< BugReporterVisitor > visitor)
Add custom or predefined bug report visitors to this report.
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 Decl::Kind getKind(const Decl *D)
A trivial tuple used to represent a source range.
This represents a decl that may have a name.
Optional< T > getAs() const
Convert to the specified ProgramPoint type, returning None if this ProgramPoint is not of the desired...
static void CompactMacroExpandedPieces(PathPieces &path, const SourceManager &SM)
CompactMacroExpandedPieces - This function postprocesses a PathDiagnostic object and collapses PathDi...
const Decl * getDeclWithIssue() const override
The smallest declaration that contains the bug location.
SourceLocation getBegin() const
This class handles loading and caching of source files into memory.
SmallVector< std::unique_ptr< BugReporterVisitor >, 8 > VisitorList
bool EQ(InterpState &S, CodePtr OpPC)