47#include "llvm/ADT/ArrayRef.h"
48#include "llvm/ADT/DenseMap.h"
49#include "llvm/ADT/DenseSet.h"
50#include "llvm/ADT/FoldingSet.h"
51#include "llvm/ADT/STLExtras.h"
52#include "llvm/ADT/SmallPtrSet.h"
53#include "llvm/ADT/StringExtras.h"
54#include "llvm/ADT/StringRef.h"
55#include "llvm/Support/Compiler.h"
56#include "llvm/Support/ErrorHandling.h"
57#include "llvm/Support/TimeProfiler.h"
58#include "llvm/Support/raw_ostream.h"
75#define DEBUG_TYPE "BugReporter"
78 "The maximum number of bug reports in the same equivalence class");
80 "The maximum number of bug reports in the same equivalence class "
81 "where at least one report is valid (not suppressed)");
83STAT_COUNTER(NumTimesReportPassesZ3,
"Number of reports passed Z3");
84STAT_COUNTER(NumTimesReportRefuted,
"Number of reports refuted by Z3");
86 "Number of times a report equivalence class was aborted by the Z3 "
89 "Number of times all reports of an equivalence class was refuted");
93void BugReporterContext::anchor() {}
103 std::pair<PathDiagnosticCallPiece *, const ExplodedNode *>;
104using CallWithEntryStack = SmallVector<CallWithEntry, 6>;
107using VisitorsDiagnosticsTy =
108 llvm::DenseMap<const ExplodedNode *, std::vector<PathDiagnosticPieceRef>>;
112using StackFrameMap = llvm::DenseMap<const PathPieces *, const StackFrame *>;
117class PathDiagnosticConstruct {
119 const PathDiagnosticConsumer *Consumer;
122 const ExplodedNode *CurrentNode;
127 const SourceManager &SM;
133 CallWithEntryStack CallStack;
137 std::unique_ptr<PathDiagnostic> PD;
140 PathDiagnosticConstruct(
const PathDiagnosticConsumer *PDC,
141 const ExplodedNode *ErrorNode,
142 const PathSensitiveBugReport *R,
143 const Decl *AnalysisEntryPoint);
147 const StackFrame *getCurrStackFrame()
const {
148 assert(CurrentNode &&
"Already reached the root!");
155 const StackFrame *getStackFrameForActivePath()
const {
156 return SFM.find(&PD->getActivePath())->getSecond();
159 const ExplodedNode *getCurrentNode()
const {
return CurrentNode; }
163 bool ascendToPrevNode() {
165 return static_cast<bool>(CurrentNode);
168 const ParentMap &getParentMap()
const {
172 const SourceManager &getSourceManager()
const {
return SM; }
174 const Stmt *getParent(
const Stmt *S)
const {
175 return getParentMap().getParent(S);
178 void updateStackFrameMap(
const PathPieces *Path,
const StackFrame *SF) {
183 const StackFrame *getStackFrameFor(
const PathPieces *Path)
const {
184 assert(SFM.count(Path) &&
185 "Failed to find the stack frame associated with these pieces!");
186 return SFM.find(Path)->getSecond();
189 bool isInStackFrameMap(
const PathPieces *Path)
const {
190 return SFM.count(Path);
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;
219 const PathSensitiveBugReport *
R;
222 const ExplodedNode *
const ErrorNode;
225 std::unique_ptr<const VisitorsDiagnosticsTy> VisitorsDiagnostics;
231 static std::optional<PathDiagnosticBuilder>
232 findValidReport(ArrayRef<PathSensitiveBugReport *> &bugReports,
233 PathSensitiveBugReporter &Reporter);
235 PathDiagnosticBuilder(
236 BugReporterContext BRC, std::unique_ptr<ExplodedGraph> BugPath,
237 PathSensitiveBugReport *r,
const ExplodedNode *ErrorNode,
238 std::unique_ptr<VisitorsDiagnosticsTy> VisitorsDiagnostics);
250 std::unique_ptr<PathDiagnostic>
251 generate(
const PathDiagnosticConsumer *PDC)
const;
255 const CallWithEntryStack &CallStack)
const;
256 void generatePathDiagnosticsForNode(PathDiagnosticConstruct &
C,
257 PathDiagnosticLocation &PrevLoc)
const;
259 void generateMinimalDiagForBlockEdge(PathDiagnosticConstruct &
C,
263 generateDiagForGotoOP(
const PathDiagnosticConstruct &
C,
const Stmt *S,
264 PathDiagnosticLocation &Start)
const;
267 generateDiagForSwitchOP(
const PathDiagnosticConstruct &
C,
const CFGBlock *Dst,
268 PathDiagnosticLocation &Start)
const;
271 generateDiagForBinaryOP(
const PathDiagnosticConstruct &
C,
const Stmt *
T,
272 const CFGBlock *Src,
const CFGBlock *DstC)
const;
274 PathDiagnosticLocation
275 ExecutionContinues(
const PathDiagnosticConstruct &
C)
const;
277 PathDiagnosticLocation
278 ExecutionContinues(llvm::raw_string_ostream &os,
279 const PathDiagnosticConstruct &
C)
const;
281 const PathSensitiveBugReport *getBugReport()
const {
return R; }
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();
291 const auto &BT =
R->getBugType();
292 return (
"Flushing EQC " + BT.getDescription()).str();
296 const SourceManager &SM) {
298 assert(llvm::timeTraceProfilerEnabled());
300 const auto &BugReports =
EQ.getReports();
301 if (BugReports.empty())
303 const BugReport *
R = BugReports.front().get();
304 const auto &BT =
R->getBugType();
305 auto Loc =
R->getLocation().asLocation();
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())) {
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()) {
474 R->isInteresting(
C.getStackFrameFor(&call.path))))
477 containsSomethingInteresting =
true;
484 containsSomethingInteresting =
true;
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());
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())
621 llvm::raw_string_ostream &os,
const PathDiagnosticConstruct &
C)
const {
623 os << (os.str().empty() ?
"Execution " :
"execution ");
627 os <<
"continues on line "
628 << getSourceManager().getExpansionLineNumber(
Loc.asLocation());
630 os <<
"jumps to the end of the ";
631 const Decl *D =
C.getCurrStackFrame()->getDecl();
638 os <<
"anonymous block";
654 case Stmt::ForStmtClass:
655 case Stmt::DoStmtClass:
656 case Stmt::WhileStmtClass:
657 case Stmt::ObjCForCollectionStmtClass:
658 case Stmt::CXXForRangeStmtClass:
669 bool allowNestedContexts =
false) {
676 switch (Parent->getStmtClass()) {
677 case Stmt::BinaryOperatorClass: {
679 if (B->isLogicalOp())
683 case Stmt::CompoundStmtClass:
684 case Stmt::StmtExprClass:
686 case Stmt::ChooseExprClass:
693 case Stmt::BinaryConditionalOperatorClass:
694 case Stmt::ConditionalOperatorClass:
697 if (allowNestedContexts ||
702 case Stmt::CXXForRangeStmtClass:
706 case Stmt::DoStmtClass:
708 case Stmt::ForStmtClass:
712 case Stmt::IfStmtClass:
716 case Stmt::ObjCForCollectionStmtClass:
720 case Stmt::WhileStmtClass:
731 assert(S &&
"Cannot have null Stmt for PathDiagnosticLocation");
750void PathDiagnosticBuilder::updateStackPiecesWithMessage(
752 if (
R->hasCallStackHint(P))
753 for (
const auto &I : CallStack) {
756 std::string stackMsg =
R->getCallStackMessage(P, N);
767 const SourceManager& SM);
770 const PathDiagnosticConstruct &
C,
const CFGBlock *Dst,
773 const SourceManager &SM = getSourceManager();
776 llvm::raw_string_ostream os(sbuf);
779 if (
const Stmt *S = Dst->
getLabel()) {
784 os <<
"No cases match in the switch statement; "
785 "control jumps to line "
788 case Stmt::DefaultStmtClass:
789 os <<
"Control jumps to the 'default' case at line "
793 case Stmt::CaseStmtClass: {
794 os <<
"Control jumps to 'case ";
796 const Expr *LHS = Case->getLHS()->IgnoreParenImpCasts();
799 bool GetRawInt =
true;
801 if (
const auto *DR = dyn_cast<DeclRefExpr>(LHS)) {
804 const auto *D = dyn_cast<EnumConstantDecl>(DR->getDecl());
820 os <<
"'Default' branch taken; ";
821 End = ExecutionContinues(os,
C);
823 return std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, sbuf);
827 const PathDiagnosticConstruct &
C,
const Stmt *S,
830 llvm::raw_string_ostream os(sbuf);
834 return std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, sbuf);
838 const PathDiagnosticConstruct &
C,
const Stmt *
T,
const CFGBlock *Src,
839 const CFGBlock *Dst)
const {
841 const SourceManager &SM = getSourceManager();
845 llvm::raw_string_ostream os(sbuf);
846 os <<
"Left side of '";
849 if (B->getOpcode() == BO_LAnd) {
861 End = ExecutionContinues(
C);
864 assert(B->getOpcode() == BO_LOr);
871 End = ExecutionContinues(
C);
879 return std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, sbuf);
882void PathDiagnosticBuilder::generateMinimalDiagForBlockEdge(
883 PathDiagnosticConstruct &
C, BlockEdge BE)
const {
884 const SourceManager &SM = getSourceManager();
885 const StackFrame *SF =
C.getCurrStackFrame();
886 const CFGBlock *Src = BE.
getSrc();
887 const CFGBlock *Dst = BE.
getDst();
893 switch (
T->getStmtClass()) {
897 case Stmt::GotoStmtClass:
898 case Stmt::IndirectGotoStmtClass: {
899 if (
const Stmt *S =
C.getCurrentNode()->getNextStmtForDiagnostics())
900 C.getActivePath().push_front(generateDiagForGotoOP(
C, S, Start));
904 case Stmt::SwitchStmtClass: {
905 C.getActivePath().push_front(generateDiagForSwitchOP(
C, Dst, Start));
909 case Stmt::BreakStmtClass:
910 case Stmt::ContinueStmtClass: {
912 llvm::raw_string_ostream os(sbuf);
914 C.getActivePath().push_front(
915 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, sbuf));
920 case Stmt::BinaryConditionalOperatorClass:
921 case Stmt::ConditionalOperatorClass: {
923 llvm::raw_string_ostream os(sbuf);
924 os <<
"'?' condition is ";
933 if (
const Stmt *S = End.
asStmt())
936 C.getActivePath().push_front(
937 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, sbuf));
942 case Stmt::BinaryOperatorClass: {
943 if (!
C.supportsLogicalOpControlFlow())
946 C.getActivePath().push_front(generateDiagForBinaryOP(
C,
T, Src, Dst));
950 case Stmt::DoStmtClass:
953 llvm::raw_string_ostream os(sbuf);
955 os <<
"Loop condition is true; ";
958 if (
const Stmt *S = End.
asStmt())
961 C.getActivePath().push_front(
962 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, sbuf));
966 if (
const Stmt *S = End.
asStmt())
969 C.getActivePath().push_front(
970 std::make_shared<PathDiagnosticControlFlowPiece>(
971 Start, End,
"Loop condition is false; exiting loop"));
975 case Stmt::WhileStmtClass:
976 case Stmt::ForStmtClass:
979 llvm::raw_string_ostream os(sbuf);
981 os <<
"Loop condition is false; ";
983 if (
const Stmt *S = End.
asStmt())
986 C.getActivePath().push_front(
987 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, sbuf));
990 if (
const Stmt *S = End.
asStmt())
993 C.getActivePath().push_front(
994 std::make_shared<PathDiagnosticControlFlowPiece>(
995 Start, End,
"Loop condition is true; entering loop body"));
1000 case Stmt::IfStmtClass: {
1003 if (
const Stmt *S = End.
asStmt())
1007 C.getActivePath().push_front(
1008 std::make_shared<PathDiagnosticControlFlowPiece>(
1009 Start, End,
"Taking false branch"));
1011 C.getActivePath().push_front(
1012 std::make_shared<PathDiagnosticControlFlowPiece>(
1013 Start, End,
"Taking true branch"));
1026 case Stmt::ForStmtClass:
1027 case Stmt::WhileStmtClass:
1028 case Stmt::ObjCForCollectionStmtClass:
1029 case Stmt::CXXForRangeStmtClass:
1058 const Stmt *S = SP->getStmt();
1068 const Stmt *LoopBody =
nullptr;
1070 case Stmt::CXXForRangeStmtClass: {
1076 LoopBody = FR->getBody();
1079 case Stmt::ForStmtClass: {
1083 LoopBody = FS->getBody();
1086 case Stmt::ObjCForCollectionStmtClass: {
1088 LoopBody = FC->getBody();
1091 case Stmt::WhileStmtClass:
1122 std::make_shared<PathDiagnosticControlFlowPiece>(NewLoc, PrevLoc));
1130 if (
const auto *FS = dyn_cast_or_null<ObjCForCollectionStmt>(S))
1131 return FS->getElement();
1138 "Loop body skipped when range is empty";
1140 "Loop body skipped when collection is empty";
1142static std::unique_ptr<FilesToLineNumsMap>
1145void PathDiagnosticBuilder::generatePathDiagnosticsForNode(
1156 if (
C.shouldAddPathEdges()) {
1158 const StackFrame *CalleeSF = CE->getCalleeStackFrame();
1172 bool VisitedEntireCall =
C.PD->isWithinCall();
1173 C.PD->popActivePath();
1176 if (VisitedEntireCall) {
1181 const Decl *Caller = CE->getStackFrame()->getDecl();
1183 assert(
C.getActivePath().size() == 1 &&
1184 C.getActivePath().front().get() ==
Call);
1188 assert(
C.isInStackFrameMap(&
C.getActivePath()) &&
1189 "When we ascend to a previously unvisited call, the active path's "
1190 "address shouldn't change, but rather should be compacted into "
1191 "a single CallEvent!");
1192 C.updateStackFrameMap(&
C.getActivePath(),
C.getCurrStackFrame());
1195 assert(!
C.isInStackFrameMap(&
Call->path) &&
1196 "When we ascend to a previously unvisited call, this must be the "
1197 "first time we encounter the caller stack frame!");
1198 C.updateStackFrameMap(&
Call->path, CE->getCalleeStackFrame());
1203 PrevLoc =
Call->getLocation();
1205 if (!
C.CallStack.empty()) {
1206 assert(
C.CallStack.back().first ==
Call);
1207 C.CallStack.pop_back();
1212 assert(
C.getCurrStackFrame() ==
C.getStackFrameForActivePath() &&
1213 "The current position in the bug path is out of sync with the "
1214 "stack frame associated with the active path!");
1217 if (std::optional<CallExitEnd> CE = P.
getAs<CallExitEnd>()) {
1223 assert(!
C.isInStackFrameMap(&
Call->path) &&
1224 "We just entered a call, this must've been the first time we "
1225 "encounter its stack frame!");
1226 C.updateStackFrameMap(&
Call->path, CE->getCalleeStackFrame());
1228 if (
C.shouldAddPathEdges()) {
1234 auto *P =
Call.get();
1235 C.getActivePath().push_front(std::move(
Call));
1238 C.PD->pushActivePath(&P->path);
1239 C.CallStack.push_back(CallWithEntry(P,
C.getCurrentNode()));
1243 if (
auto PS = P.
getAs<PostStmt>()) {
1244 if (!
C.shouldAddPathEdges())
1256 }
else if (
auto BE = P.
getAs<BlockEdge>()) {
1258 if (
C.shouldAddControlNotes()) {
1259 generateMinimalDiagForBlockEdge(
C, *BE);
1262 if (!
C.shouldAddPathEdges()) {
1269 const Stmt *Body =
nullptr;
1271 if (
const auto *FS = dyn_cast<ForStmt>(
Loop))
1272 Body = FS->getBody();
1273 else if (
const auto *WS = dyn_cast<WhileStmt>(
Loop))
1274 Body = WS->getBody();
1275 else if (
const auto *OFS = dyn_cast<ObjCForCollectionStmt>(
Loop)) {
1276 Body = OFS->getBody();
1277 }
else if (
const auto *FRS = dyn_cast<CXXForRangeStmt>(
Loop)) {
1278 Body = FRS->getBody();
1282 auto p = std::make_shared<PathDiagnosticEventPiece>(
1283 L,
"Looping back to the head of the loop");
1284 p->setPrunable(
true);
1288 if (!
C.shouldAddControlNotes()) {
1289 C.getActivePath().push_front(std::move(p));
1292 if (
const auto *CS = dyn_cast_or_null<CompoundStmt>(Body)) {
1298 const CFGBlock *BSrc = BE->
getSrc();
1299 const ParentMap &PM =
C.getParentMap();
1312 if (!IsInLoopBody) {
1327 C.getCurrStackFrame());
1328 auto PE = std::make_shared<PathDiagnosticEventPiece>(L, str);
1329 PE->setPrunable(
true);
1333 if (!
C.shouldAddControlNotes()) {
1334 C.getActivePath().push_front(std::move(PE));
1345static std::unique_ptr<PathDiagnostic>
1347 const Decl *AnalysisEntryPoint) {
1348 const BugType &BT = R->getBugType();
1349 return std::make_unique<PathDiagnostic>(
1351 R->getDescription(), R->getShortDescription(
false),
1352 BT.
getCategory(), R->getUniqueingLocation(), R->getUniqueingDecl(),
1353 AnalysisEntryPoint, std::make_unique<FilesToLineNumsMap>());
1356static std::unique_ptr<PathDiagnostic>
1359 const Decl *AnalysisEntryPoint) {
1360 const BugType &BT = R->getBugType();
1361 return std::make_unique<PathDiagnostic>(
1363 R->getDescription(), R->getShortDescription(
false),
1364 BT.
getCategory(), R->getUniqueingLocation(), R->getUniqueingDecl(),
1389 case Stmt::BinaryOperatorClass: {
1391 if (!BO->isLogicalOp())
1393 return BO->getLHS() == Cond || BO->getRHS() == Cond;
1395 case Stmt::IfStmtClass:
1397 case Stmt::ForStmtClass:
1399 case Stmt::WhileStmtClass:
1401 case Stmt::DoStmtClass:
1403 case Stmt::ChooseExprClass:
1405 case Stmt::IndirectGotoStmtClass:
1407 case Stmt::SwitchStmtClass:
1409 case Stmt::BinaryConditionalOperatorClass:
1411 case Stmt::ConditionalOperatorClass: {
1413 return CO->getCond() == Cond ||
1414 CO->getLHS() == Cond ||
1415 CO->getRHS() == Cond;
1417 case Stmt::ObjCForCollectionStmtClass:
1419 case Stmt::CXXForRangeStmtClass: {
1421 return FRS->getCond() == Cond || FRS->getRangeInit() == Cond;
1429 if (
const auto *FS = dyn_cast<ForStmt>(FL))
1430 return FS->getInc() == S || FS->getInit() == S;
1431 if (
const auto *FRS = dyn_cast<CXXForRangeStmt>(FL))
1432 return FRS->getInc() == S || FRS->getRangeStmt() == S ||
1433 FRS->getLoopVarStmt() || FRS->getRangeInit() == S;
1446 PathPieces::iterator Prev = pieces.end();
1447 for (PathPieces::iterator I = pieces.begin(), E = Prev; I != E;
1449 auto *Piece = dyn_cast<PathDiagnosticControlFlowPiece>(I->get());
1458 const Stmt *InnerStmt =
nullptr;
1459 while (NextSrcContext.
isValid() && NextSrcContext.
asStmt() != InnerStmt) {
1460 SrcContexts.push_back(NextSrcContext);
1461 InnerStmt = NextSrcContext.
asStmt();
1470 const Stmt *Dst = Piece->getEndLocation().getStmtOrNull();
1480 if (llvm::is_contained(SrcContexts, DstContext))
1484 Piece->setStartLocation(DstContext);
1489 auto *PrevPiece = dyn_cast<PathDiagnosticControlFlowPiece>(Prev->get());
1492 if (
const Stmt *PrevSrc =
1493 PrevPiece->getStartLocation().getStmtOrNull()) {
1495 if (PrevSrcParent ==
1497 PrevPiece->setEndLocation(DstContext);
1508 std::make_shared<PathDiagnosticControlFlowPiece>(SrcLoc, DstContext);
1510 I = pieces.insert(I, std::move(P));
1526 for (PathPieces::iterator I = pieces.begin(), E = pieces.end(); I != E; ++I) {
1527 const auto *PieceI = dyn_cast<PathDiagnosticControlFlowPiece>(I->get());
1532 const Stmt *s1Start = PieceI->getStartLocation().getStmtOrNull();
1533 const Stmt *s1End = PieceI->getEndLocation().getStmtOrNull();
1535 if (!s1Start || !s1End)
1538 PathPieces::iterator NextI = I; ++NextI;
1548 const auto *EV = dyn_cast<PathDiagnosticEventPiece>(NextI->get());
1550 StringRef S = EV->getString();
1559 PieceNextI = dyn_cast<PathDiagnosticControlFlowPiece>(NextI->get());
1569 if (!s2Start || !s2End || s1End != s2Start)
1585 I = pieces.erase(I);
1602 return std::nullopt;
1606 return std::nullopt;
1610 StringRef Snippet = Buffer->getBuffer().slice(BeginOffset, EndOffset);
1616 if (Snippet.find_first_of(
"\r\n") != StringRef::npos)
1617 return std::nullopt;
1620 return Snippet.size();
1646 for (PathPieces::iterator I = Path.begin(), E = Path.end(); I != E; ) {
1648 const auto *PieceI = dyn_cast<PathDiagnosticControlFlowPiece>(I->get());
1655 const Stmt *s1Start = PieceI->getStartLocation().getStmtOrNull();
1656 const Stmt *s1End = PieceI->getEndLocation().getStmtOrNull();
1658 PathPieces::iterator NextI = I; ++NextI;
1662 const auto *PieceNextI =
1663 dyn_cast<PathDiagnosticControlFlowPiece>(NextI->get());
1670 PieceNextI = dyn_cast<PathDiagnosticControlFlowPiece>(NextI->get());
1679 const Stmt *s2Start = PieceNextI->getStartLocation().getStmtOrNull();
1680 const Stmt *s2End = PieceNextI->getEndLocation().getStmtOrNull();
1682 if (s1Start && s2Start && s1Start == s2End && s2Start == s1End) {
1683 const size_t MAX_SHORT_LINE_LENGTH = 80;
1685 if (s1Length && *s1Length <= MAX_SHORT_LINE_LENGTH) {
1687 if (s2Length && *s2Length <= MAX_SHORT_LINE_LENGTH) {
1689 I = Path.erase(NextI);
1712 bool erased =
false;
1714 for (PathPieces::iterator I = path.begin(), E = path.end(); I != E;
1718 const auto *PieceI = dyn_cast<PathDiagnosticControlFlowPiece>(I->get());
1723 const Stmt *start = PieceI->getStartLocation().getStmtOrNull();
1724 const Stmt *end = PieceI->getEndLocation().getStmtOrNull();
1742 std::swap(SecondLoc, FirstLoc);
1751 const size_t MAX_PUNY_EDGE_LENGTH = 2;
1752 if (*ByteWidth <= MAX_PUNY_EDGE_LENGTH) {
1764 for (PathPieces::iterator I = path.begin(), E = path.end(); I != E; ++I) {
1765 const auto *PieceI = dyn_cast<PathDiagnosticEventPiece>(I->get());
1770 PathPieces::iterator NextI = I; ++NextI;
1774 const auto *PieceNextI = dyn_cast<PathDiagnosticEventPiece>(NextI->get());
1780 if (PieceI->getString() == PieceNextI->getString()) {
1788 bool hasChanges =
false;
1794 for (PathPieces::iterator I = path.begin(), E = path.end(); I != E; ) {
1796 if (
auto *CallI = dyn_cast<PathDiagnosticCallPiece>(I->get())) {
1799 if (!OCS.count(CallI)) {
1809 auto *PieceI = dyn_cast<PathDiagnosticControlFlowPiece>(I->get());
1816 const Stmt *s1Start = PieceI->getStartLocation().getStmtOrNull();
1817 const Stmt *s1End = PieceI->getEndLocation().getStmtOrNull();
1821 PathPieces::iterator NextI = I; ++NextI;
1825 const auto *PieceNextI = dyn_cast<PathDiagnosticControlFlowPiece>(NextI->get());
1832 const Stmt *s2Start = PieceNextI->getStartLocation().getStmtOrNull();
1833 const Stmt *s2End = PieceNextI->getEndLocation().getStmtOrNull();
1851 if (level1 && level1 == level2 && level1 == level3 && level1 == level4) {
1852 PieceI->setEndLocation(PieceNextI->getEndLocation());
1865 if (s1End && s1End == s2Start && level2) {
1866 bool removeEdge =
false;
1892 else if (s1Start && s2End &&
1905 else if (s1Start && s2End &&
1907 SourceRange EdgeRange(PieceI->getEndLocation().asLocation(),
1908 PieceI->getStartLocation().asLocation());
1915 PieceI->setEndLocation(PieceNextI->getEndLocation());
1929 if (s1End == s2Start) {
1930 const auto *FS = dyn_cast_or_null<ObjCForCollectionStmt>(level3);
1931 if (FS && FS->getCollection()->IgnoreParens() == s2Start &&
1932 s2End == FS->getElement()) {
1933 PieceI->setEndLocation(PieceNextI->getEndLocation());
1970 const auto *FirstEdge =
1971 dyn_cast<PathDiagnosticControlFlowPiece>(Path.front().get());
1975 const Decl *D =
C.getStackFrameFor(&Path)->getDecl();
1978 if (FirstEdge->getStartLocation() != EntryLoc)
1990 for (
const auto &P : path) {
1993 unsigned LineNo =
Loc.getLineNumber();
1995 ExecutedLines[FID].insert(LineNo);
1999PathDiagnosticConstruct::PathDiagnosticConstruct(
2002 : Consumer(PDC), CurrentNode(ErrorNode),
2003 SM(CurrentNode->getCodeDecl().getASTContext().getSourceManager()),
2005 AnalysisEntryPoint)) {
2009PathDiagnosticBuilder::PathDiagnosticBuilder(
2012 std::unique_ptr<VisitorsDiagnosticsTy> VisitorsDiagnostics)
2014 ErrorNode(ErrorNode),
2015 VisitorsDiagnostics(
std::
move(VisitorsDiagnostics)) {}
2017std::unique_ptr<PathDiagnostic>
2019 const Decl *EntryPoint = getBugReporter().getAnalysisEntryPoint();
2020 PathDiagnosticConstruct Construct(PDC, ErrorNode, R, EntryPoint);
2022 const SourceManager &SM = getSourceManager();
2023 const AnalyzerOptions &Opts = getAnalyzerOptions();
2029 auto EndNotes = VisitorsDiagnostics->find(ErrorNode);
2031 if (EndNotes != VisitorsDiagnostics->end()) {
2032 assert(!EndNotes->second.empty());
2033 LastPiece = EndNotes->second[0];
2038 Construct.PD->setEndOfPath(LastPiece);
2040 PathDiagnosticLocation PrevLoc = Construct.PD->getLocation();
2043 while (Construct.ascendToPrevNode()) {
2044 generatePathDiagnosticsForNode(Construct, PrevLoc);
2046 auto VisitorNotes = VisitorsDiagnostics->find(Construct.getCurrentNode());
2047 if (VisitorNotes == VisitorsDiagnostics->end())
2052 std::set<llvm::FoldingSetNodeID> DeduplicationSet;
2056 llvm::FoldingSetNodeID
ID;
2058 if (!DeduplicationSet.insert(ID).second)
2063 updateStackPiecesWithMessage(
Note, Construct.CallStack);
2064 Construct.getActivePath().push_front(
Note);
2071 const StackFrame *CalleeSF = Construct.getStackFrameForActivePath();
2079 if (!Construct.PD->path.empty()) {
2080 if (
R->shouldPrunePath() && Opts.ShouldPrunePaths) {
2081 bool stillHasNotes =
2083 assert(stillHasNotes);
2084 (void)stillHasNotes;
2088 if (!Opts.ShouldAddPopUpNotes)
2101 while (
optimizeEdges(Construct, Construct.getMutablePieces(), OCS)) {
2116 if (Opts.ShouldDisplayMacroExpansions)
2119 return std::move(Construct.PD);
2126void BugType::anchor() {}
2132LLVM_ATTRIBUTE_USED
static bool
2134 for (
const std::pair<StringRef, StringRef> &Pair : Registry.Dependencies) {
2135 if (Pair.second == CheckerName)
2142 StringRef CheckerName) {
2144 if (
Checker.FullName == CheckerName)
2148 "Checker name not found in CheckerRegistry -- did you retrieve it "
2149 "correctly from CheckerManager::getCurrentCheckerName?");
2153 const BugType &bt,
const llvm::Twine &shortDesc,
const llvm::Twine &desc,
2155 const Decl *DeclToUnique)
2159 assert(
ErrorNode &&
"The error node must be non-null!");
2161 ->getAnalysisManager()
2162 .getCheckerManager()
2163 ->getCheckerRegistryData(),
2165 "Some checkers depend on this one! We don't allow dependency "
2166 "checkers to emit warnings, because checkers should depend on "
2167 "*modeling*, not *diagnostics*.");
2171 ->getAnalysisManager()
2172 .getCheckerManager()
2173 ->getCheckerRegistryData(),
2175 "Hidden checkers musn't emit diagnostics as they are by definition "
2176 "non-user facing!");
2180 std::unique_ptr<BugReporterVisitor> visitor) {
2184 llvm::FoldingSetNodeID ID;
2185 visitor->Profile(ID);
2187 llvm::FoldingSetInsertToken InsertToken;
2192 Callbacks.push_back(std::move(visitor));
2207 hash.AddInteger(
static_cast<int>(
getKind()));
2208 hash.AddPointer(&
BT);
2210 assert(Location.isValid());
2211 Location.Profile(hash);
2214 if (!range.isValid())
2216 hash.Add(range.getBegin());
2217 hash.Add(range.getEnd());
2222 hash.AddInteger(
static_cast<int>(
getKind()));
2223 hash.AddPointer(&
BT);
2233 hash.AddPointer(
ErrorNode->getCurrentOrPreviousStmtForDiagnostics());
2237 if (!range.isValid())
2239 hash.Add(range.getBegin());
2240 hash.Add(range.getEnd());
2246 llvm::DenseMap<T, bugreporter::TrackingKind> &InterestingnessMap,
T Val,
2248 auto Result = InterestingnessMap.insert({Val, TKind});
2268 "BugReport::markInteresting currently can only handle 2 different "
2269 "tracking kinds! Please define what tracking kind should this entitiy"
2270 "have, if it was already marked as interesting with a different kind!");
2282 if (
const auto *meta = dyn_cast<SymbolMetadata>(sym))
2294 if (
const auto *meta = dyn_cast<SymbolMetadata>(sym))
2303 R = R->getBaseRegion();
2306 if (
const auto *SR = dyn_cast<SymbolicRegion>(R))
2314 R = R->getBaseRegion();
2317 if (
const auto *SR = dyn_cast<SymbolicRegion>(R))
2333std::optional<bugreporter::TrackingKind>
2352 "BugReport::getInterestingnessKind currently can only handle 2 different "
2353 "tracking kinds! Please define what tracking kind should we return here "
2354 "when the kind of getAsRegion() and getAsSymbol() is different!");
2355 return std::nullopt;
2358std::optional<bugreporter::TrackingKind>
2361 return std::nullopt;
2366 return std::nullopt;
2367 return It->getSecond();
2370std::optional<bugreporter::TrackingKind>
2373 return std::nullopt;
2375 R = R->getBaseRegion();
2378 return It->getSecond();
2380 if (
const auto *SR = dyn_cast<SymbolicRegion>(R))
2382 return std::nullopt;
2408 const Stmt *S =
nullptr;
2412 if (BE->getBlock() == &Exit)
2413 S =
ErrorNode->getPreviousStmtForDiagnostics();
2455 assert(
ErrorNode &&
"Cannot create a location with a null node.");
2462 .getSourceManager();
2475 S =
ErrorNode->getNextStmtForDiagnostics();
2482 if (
const auto *AS = dyn_cast<AttributedStmt>(S))
2483 S = AS->getSubStmt();
2486 if (
const auto *ME = dyn_cast<MemberExpr>(S))
2490 if (
const auto *B = dyn_cast<BinaryOperator>(S))
2511 return Eng.getGraph();
2515 return Eng.getStateManager();
2519 : D(D), UserSuppressions(D.getASTContext()) {}
2523 assert(StrBugTypes.empty() &&
2524 "Destroying BugReporter before diagnostics are emitted!");
2527 for (
const auto I : EQClassesVector)
2534 for (
const auto EQ : EQClassesVector)
2541 StrBugTypes.clear();
2554 std::unique_ptr<ExplodedGraph> BugPath;
2561class BugPathGetter {
2562 std::unique_ptr<ExplodedGraph> TrimmedGraph;
2564 using PriorityMapTy = llvm::DenseMap<const ExplodedNode *, unsigned>;
2567 PriorityMapTy PriorityMap;
2571 using ReportNewNodePair =
2572 std::pair<PathSensitiveBugReport *, const ExplodedNode *>;
2575 BugPathInfo CurrentBugPath;
2578 template <
bool Descending>
2579 class PriorityCompare {
2580 const PriorityMapTy &PriorityMap;
2583 PriorityCompare(
const PriorityMapTy &M) : PriorityMap(M) {}
2586 PriorityMapTy::const_iterator LI = PriorityMap.find(LHS);
2587 PriorityMapTy::const_iterator RI = PriorityMap.find(RHS);
2588 PriorityMapTy::const_iterator E = PriorityMap.end();
2595 return Descending ? LI->second > RI->second
2596 : LI->second < RI->second;
2599 bool operator()(
const ReportNewNodePair &LHS,
2600 const ReportNewNodePair &RHS)
const {
2601 return (*
this)(LHS.second, RHS.second);
2606 BugPathGetter(
const ExplodedGraph *OriginalGraph,
2607 ArrayRef<PathSensitiveBugReport *> &bugReports);
2609 BugPathInfo *getNextBugPath();
2614BugPathGetter::BugPathGetter(
const ExplodedGraph *OriginalGraph,
2615 ArrayRef<PathSensitiveBugReport *> &bugReports) {
2616 SmallVector<const ExplodedNode *, 32> Nodes;
2617 for (
const auto I : bugReports) {
2618 assert(I->isValid() &&
2619 "We only allow BugReporterVisitors and BugReporter itself to "
2620 "invalidate reports!");
2621 Nodes.emplace_back(I->getErrorNode());
2627 TrimmedGraph = OriginalGraph->
trim(Nodes, &ForwardMap);
2632 llvm::SmallPtrSet<const ExplodedNode *, 32> RemainingNodes;
2637 "Failed to construct a trimmed graph that contains this error "
2639 ReportNodes.emplace_back(
Report, NewNode);
2640 RemainingNodes.insert(NewNode);
2643 assert(!RemainingNodes.empty() &&
"No error node found in the trimmed graph");
2646 std::queue<const ExplodedNode *> WS;
2648 WS.push(TrimmedGraph->getRoot());
2649 unsigned Priority = 0;
2651 while (!WS.empty()) {
2655 PriorityMapTy::iterator PriorityEntry;
2657 std::tie(PriorityEntry, IsNew) = PriorityMap.insert({Node, Priority});
2661 assert(PriorityEntry->second <= Priority);
2665 if (RemainingNodes.erase(Node))
2666 if (RemainingNodes.empty())
2674 llvm::sort(ReportNodes, PriorityCompare<true>(PriorityMap));
2677BugPathInfo *BugPathGetter::getNextBugPath() {
2678 if (ReportNodes.empty())
2682 std::tie(CurrentBugPath.Report, OrigN) = ReportNodes.pop_back_val();
2683 assert(PriorityMap.contains(OrigN) &&
"error node not accessible from root");
2687 auto GNew = std::make_unique<ExplodedGraph>();
2703 CurrentBugPath.ErrorNode = NewN;
2709 assert(OrigN == TrimmedGraph->getRoot() &&
2710 "There should be only one root!");
2711 GNew->designateAsRoot(NewN);
2718 PriorityCompare<false>(PriorityMap));
2721 CurrentBugPath.BugPath = std::move(GNew);
2723 return &CurrentBugPath;
2730 using MacroStackTy = std::vector<
2731 std::pair<std::shared_ptr<PathDiagnosticMacroPiece>,
SourceLocation>>;
2733 using PiecesTy = std::vector<PathDiagnosticPieceRef>;
2735 MacroStackTy MacroStack;
2738 for (PathPieces::const_iterator I = path.begin(), E = path.end();
2740 const auto &piece = *I;
2743 if (
auto *call = dyn_cast<PathDiagnosticCallPiece>(&*piece)) {
2756 if (
Loc.isFileID()) {
2758 Pieces.push_back(piece);
2762 assert(
Loc.isMacroID());
2765 if (!MacroStack.empty() && InstantiationLoc == MacroStack.back().second) {
2766 MacroStack.back().first->subPieces.push_back(piece);
2772 std::shared_ptr<PathDiagnosticMacroPiece> MacroGroup;
2779 while (!MacroStack.empty()) {
2780 if (InstantiationLoc == MacroStack.back().second) {
2781 MacroGroup = MacroStack.back().first;
2785 if (ParentInstantiationLoc == MacroStack.back().second) {
2786 MacroGroup = MacroStack.back().first;
2790 MacroStack.pop_back();
2793 if (!MacroGroup || ParentInstantiationLoc == MacroStack.back().second) {
2795 auto NewGroup = std::make_shared<PathDiagnosticMacroPiece>(
2799 MacroGroup->subPieces.push_back(NewGroup);
2801 assert(InstantiationLoc.
isFileID());
2802 Pieces.push_back(NewGroup);
2805 MacroGroup = NewGroup;
2806 MacroStack.push_back(std::make_pair(MacroGroup, InstantiationLoc));
2810 MacroGroup->subPieces.push_back(piece);
2816 llvm::append_range(path, Pieces);
2822static std::unique_ptr<VisitorsDiagnosticsTy>
2826 std::unique_ptr<VisitorsDiagnosticsTy> Notes =
2827 std::make_unique<VisitorsDiagnosticsTy>();
2840 for (std::unique_ptr<BugReporterVisitor> &Visitor : R->visitors())
2841 visitors.push_back(std::move(Visitor));
2848 for (
auto &
V : visitors) {
2849 V->finalizeVisitor(ErrorNode, BRC, *R);
2851 if (
auto Piece =
V->getEndPath(ErrorNode, BRC, *R)) {
2852 assert(!LastPiece &&
2853 "There can only be one final piece in a diagnostic.");
2855 "The final piece must contain a message!");
2856 LastPiece = std::move(Piece);
2857 (*Notes)[ErrorNode].push_back(LastPiece);
2863 for (
auto &
V : visitors) {
2864 auto P =
V->VisitNode(NextNode, BRC, *R);
2866 (*Notes)[NextNode].push_back(std::move(P));
2878std::optional<PathDiagnosticBuilder> PathDiagnosticBuilder::findValidReport(
2879 ArrayRef<PathSensitiveBugReport *> &bugReports,
2883 BugPathGetter BugGraph(&Reporter.
getGraph(), bugReports);
2885 while (BugPathInfo *BugPath = BugGraph.getNextBugPath()) {
2888 assert(R &&
"No original report found for sliced graph.");
2889 assert(
R->isValid() &&
"Report selected by trimmed graph marked invalid.");
2904 std::unique_ptr<VisitorsDiagnosticsTy> visitorNotes =
2909 llvm::TimeTraceScope TCS{
"Crosscheck with Z3"};
2920 switch (Z3Oracle.interpretQueryResult(CrosscheckResult)) {
2922 ++NumTimesReportRefuted;
2923 R->markInvalid(
"Infeasible constraints",
nullptr);
2926 ++NumTimesReportEQClassAborted;
2929 ++NumTimesReportPassesZ3;
2934 assert(
R->isValid());
2935 return PathDiagnosticBuilder(std::move(BRC), std::move(BugPath->BugPath),
2936 BugPath->Report, BugPath->ErrorNode,
2937 std::move(visitorNotes));
2941 ++NumTimesReportEQClassWasExhausted;
2945std::unique_ptr<DiagnosticForConsumerMapTy>
2947 ArrayRef<std::unique_ptr<PathDiagnosticConsumer>> consumers,
2949 assert(!bugReports.empty());
2951 auto Out = std::make_unique<DiagnosticForConsumerMapTy>();
2953 std::optional<PathDiagnosticBuilder> PDB =
2954 PathDiagnosticBuilder::findValidReport(bugReports, *
this);
2957 for (
const auto &PC : consumers) {
2958 if (std::unique_ptr<PathDiagnostic> PD = PDB->generate(PC.get())) {
2959 (*Out)[PC.get()] = std::move(PD);
2968 bool ValidSourceLoc = R->getLocation().isValid();
2969 assert(ValidSourceLoc);
2972 if (!ValidSourceLoc)
2976 if (UserSuppressions.isSuppressed(*R))
2980 llvm::FoldingSetNodeID ID;
2984 llvm::FoldingSetInsertToken InsertToken;
2989 EQClasses.insert(EQ, InsertToken);
2990 EQClassesVector.push_back(EQ);
2992 EQ->AddReport(std::move(R));
2996 if (
auto PR = dyn_cast<PathSensitiveBugReport>(R.get()))
3000 assert((E->isSink() || E->getLocation().getTag()) &&
3001 "Error node must either be a sink or have a tag");
3023struct FRIEC_WLItem {
3028 : N(n), I(N->succ_begin()), E(N->succ_end()) {}
3033BugReport *PathSensitiveBugReporter::findReportInEquivalenceClass(
3038 assert(
EQ.getReports().size() > 0);
3039 const BugType& BT =
EQ.getReports()[0]->getBugType();
3041 BugReport *
R =
EQ.getReports()[0].get();
3042 for (
auto &J :
EQ.getReports()) {
3043 if (
auto *PR = dyn_cast<PathSensitiveBugReport>(J.get())) {
3045 bugReports.push_back(PR);
3057 BugReport *exampleReport =
nullptr;
3059 for (
const auto &I:
EQ.getReports()) {
3060 auto *
R = dyn_cast<PathSensitiveBugReport>(I.get());
3064 const ExplodedNode *errorNode =
R->getErrorNode();
3065 if (errorNode->
isSink()) {
3067 "BugType::isSuppressSink() should not be 'true' for sink end nodes");
3071 bugReports.push_back(R);
3081 if (
const CFGBlock *ErrorB = errorNode->
getCFGBlock())
3082 if (ErrorB->isInevitablySinking())
3087 using WLItem = FRIEC_WLItem;
3088 using DFSWorkList = SmallVector<WLItem, 10>;
3090 llvm::DenseMap<const ExplodedNode *, unsigned> Visited;
3093 WL.push_back(errorNode);
3094 Visited[errorNode] = 1;
3096 while (!WL.empty()) {
3097 WLItem &WI = WL.back();
3098 assert(!WI.N->succ_empty());
3100 for (; WI.I != WI.E; ++WI.I) {
3101 const ExplodedNode *Succ = *WI.I;
3106 bugReports.push_back(R);
3117 unsigned &mark = Visited[Succ];
3127 if (!WL.empty() && &WL.back() == &WI)
3134 return exampleReport;
3138 llvm::TimeTraceScope TCS{timeTraceName(EQ), [&]() {
3141 SmallVector<BugReport*, 10> bugReports;
3142 BugReport *report = findReportInEquivalenceClass(EQ, bugReports);
3147 for (
const std::string &CheckerOrPackage :
3154 std::unique_ptr<DiagnosticForConsumerMapTy> Diagnostics =
3157 for (
auto &P : *Diagnostics) {
3158 PathDiagnosticConsumer *Consumer = P.first;
3159 std::unique_ptr<PathDiagnostic> &PD = P.second;
3163 if (PD->path.empty()) {
3165 auto piece = std::make_unique<PathDiagnosticEventPiece>(
3167 for (SourceRange Range : report->
getRanges())
3168 piece->addRange(Range);
3169 PD->setEndOfPath(std::move(piece));
3172 PathPieces &Pieces = PD->getMutablePieces();
3176 for (
const auto &I : llvm::reverse(report->
getNotes())) {
3177 PathDiagnosticNotePiece *Piece = I.get();
3178 auto ConvertedPiece = std::make_shared<PathDiagnosticEventPiece>(
3181 ConvertedPiece->addRange(R);
3183 Pieces.push_front(std::move(ConvertedPiece));
3186 for (
const auto &I : llvm::reverse(report->
getNotes()))
3187 Pieces.push_front(I);
3190 for (
const auto &I : report->
getFixits())
3191 Pieces.back()->addFixit(I);
3199 Pieces.push_front(std::make_shared<PathDiagnosticEventPiece>(
3201 "[debug] analyzing from " +
3215 if (
const auto FD = dyn_cast<FunctionDecl>(Signature)) {
3216 SignatureSourceRange = FD->getSourceRange();
3217 }
else if (
const auto OD = dyn_cast<ObjCMethodDecl>(Signature)) {
3218 SignatureSourceRange = OD->getSourceRange();
3224 : SignatureSourceRange.
getEnd();
3231 for (
unsigned Line = StartLine;
Line <= EndLine;
Line++)
3232 ExecutedLines[FID].insert(
Line);
3244 ExecutedLines[FID].insert(LineNo);
3249static std::unique_ptr<FilesToLineNumsMap>
3251 auto ExecutedLines = std::make_unique<FilesToLineNumsMap>();
3260 const Decl *D = CE->getCalleeStackFrame()->getDecl();
3271 if (
const auto *RS = dyn_cast_or_null<ReturnStmt>(P)) {
3276 if (isa_and_nonnull<SwitchCase, LabelStmt>(P))
3282 return ExecutedLines;
3285std::unique_ptr<DiagnosticForConsumerMapTy>
3288 ArrayRef<std::unique_ptr<PathDiagnosticConsumer>> consumers,
3291 auto Out = std::make_unique<DiagnosticForConsumerMapTy>();
3292 for (
const auto &Consumer : consumers)
3293 (*Out)[Consumer.get()] =
3308 "The call piece should not be in a header file.");
3320 if (
auto *CPInner = dyn_cast<PathDiagnosticCallPiece>(Path.back().get()))
3328 if (PD.
path.empty())
3337 if (
auto *CP = dyn_cast<PathDiagnosticCallPiece>(LastP)) {
3344 const auto *ND = dyn_cast<NamedDecl>(CP->
getCallee());
3347 llvm::raw_svector_ostream os(buf);
3348 os <<
" (within a call to '" << ND->getDeclName() <<
"')";
3361std::unique_ptr<DiagnosticForConsumerMapTy>
3362PathSensitiveBugReporter::generateDiagnosticForConsumerMap(
3364 ArrayRef<std::unique_ptr<PathDiagnosticConsumer>> consumers,
3365 ArrayRef<BugReport *> bugReports) {
3368 consumers, bugReports);
3374 assert(!bugReports.empty());
3375 MaxBugClassSize.updateMax(bugReports.size());
3378 ArrayRef<PathSensitiveBugReport *> convertedArrayOfReports(
3379 reinterpret_cast<PathSensitiveBugReport *
const *
>(&*bugReports.begin()),
3380 reinterpret_cast<PathSensitiveBugReport *
const *
>(&*bugReports.end()));
3382 consumers, convertedArrayOfReports);
3387 MaxValidBugClassSize.updateMax(bugReports.size());
3392 for (
auto const &P : *Out)
3393 if (Opts.ShouldReportIssuesInMainSourceFile && !Opts.
AnalyzeAll)
3401 StringRef Name, StringRef Category,
3411 StringRef name, StringRef category,
3416 BugType *BT = getBugTypeForName(CheckName, name, category);
3417 auto R = std::make_unique<BasicBugReport>(*BT, str,
Loc);
3418 R->setDeclWithIssue(DeclWithIssue);
3419 for (
const auto &SR : Ranges)
3421 for (
const auto &FH : Fixits)
3422 R->addFixItHint(FH);
3427 StringRef name, StringRef category) {
3429 llvm::raw_svector_ostream(fullDesc)
3430 << CheckName <<
":" << name <<
":" << category;
3431 std::unique_ptr<BugType> &BT = StrBugTypes[fullDesc];
3433 BT = std::make_unique<BugType>(CheckName, name, category);
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 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 isContainedByStmt(const ParentMap &PM, const Stmt *S, const Stmt *SubS)
constexpr llvm::StringLiteral StrEnteringLoop
static PathDiagnosticLocation getEnclosingStmtLocation(const Stmt *S, const StackFrame *SF, bool allowNestedContexts=false)
static void addEdgeToPath(PathPieces &path, PathDiagnosticLocation &PrevLoc, PathDiagnosticLocation NewLoc)
Adds a sanitized control-flow diagnostic edge to a path.
static void addContextEdges(PathPieces &pieces, const StackFrame *SF)
Adds synthetic edges from top-level statements to their subexpressions.
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 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.
Result
Implement __builtin_bit_cast and related operations.
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
const StackFrame * getStackFrame(const StackFrame *ParentSF, const void *Data, const Expr *E, const CFGBlock *Blk, unsigned BlockCount, unsigned Index)
Obtain a context of the call stack using its parent context.
bool isBodyAutosynthesizedFromModelFile() const
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
const Stmt * getTerminatorCondition(bool StripParens=true) const
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 StackFrame * getCalleeStackFrame() const
SourceLocation getEnd() 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) const
EvaluateKnownConstInt - Call EvaluateAsRValue and return the folded integer.
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.
unsigned getExpansionLineNumber(bool *Invalid=nullptr) const
IfStmt - This represents an if/then/else.
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.
T castAs() const
Convert to the specified ProgramPoint type, asserting that this ProgramPoint is of the desired type.
const StackFrame * getStackFrame() const
std::optional< T > getAs() const
Convert to the specified ProgramPoint type, returning std::nullopt if this ProgramPoint is not of the...
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.
FileID getFileID(SourceLocation SpellingLoc) const
Return the FileID for a SourceLocation.
unsigned getFileOffset(SourceLocation SpellingLoc) const
Returns the offset from the start of the file that the specified SourceLocation represents.
unsigned getExpansionLineNumber(SourceLocation Loc, bool *Invalid=nullptr) const
CharSourceRange getExpansionRange(SourceLocation Loc) const
Given a SourceLocation object, return the range of tokens covered by the expansion in the ultimate fi...
bool isWrittenInSameFile(SourceLocation Loc1, SourceLocation Loc2) const
Returns true if the spelling locations for both SourceLocations are part of the same file buffer.
StringRef getFilename(SourceLocation SpellingLoc) const
Return the filename of the file containing a SourceLocation.
SourceLocation getExpansionLoc(SourceLocation Loc) const
Given a SourceLocation object Loc, return the expansion location referenced by the ID.
bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const
Determines the order of 2 source locations in the translation unit.
std::optional< llvm::MemoryBufferRef > getBufferOrNone(FileID FID, SourceLocation Loc=SourceLocation()) const
Return the buffer for the specified FileID.
A trivial tuple used to represent a source range.
SourceLocation getEnd() const
SourceLocation getBegin() const
It represents a stack frame of the call stack.
const ParentMap & getParentMap() const
LLVM_ATTRIBUTE_RETURNS_NONNULL AnalysisDeclContext * getAnalysisDeclContext() const
const Expr * getCallSite() const
const Decl * getDecl() 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)
void Profile(llvm::FoldingSetNodeID &hash) const override
Reports are uniqued to ensure that we do not emit multiple diagnostics for each bug.
This class provides an interface through which checkers can create individual bug reports.
BugReport(Kind kind, const BugType &bt, const llvm::Twine &desc)
llvm::ArrayRef< FixItHint > getFixits() const
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()
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 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()
SVal getSVal(const Expr *E) const
Get the value of an arbitrary expression at this node.
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
std::optional< T > getLocationAs() const &
ExplodedNode * getFirstPred()
const ExplodedNode *const * const_succ_iterator
const StackFrame * getStackFrame() const
Suppress reports that might lead to known false positives.
MemRegion - The root abstract class for all memory regions.
Prints path notes when a message is sent to a nil receiver.
PathDiagnosticLocation getLocation() const override
void setCallee(const CallEnter &CE, const SourceManager &SM)
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
static SourceLocation getValidSourceLocation(const Stmt *S, StackFrameOrAnalysisDeclContext SFAC, bool UseEndOfStatement=false)
Construct a source location that corresponds to either the beginning or the end of the given statemen...
static PathDiagnosticLocation createDeclEnd(const StackFrame *SF, const SourceManager &SM)
Constructs a location for the end of the enclosing declaration body.
void Profile(llvm::FoldingSetNodeID &ID) const
const SourceManager & getManager() const
static PathDiagnosticLocation createEnd(const Stmt *S, const SourceManager &SM, const StackFrameOrAnalysisDeclContext SFAC)
Create a location for the end of the statement.
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 PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
FullSourceLoc asLocation() const
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.
SmallVector< std::unique_ptr< BugReporterVisitor >, 8 > VisitorList
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.
PathSensitiveBugReport(const BugType &bt, const llvm::Twine &desc, const ExplodedNode *errorNode)
const Decl * getDeclWithIssue() const override
The smallest declaration that contains the bug location.
PathDiagnosticLocation UniqueingLocation
Reports with different uniqueing locations are considered to be different for the purposes of dedupli...
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 ExplodedNode * getErrorNode() const
llvm::SmallPtrSet< const StackFrame *, 2 > InterestingStackFrames
A set of stack frames that correspond to call sites which should be considered "interesting".
const ExplodedNode * ErrorNode
The ExplodedGraph node against which the report was thrown.
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.
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.
const Decl * UniqueingDecl
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
const SymExpr * SymbolRef
@ CF
Indicates that the tracked object is a CF object.
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
std::map< FileID, std::set< unsigned > > FilesToLineNumsMap
File IDs mapped to sets of line numbers.
bool EQ(InterpState &S, CodePtr OpPC)
std::variant< struct RequiresDecl, struct HeaderDecl, struct UmbrellaDirDecl, struct ModuleDecl, struct ExcludeDecl, struct ExportDecl, struct ExportAsDecl, struct ExternModuleDecl, struct UseDecl, struct LinkDecl, struct ConfigMacrosDecl, struct ConflictDecl > Decl
All declarations that can appear in a module declaration.
Top level wrappers for InstallAPI frontend operations.
bool isa(CodeGen::Address addr)
const FunctionProtoType * T
U cast(CodeGen::Address addr)
Diagnostic wrappers for TextAPI types for error reporting.