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 LocationContextMap =
113 llvm::DenseMap<const PathPieces *, const LocationContext *>;
118class PathDiagnosticConstruct {
120 const PathDiagnosticConsumer *Consumer;
123 const ExplodedNode *CurrentNode;
127 LocationContextMap LCM;
128 const SourceManager &
SM;
134 CallWithEntryStack CallStack;
138 std::unique_ptr<PathDiagnostic> PD;
141 PathDiagnosticConstruct(
const PathDiagnosticConsumer *PDC,
142 const ExplodedNode *ErrorNode,
143 const PathSensitiveBugReport *R,
144 const Decl *AnalysisEntryPoint);
148 const LocationContext *getCurrLocationContext()
const {
149 assert(CurrentNode &&
"Already reached the root!");
156 const LocationContext *getLocationContextForActivePath()
const {
157 return LCM.find(&PD->getActivePath())->getSecond();
160 const ExplodedNode *getCurrentNode()
const {
return CurrentNode; }
164 bool ascendToPrevNode() {
166 return static_cast<bool>(CurrentNode);
169 const ParentMap &getParentMap()
const {
173 const SourceManager &getSourceManager()
const {
return SM; }
175 const Stmt *getParent(
const Stmt *S)
const {
179 void updateLocCtxMap(
const PathPieces *Path,
const LocationContext *LC) {
184 const LocationContext *getLocationContextFor(
const PathPieces *Path)
const {
185 assert(LCM.count(Path) &&
186 "Failed to find the context associated with these pieces!");
187 return LCM.find(Path)->getSecond();
190 bool isInLocCtxMap(
const PathPieces *Path)
const {
return LCM.count(Path); }
192 PathPieces &getActivePath() {
return PD->getActivePath(); }
193 PathPieces &getMutablePieces() {
return PD->getMutablePieces(); }
196 bool shouldAddControlNotes()
const {
199 bool shouldGenerateDiagnostics()
const {
202 bool supportsLogicalOpControlFlow()
const {
213 std::unique_ptr<const ExplodedGraph> BugPath;
218 const PathSensitiveBugReport *R;
221 const ExplodedNode *
const ErrorNode;
224 std::unique_ptr<const VisitorsDiagnosticsTy> VisitorsDiagnostics;
230 static std::optional<PathDiagnosticBuilder>
231 findValidReport(ArrayRef<PathSensitiveBugReport *> &bugReports,
232 PathSensitiveBugReporter &Reporter);
234 PathDiagnosticBuilder(
235 BugReporterContext BRC, std::unique_ptr<ExplodedGraph> BugPath,
236 PathSensitiveBugReport *r,
const ExplodedNode *ErrorNode,
237 std::unique_ptr<VisitorsDiagnosticsTy> VisitorsDiagnostics);
249 std::unique_ptr<PathDiagnostic>
250 generate(
const PathDiagnosticConsumer *PDC)
const;
254 const CallWithEntryStack &CallStack)
const;
255 void generatePathDiagnosticsForNode(PathDiagnosticConstruct &
C,
256 PathDiagnosticLocation &PrevLoc)
const;
258 void generateMinimalDiagForBlockEdge(PathDiagnosticConstruct &
C,
262 generateDiagForGotoOP(
const PathDiagnosticConstruct &
C,
const Stmt *S,
263 PathDiagnosticLocation &Start)
const;
266 generateDiagForSwitchOP(
const PathDiagnosticConstruct &
C,
const CFGBlock *Dst,
267 PathDiagnosticLocation &Start)
const;
270 generateDiagForBinaryOP(
const PathDiagnosticConstruct &
C,
const Stmt *
T,
271 const CFGBlock *Src,
const CFGBlock *DstC)
const;
273 PathDiagnosticLocation
274 ExecutionContinues(
const PathDiagnosticConstruct &
C)
const;
276 PathDiagnosticLocation
277 ExecutionContinues(llvm::raw_string_ostream &os,
278 const PathDiagnosticConstruct &
C)
const;
280 const PathSensitiveBugReport *getBugReport()
const {
return R; }
284 if (!llvm::timeTraceProfilerEnabled())
286 const auto &BugReports =
EQ.getReports();
287 if (BugReports.empty())
288 return "Empty Equivalence Class";
289 const BugReport *R = BugReports.front().get();
291 return (
"Flushing EQC " + BT.getDescription()).str();
295 const SourceManager &
SM) {
297 assert(llvm::timeTraceProfilerEnabled());
299 const auto &BugReports =
EQ.getReports();
300 if (BugReports.empty())
302 const BugReport *R = BugReports.front().get();
305 std::string
File =
SM.getFilename(
Loc).str();
306 return {BT.getCheckerName().str(), std::move(
File),
307 static_cast<int>(
Loc.getLineNumber())};
327 const auto *CE = dyn_cast_or_null<CallExpr>(CallSite);
332 for (
auto [Idx, ArgExpr] : llvm::enumerate(CE->arguments())) {
344 if (ArgExpr->getType()->isVoidPointerType())
369 return (llvm::Twine(Msg) +
" via " + std::to_string(ArgIndex) +
370 llvm::getOrdinalSuffix(ArgIndex) +
" parameter").str();
390 if (
X->getTag() == tagPreferred && Y->
getTag() == tagLesser)
393 if (Y->
getTag() == tagPreferred &&
X->getTag() == tagLesser)
405 unsigned N = path.size();
412 for (
unsigned i = 0; i < N; ++i) {
413 auto piece = std::move(path.front());
416 switch (piece->getKind()) {
427 if (
auto *nextEvent =
428 dyn_cast<PathDiagnosticEventPiece>(path.front().get())) {
433 if (
auto *pieceToKeep =
435 piece = std::move(pieceToKeep == event ? piece : path.front());
447 path.push_back(std::move(piece));
457 bool IsInteresting =
false) {
458 bool containsSomethingInteresting = IsInteresting;
459 const unsigned N = pieces.size();
461 for (
unsigned i = 0 ; i < N ; ++i) {
464 auto piece = std::move(pieces.front());
467 switch (piece->getKind()) {
476 containsSomethingInteresting =
true;
483 containsSomethingInteresting =
true;
491 containsSomethingInteresting |= !
event.isPrunable();
500 pieces.push_back(std::move(piece));
503 return containsSomethingInteresting;
508 for (
unsigned int i = 0; i < Path.size(); ++i) {
509 auto Piece = std::move(Path.front());
512 Path.push_back(std::move(Piece));
528 for (
const auto &I : Pieces) {
529 auto *
Call = dyn_cast<PathDiagnosticCallPiece>(I.get());
534 if (LastCallLocation) {
536 if (CallerIsImplicit || !
Call->callEnter.asLocation().isValid())
537 Call->callEnter = *LastCallLocation;
538 if (CallerIsImplicit || !
Call->callReturn.asLocation().isValid())
539 Call->callReturn = *LastCallLocation;
545 if (
Call->callEnterWithin.asLocation().isValid() &&
547 ThisCallLocation = &
Call->callEnterWithin;
549 ThisCallLocation = &
Call->callEnter;
551 assert(ThisCallLocation &&
"Outermost call has an invalid location");
560 for (PathPieces::iterator I = Pieces.begin(), E = Pieces.end(); I != E;) {
561 if (
auto *
C = dyn_cast<PathDiagnosticCallPiece>(I->get()))
564 if (
auto *M = dyn_cast<PathDiagnosticMacroPiece>(I->get()))
567 if (
auto *
CF = dyn_cast<PathDiagnosticControlFlowPiece>(I->get())) {
568 const Stmt *Start =
CF->getStartLocation().asStmt();
569 const Stmt *End =
CF->getEndLocation().asStmt();
570 if (isa_and_nonnull<CXXDefaultInitExpr>(Start)) {
573 }
else if (isa_and_nonnull<CXXDefaultInitExpr>(End)) {
574 PathPieces::iterator
Next = std::next(I);
577 dyn_cast<PathDiagnosticControlFlowPiece>(
Next->get())) {
578 NextCF->setStartLocation(
CF->getStartLocation());
594 for (PathPieces::iterator I = Pieces.begin(), E = Pieces.end(); I != E;) {
595 if (
auto *
C = dyn_cast<PathDiagnosticCallPiece>(I->get()))
598 if (
auto *M = dyn_cast<PathDiagnosticMacroPiece>(I->get()))
601 if (!(*I)->getLocation().isValid() ||
602 !(*I)->getLocation().asLocation().isValid()) {
611 const PathDiagnosticConstruct &
C)
const {
612 if (
const Stmt *S =
C.getCurrentNode()->getNextStmtForDiagnostics())
614 C.getCurrLocationContext());
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.getCurrLocationContext()->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) {
866 End = ExecutionContinues(
C);
869 assert(B->getOpcode() == BO_LOr);
877 End = ExecutionContinues(
C);
885 return std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, sbuf);
888void PathDiagnosticBuilder::generateMinimalDiagForBlockEdge(
889 PathDiagnosticConstruct &
C, BlockEdge BE)
const {
890 const SourceManager &
SM = getSourceManager();
891 const LocationContext *LC =
C.getCurrLocationContext();
892 const CFGBlock *Src = BE.
getSrc();
893 const CFGBlock *Dst = BE.
getDst();
899 switch (
T->getStmtClass()) {
903 case Stmt::GotoStmtClass:
904 case Stmt::IndirectGotoStmtClass: {
905 if (
const Stmt *S =
C.getCurrentNode()->getNextStmtForDiagnostics())
906 C.getActivePath().push_front(generateDiagForGotoOP(
C, S, Start));
910 case Stmt::SwitchStmtClass: {
911 C.getActivePath().push_front(generateDiagForSwitchOP(
C, Dst, Start));
915 case Stmt::BreakStmtClass:
916 case Stmt::ContinueStmtClass: {
918 llvm::raw_string_ostream os(sbuf);
920 C.getActivePath().push_front(
921 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, sbuf));
926 case Stmt::BinaryConditionalOperatorClass:
927 case Stmt::ConditionalOperatorClass: {
929 llvm::raw_string_ostream os(sbuf);
930 os <<
"'?' condition is ";
939 if (
const Stmt *S = End.
asStmt())
942 C.getActivePath().push_front(
943 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, sbuf));
948 case Stmt::BinaryOperatorClass: {
949 if (!
C.supportsLogicalOpControlFlow())
952 C.getActivePath().push_front(generateDiagForBinaryOP(
C,
T, Src, Dst));
956 case Stmt::DoStmtClass:
959 llvm::raw_string_ostream os(sbuf);
961 os <<
"Loop condition is true. ";
964 if (
const Stmt *S = End.
asStmt())
967 C.getActivePath().push_front(
968 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, sbuf));
972 if (
const Stmt *S = End.
asStmt())
975 C.getActivePath().push_front(
976 std::make_shared<PathDiagnosticControlFlowPiece>(
977 Start, End,
"Loop condition is false. Exiting loop"));
981 case Stmt::WhileStmtClass:
982 case Stmt::ForStmtClass:
985 llvm::raw_string_ostream os(sbuf);
987 os <<
"Loop condition is false. ";
989 if (
const Stmt *S = End.
asStmt())
992 C.getActivePath().push_front(
993 std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, sbuf));
996 if (
const Stmt *S = End.
asStmt())
999 C.getActivePath().push_front(
1000 std::make_shared<PathDiagnosticControlFlowPiece>(
1001 Start, End,
"Loop condition is true. Entering loop body"));
1006 case Stmt::IfStmtClass: {
1009 if (
const Stmt *S = End.
asStmt())
1013 C.getActivePath().push_front(
1014 std::make_shared<PathDiagnosticControlFlowPiece>(
1015 Start, End,
"Taking false branch"));
1017 C.getActivePath().push_front(
1018 std::make_shared<PathDiagnosticControlFlowPiece>(
1019 Start, End,
"Taking true branch"));
1032 case Stmt::ForStmtClass:
1033 case Stmt::WhileStmtClass:
1034 case Stmt::ObjCForCollectionStmtClass:
1035 case Stmt::CXXForRangeStmtClass:
1064 const Stmt *S = SP->getStmt();
1074 const Stmt *LoopBody =
nullptr;
1076 case Stmt::CXXForRangeStmtClass: {
1082 LoopBody = FR->getBody();
1085 case Stmt::ForStmtClass: {
1089 LoopBody = FS->getBody();
1092 case Stmt::ObjCForCollectionStmtClass: {
1094 LoopBody = FC->getBody();
1097 case Stmt::WhileStmtClass:
1128 std::make_shared<PathDiagnosticControlFlowPiece>(NewLoc, PrevLoc));
1136 if (
const auto *FS = dyn_cast_or_null<ObjCForCollectionStmt>(S))
1137 return FS->getElement();
1144 "Loop body skipped when range is empty";
1146 "Loop body skipped when collection is empty";
1148static std::unique_ptr<FilesToLineNumsMap>
1151void PathDiagnosticBuilder::generatePathDiagnosticsForNode(
1162 if (
C.shouldAddPathEdges()) {
1178 bool VisitedEntireCall =
C.PD->isWithinCall();
1179 C.PD->popActivePath();
1182 if (VisitedEntireCall) {
1187 const Decl *Caller = CE->getLocationContext()->getDecl();
1189 assert(
C.getActivePath().size() == 1 &&
1190 C.getActivePath().front().get() ==
Call);
1194 assert(
C.isInLocCtxMap(&
C.getActivePath()) &&
1195 "When we ascend to a previously unvisited call, the active path's "
1196 "address shouldn't change, but rather should be compacted into "
1197 "a single CallEvent!");
1198 C.updateLocCtxMap(&
C.getActivePath(),
C.getCurrLocationContext());
1201 assert(!
C.isInLocCtxMap(&
Call->path) &&
1202 "When we ascend to a previously unvisited call, this must be the "
1203 "first time we encounter the caller context!");
1204 C.updateLocCtxMap(&
Call->path, CE->getCalleeContext());
1209 PrevLoc =
Call->getLocation();
1211 if (!
C.CallStack.empty()) {
1212 assert(
C.CallStack.back().first ==
Call);
1213 C.CallStack.pop_back();
1218 assert(
C.getCurrLocationContext() ==
C.getLocationContextForActivePath() &&
1219 "The current position in the bug path is out of sync with the "
1220 "location context associated with the active path!");
1223 if (std::optional<CallExitEnd> CE = P.
getAs<CallExitEnd>()) {
1229 assert(!
C.isInLocCtxMap(&
Call->path) &&
1230 "We just entered a call, this must've been the first time we "
1231 "encounter its context!");
1232 C.updateLocCtxMap(&
Call->path, CE->getCalleeContext());
1234 if (
C.shouldAddPathEdges()) {
1240 auto *P =
Call.get();
1241 C.getActivePath().push_front(std::move(
Call));
1244 C.PD->pushActivePath(&P->path);
1245 C.CallStack.push_back(CallWithEntry(P,
C.getCurrentNode()));
1249 if (
auto PS = P.
getAs<PostStmt>()) {
1250 if (!
C.shouldAddPathEdges())
1262 }
else if (
auto BE = P.
getAs<BlockEdge>()) {
1264 if (
C.shouldAddControlNotes()) {
1265 generateMinimalDiagForBlockEdge(
C, *BE);
1268 if (!
C.shouldAddPathEdges()) {
1275 const Stmt *Body =
nullptr;
1277 if (
const auto *FS = dyn_cast<ForStmt>(
Loop))
1278 Body = FS->getBody();
1279 else if (
const auto *WS = dyn_cast<WhileStmt>(
Loop))
1280 Body = WS->getBody();
1281 else if (
const auto *OFS = dyn_cast<ObjCForCollectionStmt>(
Loop)) {
1282 Body = OFS->getBody();
1283 }
else if (
const auto *FRS = dyn_cast<CXXForRangeStmt>(
Loop)) {
1284 Body = FRS->getBody();
1288 auto p = std::make_shared<PathDiagnosticEventPiece>(
1289 L,
"Looping back to the head of the loop");
1290 p->setPrunable(
true);
1294 if (!
C.shouldAddControlNotes()) {
1295 C.getActivePath().push_front(std::move(p));
1298 if (
const auto *CS = dyn_cast_or_null<CompoundStmt>(Body)) {
1304 const CFGBlock *BSrc = BE->
getSrc();
1305 const ParentMap &PM =
C.getParentMap();
1318 if (!IsInLoopBody) {
1333 C.getCurrLocationContext());
1334 auto PE = std::make_shared<PathDiagnosticEventPiece>(L, str);
1335 PE->setPrunable(
true);
1339 if (!
C.shouldAddControlNotes()) {
1340 C.getActivePath().push_front(std::move(PE));
1351static std::unique_ptr<PathDiagnostic>
1353 const Decl *AnalysisEntryPoint) {
1355 return std::make_unique<PathDiagnostic>(
1359 AnalysisEntryPoint, std::make_unique<FilesToLineNumsMap>());
1362static std::unique_ptr<PathDiagnostic>
1365 const Decl *AnalysisEntryPoint) {
1367 return std::make_unique<PathDiagnostic>(
1395 case Stmt::BinaryOperatorClass: {
1397 if (!BO->isLogicalOp())
1399 return BO->getLHS() ==
Cond || BO->getRHS() ==
Cond;
1401 case Stmt::IfStmtClass:
1403 case Stmt::ForStmtClass:
1405 case Stmt::WhileStmtClass:
1407 case Stmt::DoStmtClass:
1409 case Stmt::ChooseExprClass:
1411 case Stmt::IndirectGotoStmtClass:
1413 case Stmt::SwitchStmtClass:
1415 case Stmt::BinaryConditionalOperatorClass:
1417 case Stmt::ConditionalOperatorClass: {
1419 return CO->getCond() ==
Cond ||
1420 CO->getLHS() ==
Cond ||
1421 CO->getRHS() ==
Cond;
1423 case Stmt::ObjCForCollectionStmtClass:
1425 case Stmt::CXXForRangeStmtClass: {
1427 return FRS->getCond() ==
Cond || FRS->getRangeInit() ==
Cond;
1435 if (
const auto *FS = dyn_cast<ForStmt>(FL))
1436 return FS->getInc() == S || FS->getInit() == S;
1437 if (
const auto *FRS = dyn_cast<CXXForRangeStmt>(FL))
1438 return FRS->getInc() == S || FRS->getRangeStmt() == S ||
1439 FRS->getLoopVarStmt() || FRS->getRangeInit() == S;
1452 PathPieces::iterator Prev = pieces.end();
1453 for (PathPieces::iterator I = pieces.begin(), E = Prev; I != E;
1455 auto *Piece = dyn_cast<PathDiagnosticControlFlowPiece>(I->get());
1464 const Stmt *InnerStmt =
nullptr;
1465 while (NextSrcContext.
isValid() && NextSrcContext.
asStmt() != InnerStmt) {
1466 SrcContexts.push_back(NextSrcContext);
1467 InnerStmt = NextSrcContext.
asStmt();
1476 const Stmt *Dst = Piece->getEndLocation().getStmtOrNull();
1486 if (llvm::is_contained(SrcContexts, DstContext))
1490 Piece->setStartLocation(DstContext);
1495 auto *PrevPiece = dyn_cast<PathDiagnosticControlFlowPiece>(Prev->get());
1498 if (
const Stmt *PrevSrc =
1499 PrevPiece->getStartLocation().getStmtOrNull()) {
1501 if (PrevSrcParent ==
1503 PrevPiece->setEndLocation(DstContext);
1514 std::make_shared<PathDiagnosticControlFlowPiece>(SrcLoc, DstContext);
1516 I = pieces.insert(I, std::move(P));
1532 for (PathPieces::iterator I = pieces.begin(), E = pieces.end(); I != E; ++I) {
1533 const auto *PieceI = dyn_cast<PathDiagnosticControlFlowPiece>(I->get());
1538 const Stmt *s1Start = PieceI->getStartLocation().getStmtOrNull();
1539 const Stmt *s1End = PieceI->getEndLocation().getStmtOrNull();
1541 if (!s1Start || !s1End)
1544 PathPieces::iterator NextI = I; ++NextI;
1554 const auto *EV = dyn_cast<PathDiagnosticEventPiece>(NextI->get());
1556 StringRef S = EV->getString();
1565 PieceNextI = dyn_cast<PathDiagnosticControlFlowPiece>(NextI->get());
1575 if (!s2Start || !s2End || s1End != s2Start)
1591 I = pieces.erase(I);
1604 SM.getExpansionRange(
Range.getEnd()).getEnd());
1607 if (FID !=
SM.getFileID(ExpansionRange.
getEnd()))
1608 return std::nullopt;
1610 std::optional<MemoryBufferRef> Buffer =
SM.getBufferOrNone(FID);
1612 return std::nullopt;
1614 unsigned BeginOffset =
SM.getFileOffset(ExpansionRange.
getBegin());
1615 unsigned EndOffset =
SM.getFileOffset(ExpansionRange.
getEnd());
1616 StringRef Snippet = Buffer->getBuffer().slice(BeginOffset, EndOffset);
1622 if (Snippet.find_first_of(
"\r\n") != StringRef::npos)
1623 return std::nullopt;
1626 return Snippet.size();
1652 for (PathPieces::iterator I = Path.begin(), E = Path.end(); I != E; ) {
1654 const auto *PieceI = dyn_cast<PathDiagnosticControlFlowPiece>(I->get());
1661 const Stmt *s1Start = PieceI->getStartLocation().getStmtOrNull();
1662 const Stmt *s1End = PieceI->getEndLocation().getStmtOrNull();
1664 PathPieces::iterator NextI = I; ++NextI;
1668 const auto *PieceNextI =
1669 dyn_cast<PathDiagnosticControlFlowPiece>(NextI->get());
1676 PieceNextI = dyn_cast<PathDiagnosticControlFlowPiece>(NextI->get());
1685 const Stmt *s2Start = PieceNextI->getStartLocation().getStmtOrNull();
1686 const Stmt *s2End = PieceNextI->getEndLocation().getStmtOrNull();
1688 if (s1Start && s2Start && s1Start == s2End && s2Start == s1End) {
1689 const size_t MAX_SHORT_LINE_LENGTH = 80;
1691 if (s1Length && *s1Length <= MAX_SHORT_LINE_LENGTH) {
1693 if (s2Length && *s2Length <= MAX_SHORT_LINE_LENGTH) {
1695 I = Path.erase(NextI);
1718 bool erased =
false;
1720 for (PathPieces::iterator I = path.begin(), E = path.end(); I != E;
1724 const auto *PieceI = dyn_cast<PathDiagnosticControlFlowPiece>(I->get());
1729 const Stmt *start = PieceI->getStartLocation().getStmtOrNull();
1730 const Stmt *end = PieceI->getEndLocation().getStmtOrNull();
1745 if (!
SM.isWrittenInSameFile(FirstLoc, SecondLoc))
1747 if (
SM.isBeforeInTranslationUnit(SecondLoc, FirstLoc))
1748 std::swap(SecondLoc, FirstLoc);
1757 const size_t MAX_PUNY_EDGE_LENGTH = 2;
1758 if (*ByteWidth <= MAX_PUNY_EDGE_LENGTH) {
1770 for (PathPieces::iterator I = path.begin(), E = path.end(); I != E; ++I) {
1771 const auto *PieceI = dyn_cast<PathDiagnosticEventPiece>(I->get());
1776 PathPieces::iterator NextI = I; ++NextI;
1780 const auto *PieceNextI = dyn_cast<PathDiagnosticEventPiece>(NextI->get());
1786 if (PieceI->getString() == PieceNextI->getString()) {
1794 bool hasChanges =
false;
1800 for (PathPieces::iterator I = path.begin(), E = path.end(); I != E; ) {
1802 if (
auto *CallI = dyn_cast<PathDiagnosticCallPiece>(I->get())) {
1805 if (!OCS.count(CallI)) {
1815 auto *PieceI = dyn_cast<PathDiagnosticControlFlowPiece>(I->get());
1822 const Stmt *s1Start = PieceI->getStartLocation().getStmtOrNull();
1823 const Stmt *s1End = PieceI->getEndLocation().getStmtOrNull();
1827 PathPieces::iterator NextI = I; ++NextI;
1831 const auto *PieceNextI = dyn_cast<PathDiagnosticControlFlowPiece>(NextI->get());
1838 const Stmt *s2Start = PieceNextI->getStartLocation().getStmtOrNull();
1839 const Stmt *s2End = PieceNextI->getEndLocation().getStmtOrNull();
1857 if (level1 && level1 == level2 && level1 == level3 && level1 == level4) {
1858 PieceI->setEndLocation(PieceNextI->getEndLocation());
1871 if (s1End && s1End == s2Start && level2) {
1872 bool removeEdge =
false;
1898 else if (s1Start && s2End &&
1911 else if (s1Start && s2End &&
1913 SourceRange EdgeRange(PieceI->getEndLocation().asLocation(),
1914 PieceI->getStartLocation().asLocation());
1921 PieceI->setEndLocation(PieceNextI->getEndLocation());
1935 if (s1End == s2Start) {
1936 const auto *FS = dyn_cast_or_null<ObjCForCollectionStmt>(level3);
1937 if (FS && FS->getCollection()->IgnoreParens() == s2Start &&
1938 s2End == FS->getElement()) {
1939 PieceI->setEndLocation(PieceNextI->getEndLocation());
1976 const auto *FirstEdge =
1977 dyn_cast<PathDiagnosticControlFlowPiece>(Path.front().get());
1981 const Decl *D =
C.getLocationContextFor(&Path)->getDecl();
1984 if (FirstEdge->getStartLocation() != EntryLoc)
1996 for (
const auto &P : path) {
1999 unsigned LineNo =
Loc.getLineNumber();
2001 ExecutedLines[FID].insert(LineNo);
2005PathDiagnosticConstruct::PathDiagnosticConstruct(
2008 : Consumer(PDC), CurrentNode(ErrorNode),
2009 SM(CurrentNode->getCodeDecl().getASTContext().getSourceManager()),
2011 AnalysisEntryPoint)) {
2015PathDiagnosticBuilder::PathDiagnosticBuilder(
2018 std::unique_ptr<VisitorsDiagnosticsTy> VisitorsDiagnostics)
2020 ErrorNode(ErrorNode),
2021 VisitorsDiagnostics(
std::
move(VisitorsDiagnostics)) {}
2023std::unique_ptr<PathDiagnostic>
2025 const Decl *EntryPoint = getBugReporter().getAnalysisEntryPoint();
2026 PathDiagnosticConstruct Construct(PDC, ErrorNode, R, EntryPoint);
2028 const SourceManager &
SM = getSourceManager();
2029 const AnalyzerOptions &Opts = getAnalyzerOptions();
2035 auto EndNotes = VisitorsDiagnostics->find(ErrorNode);
2037 if (EndNotes != VisitorsDiagnostics->end()) {
2038 assert(!EndNotes->second.empty());
2039 LastPiece = EndNotes->second[0];
2044 Construct.PD->setEndOfPath(LastPiece);
2046 PathDiagnosticLocation PrevLoc = Construct.PD->getLocation();
2049 while (Construct.ascendToPrevNode()) {
2050 generatePathDiagnosticsForNode(Construct, PrevLoc);
2052 auto VisitorNotes = VisitorsDiagnostics->find(Construct.getCurrentNode());
2053 if (VisitorNotes == VisitorsDiagnostics->end())
2058 std::set<llvm::FoldingSetNodeID> DeduplicationSet;
2062 llvm::FoldingSetNodeID
ID;
2064 if (!DeduplicationSet.insert(ID).second)
2069 updateStackPiecesWithMessage(
Note, Construct.CallStack);
2070 Construct.getActivePath().push_front(
Note);
2077 const StackFrameContext *CalleeLC =
2078 Construct.getLocationContextForActivePath()->
getStackFrame();
2086 if (!Construct.PD->path.empty()) {
2088 bool stillHasNotes =
2090 assert(stillHasNotes);
2091 (void)stillHasNotes;
2095 if (!Opts.ShouldAddPopUpNotes)
2108 while (
optimizeEdges(Construct, Construct.getMutablePieces(), OCS)) {
2123 if (Opts.ShouldDisplayMacroExpansions)
2126 return std::move(Construct.PD);
2133void BugType::anchor() {}
2139LLVM_ATTRIBUTE_USED
static bool
2141 for (
const std::pair<StringRef, StringRef> &Pair : Registry.Dependencies) {
2142 if (Pair.second == CheckerName)
2149 StringRef CheckerName) {
2151 if (
Checker.FullName == CheckerName)
2155 "Checker name not found in CheckerRegistry -- did you retrieve it "
2156 "correctly from CheckerManager::getCurrentCheckerName?");
2160 const BugType &bt, StringRef shortDesc, StringRef desc,
2162 const Decl *DeclToUnique)
2166 assert(
ErrorNode &&
"The error node must be non-null!");
2168 ->getAnalysisManager()
2169 .getCheckerManager()
2170 ->getCheckerRegistryData(),
2172 "Some checkers depend on this one! We don't allow dependency "
2173 "checkers to emit warnings, because checkers should depend on "
2174 "*modeling*, not *diagnostics*.");
2178 ->getAnalysisManager()
2179 .getCheckerManager()
2180 ->getCheckerRegistryData(),
2182 "Hidden checkers musn't emit diagnostics as they are by definition "
2183 "non-user facing!");
2187 std::unique_ptr<BugReporterVisitor> visitor) {
2191 llvm::FoldingSetNodeID ID;
2192 visitor->Profile(ID);
2194 void *InsertPos =
nullptr;
2199 Callbacks.push_back(std::move(visitor));
2216 hash.AddInteger(
static_cast<int>(
getKind()));
2217 hash.AddPointer(&
BT);
2219 assert(Location.isValid());
2220 Location.Profile(hash);
2223 if (!range.isValid())
2225 hash.Add(range.getBegin());
2226 hash.Add(range.getEnd());
2231 hash.AddInteger(
static_cast<int>(
getKind()));
2232 hash.AddPointer(&
BT);
2242 hash.AddPointer(
ErrorNode->getCurrentOrPreviousStmtForDiagnostics());
2246 if (!range.isValid())
2248 hash.Add(range.getBegin());
2249 hash.Add(range.getEnd());
2255 llvm::DenseMap<T, bugreporter::TrackingKind> &InterestingnessMap,
T Val,
2257 auto Result = InterestingnessMap.insert({Val, TKind});
2277 "BugReport::markInteresting currently can only handle 2 different "
2278 "tracking kinds! Please define what tracking kind should this entitiy"
2279 "have, if it was already marked as interesting with a different kind!");
2291 if (
const auto *meta = dyn_cast<SymbolMetadata>(sym))
2303 if (
const auto *meta = dyn_cast<SymbolMetadata>(sym))
2315 if (
const auto *SR = dyn_cast<SymbolicRegion>(R))
2326 if (
const auto *SR = dyn_cast<SymbolicRegion>(R))
2342std::optional<bugreporter::TrackingKind>
2361 "BugReport::getInterestingnessKind currently can only handle 2 different "
2362 "tracking kinds! Please define what tracking kind should we return here "
2363 "when the kind of getAsRegion() and getAsSymbol() is different!");
2364 return std::nullopt;
2367std::optional<bugreporter::TrackingKind>
2370 return std::nullopt;
2375 return std::nullopt;
2376 return It->getSecond();
2379std::optional<bugreporter::TrackingKind>
2382 return std::nullopt;
2387 return It->getSecond();
2389 if (
const auto *SR = dyn_cast<SymbolicRegion>(R))
2391 return std::nullopt;
2417 const Stmt *S =
nullptr;
2421 if (BE->getBlock() == &Exit)
2422 S =
ErrorNode->getPreviousStmtForDiagnostics();
2464 assert(
ErrorNode &&
"Cannot create a location with a null node.");
2469 ErrorNode->getState()->getStateManager().getContext().getSourceManager();
2482 S =
ErrorNode->getNextStmtForDiagnostics();
2489 if (
const auto *AS = dyn_cast<AttributedStmt>(S))
2490 S = AS->getSubStmt();
2493 if (
const auto *ME = dyn_cast<MemberExpr>(S))
2497 if (
const auto *B = dyn_cast<BinaryOperator>(S))
2519 return Eng.getGraph();
2523 return Eng.getStateManager();
2527 : D(D), UserSuppressions(D.getASTContext()) {}
2531 assert(StrBugTypes.empty() &&
2532 "Destroying BugReporter before diagnostics are emitted!");
2535 for (
const auto I : EQClassesVector)
2542 for (
const auto EQ : EQClassesVector)
2549 StrBugTypes.clear();
2562 std::unique_ptr<ExplodedGraph> BugPath;
2569class BugPathGetter {
2570 std::unique_ptr<ExplodedGraph> TrimmedGraph;
2572 using PriorityMapTy = llvm::DenseMap<const ExplodedNode *, unsigned>;
2575 PriorityMapTy PriorityMap;
2579 using ReportNewNodePair =
2580 std::pair<PathSensitiveBugReport *, const ExplodedNode *>;
2583 BugPathInfo CurrentBugPath;
2586 template <
bool Descending>
2587 class PriorityCompare {
2588 const PriorityMapTy &PriorityMap;
2591 PriorityCompare(
const PriorityMapTy &M) : PriorityMap(M) {}
2594 PriorityMapTy::const_iterator LI = PriorityMap.find(LHS);
2595 PriorityMapTy::const_iterator RI = PriorityMap.find(RHS);
2596 PriorityMapTy::const_iterator E = PriorityMap.end();
2603 return Descending ? LI->second > RI->second
2604 : LI->second < RI->second;
2607 bool operator()(
const ReportNewNodePair &LHS,
2608 const ReportNewNodePair &RHS)
const {
2609 return (*
this)(LHS.second, RHS.second);
2614 BugPathGetter(
const ExplodedGraph *OriginalGraph,
2615 ArrayRef<PathSensitiveBugReport *> &bugReports);
2617 BugPathInfo *getNextBugPath();
2622BugPathGetter::BugPathGetter(
const ExplodedGraph *OriginalGraph,
2623 ArrayRef<PathSensitiveBugReport *> &bugReports) {
2624 SmallVector<const ExplodedNode *, 32> Nodes;
2625 for (
const auto I : bugReports) {
2626 assert(I->isValid() &&
2627 "We only allow BugReporterVisitors and BugReporter itself to "
2628 "invalidate reports!");
2629 Nodes.emplace_back(I->getErrorNode());
2635 TrimmedGraph = OriginalGraph->
trim(Nodes, &ForwardMap);
2640 llvm::SmallPtrSet<const ExplodedNode *, 32> RemainingNodes;
2645 "Failed to construct a trimmed graph that contains this error "
2647 ReportNodes.emplace_back(
Report, NewNode);
2648 RemainingNodes.insert(NewNode);
2651 assert(!RemainingNodes.empty() &&
"No error node found in the trimmed graph");
2654 std::queue<const ExplodedNode *> WS;
2656 WS.push(TrimmedGraph->getRoot());
2657 unsigned Priority = 0;
2659 while (!WS.empty()) {
2663 PriorityMapTy::iterator PriorityEntry;
2665 std::tie(PriorityEntry, IsNew) = PriorityMap.insert({Node, Priority});
2669 assert(PriorityEntry->second <= Priority);
2673 if (RemainingNodes.erase(Node))
2674 if (RemainingNodes.empty())
2682 llvm::sort(ReportNodes, PriorityCompare<true>(PriorityMap));
2685BugPathInfo *BugPathGetter::getNextBugPath() {
2686 if (ReportNodes.empty())
2690 std::tie(CurrentBugPath.Report, OrigN) = ReportNodes.pop_back_val();
2691 assert(PriorityMap.contains(OrigN) &&
"error node not accessible from root");
2695 auto GNew = std::make_unique<ExplodedGraph>();
2711 CurrentBugPath.ErrorNode = NewN;
2717 assert(OrigN == TrimmedGraph->getRoot() &&
2718 "There should be only one root!");
2719 GNew->designateAsRoot(NewN);
2726 PriorityCompare<false>(PriorityMap));
2729 CurrentBugPath.BugPath = std::move(GNew);
2731 return &CurrentBugPath;
2738 using MacroStackTy = std::vector<
2739 std::pair<std::shared_ptr<PathDiagnosticMacroPiece>,
SourceLocation>>;
2741 using PiecesTy = std::vector<PathDiagnosticPieceRef>;
2743 MacroStackTy MacroStack;
2746 for (PathPieces::const_iterator I = path.begin(), E = path.end();
2748 const auto &piece = *I;
2751 if (
auto *call = dyn_cast<PathDiagnosticCallPiece>(&*piece)) {
2761 SM.getExpansionLoc(
Loc) :
2764 if (
Loc.isFileID()) {
2766 Pieces.push_back(piece);
2770 assert(
Loc.isMacroID());
2773 if (!MacroStack.empty() && InstantiationLoc == MacroStack.back().second) {
2774 MacroStack.back().first->subPieces.push_back(piece);
2780 std::shared_ptr<PathDiagnosticMacroPiece> MacroGroup;
2783 SM.getExpansionLoc(
Loc) :
2787 while (!MacroStack.empty()) {
2788 if (InstantiationLoc == MacroStack.back().second) {
2789 MacroGroup = MacroStack.back().first;
2793 if (ParentInstantiationLoc == MacroStack.back().second) {
2794 MacroGroup = MacroStack.back().first;
2798 MacroStack.pop_back();
2801 if (!MacroGroup || ParentInstantiationLoc == MacroStack.back().second) {
2803 auto NewGroup = std::make_shared<PathDiagnosticMacroPiece>(
2807 MacroGroup->subPieces.push_back(NewGroup);
2809 assert(InstantiationLoc.
isFileID());
2810 Pieces.push_back(NewGroup);
2813 MacroGroup = NewGroup;
2814 MacroStack.push_back(std::make_pair(MacroGroup, InstantiationLoc));
2818 MacroGroup->subPieces.push_back(piece);
2824 llvm::append_range(path, Pieces);
2830static std::unique_ptr<VisitorsDiagnosticsTy>
2834 std::unique_ptr<VisitorsDiagnosticsTy> Notes =
2835 std::make_unique<VisitorsDiagnosticsTy>();
2848 for (std::unique_ptr<BugReporterVisitor> &Visitor : R->
visitors())
2849 visitors.push_back(std::move(Visitor));
2856 for (
auto &
V : visitors) {
2857 V->finalizeVisitor(BRC, ErrorNode, *R);
2859 if (
auto Piece =
V->getEndPath(BRC, ErrorNode, *R)) {
2860 assert(!LastPiece &&
2861 "There can only be one final piece in a diagnostic.");
2863 "The final piece must contain a message!");
2864 LastPiece = std::move(Piece);
2865 (*Notes)[ErrorNode].push_back(LastPiece);
2871 for (
auto &
V : visitors) {
2872 auto P =
V->VisitNode(NextNode, BRC, *R);
2874 (*Notes)[NextNode].push_back(std::move(P));
2886std::optional<PathDiagnosticBuilder> PathDiagnosticBuilder::findValidReport(
2887 ArrayRef<PathSensitiveBugReport *> &bugReports,
2891 BugPathGetter BugGraph(&Reporter.
getGraph(), bugReports);
2893 while (BugPathInfo *BugPath = BugGraph.getNextBugPath()) {
2896 assert(R &&
"No original report found for sliced graph.");
2897 assert(R->
isValid() &&
"Report selected by trimmed graph marked invalid.");
2912 std::unique_ptr<VisitorsDiagnosticsTy> visitorNotes =
2917 llvm::TimeTraceScope TCS{
"Crosscheck with Z3"};
2928 switch (Z3Oracle.interpretQueryResult(CrosscheckResult)) {
2930 ++NumTimesReportRefuted;
2931 R->
markInvalid(
"Infeasible constraints",
nullptr);
2934 ++NumTimesReportEQClassAborted;
2937 ++NumTimesReportPassesZ3;
2943 return PathDiagnosticBuilder(std::move(BRC), std::move(BugPath->BugPath),
2944 BugPath->Report, BugPath->ErrorNode,
2945 std::move(visitorNotes));
2949 ++NumTimesReportEQClassWasExhausted;
2953std::unique_ptr<DiagnosticForConsumerMapTy>
2955 ArrayRef<std::unique_ptr<PathDiagnosticConsumer>> consumers,
2957 assert(!bugReports.empty());
2959 auto Out = std::make_unique<DiagnosticForConsumerMapTy>();
2961 std::optional<PathDiagnosticBuilder> PDB =
2962 PathDiagnosticBuilder::findValidReport(bugReports, *
this);
2965 for (
const auto &PC : consumers) {
2966 if (std::unique_ptr<PathDiagnostic> PD = PDB->generate(PC.get())) {
2967 (*Out)[PC.get()] = std::move(PD);
2976 bool ValidSourceLoc = R->getLocation().isValid();
2977 assert(ValidSourceLoc);
2980 if (!ValidSourceLoc)
2984 if (UserSuppressions.isSuppressed(*R))
2988 llvm::FoldingSetNodeID ID;
2997 EQClasses.InsertNode(EQ, InsertPos);
2998 EQClassesVector.push_back(EQ);
3000 EQ->AddReport(std::move(R));
3004 if (
auto PR = dyn_cast<PathSensitiveBugReport>(R.get()))
3008 assert((E->isSink() || E->getLocation().getTag()) &&
3009 "Error node must either be a sink or have a tag");
3012 E->getLocationContext()->getAnalysisDeclContext();
3031struct FRIEC_WLItem {
3036 : N(n), I(N->succ_begin()), E(N->succ_end()) {}
3041BugReport *PathSensitiveBugReporter::findReportInEquivalenceClass(
3046 assert(
EQ.getReports().size() > 0);
3047 const BugType& BT =
EQ.getReports()[0]->getBugType();
3049 BugReport *R =
EQ.getReports()[0].get();
3050 for (
auto &J :
EQ.getReports()) {
3051 if (
auto *PR = dyn_cast<PathSensitiveBugReport>(J.get())) {
3053 bugReports.push_back(PR);
3065 BugReport *exampleReport =
nullptr;
3067 for (
const auto &I:
EQ.getReports()) {
3068 auto *R = dyn_cast<PathSensitiveBugReport>(I.get());
3072 const ExplodedNode *errorNode = R->getErrorNode();
3073 if (errorNode->
isSink()) {
3075 "BugType::isSuppressSink() should not be 'true' for sink end nodes");
3079 bugReports.push_back(R);
3089 if (
const CFGBlock *ErrorB = errorNode->
getCFGBlock())
3090 if (ErrorB->isInevitablySinking())
3095 using WLItem = FRIEC_WLItem;
3096 using DFSWorkList = SmallVector<WLItem, 10>;
3098 llvm::DenseMap<const ExplodedNode *, unsigned> Visited;
3101 WL.push_back(errorNode);
3102 Visited[errorNode] = 1;
3104 while (!WL.empty()) {
3105 WLItem &WI = WL.back();
3106 assert(!WI.N->succ_empty());
3108 for (; WI.I != WI.E; ++WI.I) {
3109 const ExplodedNode *Succ = *WI.I;
3114 bugReports.push_back(R);
3125 unsigned &mark = Visited[Succ];
3135 if (!WL.empty() && &WL.back() == &WI)
3142 return exampleReport;
3146 llvm::TimeTraceScope TCS{timeTraceName(EQ), [&]() {
3149 SmallVector<BugReport*, 10> bugReports;
3150 BugReport *report = findReportInEquivalenceClass(EQ, bugReports);
3155 for (
const std::string &CheckerOrPackage :
3162 std::unique_ptr<DiagnosticForConsumerMapTy> Diagnostics =
3165 for (
auto &P : *Diagnostics) {
3166 PathDiagnosticConsumer *Consumer = P.first;
3167 std::unique_ptr<PathDiagnostic> &PD = P.second;
3171 if (PD->path.empty()) {
3173 auto piece = std::make_unique<PathDiagnosticEventPiece>(
3175 for (SourceRange Range : report->
getRanges())
3176 piece->addRange(Range);
3177 PD->setEndOfPath(std::move(piece));
3180 PathPieces &Pieces = PD->getMutablePieces();
3184 for (
const auto &I : llvm::reverse(report->
getNotes())) {
3185 PathDiagnosticNotePiece *Piece = I.get();
3186 auto ConvertedPiece = std::make_shared<PathDiagnosticEventPiece>(
3189 ConvertedPiece->addRange(R);
3191 Pieces.push_front(std::move(ConvertedPiece));
3194 for (
const auto &I : llvm::reverse(report->
getNotes()))
3195 Pieces.push_front(I);
3198 for (
const auto &I : report->
getFixits())
3199 Pieces.back()->addFixit(I);
3207 Pieces.push_front(std::make_shared<PathDiagnosticEventPiece>(
3209 "[debug] analyzing from " +
3223 if (
const auto FD = dyn_cast<FunctionDecl>(Signature)) {
3224 SignatureSourceRange = FD->getSourceRange();
3225 }
else if (
const auto OD = dyn_cast<ObjCMethodDecl>(Signature)) {
3226 SignatureSourceRange = OD->getSourceRange();
3232 : SignatureSourceRange.
getEnd();
3235 unsigned StartLine =
SM.getExpansionLineNumber(Start);
3236 unsigned EndLine =
SM.getExpansionLineNumber(End);
3238 FileID FID =
SM.getFileID(
SM.getExpansionLoc(Start));
3239 for (
unsigned Line = StartLine;
Line <= EndLine;
Line++)
3240 ExecutedLines[FID].insert(
Line);
3250 FileID FID =
SM.getFileID(ExpansionLoc);
3251 unsigned LineNo =
SM.getExpansionLineNumber(ExpansionLoc);
3252 ExecutedLines[FID].insert(LineNo);
3257static std::unique_ptr<FilesToLineNumsMap>
3259 auto ExecutedLines = std::make_unique<FilesToLineNumsMap>();
3268 const Decl* D = CE->getCalleeContext()->getDecl();
3279 if (
const auto *RS = dyn_cast_or_null<ReturnStmt>(P)) {
3284 if (isa_and_nonnull<SwitchCase, LabelStmt>(P))
3290 return ExecutedLines;
3293std::unique_ptr<DiagnosticForConsumerMapTy>
3296 ArrayRef<std::unique_ptr<PathDiagnosticConsumer>> consumers,
3299 auto Out = std::make_unique<DiagnosticForConsumerMapTy>();
3300 for (
const auto &Consumer : consumers)
3301 (*Out)[Consumer.get()] =
3316 "The call piece should not be in a header file.");
3328 if (
auto *CPInner = dyn_cast<PathDiagnosticCallPiece>(Path.back().get()))
3336 if (PD.
path.empty())
3345 if (
auto *CP = dyn_cast<PathDiagnosticCallPiece>(LastP)) {
3352 const auto *ND = dyn_cast<NamedDecl>(CP->
getCallee());
3355 llvm::raw_svector_ostream os(buf);
3356 os <<
" (within a call to '" << ND->getDeclName() <<
"')";
3369std::unique_ptr<DiagnosticForConsumerMapTy>
3370PathSensitiveBugReporter::generateDiagnosticForConsumerMap(
3372 ArrayRef<std::unique_ptr<PathDiagnosticConsumer>> consumers,
3373 ArrayRef<BugReport *> bugReports) {
3376 consumers, bugReports);
3382 assert(!bugReports.empty());
3383 MaxBugClassSize.updateMax(bugReports.size());
3386 ArrayRef<PathSensitiveBugReport *> convertedArrayOfReports(
3387 reinterpret_cast<PathSensitiveBugReport *
const *
>(&*bugReports.begin()),
3388 reinterpret_cast<PathSensitiveBugReport *
const *
>(&*bugReports.end()));
3390 consumers, convertedArrayOfReports);
3395 MaxValidBugClassSize.updateMax(bugReports.size());
3400 for (
auto const &P : *Out)
3401 if (Opts.ShouldReportIssuesInMainSourceFile && !Opts.
AnalyzeAll)
3409 StringRef Name, StringRef Category,
3419 StringRef name, StringRef category,
3424 BugType *BT = getBugTypeForName(CheckName, name, category);
3425 auto R = std::make_unique<BasicBugReport>(*BT, str,
Loc);
3426 R->setDeclWithIssue(DeclWithIssue);
3427 for (
const auto &SR : Ranges)
3429 for (
const auto &FH : Fixits)
3435 StringRef name, StringRef category) {
3437 llvm::raw_svector_ostream(fullDesc)
3438 << CheckName <<
":" << name <<
":" << category;
3439 std::unique_ptr<BugType> &BT = StrBugTypes[fullDesc];
3441 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 PathDiagnosticLocation getEnclosingStmtLocation(const Stmt *S, const LocationContext *LC, bool allowNestedContexts=false)
static std::unique_ptr< FilesToLineNumsMap > findExecutedLines(const SourceManager &SM, const ExplodedNode *N)
static bool isConditionForTerminator(const Stmt *S, const Stmt *Cond)
static void updateExecutedLinesWithDiagnosticPieces(PathDiagnostic &PD)
Populate executes lines with lines containing at least one diagnostics.
static void removeRedundantMsgs(PathPieces &path)
An optimization pass over PathPieces that removes redundant diagnostics generated by both ConditionBR...
constexpr llvm::StringLiteral StrLoopCollectionEmpty
static void adjustCallLocations(PathPieces &Pieces, PathDiagnosticLocation *LastCallLocation=nullptr)
Recursively scan through a path and make sure that all call pieces have valid locations.
static void removeIdenticalEvents(PathPieces &path)
static const Stmt * getTerminatorCondition(const CFGBlock *B)
A customized wrapper for CFGBlock::getTerminatorCondition() which returns the element for ObjCForColl...
static std::unique_ptr< VisitorsDiagnosticsTy > generateVisitorsDiagnostics(PathSensitiveBugReport *R, const ExplodedNode *ErrorNode, BugReporterContext &BRC)
Generate notes from all visitors.
static bool removeUnneededCalls(const PathDiagnosticConstruct &C, PathPieces &pieces, const PathSensitiveBugReport *R, bool IsInteresting=false)
Recursively scan through a path and prune out calls and macros pieces that aren't needed.
static const Stmt * findReasonableStmtCloseToFunctionExit(const ExplodedNode *N)
static void populateExecutedLinesWithStmt(const Stmt *S, const SourceManager &SM, FilesToLineNumsMap &ExecutedLines)
static bool isJumpToFalseBranch(const BlockEdge *BE)
static std::optional< size_t > getLengthOnSingleLine(const SourceManager &SM, SourceRange Range)
Returns the number of bytes in the given (character-based) SourceRange.
static bool isContainedByStmt(const ParentMap &PM, const Stmt *S, const Stmt *SubS)
constexpr llvm::StringLiteral StrEnteringLoop
static void addEdgeToPath(PathPieces &path, PathDiagnosticLocation &PrevLoc, PathDiagnosticLocation NewLoc)
Adds a sanitized control-flow diagnostic edge to a path.
static bool isIncrementOrInitInForLoop(const Stmt *S, const Stmt *FL)
static std::unique_ptr< PathDiagnostic > generateEmptyDiagnosticForReport(const PathSensitiveBugReport *R, const SourceManager &SM, const Decl *AnalysisEntryPoint)
static void removeContextCycles(PathPieces &Path, const SourceManager &SM)
Eliminate two-edge cycles created by addContextEdges().
static bool lexicalContains(const ParentMap &PM, const Stmt *X, const Stmt *Y)
Return true if X is contained by Y.
static std::unique_ptr< PathDiagnostic > generateDiagnosticForBasicReport(const BasicBugReport *R, const Decl *AnalysisEntryPoint)
static void removePopUpNotes(PathPieces &Path)
Same logic as above to remove extra pieces.
static void insertToInterestingnessMap(llvm::DenseMap< T, bugreporter::TrackingKind > &InterestingnessMap, T Val, bugreporter::TrackingKind TKind)
constexpr llvm::StringLiteral StrLoopBodyZero
static const Stmt * getEnclosingParent(const Stmt *S, const ParentMap &PM)
static void removePunyEdges(PathPieces &path, const SourceManager &SM, const ParentMap &PM)
static const Stmt * getStmtParent(const Stmt *S, const ParentMap &PM)
static bool exitingDestructor(const ExplodedNode *N)
static void CompactMacroExpandedPieces(PathPieces &path, const SourceManager &SM)
CompactMacroExpandedPieces - This function postprocesses a PathDiagnostic object and collapses PathDi...
static void simplifySimpleBranches(PathPieces &pieces)
Move edges from a branch condition to a branch target when the condition is simple.
static void populateExecutedLinesWithFunctionSignature(const Decl *Signature, const SourceManager &SM, FilesToLineNumsMap &ExecutedLines)
Insert all lines participating in the function signature Signature into ExecutedLines.
static void resetDiagnosticLocationToMainFile(PathDiagnostic &PD)
static bool optimizeEdges(const PathDiagnosticConstruct &C, PathPieces &path, OptimizedCallsSet &OCS)
static bool hasImplicitBody(const Decl *D)
Returns true if the given decl has been implicitly given a body, either by the analyzer or by the com...
static PathDiagnosticCallPiece * getFirstStackedCallToHeaderFile(PathDiagnosticCallPiece *CP, const SourceManager &SMgr)
llvm::DenseSet< const PathDiagnosticCallPiece * > OptimizedCallsSet
static void addContextEdges(PathPieces &pieces, const LocationContext *LC)
Adds synthetic edges from top-level statements to their subexpressions.
static LLVM_ATTRIBUTE_USED bool isDependency(const CheckerRegistryData &Registry, StringRef CheckerName)
static PathDiagnosticEventPiece * eventsDescribeSameCondition(PathDiagnosticEventPiece *X, PathDiagnosticEventPiece *Y)
static bool isInLoopBody(const ParentMap &PM, const Stmt *S, const Stmt *Term)
static void removeEdgesToDefaultInitializers(PathPieces &Pieces)
Remove edges in and out of C++ default initializer expressions.
static const Stmt * getStmtBeforeCond(const ParentMap &PM, const Stmt *Term, const ExplodedNode *N)
static void removePiecesWithInvalidLocations(PathPieces &Pieces)
Remove all pieces with invalid locations as these cannot be serialized.
static LLVM_ATTRIBUTE_USED bool isHidden(const CheckerRegistryData &Registry, StringRef CheckerName)
static llvm::TimeTraceMetadata timeTraceMetadata(const ExplodedNode *Pred, const ProgramPoint &Loc)
#define STAT_COUNTER(VARNAME, DESC)
#define STAT_MAX(VARNAME, DESC)
Defines the clang::Expr interface and subclasses for C++ expressions.
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
Defines the clang::SourceLocation class and associated facilities.
Defines the SourceManager interface.
Defines the Objective-C statement AST node classes.
SourceManager & getSourceManager()
AnalysisDeclContext contains the context data for the function, method or block under analysis.
static std::string getFunctionName(const Decl *D)
bool isBodyAutosynthesized() const
bool isBodyAutosynthesizedFromModelFile() const
const CFGBlock * getSrc() const
const CFGBlock * getDst() const
Represents a single basic block in a source-level CFG.
succ_iterator succ_begin()
Stmt * getTerminatorStmt()
const Stmt * getLoopTarget() const
Stmt * getTerminatorCondition(bool StripParens=true)
unsigned succ_size() const
CXXForRangeStmt - This represents C++0x [stmt.ranged]'s ranged for statement, represented as 'for (ra...
Represents a point when we begin processing an inlined call.
Represents a point when we finish the call exit sequence (for inlined call).
const StackFrameContext * getCalleeContext() const
Decl - This represents one declaration (or definition), e.g.
ASTContext & getASTContext() const LLVM_READONLY
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
virtual bool hasBody() const
Returns true if this Decl represents a declaration for a body of code, such as a function or method d...
SourceLocation getLocation() const
This represents one expression.
llvm::APSInt EvaluateKnownConstInt(const ASTContext &Ctx) 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.
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
const Decl * getDecl() const
const ParentMap & getParentMap() const
const StackFrameContext * getStackFrame() const
Represents Objective-C's collection statement.
bool isConsumedExpr(Expr *E) const
Stmt * getParent(Stmt *) const
Stmt * getParentIgnoreParens(Stmt *) const
Represents a point after we ran remove dead bindings AFTER processing the given statement.
Represents a program point just before an implicit call event.
T castAs() const
Convert to the specified ProgramPoint type, asserting that this ProgramPoint is of the desired type.
std::optional< T > getAs() const
Convert to the specified ProgramPoint type, returning std::nullopt if this ProgramPoint is not of the...
const LocationContext * getLocationContext() const
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
This class handles loading and caching of source files into memory.
A trivial tuple used to represent a source range.
SourceLocation getEnd() const
SourceLocation getBegin() const
It represents a stack frame of the call stack (based on CallEvent).
const Stmt * getCallSite() const
Stmt - This represents one statement.
StmtClass getStmtClass() const
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
SourceLocation getBeginLoc() const LLVM_READONLY
WhileStmt - This represents a 'while' stmt.
static bool isInCodeFile(SourceLocation SL, const SourceManager &SM)
const Decl * getDeclWithIssue() const override
The smallest declaration that contains the bug location.
PathDiagnosticLocation getUniqueingLocation() const override
Get the location on which the report should be uniqued.
void Profile(llvm::FoldingSetNodeID &hash) const override
Reports are uniqued to ensure that we do not emit multiple diagnostics for each bug.
const Decl * getUniqueingDecl() const override
Get the declaration that corresponds to (usually contains) the uniqueing location.
This class provides an interface through which checkers can create individual bug reports.
llvm::ArrayRef< FixItHint > getFixits() const
void addRange(SourceRange R)
Add a range to a bug report.
SmallVector< SourceRange, 4 > Ranges
virtual PathDiagnosticLocation getLocation() const =0
The primary location of the bug report that points at the undesirable behavior in the code.
ArrayRef< std::shared_ptr< PathDiagnosticNotePiece > > getNotes()
BugReport(Kind kind, const BugType &bt, StringRef desc)
void addFixItHint(const FixItHint &F)
Add a fix-it hint to the bug report.
StringRef getDescription() const
A verbose warning message that is appropriate for displaying next to the source code that introduces ...
const BugType & getBugType() const
StringRef getShortDescription(bool UseFallback=true) const
A short general warning message that is appropriate for displaying in the list of all reported bugs.
virtual ArrayRef< SourceRange > getRanges() const
Get the SourceRanges associated with the report.
static PathDiagnosticPieceRef getDefaultEndPath(const BugReporterContext &BRC, const ExplodedNode *N, const PathSensitiveBugReport &BR)
Generates the default final diagnostic piece.
virtual ~BugReporterVisitor()
void FlushReports()
Generate and flush diagnostics for all bug reports.
BugReporter(BugReporterData &d)
const SourceManager & getSourceManager()
const Decl * getAnalysisEntryPoint() const
Get the top-level entry point for the issue to be reported.
ArrayRef< std::unique_ptr< PathDiagnosticConsumer > > getPathDiagnosticConsumers()
void EmitBasicReport(const Decl *DeclWithIssue, const CheckerFrontend *Checker, StringRef BugName, StringRef BugCategory, StringRef BugStr, PathDiagnosticLocation Loc, ArrayRef< SourceRange > Ranges={}, ArrayRef< FixItHint > Fixits={})
virtual std::unique_ptr< DiagnosticForConsumerMapTy > generateDiagnosticForConsumerMap(BugReport *exampleReport, ArrayRef< std::unique_ptr< PathDiagnosticConsumer > > consumers, ArrayRef< BugReport * > bugReports)
Generate the diagnostics for the given bug report.
const AnalyzerOptions & getAnalyzerOptions()
virtual void emitReport(std::unique_ptr< BugReport > R)
Add the given report to the set of reports tracked by BugReporter.
bool isSuppressOnSink() const
isSuppressOnSink - Returns true if bug reports associated with this bug type should be suppressed if ...
StringRef getCategory() const
StringRef getDescription() const
StringRef getCheckerName() const
A CheckerFrontend instance is what the user recognizes as "one checker": it has a public canonical na...
CheckerNameRef getName() const
This wrapper is used to ensure that only StringRefs originating from the CheckerRegistry are used as ...
Simple checker classes that implement one frontend (i.e.
Visitor that tries to report interesting diagnostics from conditions.
static bool isPieceMessageGeneric(const PathDiagnosticPiece *Piece)
static const char * getTag()
Return the tag associated with this visitor.
bool isValid() const =delete
std::unique_ptr< ExplodedGraph > trim(ArrayRef< const NodeTy * > Nodes, InterExplodedGraphMap *ForwardMap=nullptr, InterExplodedGraphMap *InverseMap=nullptr) const
Creates a trimmed version of the graph that only contains paths leading to the given nodes.
const CFGBlock * getCFGBlock() const
const ProgramStateRef & getState() const
pred_iterator pred_begin()
const Stmt * getStmtForDiagnostics() const
If the node's program point corresponds to a statement, retrieve that statement.
const Stmt * getPreviousStmtForDiagnostics() const
Find the statement that was executed immediately before this node.
ProgramPoint getLocation() const
getLocation - Returns the edge associated with the given node.
void addPredecessor(ExplodedNode *V, ExplodedGraph &G)
addPredeccessor - Adds a predecessor to the current node, and in tandem add this node as a successor ...
const Stmt * getNextStmtForDiagnostics() const
Find the next statement that was executed on this node's execution path.
const ParentMap & getParentMap() const
SVal getSVal(const Stmt *S) const
Get the value of an arbitrary expression at this node.
const LocationContext * getLocationContext() const
std::optional< T > getLocationAs() const &
ExplodedNode * getFirstPred()
const ExplodedNode *const * const_succ_iterator
Suppress reports that might lead to known false positives.
MemRegion - The root abstract class for all memory regions.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getBaseRegion() const
Prints path notes when a message is sent to a nil receiver.
PathDiagnosticLocation getLocation() const override
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
void Profile(llvm::FoldingSetNodeID &ID) const
const SourceManager & getManager() const
static PathDiagnosticLocation createOperatorLoc(const BinaryOperator *BO, const SourceManager &SM)
Create the location for the operator of the binary expression.
static PathDiagnosticLocation createEndBrace(const CompoundStmt *CS, const SourceManager &SM)
Create a location for the end of the compound statement.
static SourceLocation getValidSourceLocation(const Stmt *S, LocationOrAnalysisDeclContext LAC, bool UseEndOfStatement=false)
Construct a source location that corresponds to either the beginning or the end of the given statemen...
static PathDiagnosticLocation createEnd(const Stmt *S, const SourceManager &SM, const LocationOrAnalysisDeclContext LAC)
Create a location for the end of the statement.
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
FullSourceLoc asLocation() const
static PathDiagnosticLocation createDeclEnd(const LocationContext *LC, const SourceManager &SM)
Constructs a location for the end of the enclosing declaration body.
const Stmt * getStmtOrNull() const
static PathDiagnosticLocation createSingleLocation(const PathDiagnosticLocation &PDL)
Convert the given location into a single kind location.
ArrayRef< SourceRange > getRanges() const
Return the SourceRanges associated with this PathDiagnosticPiece.
virtual PathDiagnosticLocation getLocation() const =0
void setAsLastInMainSourceFile()
const void * getTag() const
Return the opaque tag (if any) on the PathDiagnosticPiece.
StringRef getString() const
PathDiagnosticLocation getLocation() const override
PathDiagnostic - PathDiagnostic objects represent a single path-sensitive diagnostic.
void setDeclWithIssue(const Decl *D)
void appendToDesc(StringRef S)
void setLocation(PathDiagnosticLocation NewLoc)
const FilesToLineNumsMap & getExecutedLines() const
PathPieces flatten(bool ShouldFlattenMacros) const
void markInteresting(SymbolRef sym, bugreporter::TrackingKind TKind=bugreporter::TrackingKind::Thorough)
Marks a symbol as interesting.
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.
bool shouldPrunePath() const
Indicates whether or not any path pruning should take place when generating a PathDiagnostic from thi...
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 Decl * getUniqueingDecl() const override
Get the declaration containing the uniqueing location.
const ExplodedNode * getErrorNode() const
PathSensitiveBugReport(const BugType &bt, StringRef desc, const ExplodedNode *errorNode)
const ExplodedNode * ErrorNode
The ExplodedGraph node against which the report was thrown.
void markInvalid(const void *Tag, const void *Data)
Marks the current report as invalid, meaning that it is probably a false positive and should not be r...
void Profile(llvm::FoldingSetNodeID &hash) const override
Profile to identify equivalent bug reports for error report coalescing.
void clearVisitors()
Remove all visitors attached to this bug report.
void addVisitor(std::unique_ptr< BugReporterVisitor > visitor)
Add custom or predefined bug report visitors to this report.
bool isValid() const
Returns whether or not this report should be considered valid.
std::optional< bugreporter::TrackingKind > getInterestingnessKind(SymbolRef sym) const
void markNotInteresting(SymbolRef sym)
llvm::DenseMap< const MemRegion *, bugreporter::TrackingKind > InterestingRegions
A (stack of) set of regions that are registered with this report as being "interesting",...
bool isInteresting(SymbolRef sym) const
const SourceRange ErrorNodeRange
The range that corresponds to ErrorNode's program point.
llvm::FoldingSet< BugReporterVisitor > CallbacksSet
Used for ensuring the visitors are only added once.
llvm::SmallPtrSet< const LocationContext *, 2 > InterestingLocationContexts
A set of location contexts that correspoind to call sites which should be considered "interesting".
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)
const FunctionProtoType * T
U cast(CodeGen::Address addr)
Diagnostic wrappers for TextAPI types for error reporting.