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 {
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();
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())) {
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 if (os.str().empty())
629 os <<
"Execution continues on line "
630 << getSourceManager().getExpansionLineNumber(
Loc.asLocation())
633 os <<
"Execution jumps to the end of the ";
634 const Decl *D =
C.getCurrStackFrame()->getDecl();
641 os <<
"anonymous block";
658 case Stmt::ForStmtClass:
659 case Stmt::DoStmtClass:
660 case Stmt::WhileStmtClass:
661 case Stmt::ObjCForCollectionStmtClass:
662 case Stmt::CXXForRangeStmtClass:
673 bool allowNestedContexts =
false) {
680 switch (Parent->getStmtClass()) {
681 case Stmt::BinaryOperatorClass: {
683 if (B->isLogicalOp())
687 case Stmt::CompoundStmtClass:
688 case Stmt::StmtExprClass:
690 case Stmt::ChooseExprClass:
697 case Stmt::BinaryConditionalOperatorClass:
698 case Stmt::ConditionalOperatorClass:
701 if (allowNestedContexts ||
706 case Stmt::CXXForRangeStmtClass:
710 case Stmt::DoStmtClass:
712 case Stmt::ForStmtClass:
716 case Stmt::IfStmtClass:
720 case Stmt::ObjCForCollectionStmtClass:
724 case Stmt::WhileStmtClass:
735 assert(S &&
"Cannot have null Stmt for PathDiagnosticLocation");
754void PathDiagnosticBuilder::updateStackPiecesWithMessage(
756 if (
R->hasCallStackHint(P))
757 for (
const auto &I : CallStack) {
760 std::string stackMsg =
R->getCallStackMessage(P, N);
771 const SourceManager&
SM);
774 const PathDiagnosticConstruct &
C,
const CFGBlock *Dst,
777 const SourceManager &
SM = getSourceManager();
780 llvm::raw_string_ostream os(sbuf);
783 if (
const Stmt *S = Dst->
getLabel()) {
788 os <<
"No cases match in the switch statement. "
789 "Control jumps to line "
792 case Stmt::DefaultStmtClass:
793 os <<
"Control jumps to the 'default' case at line "
797 case Stmt::CaseStmtClass: {
798 os <<
"Control jumps to 'case ";
800 const Expr *LHS = Case->getLHS()->IgnoreParenImpCasts();
803 bool GetRawInt =
true;
805 if (
const auto *DR = dyn_cast<DeclRefExpr>(LHS)) {
808 const auto *D = dyn_cast<EnumConstantDecl>(DR->getDecl());
824 os <<
"'Default' branch taken. ";
825 End = ExecutionContinues(os,
C);
827 return std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, sbuf);
831 const PathDiagnosticConstruct &
C,
const Stmt *S,
834 llvm::raw_string_ostream os(sbuf);
838 return std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, sbuf);
842 const PathDiagnosticConstruct &
C,
const Stmt *T,
const CFGBlock *Src,
843 const CFGBlock *Dst)
const {
845 const SourceManager &
SM = getSourceManager();
849 llvm::raw_string_ostream os(sbuf);
850 os <<
"Left side of '";
853 if (B->getOpcode() == BO_LAnd) {
865 End = ExecutionContinues(
C);
868 assert(B->getOpcode() == BO_LOr);
875 End = ExecutionContinues(
C);
883 return std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, sbuf);
886void PathDiagnosticBuilder::generateMinimalDiagForBlockEdge(
887 PathDiagnosticConstruct &
C, BlockEdge BE)
const {
888 const SourceManager &
SM = getSourceManager();
889 const StackFrame *SF =
C.getCurrStackFrame();
890 const CFGBlock *Src = BE.
getSrc();
891 const CFGBlock *Dst = BE.
getDst();
901 case Stmt::GotoStmtClass:
902 case Stmt::IndirectGotoStmtClass: {
903 if (
const Stmt *S =
C.getCurrentNode()->getNextStmtForDiagnostics())
904 C.getActivePath().push_front(generateDiagForGotoOP(
C, S, Start));
908 case Stmt::SwitchStmtClass: {
909 C.getActivePath().push_front(generateDiagForSwitchOP(
C, Dst, Start));
913 case Stmt::BreakStmtClass:
914 case Stmt::ContinueStmtClass: {
916 llvm::raw_string_ostream os(sbuf);
918 C.getActivePath().push_front(
919 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, sbuf));
924 case Stmt::BinaryConditionalOperatorClass:
925 case Stmt::ConditionalOperatorClass: {
927 llvm::raw_string_ostream os(sbuf);
928 os <<
"'?' condition is ";
937 if (
const Stmt *S = End.
asStmt())
940 C.getActivePath().push_front(
941 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, sbuf));
946 case Stmt::BinaryOperatorClass: {
947 if (!
C.supportsLogicalOpControlFlow())
950 C.getActivePath().push_front(generateDiagForBinaryOP(
C, T, Src, Dst));
954 case Stmt::DoStmtClass:
957 llvm::raw_string_ostream os(sbuf);
959 os <<
"Loop condition is true. ";
962 if (
const Stmt *S = End.
asStmt())
965 C.getActivePath().push_front(
966 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, sbuf));
970 if (
const Stmt *S = End.
asStmt())
973 C.getActivePath().push_front(
974 std::make_shared<PathDiagnosticControlFlowPiece>(
975 Start, End,
"Loop condition is false. Exiting loop"));
979 case Stmt::WhileStmtClass:
980 case Stmt::ForStmtClass:
983 llvm::raw_string_ostream os(sbuf);
985 os <<
"Loop condition is false. ";
987 if (
const Stmt *S = End.
asStmt())
990 C.getActivePath().push_front(
991 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, sbuf));
994 if (
const Stmt *S = End.
asStmt())
997 C.getActivePath().push_front(
998 std::make_shared<PathDiagnosticControlFlowPiece>(
999 Start, End,
"Loop condition is true. Entering loop body"));
1004 case Stmt::IfStmtClass: {
1007 if (
const Stmt *S = End.
asStmt())
1011 C.getActivePath().push_front(
1012 std::make_shared<PathDiagnosticControlFlowPiece>(
1013 Start, End,
"Taking false branch"));
1015 C.getActivePath().push_front(
1016 std::make_shared<PathDiagnosticControlFlowPiece>(
1017 Start, End,
"Taking true branch"));
1030 case Stmt::ForStmtClass:
1031 case Stmt::WhileStmtClass:
1032 case Stmt::ObjCForCollectionStmtClass:
1033 case Stmt::CXXForRangeStmtClass:
1062 const Stmt *S = SP->getStmt();
1072 const Stmt *LoopBody =
nullptr;
1074 case Stmt::CXXForRangeStmtClass: {
1080 LoopBody = FR->getBody();
1083 case Stmt::ForStmtClass: {
1087 LoopBody = FS->getBody();
1090 case Stmt::ObjCForCollectionStmtClass: {
1092 LoopBody = FC->getBody();
1095 case Stmt::WhileStmtClass:
1126 std::make_shared<PathDiagnosticControlFlowPiece>(NewLoc, PrevLoc));
1134 if (
const auto *FS = dyn_cast_or_null<ObjCForCollectionStmt>(S))
1135 return FS->getElement();
1142 "Loop body skipped when range is empty";
1144 "Loop body skipped when collection is empty";
1146static std::unique_ptr<FilesToLineNumsMap>
1149void PathDiagnosticBuilder::generatePathDiagnosticsForNode(
1160 if (
C.shouldAddPathEdges()) {
1162 const StackFrame *CalleeSF = CE->getCalleeStackFrame();
1176 bool VisitedEntireCall =
C.PD->isWithinCall();
1177 C.PD->popActivePath();
1180 if (VisitedEntireCall) {
1185 const Decl *Caller = CE->getStackFrame()->getDecl();
1187 assert(
C.getActivePath().size() == 1 &&
1188 C.getActivePath().front().get() ==
Call);
1192 assert(
C.isInStackFrameMap(&
C.getActivePath()) &&
1193 "When we ascend to a previously unvisited call, the active path's "
1194 "address shouldn't change, but rather should be compacted into "
1195 "a single CallEvent!");
1196 C.updateStackFrameMap(&
C.getActivePath(),
C.getCurrStackFrame());
1199 assert(!
C.isInStackFrameMap(&
Call->path) &&
1200 "When we ascend to a previously unvisited call, this must be the "
1201 "first time we encounter the caller stack frame!");
1202 C.updateStackFrameMap(&
Call->path, CE->getCalleeStackFrame());
1207 PrevLoc =
Call->getLocation();
1209 if (!
C.CallStack.empty()) {
1210 assert(
C.CallStack.back().first ==
Call);
1211 C.CallStack.pop_back();
1216 assert(
C.getCurrStackFrame() ==
C.getStackFrameForActivePath() &&
1217 "The current position in the bug path is out of sync with the "
1218 "stack frame associated with the active path!");
1221 if (std::optional<CallExitEnd> CE = P.
getAs<CallExitEnd>()) {
1227 assert(!
C.isInStackFrameMap(&
Call->path) &&
1228 "We just entered a call, this must've been the first time we "
1229 "encounter its stack frame!");
1230 C.updateStackFrameMap(&
Call->path, CE->getCalleeStackFrame());
1232 if (
C.shouldAddPathEdges()) {
1238 auto *P =
Call.get();
1239 C.getActivePath().push_front(std::move(
Call));
1242 C.PD->pushActivePath(&P->path);
1243 C.CallStack.push_back(CallWithEntry(P,
C.getCurrentNode()));
1247 if (
auto PS = P.
getAs<PostStmt>()) {
1248 if (!
C.shouldAddPathEdges())
1260 }
else if (
auto BE = P.
getAs<BlockEdge>()) {
1262 if (
C.shouldAddControlNotes()) {
1263 generateMinimalDiagForBlockEdge(
C, *BE);
1266 if (!
C.shouldAddPathEdges()) {
1273 const Stmt *Body =
nullptr;
1275 if (
const auto *FS = dyn_cast<ForStmt>(
Loop))
1276 Body = FS->getBody();
1277 else if (
const auto *WS = dyn_cast<WhileStmt>(
Loop))
1278 Body = WS->getBody();
1279 else if (
const auto *OFS = dyn_cast<ObjCForCollectionStmt>(
Loop)) {
1280 Body = OFS->getBody();
1281 }
else if (
const auto *FRS = dyn_cast<CXXForRangeStmt>(
Loop)) {
1282 Body = FRS->getBody();
1286 auto p = std::make_shared<PathDiagnosticEventPiece>(
1287 L,
"Looping back to the head of the loop");
1288 p->setPrunable(
true);
1292 if (!
C.shouldAddControlNotes()) {
1293 C.getActivePath().push_front(std::move(p));
1296 if (
const auto *CS = dyn_cast_or_null<CompoundStmt>(Body)) {
1302 const CFGBlock *BSrc = BE->
getSrc();
1303 const ParentMap &PM =
C.getParentMap();
1316 if (!IsInLoopBody) {
1331 C.getCurrStackFrame());
1332 auto PE = std::make_shared<PathDiagnosticEventPiece>(L, str);
1333 PE->setPrunable(
true);
1337 if (!
C.shouldAddControlNotes()) {
1338 C.getActivePath().push_front(std::move(PE));
1349static std::unique_ptr<PathDiagnostic>
1351 const Decl *AnalysisEntryPoint) {
1352 const BugType &BT = R->getBugType();
1353 return std::make_unique<PathDiagnostic>(
1355 R->getDescription(), R->getShortDescription(
false),
1356 BT.
getCategory(), R->getUniqueingLocation(), R->getUniqueingDecl(),
1357 AnalysisEntryPoint, std::make_unique<FilesToLineNumsMap>());
1360static std::unique_ptr<PathDiagnostic>
1363 const Decl *AnalysisEntryPoint) {
1364 const BugType &BT = R->getBugType();
1365 return std::make_unique<PathDiagnostic>(
1367 R->getDescription(), R->getShortDescription(
false),
1368 BT.
getCategory(), R->getUniqueingLocation(), R->getUniqueingDecl(),
1393 case Stmt::BinaryOperatorClass: {
1395 if (!BO->isLogicalOp())
1397 return BO->getLHS() ==
Cond || BO->getRHS() ==
Cond;
1399 case Stmt::IfStmtClass:
1401 case Stmt::ForStmtClass:
1403 case Stmt::WhileStmtClass:
1405 case Stmt::DoStmtClass:
1407 case Stmt::ChooseExprClass:
1409 case Stmt::IndirectGotoStmtClass:
1411 case Stmt::SwitchStmtClass:
1413 case Stmt::BinaryConditionalOperatorClass:
1415 case Stmt::ConditionalOperatorClass: {
1417 return CO->getCond() ==
Cond ||
1418 CO->getLHS() ==
Cond ||
1419 CO->getRHS() ==
Cond;
1421 case Stmt::ObjCForCollectionStmtClass:
1423 case Stmt::CXXForRangeStmtClass: {
1425 return FRS->getCond() ==
Cond || FRS->getRangeInit() ==
Cond;
1433 if (
const auto *FS = dyn_cast<ForStmt>(FL))
1434 return FS->getInc() == S || FS->getInit() == S;
1435 if (
const auto *FRS = dyn_cast<CXXForRangeStmt>(FL))
1436 return FRS->getInc() == S || FRS->getRangeStmt() == S ||
1437 FRS->getLoopVarStmt() || FRS->getRangeInit() == S;
1450 PathPieces::iterator Prev = pieces.end();
1451 for (PathPieces::iterator I = pieces.begin(), E = Prev; I != E;
1453 auto *Piece = dyn_cast<PathDiagnosticControlFlowPiece>(I->get());
1462 const Stmt *InnerStmt =
nullptr;
1463 while (NextSrcContext.
isValid() && NextSrcContext.
asStmt() != InnerStmt) {
1464 SrcContexts.push_back(NextSrcContext);
1465 InnerStmt = NextSrcContext.
asStmt();
1474 const Stmt *Dst = Piece->getEndLocation().getStmtOrNull();
1484 if (llvm::is_contained(SrcContexts, DstContext))
1488 Piece->setStartLocation(DstContext);
1493 auto *PrevPiece = dyn_cast<PathDiagnosticControlFlowPiece>(Prev->get());
1496 if (
const Stmt *PrevSrc =
1497 PrevPiece->getStartLocation().getStmtOrNull()) {
1499 if (PrevSrcParent ==
1501 PrevPiece->setEndLocation(DstContext);
1512 std::make_shared<PathDiagnosticControlFlowPiece>(SrcLoc, DstContext);
1514 I = pieces.insert(I, std::move(P));
1530 for (PathPieces::iterator I = pieces.begin(), E = pieces.end(); I != E; ++I) {
1531 const auto *PieceI = dyn_cast<PathDiagnosticControlFlowPiece>(I->get());
1536 const Stmt *s1Start = PieceI->getStartLocation().getStmtOrNull();
1537 const Stmt *s1End = PieceI->getEndLocation().getStmtOrNull();
1539 if (!s1Start || !s1End)
1542 PathPieces::iterator NextI = I; ++NextI;
1552 const auto *EV = dyn_cast<PathDiagnosticEventPiece>(NextI->get());
1554 StringRef S = EV->getString();
1563 PieceNextI = dyn_cast<PathDiagnosticControlFlowPiece>(NextI->get());
1573 if (!s2Start || !s2End || s1End != s2Start)
1589 I = pieces.erase(I);
1602 SM.getExpansionRange(
Range.getEnd()).getEnd());
1605 if (FID !=
SM.getFileID(ExpansionRange.
getEnd()))
1606 return std::nullopt;
1608 std::optional<MemoryBufferRef> Buffer =
SM.getBufferOrNone(FID);
1610 return std::nullopt;
1612 unsigned BeginOffset =
SM.getFileOffset(ExpansionRange.
getBegin());
1613 unsigned EndOffset =
SM.getFileOffset(ExpansionRange.
getEnd());
1614 StringRef Snippet = Buffer->getBuffer().slice(BeginOffset, EndOffset);
1620 if (Snippet.find_first_of(
"\r\n") != StringRef::npos)
1621 return std::nullopt;
1624 return Snippet.size();
1650 for (PathPieces::iterator I = Path.begin(), E = Path.end(); I != E; ) {
1652 const auto *PieceI = dyn_cast<PathDiagnosticControlFlowPiece>(I->get());
1659 const Stmt *s1Start = PieceI->getStartLocation().getStmtOrNull();
1660 const Stmt *s1End = PieceI->getEndLocation().getStmtOrNull();
1662 PathPieces::iterator NextI = I; ++NextI;
1666 const auto *PieceNextI =
1667 dyn_cast<PathDiagnosticControlFlowPiece>(NextI->get());
1674 PieceNextI = dyn_cast<PathDiagnosticControlFlowPiece>(NextI->get());
1683 const Stmt *s2Start = PieceNextI->getStartLocation().getStmtOrNull();
1684 const Stmt *s2End = PieceNextI->getEndLocation().getStmtOrNull();
1686 if (s1Start && s2Start && s1Start == s2End && s2Start == s1End) {
1687 const size_t MAX_SHORT_LINE_LENGTH = 80;
1689 if (s1Length && *s1Length <= MAX_SHORT_LINE_LENGTH) {
1691 if (s2Length && *s2Length <= MAX_SHORT_LINE_LENGTH) {
1693 I = Path.erase(NextI);
1716 bool erased =
false;
1718 for (PathPieces::iterator I = path.begin(), E = path.end(); I != E;
1722 const auto *PieceI = dyn_cast<PathDiagnosticControlFlowPiece>(I->get());
1727 const Stmt *start = PieceI->getStartLocation().getStmtOrNull();
1728 const Stmt *end = PieceI->getEndLocation().getStmtOrNull();
1743 if (!
SM.isWrittenInSameFile(FirstLoc, SecondLoc))
1745 if (
SM.isBeforeInTranslationUnit(SecondLoc, FirstLoc))
1746 std::swap(SecondLoc, FirstLoc);
1755 const size_t MAX_PUNY_EDGE_LENGTH = 2;
1756 if (*ByteWidth <= MAX_PUNY_EDGE_LENGTH) {
1768 for (PathPieces::iterator I = path.begin(), E = path.end(); I != E; ++I) {
1769 const auto *PieceI = dyn_cast<PathDiagnosticEventPiece>(I->get());
1774 PathPieces::iterator NextI = I; ++NextI;
1778 const auto *PieceNextI = dyn_cast<PathDiagnosticEventPiece>(NextI->get());
1784 if (PieceI->getString() == PieceNextI->getString()) {
1792 bool hasChanges =
false;
1798 for (PathPieces::iterator I = path.begin(), E = path.end(); I != E; ) {
1800 if (
auto *CallI = dyn_cast<PathDiagnosticCallPiece>(I->get())) {
1803 if (!OCS.count(CallI)) {
1813 auto *PieceI = dyn_cast<PathDiagnosticControlFlowPiece>(I->get());
1820 const Stmt *s1Start = PieceI->getStartLocation().getStmtOrNull();
1821 const Stmt *s1End = PieceI->getEndLocation().getStmtOrNull();
1825 PathPieces::iterator NextI = I; ++NextI;
1829 const auto *PieceNextI = dyn_cast<PathDiagnosticControlFlowPiece>(NextI->get());
1836 const Stmt *s2Start = PieceNextI->getStartLocation().getStmtOrNull();
1837 const Stmt *s2End = PieceNextI->getEndLocation().getStmtOrNull();
1855 if (level1 && level1 == level2 && level1 == level3 && level1 == level4) {
1856 PieceI->setEndLocation(PieceNextI->getEndLocation());
1869 if (s1End && s1End == s2Start && level2) {
1870 bool removeEdge =
false;
1896 else if (s1Start && s2End &&
1909 else if (s1Start && s2End &&
1911 SourceRange EdgeRange(PieceI->getEndLocation().asLocation(),
1912 PieceI->getStartLocation().asLocation());
1919 PieceI->setEndLocation(PieceNextI->getEndLocation());
1933 if (s1End == s2Start) {
1934 const auto *FS = dyn_cast_or_null<ObjCForCollectionStmt>(level3);
1935 if (FS && FS->getCollection()->IgnoreParens() == s2Start &&
1936 s2End == FS->getElement()) {
1937 PieceI->setEndLocation(PieceNextI->getEndLocation());
1974 const auto *FirstEdge =
1975 dyn_cast<PathDiagnosticControlFlowPiece>(Path.front().get());
1979 const Decl *D =
C.getStackFrameFor(&Path)->getDecl();
1982 if (FirstEdge->getStartLocation() != EntryLoc)
1994 for (
const auto &P : path) {
1997 unsigned LineNo =
Loc.getLineNumber();
1999 ExecutedLines[FID].insert(LineNo);
2003PathDiagnosticConstruct::PathDiagnosticConstruct(
2006 : Consumer(PDC), CurrentNode(ErrorNode),
2007 SM(CurrentNode->getCodeDecl().getASTContext().getSourceManager()),
2009 AnalysisEntryPoint)) {
2013PathDiagnosticBuilder::PathDiagnosticBuilder(
2016 std::unique_ptr<VisitorsDiagnosticsTy> VisitorsDiagnostics)
2018 ErrorNode(ErrorNode),
2019 VisitorsDiagnostics(
std::
move(VisitorsDiagnostics)) {}
2021std::unique_ptr<PathDiagnostic>
2023 const Decl *EntryPoint = getBugReporter().getAnalysisEntryPoint();
2024 PathDiagnosticConstruct Construct(PDC, ErrorNode, R, EntryPoint);
2026 const SourceManager &
SM = getSourceManager();
2027 const AnalyzerOptions &Opts = getAnalyzerOptions();
2033 auto EndNotes = VisitorsDiagnostics->find(ErrorNode);
2035 if (EndNotes != VisitorsDiagnostics->end()) {
2036 assert(!EndNotes->second.empty());
2037 LastPiece = EndNotes->second[0];
2042 Construct.PD->setEndOfPath(LastPiece);
2044 PathDiagnosticLocation PrevLoc = Construct.PD->getLocation();
2047 while (Construct.ascendToPrevNode()) {
2048 generatePathDiagnosticsForNode(Construct, PrevLoc);
2050 auto VisitorNotes = VisitorsDiagnostics->find(Construct.getCurrentNode());
2051 if (VisitorNotes == VisitorsDiagnostics->end())
2056 std::set<llvm::FoldingSetNodeID> DeduplicationSet;
2060 llvm::FoldingSetNodeID
ID;
2062 if (!DeduplicationSet.insert(ID).second)
2067 updateStackPiecesWithMessage(
Note, Construct.CallStack);
2068 Construct.getActivePath().push_front(
Note);
2075 const StackFrame *CalleeSF = Construct.getStackFrameForActivePath();
2083 if (!Construct.PD->path.empty()) {
2084 if (
R->shouldPrunePath() && Opts.ShouldPrunePaths) {
2085 bool stillHasNotes =
2087 assert(stillHasNotes);
2088 (void)stillHasNotes;
2092 if (!Opts.ShouldAddPopUpNotes)
2105 while (
optimizeEdges(Construct, Construct.getMutablePieces(), OCS)) {
2120 if (Opts.ShouldDisplayMacroExpansions)
2123 return std::move(Construct.PD);
2130void BugType::anchor() {}
2136LLVM_ATTRIBUTE_USED
static bool
2138 for (
const std::pair<StringRef, StringRef> &Pair : Registry.Dependencies) {
2139 if (Pair.second == CheckerName)
2146 StringRef CheckerName) {
2148 if (
Checker.FullName == CheckerName)
2152 "Checker name not found in CheckerRegistry -- did you retrieve it "
2153 "correctly from CheckerManager::getCurrentCheckerName?");
2157 const BugType &bt, StringRef shortDesc, StringRef desc,
2159 const Decl *DeclToUnique)
2163 assert(
ErrorNode &&
"The error node must be non-null!");
2165 ->getAnalysisManager()
2166 .getCheckerManager()
2167 ->getCheckerRegistryData(),
2169 "Some checkers depend on this one! We don't allow dependency "
2170 "checkers to emit warnings, because checkers should depend on "
2171 "*modeling*, not *diagnostics*.");
2175 ->getAnalysisManager()
2176 .getCheckerManager()
2177 ->getCheckerRegistryData(),
2179 "Hidden checkers musn't emit diagnostics as they are by definition "
2180 "non-user facing!");
2184 std::unique_ptr<BugReporterVisitor> visitor) {
2188 llvm::FoldingSetNodeID ID;
2189 visitor->Profile(ID);
2191 void *InsertPos =
nullptr;
2196 Callbacks.push_back(std::move(visitor));
2211 hash.AddInteger(
static_cast<int>(
getKind()));
2212 hash.AddPointer(&
BT);
2214 assert(Location.isValid());
2215 Location.Profile(hash);
2218 if (!range.isValid())
2220 hash.Add(range.getBegin());
2221 hash.Add(range.getEnd());
2226 hash.AddInteger(
static_cast<int>(
getKind()));
2227 hash.AddPointer(&
BT);
2237 hash.AddPointer(
ErrorNode->getCurrentOrPreviousStmtForDiagnostics());
2241 if (!range.isValid())
2243 hash.Add(range.getBegin());
2244 hash.Add(range.getEnd());
2250 llvm::DenseMap<T, bugreporter::TrackingKind> &InterestingnessMap, T Val,
2252 auto Result = InterestingnessMap.insert({Val, TKind});
2272 "BugReport::markInteresting currently can only handle 2 different "
2273 "tracking kinds! Please define what tracking kind should this entitiy"
2274 "have, if it was already marked as interesting with a different kind!");
2286 if (
const auto *meta = dyn_cast<SymbolMetadata>(sym))
2298 if (
const auto *meta = dyn_cast<SymbolMetadata>(sym))
2307 R = R->getBaseRegion();
2310 if (
const auto *SR = dyn_cast<SymbolicRegion>(R))
2318 R = R->getBaseRegion();
2321 if (
const auto *SR = dyn_cast<SymbolicRegion>(R))
2337std::optional<bugreporter::TrackingKind>
2356 "BugReport::getInterestingnessKind currently can only handle 2 different "
2357 "tracking kinds! Please define what tracking kind should we return here "
2358 "when the kind of getAsRegion() and getAsSymbol() is different!");
2359 return std::nullopt;
2362std::optional<bugreporter::TrackingKind>
2365 return std::nullopt;
2370 return std::nullopt;
2371 return It->getSecond();
2374std::optional<bugreporter::TrackingKind>
2377 return std::nullopt;
2379 R = R->getBaseRegion();
2382 return It->getSecond();
2384 if (
const auto *SR = dyn_cast<SymbolicRegion>(R))
2386 return std::nullopt;
2412 const Stmt *S =
nullptr;
2416 if (BE->getBlock() == &Exit)
2417 S =
ErrorNode->getPreviousStmtForDiagnostics();
2459 assert(
ErrorNode &&
"Cannot create a location with a null node.");
2466 .getSourceManager();
2479 S =
ErrorNode->getNextStmtForDiagnostics();
2486 if (
const auto *AS = dyn_cast<AttributedStmt>(S))
2487 S = AS->getSubStmt();
2490 if (
const auto *ME = dyn_cast<MemberExpr>(S))
2494 if (
const auto *B = dyn_cast<BinaryOperator>(S))
2515 return Eng.getGraph();
2519 return Eng.getStateManager();
2523 : D(D), UserSuppressions(D.getASTContext()) {}
2527 assert(StrBugTypes.empty() &&
2528 "Destroying BugReporter before diagnostics are emitted!");
2531 for (
const auto I : EQClassesVector)
2538 for (
const auto EQ : EQClassesVector)
2545 StrBugTypes.clear();
2558 std::unique_ptr<ExplodedGraph> BugPath;
2565class BugPathGetter {
2566 std::unique_ptr<ExplodedGraph> TrimmedGraph;
2568 using PriorityMapTy = llvm::DenseMap<const ExplodedNode *, unsigned>;
2571 PriorityMapTy PriorityMap;
2575 using ReportNewNodePair =
2576 std::pair<PathSensitiveBugReport *, const ExplodedNode *>;
2579 BugPathInfo CurrentBugPath;
2582 template <
bool Descending>
2583 class PriorityCompare {
2584 const PriorityMapTy &PriorityMap;
2587 PriorityCompare(
const PriorityMapTy &M) : PriorityMap(M) {}
2590 PriorityMapTy::const_iterator LI = PriorityMap.find(LHS);
2591 PriorityMapTy::const_iterator RI = PriorityMap.find(RHS);
2592 PriorityMapTy::const_iterator E = PriorityMap.end();
2599 return Descending ? LI->second > RI->second
2600 : LI->second < RI->second;
2603 bool operator()(
const ReportNewNodePair &LHS,
2604 const ReportNewNodePair &RHS)
const {
2605 return (*
this)(LHS.second, RHS.second);
2610 BugPathGetter(
const ExplodedGraph *OriginalGraph,
2611 ArrayRef<PathSensitiveBugReport *> &bugReports);
2613 BugPathInfo *getNextBugPath();
2618BugPathGetter::BugPathGetter(
const ExplodedGraph *OriginalGraph,
2619 ArrayRef<PathSensitiveBugReport *> &bugReports) {
2620 SmallVector<const ExplodedNode *, 32> Nodes;
2621 for (
const auto I : bugReports) {
2622 assert(I->isValid() &&
2623 "We only allow BugReporterVisitors and BugReporter itself to "
2624 "invalidate reports!");
2625 Nodes.emplace_back(I->getErrorNode());
2631 TrimmedGraph = OriginalGraph->
trim(Nodes, &ForwardMap);
2636 llvm::SmallPtrSet<const ExplodedNode *, 32> RemainingNodes;
2641 "Failed to construct a trimmed graph that contains this error "
2643 ReportNodes.emplace_back(
Report, NewNode);
2644 RemainingNodes.insert(NewNode);
2647 assert(!RemainingNodes.empty() &&
"No error node found in the trimmed graph");
2650 std::queue<const ExplodedNode *> WS;
2652 WS.push(TrimmedGraph->getRoot());
2653 unsigned Priority = 0;
2655 while (!WS.empty()) {
2659 PriorityMapTy::iterator PriorityEntry;
2661 std::tie(PriorityEntry, IsNew) = PriorityMap.insert({Node, Priority});
2665 assert(PriorityEntry->second <= Priority);
2669 if (RemainingNodes.erase(Node))
2670 if (RemainingNodes.empty())
2678 llvm::sort(ReportNodes, PriorityCompare<true>(PriorityMap));
2681BugPathInfo *BugPathGetter::getNextBugPath() {
2682 if (ReportNodes.empty())
2686 std::tie(CurrentBugPath.Report, OrigN) = ReportNodes.pop_back_val();
2687 assert(PriorityMap.contains(OrigN) &&
"error node not accessible from root");
2691 auto GNew = std::make_unique<ExplodedGraph>();
2707 CurrentBugPath.ErrorNode = NewN;
2713 assert(OrigN == TrimmedGraph->getRoot() &&
2714 "There should be only one root!");
2715 GNew->designateAsRoot(NewN);
2722 PriorityCompare<false>(PriorityMap));
2725 CurrentBugPath.BugPath = std::move(GNew);
2727 return &CurrentBugPath;
2734 using MacroStackTy = std::vector<
2735 std::pair<std::shared_ptr<PathDiagnosticMacroPiece>,
SourceLocation>>;
2737 using PiecesTy = std::vector<PathDiagnosticPieceRef>;
2739 MacroStackTy MacroStack;
2742 for (PathPieces::const_iterator I = path.begin(), E = path.end();
2744 const auto &piece = *I;
2747 if (
auto *call = dyn_cast<PathDiagnosticCallPiece>(&*piece)) {
2757 SM.getExpansionLoc(
Loc) :
2760 if (
Loc.isFileID()) {
2762 Pieces.push_back(piece);
2766 assert(
Loc.isMacroID());
2769 if (!MacroStack.empty() && InstantiationLoc == MacroStack.back().second) {
2770 MacroStack.back().first->subPieces.push_back(piece);
2776 std::shared_ptr<PathDiagnosticMacroPiece> MacroGroup;
2779 SM.getExpansionLoc(
Loc) :
2783 while (!MacroStack.empty()) {
2784 if (InstantiationLoc == MacroStack.back().second) {
2785 MacroGroup = MacroStack.back().first;
2789 if (ParentInstantiationLoc == MacroStack.back().second) {
2790 MacroGroup = MacroStack.back().first;
2794 MacroStack.pop_back();
2797 if (!MacroGroup || ParentInstantiationLoc == MacroStack.back().second) {
2799 auto NewGroup = std::make_shared<PathDiagnosticMacroPiece>(
2803 MacroGroup->subPieces.push_back(NewGroup);
2805 assert(InstantiationLoc.
isFileID());
2806 Pieces.push_back(NewGroup);
2809 MacroGroup = NewGroup;
2810 MacroStack.push_back(std::make_pair(MacroGroup, InstantiationLoc));
2814 MacroGroup->subPieces.push_back(piece);
2820 llvm::append_range(path, Pieces);
2826static std::unique_ptr<VisitorsDiagnosticsTy>
2830 std::unique_ptr<VisitorsDiagnosticsTy> Notes =
2831 std::make_unique<VisitorsDiagnosticsTy>();
2844 for (std::unique_ptr<BugReporterVisitor> &Visitor : R->visitors())
2845 visitors.push_back(std::move(Visitor));
2852 for (
auto &
V : visitors) {
2853 V->finalizeVisitor(BRC, ErrorNode, *R);
2855 if (
auto Piece =
V->getEndPath(BRC, ErrorNode, *R)) {
2856 assert(!LastPiece &&
2857 "There can only be one final piece in a diagnostic.");
2859 "The final piece must contain a message!");
2860 LastPiece = std::move(Piece);
2861 (*Notes)[ErrorNode].push_back(LastPiece);
2867 for (
auto &
V : visitors) {
2868 auto P =
V->VisitNode(NextNode, BRC, *R);
2870 (*Notes)[NextNode].push_back(std::move(P));
2882std::optional<PathDiagnosticBuilder> PathDiagnosticBuilder::findValidReport(
2883 ArrayRef<PathSensitiveBugReport *> &bugReports,
2887 BugPathGetter BugGraph(&Reporter.
getGraph(), bugReports);
2889 while (BugPathInfo *BugPath = BugGraph.getNextBugPath()) {
2892 assert(R &&
"No original report found for sliced graph.");
2893 assert(
R->isValid() &&
"Report selected by trimmed graph marked invalid.");
2908 std::unique_ptr<VisitorsDiagnosticsTy> visitorNotes =
2913 llvm::TimeTraceScope TCS{
"Crosscheck with Z3"};
2924 switch (Z3Oracle.interpretQueryResult(CrosscheckResult)) {
2926 ++NumTimesReportRefuted;
2927 R->markInvalid(
"Infeasible constraints",
nullptr);
2930 ++NumTimesReportEQClassAborted;
2933 ++NumTimesReportPassesZ3;
2938 assert(
R->isValid());
2939 return PathDiagnosticBuilder(std::move(BRC), std::move(BugPath->BugPath),
2940 BugPath->Report, BugPath->ErrorNode,
2941 std::move(visitorNotes));
2945 ++NumTimesReportEQClassWasExhausted;
2949std::unique_ptr<DiagnosticForConsumerMapTy>
2951 ArrayRef<std::unique_ptr<PathDiagnosticConsumer>> consumers,
2953 assert(!bugReports.empty());
2955 auto Out = std::make_unique<DiagnosticForConsumerMapTy>();
2957 std::optional<PathDiagnosticBuilder> PDB =
2958 PathDiagnosticBuilder::findValidReport(bugReports, *
this);
2961 for (
const auto &PC : consumers) {
2962 if (std::unique_ptr<PathDiagnostic> PD = PDB->generate(PC.get())) {
2963 (*Out)[PC.get()] = std::move(PD);
2972 bool ValidSourceLoc = R->getLocation().isValid();
2973 assert(ValidSourceLoc);
2976 if (!ValidSourceLoc)
2980 if (UserSuppressions.isSuppressed(*R))
2984 llvm::FoldingSetNodeID ID;
2993 EQClasses.InsertNode(EQ, InsertPos);
2994 EQClassesVector.push_back(EQ);
2996 EQ->AddReport(std::move(R));
3000 if (
auto PR = dyn_cast<PathSensitiveBugReport>(R.get()))
3004 assert((E->isSink() || E->getLocation().getTag()) &&
3005 "Error node must either be a sink or have a tag");
3027struct FRIEC_WLItem {
3032 : N(n), I(N->succ_begin()), E(N->succ_end()) {}
3037BugReport *PathSensitiveBugReporter::findReportInEquivalenceClass(
3042 assert(
EQ.getReports().size() > 0);
3043 const BugType& BT =
EQ.getReports()[0]->getBugType();
3045 BugReport *
R =
EQ.getReports()[0].get();
3046 for (
auto &J :
EQ.getReports()) {
3047 if (
auto *PR = dyn_cast<PathSensitiveBugReport>(J.get())) {
3049 bugReports.push_back(PR);
3061 BugReport *exampleReport =
nullptr;
3063 for (
const auto &I:
EQ.getReports()) {
3064 auto *
R = dyn_cast<PathSensitiveBugReport>(I.get());
3068 const ExplodedNode *errorNode =
R->getErrorNode();
3069 if (errorNode->
isSink()) {
3071 "BugType::isSuppressSink() should not be 'true' for sink end nodes");
3075 bugReports.push_back(R);
3085 if (
const CFGBlock *ErrorB = errorNode->
getCFGBlock())
3086 if (ErrorB->isInevitablySinking())
3091 using WLItem = FRIEC_WLItem;
3092 using DFSWorkList = SmallVector<WLItem, 10>;
3094 llvm::DenseMap<const ExplodedNode *, unsigned> Visited;
3097 WL.push_back(errorNode);
3098 Visited[errorNode] = 1;
3100 while (!WL.empty()) {
3101 WLItem &WI = WL.back();
3102 assert(!WI.N->succ_empty());
3104 for (; WI.I != WI.E; ++WI.I) {
3105 const ExplodedNode *Succ = *WI.I;
3110 bugReports.push_back(R);
3121 unsigned &mark = Visited[Succ];
3131 if (!WL.empty() && &WL.back() == &WI)
3138 return exampleReport;
3142 llvm::TimeTraceScope TCS{timeTraceName(EQ), [&]() {
3145 SmallVector<BugReport*, 10> bugReports;
3146 BugReport *report = findReportInEquivalenceClass(EQ, bugReports);
3151 for (
const std::string &CheckerOrPackage :
3158 std::unique_ptr<DiagnosticForConsumerMapTy> Diagnostics =
3161 for (
auto &P : *Diagnostics) {
3162 PathDiagnosticConsumer *Consumer = P.first;
3163 std::unique_ptr<PathDiagnostic> &PD = P.second;
3167 if (PD->path.empty()) {
3169 auto piece = std::make_unique<PathDiagnosticEventPiece>(
3171 for (SourceRange Range : report->
getRanges())
3172 piece->addRange(Range);
3173 PD->setEndOfPath(std::move(piece));
3176 PathPieces &Pieces = PD->getMutablePieces();
3180 for (
const auto &I : llvm::reverse(report->
getNotes())) {
3181 PathDiagnosticNotePiece *Piece = I.get();
3182 auto ConvertedPiece = std::make_shared<PathDiagnosticEventPiece>(
3185 ConvertedPiece->addRange(R);
3187 Pieces.push_front(std::move(ConvertedPiece));
3190 for (
const auto &I : llvm::reverse(report->
getNotes()))
3191 Pieces.push_front(I);
3194 for (
const auto &I : report->
getFixits())
3195 Pieces.back()->addFixit(I);
3203 Pieces.push_front(std::make_shared<PathDiagnosticEventPiece>(
3205 "[debug] analyzing from " +
3219 if (
const auto FD = dyn_cast<FunctionDecl>(Signature)) {
3220 SignatureSourceRange = FD->getSourceRange();
3221 }
else if (
const auto OD = dyn_cast<ObjCMethodDecl>(Signature)) {
3222 SignatureSourceRange = OD->getSourceRange();
3228 : SignatureSourceRange.
getEnd();
3231 unsigned StartLine =
SM.getExpansionLineNumber(Start);
3232 unsigned EndLine =
SM.getExpansionLineNumber(End);
3234 FileID FID =
SM.getFileID(
SM.getExpansionLoc(Start));
3235 for (
unsigned Line = StartLine;
Line <= EndLine;
Line++)
3236 ExecutedLines[FID].insert(
Line);
3246 FileID FID =
SM.getFileID(ExpansionLoc);
3247 unsigned LineNo =
SM.getExpansionLineNumber(ExpansionLoc);
3248 ExecutedLines[FID].insert(LineNo);
3253static std::unique_ptr<FilesToLineNumsMap>
3255 auto ExecutedLines = std::make_unique<FilesToLineNumsMap>();
3264 const Decl *D = CE->getCalleeStackFrame()->getDecl();
3275 if (
const auto *RS = dyn_cast_or_null<ReturnStmt>(P)) {
3280 if (isa_and_nonnull<SwitchCase, LabelStmt>(P))
3286 return ExecutedLines;
3289std::unique_ptr<DiagnosticForConsumerMapTy>
3292 ArrayRef<std::unique_ptr<PathDiagnosticConsumer>> consumers,
3295 auto Out = std::make_unique<DiagnosticForConsumerMapTy>();
3296 for (
const auto &Consumer : consumers)
3297 (*Out)[Consumer.get()] =
3312 "The call piece should not be in a header file.");
3324 if (
auto *CPInner = dyn_cast<PathDiagnosticCallPiece>(Path.back().get()))
3332 if (PD.
path.empty())
3341 if (
auto *CP = dyn_cast<PathDiagnosticCallPiece>(LastP)) {
3348 const auto *ND = dyn_cast<NamedDecl>(CP->
getCallee());
3351 llvm::raw_svector_ostream os(buf);
3352 os <<
" (within a call to '" << ND->getDeclName() <<
"')";
3365std::unique_ptr<DiagnosticForConsumerMapTy>
3366PathSensitiveBugReporter::generateDiagnosticForConsumerMap(
3368 ArrayRef<std::unique_ptr<PathDiagnosticConsumer>> consumers,
3369 ArrayRef<BugReport *> bugReports) {
3372 consumers, bugReports);
3378 assert(!bugReports.empty());
3379 MaxBugClassSize.updateMax(bugReports.size());
3382 ArrayRef<PathSensitiveBugReport *> convertedArrayOfReports(
3383 reinterpret_cast<PathSensitiveBugReport *
const *
>(&*bugReports.begin()),
3384 reinterpret_cast<PathSensitiveBugReport *
const *
>(&*bugReports.end()));
3386 consumers, convertedArrayOfReports);
3391 MaxValidBugClassSize.updateMax(bugReports.size());
3396 for (
auto const &P : *Out)
3397 if (Opts.ShouldReportIssuesInMainSourceFile && !Opts.
AnalyzeAll)
3405 StringRef Name, StringRef Category,
3415 StringRef name, StringRef category,
3420 BugType *BT = getBugTypeForName(CheckName, name, category);
3421 auto R = std::make_unique<BasicBugReport>(*BT, str,
Loc);
3422 R->setDeclWithIssue(DeclWithIssue);
3423 for (
const auto &SR : Ranges)
3425 for (
const auto &FH : Fixits)
3426 R->addFixItHint(FH);
3431 StringRef name, StringRef category) {
3433 llvm::raw_svector_ostream(fullDesc)
3434 << CheckName <<
":" << name <<
":" << category;
3435 std::unique_ptr<BugType> &BT = StrBugTypes[fullDesc];
3437 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
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.
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.
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()
BugReport(Kind kind, const BugType &bt, StringRef desc)
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.
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
PathSensitiveBugReport(const BugType &bt, StringRef desc, const ExplodedNode *errorNode)
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.
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
U cast(CodeGen::Address addr)
Diagnostic wrappers for TextAPI types for error reporting.