48#include "llvm/ADT/ArrayRef.h"
49#include "llvm/ADT/DenseMap.h"
50#include "llvm/ADT/DenseSet.h"
51#include "llvm/ADT/FoldingSet.h"
52#include "llvm/ADT/STLExtras.h"
53#include "llvm/ADT/SmallPtrSet.h"
54#include "llvm/ADT/StringExtras.h"
55#include "llvm/ADT/StringRef.h"
56#include "llvm/Support/Compiler.h"
57#include "llvm/Support/ErrorHandling.h"
58#include "llvm/Support/TimeProfiler.h"
59#include "llvm/Support/raw_ostream.h"
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)");
84STAT_COUNTER(NumTimesReportPassesZ3,
"Number of reports passed Z3");
85STAT_COUNTER(NumTimesReportRefuted,
"Number of reports refuted by Z3");
87 "Number of times a report equivalence class was aborted by the Z3 "
90 "Number of times all reports of an equivalence class was refuted");
94void BugReporterContext::anchor() {}
104 std::pair<PathDiagnosticCallPiece *, const ExplodedNode *>;
108using VisitorsDiagnosticsTy =
109 llvm::DenseMap<const ExplodedNode *, std::vector<PathDiagnosticPieceRef>>;
113using LocationContextMap =
114 llvm::DenseMap<const PathPieces *, const LocationContext *>;
119class PathDiagnosticConstruct {
128 LocationContextMap LCM;
135 CallWithEntryStack CallStack;
139 std::unique_ptr<PathDiagnostic> PD;
145 const Decl *AnalysisEntryPoint);
150 assert(CurrentNode &&
"Already reached the root!");
158 return LCM.find(&PD->getActivePath())->getSecond();
161 const ExplodedNode *getCurrentNode()
const {
return CurrentNode; }
165 bool ascendToPrevNode() {
167 return static_cast<bool>(CurrentNode);
171 return getCurrLocationContext()->getParentMap();
176 const Stmt *getParent(
const Stmt *S)
const {
177 return getParentMap().getParent(S);
186 assert(LCM.count(
Path) &&
187 "Failed to find the context associated with these pieces!");
188 return LCM.find(
Path)->getSecond();
193 PathPieces &getActivePath() {
return PD->getActivePath(); }
194 PathPieces &getMutablePieces() {
return PD->getMutablePieces(); }
197 bool shouldAddControlNotes()
const {
200 bool shouldGenerateDiagnostics()
const {
203 bool supportsLogicalOpControlFlow()
const {
214 std::unique_ptr<const ExplodedGraph> BugPath;
225 std::unique_ptr<const VisitorsDiagnosticsTy> VisitorsDiagnostics;
231 static std::optional<PathDiagnosticBuilder>
235 PathDiagnosticBuilder(
238 std::unique_ptr<VisitorsDiagnosticsTy> VisitorsDiagnostics);
250 std::unique_ptr<PathDiagnostic>
255 const CallWithEntryStack &CallStack)
const;
256 void generatePathDiagnosticsForNode(PathDiagnosticConstruct &
C,
259 void generateMinimalDiagForBlockEdge(PathDiagnosticConstruct &
C,
263 generateDiagForGotoOP(
const PathDiagnosticConstruct &
C,
const Stmt *S,
267 generateDiagForSwitchOP(
const PathDiagnosticConstruct &
C,
const CFGBlock *Dst,
271 generateDiagForBinaryOP(
const PathDiagnosticConstruct &
C,
const Stmt *
T,
275 ExecutionContinues(
const PathDiagnosticConstruct &
C)
const;
278 ExecutionContinues(llvm::raw_string_ostream &os,
279 const PathDiagnosticConstruct &
C)
const;
285 if (!llvm::timeTraceProfilerEnabled())
287 const auto &BugReports =
EQ.getReports();
288 if (BugReports.empty())
289 return "Empty Equivalence Class";
290 const BugReport *R = BugReports.front().get();
292 return (
"Flushing EQC " + BT.getDescription()).str();
298 assert(llvm::timeTraceProfilerEnabled());
300 const auto &BugReports =
EQ.getReports();
301 if (BugReports.empty())
303 const BugReport *R = BugReports.front().get();
306 std::string
File =
SM.getFilename(
Loc).str();
307 return {BT.getCheckerName().str(), std::move(
File),
308 static_cast<int>(
Loc.getLineNumber())};
328 const auto *CE = dyn_cast_or_null<CallExpr>(CallSite);
333 for (
auto [Idx, ArgExpr] : llvm::enumerate(CE->arguments())) {
345 if (ArgExpr->getType()->isVoidPointerType())
370 return (llvm::Twine(Msg) +
" via " + std::to_string(ArgIndex) +
371 llvm::getOrdinalSuffix(ArgIndex) +
" parameter").str();
391 if (
X->getTag() == tagPreferred && Y->
getTag() == tagLesser)
394 if (Y->
getTag() == tagPreferred &&
X->getTag() == tagLesser)
406 unsigned N = path.size();
413 for (
unsigned i = 0; i < N; ++i) {
414 auto piece = std::move(path.front());
417 switch (piece->getKind()) {
428 if (
auto *nextEvent =
429 dyn_cast<PathDiagnosticEventPiece>(path.front().get())) {
430 auto *
event = cast<PathDiagnosticEventPiece>(piece.get());
434 if (
auto *pieceToKeep =
436 piece = std::move(pieceToKeep == event ? piece : path.front());
448 path.push_back(std::move(piece));
458 bool IsInteresting =
false) {
459 bool containsSomethingInteresting = IsInteresting;
460 const unsigned N = pieces.size();
462 for (
unsigned i = 0 ; i < N ; ++i) {
465 auto piece = std::move(pieces.front());
468 switch (piece->getKind()) {
470 auto &call = cast<PathDiagnosticCallPiece>(*piece);
477 containsSomethingInteresting =
true;
481 auto ¯o = cast<PathDiagnosticMacroPiece>(*piece);
484 containsSomethingInteresting =
true;
488 auto &
event = cast<PathDiagnosticEventPiece>(*piece);
492 containsSomethingInteresting |= !
event.isPrunable();
501 pieces.push_back(std::move(piece));
504 return containsSomethingInteresting;
509 for (
unsigned int i = 0; i <
Path.size(); ++i) {
510 auto Piece = std::move(
Path.front());
512 if (!isa<PathDiagnosticPopUpPiece>(*Piece))
513 Path.push_back(std::move(Piece));
529 for (
const auto &I : Pieces) {
530 auto *
Call = dyn_cast<PathDiagnosticCallPiece>(I.get());
535 if (LastCallLocation) {
537 if (CallerIsImplicit || !
Call->callEnter.asLocation().isValid())
538 Call->callEnter = *LastCallLocation;
539 if (CallerIsImplicit || !
Call->callReturn.asLocation().isValid())
540 Call->callReturn = *LastCallLocation;
546 if (
Call->callEnterWithin.asLocation().isValid() &&
548 ThisCallLocation = &
Call->callEnterWithin;
550 ThisCallLocation = &
Call->callEnter;
552 assert(ThisCallLocation &&
"Outermost call has an invalid location");
561 for (PathPieces::iterator I = Pieces.begin(),
E = Pieces.end(); I !=
E;) {
562 if (
auto *
C = dyn_cast<PathDiagnosticCallPiece>(I->get()))
565 if (
auto *M = dyn_cast<PathDiagnosticMacroPiece>(I->get()))
568 if (
auto *
CF = dyn_cast<PathDiagnosticControlFlowPiece>(I->get())) {
569 const Stmt *Start =
CF->getStartLocation().asStmt();
570 const Stmt *End =
CF->getEndLocation().asStmt();
571 if (isa_and_nonnull<CXXDefaultInitExpr>(Start)) {
574 }
else if (isa_and_nonnull<CXXDefaultInitExpr>(End)) {
575 PathPieces::iterator Next = std::next(I);
578 dyn_cast<PathDiagnosticControlFlowPiece>(Next->get())) {
579 NextCF->setStartLocation(
CF->getStartLocation());
595 for (PathPieces::iterator I = Pieces.begin(),
E = Pieces.end(); I !=
E;) {
596 if (
auto *
C = dyn_cast<PathDiagnosticCallPiece>(I->get()))
599 if (
auto *M = dyn_cast<PathDiagnosticMacroPiece>(I->get()))
602 if (!(*I)->getLocation().isValid() ||
603 !(*I)->getLocation().asLocation().isValid()) {
612 const PathDiagnosticConstruct &
C)
const {
613 if (
const Stmt *S =
C.getCurrentNode()->getNextStmtForDiagnostics())
615 C.getCurrLocationContext());
622 llvm::raw_string_ostream &os,
const PathDiagnosticConstruct &
C)
const {
624 if (os.str().empty())
630 os <<
"Execution continues on line "
631 << getSourceManager().getExpansionLineNumber(
Loc.asLocation())
634 os <<
"Execution jumps to the end of the ";
635 const Decl *
D =
C.getCurrLocationContext()->getDecl();
636 if (isa<ObjCMethodDecl>(
D))
638 else if (isa<FunctionDecl>(
D))
641 assert(isa<BlockDecl>(
D));
642 os <<
"anonymous block";
658 switch (
Parent->getStmtClass()) {
659 case Stmt::ForStmtClass:
660 case Stmt::DoStmtClass:
661 case Stmt::WhileStmtClass:
662 case Stmt::ObjCForCollectionStmtClass:
663 case Stmt::CXXForRangeStmtClass:
674 bool allowNestedContexts =
false) {
681 switch (
Parent->getStmtClass()) {
682 case Stmt::BinaryOperatorClass: {
683 const auto *B = cast<BinaryOperator>(
Parent);
684 if (B->isLogicalOp())
688 case Stmt::CompoundStmtClass:
689 case Stmt::StmtExprClass:
691 case Stmt::ChooseExprClass:
694 if (allowNestedContexts || cast<ChooseExpr>(
Parent)->getCond() == S)
698 case Stmt::BinaryConditionalOperatorClass:
699 case Stmt::ConditionalOperatorClass:
702 if (allowNestedContexts ||
703 cast<AbstractConditionalOperator>(
Parent)->getCond() == S)
707 case Stmt::CXXForRangeStmtClass:
708 if (cast<CXXForRangeStmt>(
Parent)->getBody() == S)
711 case Stmt::DoStmtClass:
713 case Stmt::ForStmtClass:
714 if (cast<ForStmt>(
Parent)->getBody() == S)
717 case Stmt::IfStmtClass:
718 if (cast<IfStmt>(
Parent)->getCond() != S)
721 case Stmt::ObjCForCollectionStmtClass:
722 if (cast<ObjCForCollectionStmt>(
Parent)->getBody() == S)
725 case Stmt::WhileStmtClass:
726 if (cast<WhileStmt>(
Parent)->getCond() != S)
736 assert(S &&
"Cannot have null Stmt for PathDiagnosticLocation");
755void PathDiagnosticBuilder::updateStackPiecesWithMessage(
757 if (R->hasCallStackHint(
P))
758 for (
const auto &I : CallStack) {
761 std::string stackMsg = R->getCallStackMessage(
P, N);
775 const PathDiagnosticConstruct &
C,
const CFGBlock *Dst,
781 llvm::raw_string_ostream os(sbuf);
787 switch (S->getStmtClass()) {
789 os <<
"No cases match in the switch statement. "
790 "Control jumps to line "
791 << End.asLocation().getExpansionLineNumber();
793 case Stmt::DefaultStmtClass:
794 os <<
"Control jumps to the 'default' case at line "
795 << End.asLocation().getExpansionLineNumber();
798 case Stmt::CaseStmtClass: {
799 os <<
"Control jumps to 'case ";
800 const auto *Case = cast<CaseStmt>(S);
804 bool GetRawInt =
true;
806 if (
const auto *DR = dyn_cast<DeclRefExpr>(LHS)) {
809 const auto *
D = dyn_cast<EnumConstantDecl>(DR->getDecl());
820 os <<
":' at line " << End.asLocation().getExpansionLineNumber();
825 os <<
"'Default' branch taken. ";
826 End = ExecutionContinues(os,
C);
828 return std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, sbuf);
832 const PathDiagnosticConstruct &
C,
const Stmt *S,
835 llvm::raw_string_ostream os(sbuf);
838 os <<
"Control jumps to line " << End.asLocation().getExpansionLineNumber();
839 return std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, sbuf);
843 const PathDiagnosticConstruct &
C,
const Stmt *
T,
const CFGBlock *Src,
848 const auto *B = cast<BinaryOperator>(
T);
850 llvm::raw_string_ostream os(sbuf);
851 os <<
"Left side of '";
854 if (B->getOpcode() == BO_LAnd) {
867 End = ExecutionContinues(
C);
870 assert(B->getOpcode() == BO_LOr);
878 End = ExecutionContinues(
C);
886 return std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, sbuf);
889void PathDiagnosticBuilder::generateMinimalDiagForBlockEdge(
890 PathDiagnosticConstruct &
C,
BlockEdge BE)
const {
900 switch (
T->getStmtClass()) {
904 case Stmt::GotoStmtClass:
905 case Stmt::IndirectGotoStmtClass: {
906 if (
const Stmt *S =
C.getCurrentNode()->getNextStmtForDiagnostics())
907 C.getActivePath().push_front(generateDiagForGotoOP(
C, S, Start));
911 case Stmt::SwitchStmtClass: {
912 C.getActivePath().push_front(generateDiagForSwitchOP(
C, Dst, Start));
916 case Stmt::BreakStmtClass:
917 case Stmt::ContinueStmtClass: {
919 llvm::raw_string_ostream os(sbuf);
921 C.getActivePath().push_front(
922 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, sbuf));
927 case Stmt::BinaryConditionalOperatorClass:
928 case Stmt::ConditionalOperatorClass: {
930 llvm::raw_string_ostream os(sbuf);
931 os <<
"'?' condition is ";
940 if (
const Stmt *S = End.asStmt())
943 C.getActivePath().push_front(
944 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, sbuf));
949 case Stmt::BinaryOperatorClass: {
950 if (!
C.supportsLogicalOpControlFlow())
953 C.getActivePath().push_front(generateDiagForBinaryOP(
C,
T, Src, Dst));
957 case Stmt::DoStmtClass:
960 llvm::raw_string_ostream os(sbuf);
962 os <<
"Loop condition is true. ";
965 if (
const Stmt *S = End.asStmt())
968 C.getActivePath().push_front(
969 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, sbuf));
973 if (
const Stmt *S = End.asStmt())
976 C.getActivePath().push_front(
977 std::make_shared<PathDiagnosticControlFlowPiece>(
978 Start, End,
"Loop condition is false. Exiting loop"));
982 case Stmt::WhileStmtClass:
983 case Stmt::ForStmtClass:
986 llvm::raw_string_ostream os(sbuf);
988 os <<
"Loop condition is false. ";
990 if (
const Stmt *S = End.asStmt())
993 C.getActivePath().push_front(
994 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, sbuf));
997 if (
const Stmt *S = End.asStmt())
1000 C.getActivePath().push_front(
1001 std::make_shared<PathDiagnosticControlFlowPiece>(
1002 Start, End,
"Loop condition is true. Entering loop body"));
1007 case Stmt::IfStmtClass: {
1010 if (
const Stmt *S = End.asStmt())
1014 C.getActivePath().push_front(
1015 std::make_shared<PathDiagnosticControlFlowPiece>(
1016 Start, End,
"Taking false branch"));
1018 C.getActivePath().push_front(
1019 std::make_shared<PathDiagnosticControlFlowPiece>(
1020 Start, End,
"Taking true branch"));
1033 case Stmt::ForStmtClass:
1034 case Stmt::WhileStmtClass:
1035 case Stmt::ObjCForCollectionStmtClass:
1036 case Stmt::CXXForRangeStmtClass:
1065 const Stmt *S = SP->getStmt();
1075 const Stmt *LoopBody =
nullptr;
1077 case Stmt::CXXForRangeStmtClass: {
1078 const auto *FR = cast<CXXForRangeStmt>(Term);
1083 LoopBody = FR->getBody();
1086 case Stmt::ForStmtClass: {
1087 const auto *FS = cast<ForStmt>(Term);
1090 LoopBody = FS->getBody();
1093 case Stmt::ObjCForCollectionStmtClass: {
1094 const auto *FC = cast<ObjCForCollectionStmt>(Term);
1095 LoopBody = FC->getBody();
1098 case Stmt::WhileStmtClass:
1099 LoopBody = cast<WhileStmt>(Term)->getBody();
1129 std::make_shared<PathDiagnosticControlFlowPiece>(NewLoc, PrevLoc));
1137 if (
const auto *FS = dyn_cast_or_null<ObjCForCollectionStmt>(S))
1138 return FS->getElement();
1145 "Loop body skipped when range is empty";
1147 "Loop body skipped when collection is empty";
1149static std::unique_ptr<FilesToLineNumsMap>
1152void PathDiagnosticBuilder::generatePathDiagnosticsForNode(
1163 if (
C.shouldAddPathEdges()) {
1179 bool VisitedEntireCall =
C.PD->isWithinCall();
1180 C.PD->popActivePath();
1183 if (VisitedEntireCall) {
1184 Call = cast<PathDiagnosticCallPiece>(
C.getActivePath().front().get());
1188 const Decl *Caller = CE->getLocationContext()->getDecl();
1190 assert(
C.getActivePath().size() == 1 &&
1191 C.getActivePath().front().get() ==
Call);
1195 assert(
C.isInLocCtxMap(&
C.getActivePath()) &&
1196 "When we ascend to a previously unvisited call, the active path's "
1197 "address shouldn't change, but rather should be compacted into "
1198 "a single CallEvent!");
1199 C.updateLocCtxMap(&
C.getActivePath(),
C.getCurrLocationContext());
1202 assert(!
C.isInLocCtxMap(&
Call->path) &&
1203 "When we ascend to a previously unvisited call, this must be the "
1204 "first time we encounter the caller context!");
1205 C.updateLocCtxMap(&
Call->path, CE->getCalleeContext());
1207 Call->setCallee(*CE,
SM);
1210 PrevLoc =
Call->getLocation();
1212 if (!
C.CallStack.empty()) {
1213 assert(
C.CallStack.back().first ==
Call);
1214 C.CallStack.pop_back();
1219 assert(
C.getCurrLocationContext() ==
C.getLocationContextForActivePath() &&
1220 "The current position in the bug path is out of sync with the "
1221 "location context associated with the active path!");
1224 if (std::optional<CallExitEnd> CE =
P.getAs<
CallExitEnd>()) {
1230 assert(!
C.isInLocCtxMap(&
Call->path) &&
1231 "We just entered a call, this must've been the first time we "
1232 "encounter its context!");
1233 C.updateLocCtxMap(&
Call->path, CE->getCalleeContext());
1235 if (
C.shouldAddPathEdges()) {
1241 auto *
P =
Call.get();
1242 C.getActivePath().push_front(std::move(
Call));
1245 C.PD->pushActivePath(&
P->path);
1246 C.CallStack.push_back(CallWithEntry(
P,
C.getCurrentNode()));
1251 if (!
C.shouldAddPathEdges())
1257 if (!isa<ObjCForCollectionStmt>(PS->getStmt())) {
1265 if (
C.shouldAddControlNotes()) {
1266 generateMinimalDiagForBlockEdge(
C, *BE);
1269 if (!
C.shouldAddPathEdges()) {
1276 const Stmt *Body =
nullptr;
1278 if (
const auto *FS = dyn_cast<ForStmt>(
Loop))
1279 Body = FS->getBody();
1280 else if (
const auto *WS = dyn_cast<WhileStmt>(
Loop))
1281 Body = WS->getBody();
1282 else if (
const auto *OFS = dyn_cast<ObjCForCollectionStmt>(
Loop)) {
1283 Body = OFS->getBody();
1284 }
else if (
const auto *FRS = dyn_cast<CXXForRangeStmt>(
Loop)) {
1285 Body = FRS->getBody();
1289 auto p = std::make_shared<PathDiagnosticEventPiece>(
1290 L,
"Looping back to the head of the loop");
1291 p->setPrunable(
true);
1295 if (!
C.shouldAddControlNotes()) {
1296 C.getActivePath().push_front(std::move(p));
1299 if (
const auto *CS = dyn_cast_or_null<CompoundStmt>(Body)) {
1319 if (!IsInLoopBody) {
1320 if (isa<ObjCForCollectionStmt>(Term)) {
1322 }
else if (isa<CXXForRangeStmt>(Term)) {
1334 C.getCurrLocationContext());
1335 auto PE = std::make_shared<PathDiagnosticEventPiece>(L, str);
1336 PE->setPrunable(
true);
1340 if (!
C.shouldAddControlNotes()) {
1341 C.getActivePath().push_front(std::move(PE));
1344 }
else if (isa<BreakStmt, ContinueStmt, GotoStmt>(Term)) {
1352static std::unique_ptr<PathDiagnostic>
1354 const Decl *AnalysisEntryPoint) {
1356 return std::make_unique<PathDiagnostic>(
1360 AnalysisEntryPoint, std::make_unique<FilesToLineNumsMap>());
1363static std::unique_ptr<PathDiagnostic>
1366 const Decl *AnalysisEntryPoint) {
1368 return std::make_unique<PathDiagnostic>(
1385 if (isa<FullExpr, CXXBindTemporaryExpr, SubstNonTypeTemplateParmExpr>(S))
1395 switch (S->getStmtClass()) {
1396 case Stmt::BinaryOperatorClass: {
1397 const auto *BO = cast<BinaryOperator>(S);
1398 if (!BO->isLogicalOp())
1400 return BO->getLHS() == Cond || BO->getRHS() == Cond;
1402 case Stmt::IfStmtClass:
1403 return cast<IfStmt>(S)->getCond() == Cond;
1404 case Stmt::ForStmtClass:
1405 return cast<ForStmt>(S)->getCond() == Cond;
1406 case Stmt::WhileStmtClass:
1407 return cast<WhileStmt>(S)->getCond() == Cond;
1408 case Stmt::DoStmtClass:
1409 return cast<DoStmt>(S)->getCond() == Cond;
1410 case Stmt::ChooseExprClass:
1411 return cast<ChooseExpr>(S)->getCond() == Cond;
1412 case Stmt::IndirectGotoStmtClass:
1413 return cast<IndirectGotoStmt>(S)->getTarget() == Cond;
1414 case Stmt::SwitchStmtClass:
1415 return cast<SwitchStmt>(S)->getCond() == Cond;
1416 case Stmt::BinaryConditionalOperatorClass:
1417 return cast<BinaryConditionalOperator>(S)->getCond() == Cond;
1418 case Stmt::ConditionalOperatorClass: {
1419 const auto *CO = cast<ConditionalOperator>(S);
1420 return CO->getCond() == Cond ||
1421 CO->getLHS() == Cond ||
1422 CO->getRHS() == Cond;
1424 case Stmt::ObjCForCollectionStmtClass:
1425 return cast<ObjCForCollectionStmt>(S)->getElement() == Cond;
1426 case Stmt::CXXForRangeStmtClass: {
1427 const auto *FRS = cast<CXXForRangeStmt>(S);
1428 return FRS->getCond() == Cond || FRS->getRangeInit() == Cond;
1436 if (
const auto *FS = dyn_cast<ForStmt>(FL))
1437 return FS->getInc() == S || FS->getInit() == S;
1438 if (
const auto *FRS = dyn_cast<CXXForRangeStmt>(FL))
1439 return FRS->getInc() == S || FRS->getRangeStmt() == S ||
1440 FRS->getLoopVarStmt() || FRS->getRangeInit() == S;
1453 PathPieces::iterator Prev = pieces.end();
1454 for (PathPieces::iterator I = pieces.begin(),
E = Prev; I !=
E;
1456 auto *Piece = dyn_cast<PathDiagnosticControlFlowPiece>(I->get());
1465 const Stmt *InnerStmt =
nullptr;
1466 while (NextSrcContext.
isValid() && NextSrcContext.
asStmt() != InnerStmt) {
1467 SrcContexts.push_back(NextSrcContext);
1468 InnerStmt = NextSrcContext.
asStmt();
1477 const Stmt *Dst = Piece->getEndLocation().getStmtOrNull();
1487 if (llvm::is_contained(SrcContexts, DstContext))
1491 Piece->setStartLocation(DstContext);
1496 auto *PrevPiece = dyn_cast<PathDiagnosticControlFlowPiece>(Prev->get());
1499 if (
const Stmt *PrevSrc =
1500 PrevPiece->getStartLocation().getStmtOrNull()) {
1502 if (PrevSrcParent ==
1504 PrevPiece->setEndLocation(DstContext);
1515 std::make_shared<PathDiagnosticControlFlowPiece>(SrcLoc, DstContext);
1517 I = pieces.insert(I, std::move(
P));
1533 for (PathPieces::iterator I = pieces.begin(),
E = pieces.end(); I !=
E; ++I) {
1534 const auto *PieceI = dyn_cast<PathDiagnosticControlFlowPiece>(I->get());
1539 const Stmt *s1Start = PieceI->getStartLocation().getStmtOrNull();
1540 const Stmt *s1End = PieceI->getEndLocation().getStmtOrNull();
1542 if (!s1Start || !s1End)
1545 PathPieces::iterator NextI = I; ++NextI;
1555 const auto *EV = dyn_cast<PathDiagnosticEventPiece>(NextI->get());
1557 StringRef S = EV->getString();
1566 PieceNextI = dyn_cast<PathDiagnosticControlFlowPiece>(NextI->get());
1576 if (!s2Start || !s2End || s1End != s2Start)
1592 I = pieces.erase(I);
1605 SM.getExpansionRange(
Range.getEnd()).getEnd());
1608 if (FID !=
SM.getFileID(ExpansionRange.
getEnd()))
1609 return std::nullopt;
1611 std::optional<MemoryBufferRef> Buffer =
SM.getBufferOrNone(FID);
1613 return std::nullopt;
1615 unsigned BeginOffset =
SM.getFileOffset(ExpansionRange.
getBegin());
1616 unsigned EndOffset =
SM.getFileOffset(ExpansionRange.
getEnd());
1617 StringRef Snippet = Buffer->getBuffer().slice(BeginOffset, EndOffset);
1623 if (Snippet.find_first_of(
"\r\n") != StringRef::npos)
1624 return std::nullopt;
1627 return Snippet.size();
1653 for (PathPieces::iterator I =
Path.begin(),
E =
Path.end(); I !=
E; ) {
1655 const auto *PieceI = dyn_cast<PathDiagnosticControlFlowPiece>(I->get());
1662 const Stmt *s1Start = PieceI->getStartLocation().getStmtOrNull();
1663 const Stmt *s1End = PieceI->getEndLocation().getStmtOrNull();
1665 PathPieces::iterator NextI = I; ++NextI;
1669 const auto *PieceNextI =
1670 dyn_cast<PathDiagnosticControlFlowPiece>(NextI->get());
1673 if (isa<PathDiagnosticEventPiece>(NextI->get())) {
1677 PieceNextI = dyn_cast<PathDiagnosticControlFlowPiece>(NextI->get());
1686 const Stmt *s2Start = PieceNextI->getStartLocation().getStmtOrNull();
1687 const Stmt *s2End = PieceNextI->getEndLocation().getStmtOrNull();
1689 if (s1Start && s2Start && s1Start == s2End && s2Start == s1End) {
1690 const size_t MAX_SHORT_LINE_LENGTH = 80;
1692 if (s1Length && *s1Length <= MAX_SHORT_LINE_LENGTH) {
1694 if (s2Length && *s2Length <= MAX_SHORT_LINE_LENGTH) {
1696 I =
Path.erase(NextI);
1719 bool erased =
false;
1721 for (PathPieces::iterator I = path.begin(),
E = path.end(); I !=
E;
1725 const auto *PieceI = dyn_cast<PathDiagnosticControlFlowPiece>(I->get());
1730 const Stmt *start = PieceI->getStartLocation().getStmtOrNull();
1731 const Stmt *end = PieceI->getEndLocation().getStmtOrNull();
1746 if (!
SM.isWrittenInSameFile(FirstLoc, SecondLoc))
1748 if (
SM.isBeforeInTranslationUnit(SecondLoc, FirstLoc))
1749 std::swap(SecondLoc, FirstLoc);
1758 const size_t MAX_PUNY_EDGE_LENGTH = 2;
1759 if (*ByteWidth <= MAX_PUNY_EDGE_LENGTH) {
1771 for (PathPieces::iterator I = path.begin(),
E = path.end(); I !=
E; ++I) {
1772 const auto *PieceI = dyn_cast<PathDiagnosticEventPiece>(I->get());
1777 PathPieces::iterator NextI = I; ++NextI;
1781 const auto *PieceNextI = dyn_cast<PathDiagnosticEventPiece>(NextI->get());
1787 if (PieceI->getString() == PieceNextI->getString()) {
1795 bool hasChanges =
false;
1801 for (PathPieces::iterator I = path.begin(),
E = path.end(); I !=
E; ) {
1803 if (
auto *CallI = dyn_cast<PathDiagnosticCallPiece>(I->get())) {
1806 if (!OCS.count(CallI)) {
1816 auto *PieceI = dyn_cast<PathDiagnosticControlFlowPiece>(I->get());
1823 const Stmt *s1Start = PieceI->getStartLocation().getStmtOrNull();
1824 const Stmt *s1End = PieceI->getEndLocation().getStmtOrNull();
1828 PathPieces::iterator NextI = I; ++NextI;
1832 const auto *PieceNextI = dyn_cast<PathDiagnosticControlFlowPiece>(NextI->get());
1839 const Stmt *s2Start = PieceNextI->getStartLocation().getStmtOrNull();
1840 const Stmt *s2End = PieceNextI->getEndLocation().getStmtOrNull();
1858 if (level1 && level1 == level2 && level1 == level3 && level1 == level4) {
1859 PieceI->setEndLocation(PieceNextI->getEndLocation());
1872 if (s1End && s1End == s2Start && level2) {
1873 bool removeEdge =
false;
1899 else if (s1Start && s2End &&
1912 else if (s1Start && s2End &&
1914 SourceRange EdgeRange(PieceI->getEndLocation().asLocation(),
1915 PieceI->getStartLocation().asLocation());
1922 PieceI->setEndLocation(PieceNextI->getEndLocation());
1936 if (s1End == s2Start) {
1937 const auto *FS = dyn_cast_or_null<ObjCForCollectionStmt>(level3);
1938 if (FS && FS->getCollection()->IgnoreParens() == s2Start &&
1939 s2End == FS->getElement()) {
1940 PieceI->setEndLocation(PieceNextI->getEndLocation());
1977 const auto *FirstEdge =
1978 dyn_cast<PathDiagnosticControlFlowPiece>(
Path.front().get());
1982 const Decl *
D =
C.getLocationContextFor(&
Path)->getDecl();
1985 if (FirstEdge->getStartLocation() != EntryLoc)
1997 for (
const auto &
P : path) {
2000 unsigned LineNo =
Loc.getLineNumber();
2002 ExecutedLines[FID].insert(LineNo);
2006PathDiagnosticConstruct::PathDiagnosticConstruct(
2009 : Consumer(PDC), CurrentNode(ErrorNode),
2010 SM(CurrentNode->getCodeDecl().getASTContext().getSourceManager()),
2012 AnalysisEntryPoint)) {
2016PathDiagnosticBuilder::PathDiagnosticBuilder(
2019 std::unique_ptr<VisitorsDiagnosticsTy> VisitorsDiagnostics)
2021 ErrorNode(ErrorNode),
2022 VisitorsDiagnostics(
std::move(VisitorsDiagnostics)) {}
2024std::unique_ptr<PathDiagnostic>
2026 const Decl *EntryPoint = getBugReporter().getAnalysisEntryPoint();
2027 PathDiagnosticConstruct Construct(PDC, ErrorNode, R, EntryPoint);
2036 auto EndNotes = VisitorsDiagnostics->find(ErrorNode);
2038 if (EndNotes != VisitorsDiagnostics->end()) {
2039 assert(!EndNotes->second.empty());
2040 LastPiece = EndNotes->second[0];
2045 Construct.PD->setEndOfPath(LastPiece);
2050 while (Construct.ascendToPrevNode()) {
2051 generatePathDiagnosticsForNode(Construct, PrevLoc);
2053 auto VisitorNotes = VisitorsDiagnostics->find(Construct.getCurrentNode());
2054 if (VisitorNotes == VisitorsDiagnostics->end())
2059 std::set<llvm::FoldingSetNodeID> DeduplicationSet;
2063 llvm::FoldingSetNodeID
ID;
2065 if (!DeduplicationSet.insert(ID).second)
2070 updateStackPiecesWithMessage(
Note, Construct.CallStack);
2071 Construct.getActivePath().push_front(
Note);
2079 Construct.getLocationContextForActivePath()->
getStackFrame();
2087 if (!Construct.PD->path.empty()) {
2089 bool stillHasNotes =
2091 assert(stillHasNotes);
2092 (void)stillHasNotes;
2096 if (!Opts.ShouldAddPopUpNotes)
2109 while (
optimizeEdges(Construct, Construct.getMutablePieces(), OCS)) {
2124 if (Opts.ShouldDisplayMacroExpansions)
2127 return std::move(Construct.PD);
2134void BugType::anchor() {}
2140LLVM_ATTRIBUTE_USED
static bool
2142 for (
const std::pair<StringRef, StringRef> &Pair : Registry.
Dependencies) {
2143 if (Pair.second == CheckerName)
2150 StringRef CheckerName) {
2152 if (
Checker.FullName == CheckerName)
2156 "Checker name not found in CheckerRegistry -- did you retrieve it "
2157 "correctly from CheckerManager::getCurrentCheckerName?");
2161 const BugType &bt, StringRef shortDesc, StringRef desc,
2163 const Decl *DeclToUnique)
2164 :
BugReport(
Kind::PathSensitive, bt, shortDesc, desc), ErrorNode(errorNode),
2165 ErrorNodeRange(getStmt() ? getStmt()->getSourceRange() :
SourceRange()),
2166 UniqueingLocation(LocationToUnique), UniqueingDecl(DeclToUnique) {
2167 assert(
ErrorNode &&
"The error node must be non-null!");
2169 ->getAnalysisManager()
2170 .getCheckerManager()
2171 ->getCheckerRegistryData(),
2173 "Some checkers depend on this one! We don't allow dependency "
2174 "checkers to emit warnings, because checkers should depend on "
2175 "*modeling*, not *diagnostics*.");
2179 ->getAnalysisManager()
2180 .getCheckerManager()
2181 ->getCheckerRegistryData(),
2183 "Hidden checkers musn't emit diagnostics as they are by definition "
2184 "non-user facing!");
2188 std::unique_ptr<BugReporterVisitor> visitor) {
2192 llvm::FoldingSetNodeID ID;
2193 visitor->Profile(ID);
2195 void *InsertPos =
nullptr;
2200 Callbacks.push_back(std::move(visitor));
2217 hash.AddInteger(
static_cast<int>(
getKind()));
2218 hash.AddPointer(&
BT);
2224 if (!range.isValid())
2226 hash.Add(range.getBegin());
2227 hash.Add(range.getEnd());
2232 hash.AddInteger(
static_cast<int>(
getKind()));
2233 hash.AddPointer(&
BT);
2247 if (!range.isValid())
2249 hash.Add(range.getBegin());
2250 hash.Add(range.getEnd());
2256 llvm::DenseMap<T, bugreporter::TrackingKind> &InterestingnessMap,
T Val,
2258 auto Result = InterestingnessMap.insert({Val, TKind});
2278 "BugReport::markInteresting currently can only handle 2 different "
2279 "tracking kinds! Please define what tracking kind should this entitiy"
2280 "have, if it was already marked as interesting with a different kind!");
2292 if (
const auto *meta = dyn_cast<SymbolMetadata>(sym))
2304 if (
const auto *meta = dyn_cast<SymbolMetadata>(sym))
2316 if (
const auto *SR = dyn_cast<SymbolicRegion>(R))
2327 if (
const auto *SR = dyn_cast<SymbolicRegion>(R))
2343std::optional<bugreporter::TrackingKind>
2362 "BugReport::getInterestingnessKind currently can only handle 2 different "
2363 "tracking kinds! Please define what tracking kind should we return here "
2364 "when the kind of getAsRegion() and getAsSymbol() is different!");
2365 return std::nullopt;
2368std::optional<bugreporter::TrackingKind>
2371 return std::nullopt;
2376 return std::nullopt;
2377 return It->getSecond();
2380std::optional<bugreporter::TrackingKind>
2383 return std::nullopt;
2388 return It->getSecond();
2390 if (
const auto *SR = dyn_cast<SymbolicRegion>(R))
2392 return std::nullopt;
2418 const Stmt *S =
nullptr;
2422 if (BE->getBlock() == &Exit)
2465 assert(
ErrorNode &&
"Cannot create a location with a null node.");
2490 if (
const auto *AS = dyn_cast<AttributedStmt>(S))
2491 S = AS->getSubStmt();
2494 if (
const auto *ME = dyn_cast<MemberExpr>(S))
2498 if (
const auto *B = dyn_cast<BinaryOperator>(S))
2504 if (S->getBeginLoc().isValid())
2528 :
D(
D), UserSuppressions(
D.getASTContext()) {}
2532 assert(StrBugTypes.empty() &&
2533 "Destroying BugReporter before diagnostics are emitted!");
2536 for (
const auto I : EQClassesVector)
2543 for (
const auto EQ : EQClassesVector)
2550 StrBugTypes.clear();
2563 std::unique_ptr<ExplodedGraph> BugPath;
2570class BugPathGetter {
2571 std::unique_ptr<ExplodedGraph> TrimmedGraph;
2573 using PriorityMapTy = llvm::DenseMap<const ExplodedNode *, unsigned>;
2576 PriorityMapTy PriorityMap;
2580 using ReportNewNodePair =
2581 std::pair<PathSensitiveBugReport *, const ExplodedNode *>;
2584 BugPathInfo CurrentBugPath;
2587 template <
bool Descending>
2588 class PriorityCompare {
2589 const PriorityMapTy &PriorityMap;
2592 PriorityCompare(
const PriorityMapTy &M) : PriorityMap(M) {}
2595 PriorityMapTy::const_iterator LI = PriorityMap.find(LHS);
2596 PriorityMapTy::const_iterator RI = PriorityMap.find(RHS);
2597 PriorityMapTy::const_iterator
E = PriorityMap.end();
2604 return Descending ? LI->second > RI->second
2605 : LI->second < RI->second;
2608 bool operator()(
const ReportNewNodePair &LHS,
2609 const ReportNewNodePair &RHS)
const {
2610 return (*
this)(LHS.second, RHS.second);
2618 BugPathInfo *getNextBugPath();
2623BugPathGetter::BugPathGetter(
const ExplodedGraph *OriginalGraph,
2626 for (
const auto I : bugReports) {
2627 assert(I->isValid() &&
2628 "We only allow BugReporterVisitors and BugReporter itself to "
2629 "invalidate reports!");
2630 Nodes.emplace_back(I->getErrorNode());
2636 TrimmedGraph = OriginalGraph->
trim(
Nodes, &ForwardMap);
2646 "Failed to construct a trimmed graph that contains this error "
2648 ReportNodes.emplace_back(
Report, NewNode);
2649 RemainingNodes.insert(NewNode);
2652 assert(!RemainingNodes.empty() &&
"No error node found in the trimmed graph");
2655 std::queue<const ExplodedNode *> WS;
2657 WS.push(TrimmedGraph->getRoot());
2660 while (!WS.empty()) {
2664 PriorityMapTy::iterator PriorityEntry;
2666 std::tie(PriorityEntry, IsNew) = PriorityMap.insert({
Node,
Priority});
2670 assert(PriorityEntry->second <= Priority);
2674 if (RemainingNodes.erase(
Node))
2675 if (RemainingNodes.empty())
2683 llvm::sort(ReportNodes, PriorityCompare<true>(PriorityMap));
2686BugPathInfo *BugPathGetter::getNextBugPath() {
2687 if (ReportNodes.empty())
2691 std::tie(CurrentBugPath.Report, OrigN) = ReportNodes.pop_back_val();
2692 assert(PriorityMap.contains(OrigN) &&
"error node not accessible from root");
2696 auto GNew = std::make_unique<ExplodedGraph>();
2712 CurrentBugPath.ErrorNode = NewN;
2718 assert(OrigN == TrimmedGraph->getRoot() &&
2719 "There should be only one root!");
2720 GNew->designateAsRoot(NewN);
2727 PriorityCompare<false>(PriorityMap));
2730 CurrentBugPath.BugPath = std::move(GNew);
2732 return &CurrentBugPath;
2739 using MacroStackTy = std::vector<
2740 std::pair<std::shared_ptr<PathDiagnosticMacroPiece>,
SourceLocation>>;
2742 using PiecesTy = std::vector<PathDiagnosticPieceRef>;
2744 MacroStackTy MacroStack;
2747 for (PathPieces::const_iterator I = path.begin(),
E = path.end();
2749 const auto &piece = *I;
2752 if (
auto *call = dyn_cast<PathDiagnosticCallPiece>(&*piece)) {
2762 SM.getExpansionLoc(
Loc) :
2765 if (
Loc.isFileID()) {
2767 Pieces.push_back(piece);
2771 assert(
Loc.isMacroID());
2774 if (!MacroStack.empty() && InstantiationLoc == MacroStack.back().second) {
2775 MacroStack.back().first->subPieces.push_back(piece);
2781 std::shared_ptr<PathDiagnosticMacroPiece> MacroGroup;
2784 SM.getExpansionLoc(
Loc) :
2788 while (!MacroStack.empty()) {
2789 if (InstantiationLoc == MacroStack.back().second) {
2790 MacroGroup = MacroStack.back().first;
2794 if (ParentInstantiationLoc == MacroStack.back().second) {
2795 MacroGroup = MacroStack.back().first;
2799 MacroStack.pop_back();
2802 if (!MacroGroup || ParentInstantiationLoc == MacroStack.back().second) {
2804 auto NewGroup = std::make_shared<PathDiagnosticMacroPiece>(
2808 MacroGroup->subPieces.push_back(NewGroup);
2810 assert(InstantiationLoc.
isFileID());
2811 Pieces.push_back(NewGroup);
2814 MacroGroup = NewGroup;
2815 MacroStack.push_back(std::make_pair(MacroGroup, InstantiationLoc));
2819 MacroGroup->subPieces.push_back(piece);
2825 llvm::append_range(path, Pieces);
2831static std::unique_ptr<VisitorsDiagnosticsTy>
2835 std::unique_ptr<VisitorsDiagnosticsTy> Notes =
2836 std::make_unique<VisitorsDiagnosticsTy>();
2849 for (std::unique_ptr<BugReporterVisitor> &Visitor : R->
visitors())
2850 visitors.push_back(std::move(Visitor));
2857 for (
auto &
V : visitors) {
2858 V->finalizeVisitor(BRC, ErrorNode, *R);
2860 if (
auto Piece =
V->getEndPath(BRC, ErrorNode, *R)) {
2861 assert(!LastPiece &&
2862 "There can only be one final piece in a diagnostic.");
2864 "The final piece must contain a message!");
2865 LastPiece = std::move(Piece);
2866 (*Notes)[ErrorNode].push_back(LastPiece);
2872 for (
auto &
V : visitors) {
2873 auto P =
V->VisitNode(NextNode, BRC, *R);
2875 (*Notes)[NextNode].push_back(std::move(
P));
2887std::optional<PathDiagnosticBuilder> PathDiagnosticBuilder::findValidReport(
2892 BugPathGetter BugGraph(&Reporter.
getGraph(), bugReports);
2894 while (BugPathInfo *BugPath = BugGraph.getNextBugPath()) {
2897 assert(R &&
"No original report found for sliced graph.");
2898 assert(R->
isValid() &&
"Report selected by trimmed graph marked invalid.");
2913 std::unique_ptr<VisitorsDiagnosticsTy> visitorNotes =
2918 llvm::TimeTraceScope TCS{
"Crosscheck with Z3"};
2929 switch (Z3Oracle.interpretQueryResult(CrosscheckResult)) {
2931 ++NumTimesReportRefuted;
2932 R->
markInvalid(
"Infeasible constraints",
nullptr);
2935 ++NumTimesReportEQClassAborted;
2938 ++NumTimesReportPassesZ3;
2944 return PathDiagnosticBuilder(std::move(BRC), std::move(BugPath->BugPath),
2945 BugPath->Report, BugPath->ErrorNode,
2946 std::move(visitorNotes));
2950 ++NumTimesReportEQClassWasExhausted;
2954std::unique_ptr<DiagnosticForConsumerMapTy>
2956 ArrayRef<std::unique_ptr<PathDiagnosticConsumer>> consumers,
2958 assert(!bugReports.empty());
2960 auto Out = std::make_unique<DiagnosticForConsumerMapTy>();
2962 std::optional<PathDiagnosticBuilder> PDB =
2963 PathDiagnosticBuilder::findValidReport(bugReports, *
this);
2966 for (
const auto &PC : consumers) {
2967 if (std::unique_ptr<PathDiagnostic> PD = PDB->generate(PC.get())) {
2968 (*Out)[PC.get()] = std::move(PD);
2977 bool ValidSourceLoc = R->getLocation().isValid();
2978 assert(ValidSourceLoc);
2981 if (!ValidSourceLoc)
2989 llvm::FoldingSetNodeID ID;
2998 EQClasses.InsertNode(EQ, InsertPos);
2999 EQClassesVector.push_back(EQ);
3001 EQ->AddReport(std::move(R));
3005 if (
auto PR = dyn_cast<PathSensitiveBugReport>(R.get()))
3009 assert((
E->isSink() ||
E->getLocation().getTag()) &&
3010 "Error node must either be a sink or have a tag");
3013 E->getLocationContext()->getAnalysisDeclContext();
3032struct FRIEC_WLItem {
3037 : N(n), I(N->succ_begin()),
E(N->succ_end()) {}
3042BugReport *PathSensitiveBugReporter::findReportInEquivalenceClass(
3047 assert(
EQ.getReports().size() > 0);
3048 const BugType& BT =
EQ.getReports()[0]->getBugType();
3051 for (
auto &J :
EQ.getReports()) {
3052 if (
auto *PR = dyn_cast<PathSensitiveBugReport>(J.get())) {
3054 bugReports.push_back(PR);
3068 for (
const auto &I:
EQ.getReports()) {
3069 auto *R = dyn_cast<PathSensitiveBugReport>(I.get());
3074 if (errorNode->
isSink()) {
3076 "BugType::isSuppressSink() should not be 'true' for sink end nodes");
3080 bugReports.push_back(R);
3091 if (ErrorB->isInevitablySinking())
3096 using WLItem = FRIEC_WLItem;
3099 llvm::DenseMap<const ExplodedNode *, unsigned>
Visited;
3102 WL.push_back(errorNode);
3105 while (!WL.empty()) {
3106 WLItem &WI = WL.back();
3107 assert(!WI.N->succ_empty());
3109 for (; WI.I != WI.E; ++WI.I) {
3115 bugReports.push_back(R);
3126 unsigned &mark =
Visited[Succ];
3136 if (!WL.empty() && &WL.back() == &WI)
3143 return exampleReport;
3147 llvm::TimeTraceScope TCS{timeTraceName(EQ), [&]() {
3151 BugReport *report = findReportInEquivalenceClass(EQ, bugReports);
3156 for (
const std::string &CheckerOrPackage :
3163 std::unique_ptr<DiagnosticForConsumerMapTy> Diagnostics =
3166 for (
auto &
P : *Diagnostics) {
3168 std::unique_ptr<PathDiagnostic> &PD =
P.second;
3172 if (PD->path.empty()) {
3174 auto piece = std::make_unique<PathDiagnosticEventPiece>(
3177 piece->addRange(
Range);
3178 PD->setEndOfPath(std::move(piece));
3185 for (
const auto &I : llvm::reverse(report->
getNotes())) {
3187 auto ConvertedPiece = std::make_shared<PathDiagnosticEventPiece>(
3190 ConvertedPiece->addRange(R);
3192 Pieces.push_front(std::move(ConvertedPiece));
3195 for (
const auto &I : llvm::reverse(report->
getNotes()))
3196 Pieces.push_front(I);
3199 for (
const auto &I : report->
getFixits())
3200 Pieces.back()->addFixit(I);
3208 Pieces.push_front(std::make_shared<PathDiagnosticEventPiece>(
3210 "[debug] analyzing from " +
3224 if (
const auto FD = dyn_cast<FunctionDecl>(Signature)) {
3225 SignatureSourceRange = FD->getSourceRange();
3226 }
else if (
const auto OD = dyn_cast<ObjCMethodDecl>(Signature)) {
3227 SignatureSourceRange = OD->getSourceRange();
3233 : SignatureSourceRange.
getEnd();
3234 if (!Start.
isValid() || !End.isValid())
3236 unsigned StartLine =
SM.getExpansionLineNumber(Start);
3237 unsigned EndLine =
SM.getExpansionLineNumber(End);
3239 FileID FID =
SM.getFileID(
SM.getExpansionLoc(Start));
3240 for (
unsigned Line = StartLine;
Line <= EndLine;
Line++)
3241 ExecutedLines[FID].insert(
Line);
3251 FileID FID =
SM.getFileID(ExpansionLoc);
3252 unsigned LineNo =
SM.getExpansionLineNumber(ExpansionLoc);
3253 ExecutedLines[FID].insert(LineNo);
3258static std::unique_ptr<FilesToLineNumsMap>
3260 auto ExecutedLines = std::make_unique<FilesToLineNumsMap>();
3269 const Decl*
D = CE->getCalleeContext()->getDecl();
3280 if (
const auto *RS = dyn_cast_or_null<ReturnStmt>(
P)) {
3285 if (isa_and_nonnull<SwitchCase, LabelStmt>(
P))
3291 return ExecutedLines;
3294std::unique_ptr<DiagnosticForConsumerMapTy>
3297 ArrayRef<std::unique_ptr<PathDiagnosticConsumer>> consumers,
3299 auto *basicReport = cast<BasicBugReport>(exampleReport);
3300 auto Out = std::make_unique<DiagnosticForConsumerMapTy>();
3301 for (
const auto &Consumer : consumers)
3302 (*Out)[Consumer.get()] =
3317 "The call piece should not be in a header file.");
3329 if (
auto *CPInner = dyn_cast<PathDiagnosticCallPiece>(
Path.back().get()))
3337 if (PD.
path.empty())
3346 if (
auto *CP = dyn_cast<PathDiagnosticCallPiece>(LastP)) {
3353 const auto *ND = dyn_cast<NamedDecl>(CP->
getCallee());
3356 llvm::raw_svector_ostream os(buf);
3357 os <<
" (within a call to '" << ND->getDeclName() <<
"')";
3370std::unique_ptr<DiagnosticForConsumerMapTy>
3371PathSensitiveBugReporter::generateDiagnosticForConsumerMap(
3373 ArrayRef<std::unique_ptr<PathDiagnosticConsumer>> consumers,
3375 if (isa<BasicBugReport>(exampleReport))
3377 consumers, bugReports);
3383 assert(!bugReports.empty());
3384 MaxBugClassSize.updateMax(bugReports.size());
3391 consumers, convertedArrayOfReports);
3396 MaxValidBugClassSize.updateMax(bugReports.size());
3401 for (
auto const &
P : *Out)
3402 if (Opts.ShouldReportIssuesInMainSourceFile && !Opts.
AnalyzeAll)
3410 StringRef Name, StringRef
Category,
3420 StringRef name, StringRef category,
3425 BugType *BT = getBugTypeForName(CheckName, name, category);
3426 auto R = std::make_unique<BasicBugReport>(*BT, str,
Loc);
3427 R->setDeclWithIssue(DeclWithIssue);
3428 for (
const auto &SR : Ranges)
3430 for (
const auto &FH : Fixits)
3436 StringRef name, StringRef category) {
3438 llvm::raw_svector_ostream(fullDesc)
3439 << CheckName <<
":" << name <<
":" << category;
3440 std::unique_ptr<BugType> &BT = StrBugTypes[fullDesc];
3442 BT = std::make_unique<BugType>(CheckName, name, category);
BoundNodesTreeBuilder Nodes
This file defines AnalysisDeclContext, a class that manages the analysis context data for context sen...
static void dropFunctionEntryEdge(const PathDiagnosticConstruct &C, PathPieces &Path)
Drop the very first edge in a path, which should be a function entry edge.
constexpr llvm::StringLiteral StrLoopRangeEmpty
static PathDiagnosticLocation getEnclosingStmtLocation(const Stmt *S, const LocationContext *LC, bool allowNestedContexts=false)
static std::unique_ptr< FilesToLineNumsMap > findExecutedLines(const SourceManager &SM, const ExplodedNode *N)
static bool isConditionForTerminator(const Stmt *S, const Stmt *Cond)
static void updateExecutedLinesWithDiagnosticPieces(PathDiagnostic &PD)
Populate executes lines with lines containing at least one diagnostics.
static void removeRedundantMsgs(PathPieces &path)
An optimization pass over PathPieces that removes redundant diagnostics generated by both ConditionBR...
constexpr llvm::StringLiteral StrLoopCollectionEmpty
static void adjustCallLocations(PathPieces &Pieces, PathDiagnosticLocation *LastCallLocation=nullptr)
Recursively scan through a path and make sure that all call pieces have valid locations.
static void removeIdenticalEvents(PathPieces &path)
static const Stmt * getTerminatorCondition(const CFGBlock *B)
A customized wrapper for CFGBlock::getTerminatorCondition() which returns the element for ObjCForColl...
static std::unique_ptr< VisitorsDiagnosticsTy > generateVisitorsDiagnostics(PathSensitiveBugReport *R, const ExplodedNode *ErrorNode, BugReporterContext &BRC)
Generate notes from all visitors.
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.
static const Stmt * findReasonableStmtCloseToFunctionExit(const ExplodedNode *N)
static void populateExecutedLinesWithStmt(const Stmt *S, const SourceManager &SM, FilesToLineNumsMap &ExecutedLines)
static bool isJumpToFalseBranch(const BlockEdge *BE)
static std::optional< size_t > getLengthOnSingleLine(const SourceManager &SM, SourceRange Range)
Returns the number of bytes in the given (character-based) SourceRange.
static bool isLoop(const Stmt *Term)
static bool isContainedByStmt(const ParentMap &PM, const Stmt *S, const Stmt *SubS)
constexpr llvm::StringLiteral StrEnteringLoop
static void addEdgeToPath(PathPieces &path, PathDiagnosticLocation &PrevLoc, PathDiagnosticLocation NewLoc)
Adds a sanitized control-flow diagnostic edge to a path.
static bool isIncrementOrInitInForLoop(const Stmt *S, const Stmt *FL)
static std::unique_ptr< PathDiagnostic > generateEmptyDiagnosticForReport(const PathSensitiveBugReport *R, const SourceManager &SM, const Decl *AnalysisEntryPoint)
static void removeContextCycles(PathPieces &Path, const SourceManager &SM)
Eliminate two-edge cycles created by addContextEdges().
static bool lexicalContains(const ParentMap &PM, const Stmt *X, const Stmt *Y)
Return true if X is contained by Y.
static std::unique_ptr< PathDiagnostic > generateDiagnosticForBasicReport(const BasicBugReport *R, const Decl *AnalysisEntryPoint)
static void removePopUpNotes(PathPieces &Path)
Same logic as above to remove extra pieces.
static void insertToInterestingnessMap(llvm::DenseMap< T, bugreporter::TrackingKind > &InterestingnessMap, T Val, bugreporter::TrackingKind TKind)
constexpr llvm::StringLiteral StrLoopBodyZero
static const Stmt * getEnclosingParent(const Stmt *S, const ParentMap &PM)
static void removePunyEdges(PathPieces &path, const SourceManager &SM, const ParentMap &PM)
static const Stmt * getStmtParent(const Stmt *S, const ParentMap &PM)
static bool exitingDestructor(const ExplodedNode *N)
static void CompactMacroExpandedPieces(PathPieces &path, const SourceManager &SM)
CompactMacroExpandedPieces - This function postprocesses a PathDiagnostic object and collapses PathDi...
static void simplifySimpleBranches(PathPieces &pieces)
Move edges from a branch condition to a branch target when the condition is simple.
static void populateExecutedLinesWithFunctionSignature(const Decl *Signature, const SourceManager &SM, FilesToLineNumsMap &ExecutedLines)
Insert all lines participating in the function signature Signature into ExecutedLines.
static void resetDiagnosticLocationToMainFile(PathDiagnostic &PD)
static bool optimizeEdges(const PathDiagnosticConstruct &C, PathPieces &path, OptimizedCallsSet &OCS)
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...
static PathDiagnosticCallPiece * getFirstStackedCallToHeaderFile(PathDiagnosticCallPiece *CP, const SourceManager &SMgr)
llvm::DenseSet< const PathDiagnosticCallPiece * > OptimizedCallsSet
static void addContextEdges(PathPieces &pieces, const LocationContext *LC)
Adds synthetic edges from top-level statements to their subexpressions.
static LLVM_ATTRIBUTE_USED bool isDependency(const CheckerRegistryData &Registry, StringRef CheckerName)
static PathDiagnosticEventPiece * eventsDescribeSameCondition(PathDiagnosticEventPiece *X, PathDiagnosticEventPiece *Y)
static bool isInLoopBody(const ParentMap &PM, const Stmt *S, const Stmt *Term)
static void removeEdgesToDefaultInitializers(PathPieces &Pieces)
Remove edges in and out of C++ default initializer expressions.
static const Stmt * getStmtBeforeCond(const ParentMap &PM, const Stmt *Term, const ExplodedNode *N)
static void removePiecesWithInvalidLocations(PathPieces &Pieces)
Remove all pieces with invalid locations as these cannot be serialized.
static LLVM_ATTRIBUTE_USED bool isHidden(const CheckerRegistryData &Registry, StringRef CheckerName)
static llvm::TimeTraceMetadata timeTraceMetadata(const ExplodedNode *Pred, const ProgramPoint &Loc)
#define STAT_COUNTER(VARNAME, DESC)
#define STAT_MAX(VARNAME, DESC)
Defines the clang::Expr interface and subclasses for C++ expressions.
llvm::DenseSet< const void * > Visited
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
Defines the clang::SourceLocation class and associated facilities.
Defines the SourceManager interface.
Defines the Objective-C statement AST node classes.
SourceManager & getSourceManager()
AnalysisDeclContext contains the context data for the function, method or block under analysis.
static std::string getFunctionName(const Decl *D)
bool isBodyAutosynthesized() const
bool isBodyAutosynthesizedFromModelFile() const
Stores options for the analyzer from the command line.
const CFGBlock * getSrc() const
const CFGBlock * getDst() const
Represents a single basic block in a source-level CFG.
succ_iterator succ_begin()
Stmt * getTerminatorStmt()
const Stmt * getLoopTarget() const
Stmt * getTerminatorCondition(bool StripParens=true)
unsigned succ_size() const
CXXForRangeStmt - This represents C++0x [stmt.ranged]'s ranged for statement, represented as 'for (ra...
Represents a point when we begin processing an inlined call.
Represents a point when we finish the call exit sequence (for inlined call).
const StackFrameContext * getCalleeContext() const
Decl - This represents one declaration (or definition), e.g.
ASTContext & getASTContext() const LLVM_READONLY
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
virtual bool hasBody() const
Returns true if this Decl represents a declaration for a body of code, such as a function or method d...
SourceLocation getLocation() const
This represents one expression.
llvm::APSInt EvaluateKnownConstInt(const ASTContext &Ctx, SmallVectorImpl< PartialDiagnosticAt > *Diag=nullptr) const
EvaluateKnownConstInt - Call EvaluateAsRValue and return the folded integer.
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
ForStmt - This represents a 'for (init;cond;inc)' stmt.
A SourceLocation and its associated SourceManager.
IfStmt - This represents an if/then/else.
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
const Decl * getDecl() const
const ParentMap & getParentMap() const
const StackFrameContext * getStackFrame() const
Represents Objective-C's collection statement.
bool isConsumedExpr(Expr *E) const
Stmt * getParent(Stmt *) const
Stmt * getParentIgnoreParens(Stmt *) const
Represents a point after we ran remove dead bindings AFTER processing the given statement.
Represents a program point just before an implicit call event.
std::optional< T > getAs() const
Convert to the specified ProgramPoint type, returning std::nullopt if this ProgramPoint is not of the...
const LocationContext * getLocationContext() const
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
This class handles loading and caching of source files into memory.
A trivial tuple used to represent a source range.
SourceLocation getEnd() const
SourceLocation getBegin() const
It represents a stack frame of the call stack (based on CallEvent).
const Stmt * getCallSite() const
Stmt - This represents one statement.
StmtClass getStmtClass() const
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
SourceLocation getBeginLoc() const LLVM_READONLY
WhileStmt - This represents a 'while' stmt.
static bool isInCodeFile(SourceLocation SL, const SourceManager &SM)
const Decl * getDeclWithIssue() const override
The smallest declaration that contains the bug location.
PathDiagnosticLocation getUniqueingLocation() const override
Get the location on which the report should be uniqued.
void Profile(llvm::FoldingSetNodeID &hash) const override
Reports are uniqued to ensure that we do not emit multiple diagnostics for each bug.
const Decl * getUniqueingDecl() const override
Get the declaration that corresponds to (usually contains) the uniqueing location.
This class provides an interface through which checkers can create individual bug reports.
llvm::ArrayRef< FixItHint > getFixits() const
void addRange(SourceRange R)
Add a range to a bug report.
SmallVector< SourceRange, 4 > Ranges
virtual PathDiagnosticLocation getLocation() const =0
The primary location of the bug report that points at the undesirable behavior in the code.
ArrayRef< std::shared_ptr< PathDiagnosticNotePiece > > getNotes()
void addFixItHint(const FixItHint &F)
Add a fix-it hint to the bug report.
StringRef getDescription() const
A verbose warning message that is appropriate for displaying next to the source code that introduces ...
const BugType & getBugType() const
StringRef getShortDescription(bool UseFallback=true) const
A short general warning message that is appropriate for displaying in the list of all reported bugs.
virtual ArrayRef< SourceRange > getRanges() const
Get the SourceRanges associated with the report.
static PathDiagnosticPieceRef getDefaultEndPath(const BugReporterContext &BRC, const ExplodedNode *N, const PathSensitiveBugReport &BR)
Generates the default final diagnostic piece.
virtual ~BugReporterVisitor()
void FlushReports()
Generate and flush diagnostics for all bug reports.
BugReporter(BugReporterData &d)
const SourceManager & getSourceManager()
const Decl * getAnalysisEntryPoint() const
Get the top-level entry point for the issue to be reported.
ArrayRef< std::unique_ptr< PathDiagnosticConsumer > > getPathDiagnosticConsumers()
void EmitBasicReport(const Decl *DeclWithIssue, const CheckerFrontend *Checker, StringRef BugName, StringRef BugCategory, StringRef BugStr, PathDiagnosticLocation Loc, ArrayRef< SourceRange > Ranges={}, ArrayRef< FixItHint > Fixits={})
virtual std::unique_ptr< DiagnosticForConsumerMapTy > generateDiagnosticForConsumerMap(BugReport *exampleReport, ArrayRef< std::unique_ptr< PathDiagnosticConsumer > > consumers, ArrayRef< BugReport * > bugReports)
Generate the diagnostics for the given bug report.
const AnalyzerOptions & getAnalyzerOptions()
virtual void emitReport(std::unique_ptr< BugReport > R)
Add the given report to the set of reports tracked by BugReporter.
bool isSuppressed(const BugReport &)
Return true if the given bug report was explicitly suppressed by the user.
bool isSuppressOnSink() const
isSuppressOnSink - Returns true if bug reports associated with this bug type should be suppressed if ...
StringRef getCategory() const
StringRef getDescription() const
StringRef getCheckerName() const
A CheckerFrontend instance is what the user recognizes as "one checker": it has a public canonical na...
CheckerNameRef getName() const
This wrapper is used to ensure that only StringRefs originating from the CheckerRegistry are used as ...
Simple checker classes that implement one frontend (i.e.
Visitor that tries to report interesting diagnostics from conditions.
static bool isPieceMessageGeneric(const PathDiagnosticPiece *Piece)
static const char * getTag()
Return the tag associated with this visitor.
bool isValid() const =delete
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.
const CFGBlock * getCFGBlock() const
const ProgramStateRef & getState() const
pred_iterator pred_begin()
const Stmt * getStmtForDiagnostics() const
If the node's program point corresponds to a statement, retrieve that statement.
const Stmt * getPreviousStmtForDiagnostics() const
Find the statement that was executed immediately before this node.
ProgramPoint getLocation() const
getLocation - Returns the edge associated with the given node.
void addPredecessor(ExplodedNode *V, ExplodedGraph &G)
addPredeccessor - Adds a predecessor to the current node, and in tandem add this node as a successor ...
const Stmt * getNextStmtForDiagnostics() const
Find the next statement that was executed on this node's execution path.
const ParentMap & getParentMap() const
SVal getSVal(const Stmt *S) const
Get the value of an arbitrary expression at this node.
const LocationContext * getLocationContext() const
std::optional< T > getLocationAs() const &
const Stmt * getCurrentOrPreviousStmtForDiagnostics() const
Find the statement that was executed at or immediately before this node.
ExplodedNode * getFirstPred()
const ExplodedNode *const * const_succ_iterator
ProgramStateManager & getStateManager()
ExplodedGraph & getGraph()
Suppress reports that might lead to known false positives.
MemRegion - The root abstract class for all memory regions.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getBaseRegion() const
Prints path notes when a message is sent to a nil receiver.
PathDiagnosticLocation getLocation() const override
PathDiagnosticLocation callEnter
void setCallStackMessage(StringRef st)
bool hasCallStackMessage()
const Decl * getCallee() const
static std::shared_ptr< PathDiagnosticCallPiece > construct(const CallExitEnd &CE, const SourceManager &SM)
const Decl * getCaller() const
PathDiagnosticLocation callEnterWithin
virtual bool supportsLogicalOpControlFlow() const
bool shouldAddPathEdges() const
void HandlePathDiagnostic(std::unique_ptr< PathDiagnostic > D)
bool shouldAddControlNotes() const
bool shouldGenerateDiagnostics() const
PathDiagnosticLocation getStartLocation() const
void setStartLocation(const PathDiagnosticLocation &L)
PathDiagnosticLocation getEndLocation() const
static PathDiagnosticLocation createMemberLoc(const MemberExpr *ME, const SourceManager &SM)
For member expressions, return the location of the '.
const Stmt * asStmt() const
void Profile(llvm::FoldingSetNodeID &ID) const
const SourceManager & getManager() const
static PathDiagnosticLocation createOperatorLoc(const BinaryOperator *BO, const SourceManager &SM)
Create the location for the operator of the binary expression.
static PathDiagnosticLocation createEndBrace(const CompoundStmt *CS, const SourceManager &SM)
Create a location for the end of the compound statement.
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...
static PathDiagnosticLocation createEnd(const Stmt *S, const SourceManager &SM, const LocationOrAnalysisDeclContext LAC)
Create a location for the end of the statement.
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
FullSourceLoc asLocation() const
static PathDiagnosticLocation createDeclEnd(const LocationContext *LC, const SourceManager &SM)
Constructs a location for the end of the enclosing declaration body.
const Stmt * getStmtOrNull() const
static PathDiagnosticLocation createSingleLocation(const PathDiagnosticLocation &PDL)
Convert the given location into a single kind location.
ArrayRef< SourceRange > getRanges() const
Return the SourceRanges associated with this PathDiagnosticPiece.
virtual PathDiagnosticLocation getLocation() const =0
void setAsLastInMainSourceFile()
const void * getTag() const
Return the opaque tag (if any) on the PathDiagnosticPiece.
StringRef getString() const
PathDiagnosticLocation getLocation() const override
PathDiagnostic - PathDiagnostic objects represent a single path-sensitive diagnostic.
void setDeclWithIssue(const Decl *D)
void appendToDesc(StringRef S)
void setLocation(PathDiagnosticLocation NewLoc)
const FilesToLineNumsMap & getExecutedLines() const
PathPieces flatten(bool ShouldFlattenMacros) const
void markInteresting(SymbolRef sym, bugreporter::TrackingKind TKind=bugreporter::TrackingKind::Thorough)
Marks a symbol as interesting.
PathDiagnosticLocation getUniqueingLocation() const override
Get the location on which the report should be uniqued.
VisitorList Callbacks
A set of custom visitors which generate "event" diagnostics at interesting points in the path.
const Stmt * getStmt() const
PathDiagnosticLocation getLocation() const override
The primary location of the bug report that points at the undesirable behavior in the code.
const Decl * getDeclWithIssue() const override
The smallest declaration that contains the bug location.
bool shouldPrunePath() const
Indicates whether or not any path pruning should take place when generating a PathDiagnostic from thi...
ArrayRef< SourceRange > getRanges() const override
Get the SourceRanges associated with the report.
llvm::DenseMap< SymbolRef, bugreporter::TrackingKind > InterestingSymbols
Profile to identify equivalent bug reports for error report coalescing.
const Decl * getUniqueingDecl() const override
Get the declaration containing the uniqueing location.
const ExplodedNode * getErrorNode() const
PathSensitiveBugReport(const BugType &bt, StringRef desc, const ExplodedNode *errorNode)
const ExplodedNode * ErrorNode
The ExplodedGraph node against which the report was thrown.
void markInvalid(const void *Tag, const void *Data)
Marks the current report as invalid, meaning that it is probably a false positive and should not be r...
void Profile(llvm::FoldingSetNodeID &hash) const override
Profile to identify equivalent bug reports for error report coalescing.
void clearVisitors()
Remove all visitors attached to this bug report.
void addVisitor(std::unique_ptr< BugReporterVisitor > visitor)
Add custom or predefined bug report visitors to this report.
bool isValid() const
Returns whether or not this report should be considered valid.
std::optional< bugreporter::TrackingKind > getInterestingnessKind(SymbolRef sym) const
void markNotInteresting(SymbolRef sym)
llvm::DenseMap< const MemRegion *, bugreporter::TrackingKind > InterestingRegions
A (stack of) set of regions that are registered with this report as being "interesting",...
bool isInteresting(SymbolRef sym) const
const SourceRange ErrorNodeRange
The range that corresponds to ErrorNode's program point.
llvm::FoldingSet< BugReporterVisitor > CallbacksSet
Used for ensuring the visitors are only added once.
llvm::SmallPtrSet< const LocationContext *, 2 > InterestingLocationContexts
A set of location contexts that correspoind to call sites which should be considered "interesting".
GRBugReporter is used for generating path-sensitive reports.
const ExplodedGraph & getGraph() const
getGraph - Get the exploded graph created by the analysis engine for the analyzed method or function.
void emitReport(std::unique_ptr< BugReport > R) override
Add the given report to the set of reports tracked by BugReporter.
std::unique_ptr< DiagnosticForConsumerMapTy > generatePathDiagnostics(ArrayRef< std::unique_ptr< PathDiagnosticConsumer > > consumers, ArrayRef< PathSensitiveBugReport * > &bugReports)
bugReports A set of bug reports within a single equivalence class
ProgramStateManager & getStateManager() const
getStateManager - Return the state manager used by the analysis engine.
A Range represents the closed range [from, to].
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
SymbolRef getAsLocSymbol(bool IncludeBaseRegions=false) const
If this SVal is a location and wraps a symbol, return that SymbolRef.
std::string getMessage(const ExplodedNode *N) override
Search the call expression for the symbol Sym and dispatch the 'getMessageForX()' methods to construc...
virtual std::string getMessageForSymbolNotFound()
virtual std::string getMessageForReturn(const CallExpr *CallExpr)
virtual std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex)
Produces the message of the following form: 'Msg via Nth parameter'.
virtual ~StackHintGenerator()=0
The visitor detects NoteTags and displays the event notes they contain.
static const char * getTag()
Return the tag associated with this visitor.
The oracle will decide if a report should be accepted or rejected based on the results of the Z3 solv...
The bug visitor will walk all the nodes in a path and collect all the constraints.
TrackingKind
Specifies the type of tracking for an expression.
@ Thorough
Default tracking kind – specifies that as much information should be gathered about the tracked expre...
@ Condition
Specifies that a more moderate tracking should be used for the expression value.
llvm::DenseMap< const ExplodedNode *, const ExplodedNode * > InterExplodedGraphMap
std::map< FileID, std::set< unsigned > > FilesToLineNumsMap
File IDs mapped to sets of line numbers.
@ CF
Indicates that the tracked object is a CF object.
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
bool EQ(InterpState &S, CodePtr OpPC)
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
@ Result
The result type of a method or function.
const FunctionProtoType * T
Diagnostic wrappers for TextAPI types for error reporting.
llvm::SmallVector< std::pair< StringRef, StringRef >, 0 > Dependencies