1 //===--- PathDiagnostic.cpp - Path-Specific Diagnostic Handling -*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file defines the PathDiagnostic-related interfaces.
12 //===----------------------------------------------------------------------===//
14 #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
15 #include "clang/AST/Decl.h"
16 #include "clang/AST/DeclCXX.h"
17 #include "clang/AST/DeclObjC.h"
18 #include "clang/AST/Expr.h"
19 #include "clang/AST/ExprCXX.h"
20 #include "clang/AST/ParentMap.h"
21 #include "clang/AST/StmtCXX.h"
22 #include "clang/Basic/SourceManager.h"
23 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
24 #include "llvm/ADT/SmallString.h"
25 #include "llvm/ADT/StringExtras.h"
26 #include "llvm/Support/raw_ostream.h"
28 using namespace clang;
31 bool PathDiagnosticMacroPiece::containsEvent() const {
32 for (auto &P : subPieces) {
33 if (isa<PathDiagnosticEventPiece>(*P))
35 if (auto *MP = dyn_cast<PathDiagnosticMacroPiece>(P.get()))
36 if (MP->containsEvent())
42 static StringRef StripTrailingDots(StringRef s) {
43 for (StringRef::size_type i = s.size(); i != 0; --i)
45 return s.substr(0, i);
49 PathDiagnosticPiece::PathDiagnosticPiece(StringRef s,
50 Kind k, DisplayHint hint)
51 : str(StripTrailingDots(s)), kind(k), Hint(hint),
52 LastInMainSourceFile(false) {}
54 PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint)
55 : kind(k), Hint(hint), LastInMainSourceFile(false) {}
57 PathDiagnosticPiece::~PathDiagnosticPiece() {}
58 PathDiagnosticEventPiece::~PathDiagnosticEventPiece() {}
59 PathDiagnosticCallPiece::~PathDiagnosticCallPiece() {}
60 PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() {}
61 PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() {}
62 PathDiagnosticNotePiece::~PathDiagnosticNotePiece() {}
64 void PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current,
65 bool ShouldFlattenMacros) const {
66 for (auto &Piece : *this) {
67 switch (Piece->getKind()) {
68 case PathDiagnosticPiece::Call: {
69 auto &Call = cast<PathDiagnosticCallPiece>(*Piece);
70 if (auto CallEnter = Call.getCallEnterEvent())
71 Current.push_back(std::move(CallEnter));
72 Call.path.flattenTo(Primary, Primary, ShouldFlattenMacros);
73 if (auto callExit = Call.getCallExitEvent())
74 Current.push_back(std::move(callExit));
77 case PathDiagnosticPiece::Macro: {
78 auto &Macro = cast<PathDiagnosticMacroPiece>(*Piece);
79 if (ShouldFlattenMacros) {
80 Macro.subPieces.flattenTo(Primary, Primary, ShouldFlattenMacros);
82 Current.push_back(Piece);
84 Macro.subPieces.flattenTo(Primary, NewPath, ShouldFlattenMacros);
85 // FIXME: This probably shouldn't mutate the original path piece.
86 Macro.subPieces = NewPath;
90 case PathDiagnosticPiece::Event:
91 case PathDiagnosticPiece::ControlFlow:
92 case PathDiagnosticPiece::Note:
93 Current.push_back(Piece);
99 PathDiagnostic::~PathDiagnostic() {}
101 PathDiagnostic::PathDiagnostic(StringRef CheckName, const Decl *declWithIssue,
102 StringRef bugtype, StringRef verboseDesc,
103 StringRef shortDesc, StringRef category,
104 PathDiagnosticLocation LocationToUnique,
105 const Decl *DeclToUnique)
106 : CheckName(CheckName),
107 DeclWithIssue(declWithIssue),
108 BugType(StripTrailingDots(bugtype)),
109 VerboseDesc(StripTrailingDots(verboseDesc)),
110 ShortDesc(StripTrailingDots(shortDesc)),
111 Category(StripTrailingDots(category)),
112 UniqueingLoc(LocationToUnique),
113 UniqueingDecl(DeclToUnique),
116 static PathDiagnosticCallPiece *
117 getFirstStackedCallToHeaderFile(PathDiagnosticCallPiece *CP,
118 const SourceManager &SMgr) {
119 SourceLocation CallLoc = CP->callEnter.asLocation();
121 // If the call is within a macro, don't do anything (for now).
122 if (CallLoc.isMacroID())
125 assert(SMgr.isInMainFile(CallLoc) &&
126 "The call piece should be in the main file.");
128 // Check if CP represents a path through a function outside of the main file.
129 if (!SMgr.isInMainFile(CP->callEnterWithin.asLocation()))
132 const PathPieces &Path = CP->path;
136 // Check if the last piece in the callee path is a call to a function outside
138 if (PathDiagnosticCallPiece *CPInner =
139 dyn_cast<PathDiagnosticCallPiece>(Path.back().get())) {
140 return getFirstStackedCallToHeaderFile(CPInner, SMgr);
143 // Otherwise, the last piece is in the main file.
147 void PathDiagnostic::resetDiagnosticLocationToMainFile() {
151 PathDiagnosticPiece *LastP = path.back().get();
153 const SourceManager &SMgr = LastP->getLocation().getManager();
155 // We only need to check if the report ends inside headers, if the last piece
157 if (PathDiagnosticCallPiece *CP = dyn_cast<PathDiagnosticCallPiece>(LastP)) {
158 CP = getFirstStackedCallToHeaderFile(CP, SMgr);
161 CP->setAsLastInMainSourceFile();
163 // Update the path diagnostic message.
164 const NamedDecl *ND = dyn_cast<NamedDecl>(CP->getCallee());
166 SmallString<200> buf;
167 llvm::raw_svector_ostream os(buf);
168 os << " (within a call to '" << ND->getDeclName() << "')";
169 appendToDesc(os.str());
172 // Reset the report containing declaration and location.
173 DeclWithIssue = CP->getCaller();
174 Loc = CP->getLocation();
181 void PathDiagnosticConsumer::anchor() { }
183 PathDiagnosticConsumer::~PathDiagnosticConsumer() {
184 // Delete the contents of the FoldingSet if it isn't empty already.
185 for (llvm::FoldingSet<PathDiagnostic>::iterator it =
186 Diags.begin(), et = Diags.end() ; it != et ; ++it) {
191 void PathDiagnosticConsumer::HandlePathDiagnostic(
192 std::unique_ptr<PathDiagnostic> D) {
193 if (!D || D->path.empty())
196 // We need to flatten the locations (convert Stmt* to locations) because
197 // the referenced statements may be freed by the time the diagnostics
199 D->flattenLocations();
201 // If the PathDiagnosticConsumer does not support diagnostics that
202 // cross file boundaries, prune out such diagnostics now.
203 if (!supportsCrossFileDiagnostics()) {
204 // Verify that the entire path is from the same FileID.
206 const SourceManager &SMgr = D->path.front()->getLocation().getManager();
207 SmallVector<const PathPieces *, 5> WorkList;
208 WorkList.push_back(&D->path);
209 SmallString<128> buf;
210 llvm::raw_svector_ostream warning(buf);
211 warning << "warning: Path diagnostic report is not generated. Current "
212 << "output format does not support diagnostics that cross file "
213 << "boundaries. Refer to --analyzer-output for valid output "
216 while (!WorkList.empty()) {
217 const PathPieces &path = *WorkList.pop_back_val();
219 for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E;
221 const PathDiagnosticPiece *piece = I->get();
222 FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc();
224 if (FID.isInvalid()) {
225 FID = SMgr.getFileID(L);
226 } else if (SMgr.getFileID(L) != FID) {
227 llvm::errs() << warning.str();
231 // Check the source ranges.
232 ArrayRef<SourceRange> Ranges = piece->getRanges();
233 for (ArrayRef<SourceRange>::iterator I = Ranges.begin(),
234 E = Ranges.end(); I != E; ++I) {
235 SourceLocation L = SMgr.getExpansionLoc(I->getBegin());
236 if (!L.isFileID() || SMgr.getFileID(L) != FID) {
237 llvm::errs() << warning.str();
240 L = SMgr.getExpansionLoc(I->getEnd());
241 if (!L.isFileID() || SMgr.getFileID(L) != FID) {
242 llvm::errs() << warning.str();
247 if (const PathDiagnosticCallPiece *call =
248 dyn_cast<PathDiagnosticCallPiece>(piece)) {
249 WorkList.push_back(&call->path);
251 else if (const PathDiagnosticMacroPiece *macro =
252 dyn_cast<PathDiagnosticMacroPiece>(piece)) {
253 WorkList.push_back(¯o->subPieces);
259 return; // FIXME: Emit a warning?
262 // Profile the node to see if we already have something matching it
263 llvm::FoldingSetNodeID profile;
265 void *InsertPos = nullptr;
267 if (PathDiagnostic *orig = Diags.FindNodeOrInsertPos(profile, InsertPos)) {
268 // Keep the PathDiagnostic with the shorter path.
269 // Note, the enclosing routine is called in deterministic order, so the
270 // results will be consistent between runs (no reason to break ties if the
271 // size is the same).
272 const unsigned orig_size = orig->full_size();
273 const unsigned new_size = D->full_size();
274 if (orig_size <= new_size)
277 assert(orig != D.get());
278 Diags.RemoveNode(orig);
282 Diags.InsertNode(D.release());
285 static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y);
287 static Optional<bool>
288 compareControlFlow(const PathDiagnosticControlFlowPiece &X,
289 const PathDiagnosticControlFlowPiece &Y) {
290 FullSourceLoc XSL = X.getStartLocation().asLocation();
291 FullSourceLoc YSL = Y.getStartLocation().asLocation();
293 return XSL.isBeforeInTranslationUnitThan(YSL);
294 FullSourceLoc XEL = X.getEndLocation().asLocation();
295 FullSourceLoc YEL = Y.getEndLocation().asLocation();
297 return XEL.isBeforeInTranslationUnitThan(YEL);
301 static Optional<bool> compareMacro(const PathDiagnosticMacroPiece &X,
302 const PathDiagnosticMacroPiece &Y) {
303 return comparePath(X.subPieces, Y.subPieces);
306 static Optional<bool> compareCall(const PathDiagnosticCallPiece &X,
307 const PathDiagnosticCallPiece &Y) {
308 FullSourceLoc X_CEL = X.callEnter.asLocation();
309 FullSourceLoc Y_CEL = Y.callEnter.asLocation();
311 return X_CEL.isBeforeInTranslationUnitThan(Y_CEL);
312 FullSourceLoc X_CEWL = X.callEnterWithin.asLocation();
313 FullSourceLoc Y_CEWL = Y.callEnterWithin.asLocation();
314 if (X_CEWL != Y_CEWL)
315 return X_CEWL.isBeforeInTranslationUnitThan(Y_CEWL);
316 FullSourceLoc X_CRL = X.callReturn.asLocation();
317 FullSourceLoc Y_CRL = Y.callReturn.asLocation();
319 return X_CRL.isBeforeInTranslationUnitThan(Y_CRL);
320 return comparePath(X.path, Y.path);
323 static Optional<bool> comparePiece(const PathDiagnosticPiece &X,
324 const PathDiagnosticPiece &Y) {
325 if (X.getKind() != Y.getKind())
326 return X.getKind() < Y.getKind();
328 FullSourceLoc XL = X.getLocation().asLocation();
329 FullSourceLoc YL = Y.getLocation().asLocation();
331 return XL.isBeforeInTranslationUnitThan(YL);
333 if (X.getString() != Y.getString())
334 return X.getString() < Y.getString();
336 if (X.getRanges().size() != Y.getRanges().size())
337 return X.getRanges().size() < Y.getRanges().size();
339 const SourceManager &SM = XL.getManager();
341 for (unsigned i = 0, n = X.getRanges().size(); i < n; ++i) {
342 SourceRange XR = X.getRanges()[i];
343 SourceRange YR = Y.getRanges()[i];
345 if (XR.getBegin() != YR.getBegin())
346 return SM.isBeforeInTranslationUnit(XR.getBegin(), YR.getBegin());
347 return SM.isBeforeInTranslationUnit(XR.getEnd(), YR.getEnd());
351 switch (X.getKind()) {
352 case PathDiagnosticPiece::ControlFlow:
353 return compareControlFlow(cast<PathDiagnosticControlFlowPiece>(X),
354 cast<PathDiagnosticControlFlowPiece>(Y));
355 case PathDiagnosticPiece::Event:
356 case PathDiagnosticPiece::Note:
358 case PathDiagnosticPiece::Macro:
359 return compareMacro(cast<PathDiagnosticMacroPiece>(X),
360 cast<PathDiagnosticMacroPiece>(Y));
361 case PathDiagnosticPiece::Call:
362 return compareCall(cast<PathDiagnosticCallPiece>(X),
363 cast<PathDiagnosticCallPiece>(Y));
365 llvm_unreachable("all cases handled");
368 static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y) {
369 if (X.size() != Y.size())
370 return X.size() < Y.size();
372 PathPieces::const_iterator X_I = X.begin(), X_end = X.end();
373 PathPieces::const_iterator Y_I = Y.begin(), Y_end = Y.end();
375 for ( ; X_I != X_end && Y_I != Y_end; ++X_I, ++Y_I) {
376 Optional<bool> b = comparePiece(**X_I, **Y_I);
384 static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) {
385 FullSourceLoc XL = X.getLocation().asLocation();
386 FullSourceLoc YL = Y.getLocation().asLocation();
388 return XL.isBeforeInTranslationUnitThan(YL);
389 if (X.getBugType() != Y.getBugType())
390 return X.getBugType() < Y.getBugType();
391 if (X.getCategory() != Y.getCategory())
392 return X.getCategory() < Y.getCategory();
393 if (X.getVerboseDescription() != Y.getVerboseDescription())
394 return X.getVerboseDescription() < Y.getVerboseDescription();
395 if (X.getShortDescription() != Y.getShortDescription())
396 return X.getShortDescription() < Y.getShortDescription();
397 if (X.getDeclWithIssue() != Y.getDeclWithIssue()) {
398 const Decl *XD = X.getDeclWithIssue();
401 const Decl *YD = Y.getDeclWithIssue();
404 SourceLocation XDL = XD->getLocation();
405 SourceLocation YDL = YD->getLocation();
407 const SourceManager &SM = XL.getManager();
408 return SM.isBeforeInTranslationUnit(XDL, YDL);
411 PathDiagnostic::meta_iterator XI = X.meta_begin(), XE = X.meta_end();
412 PathDiagnostic::meta_iterator YI = Y.meta_begin(), YE = Y.meta_end();
413 if (XE - XI != YE - YI)
414 return (XE - XI) < (YE - YI);
415 for ( ; XI != XE ; ++XI, ++YI) {
417 return (*XI) < (*YI);
419 Optional<bool> b = comparePath(X.path, Y.path);
420 assert(b.hasValue());
424 void PathDiagnosticConsumer::FlushDiagnostics(
425 PathDiagnosticConsumer::FilesMade *Files) {
431 std::vector<const PathDiagnostic *> BatchDiags;
432 for (llvm::FoldingSet<PathDiagnostic>::iterator it = Diags.begin(),
433 et = Diags.end(); it != et; ++it) {
434 const PathDiagnostic *D = &*it;
435 BatchDiags.push_back(D);
438 // Sort the diagnostics so that they are always emitted in a deterministic
440 int (*Comp)(const PathDiagnostic *const *, const PathDiagnostic *const *) =
441 [](const PathDiagnostic *const *X, const PathDiagnostic *const *Y) {
442 assert(*X != *Y && "PathDiagnostics not uniqued!");
443 if (compare(**X, **Y))
445 assert(compare(**Y, **X) && "Not a total order!");
448 array_pod_sort(BatchDiags.begin(), BatchDiags.end(), Comp);
450 FlushDiagnosticsImpl(BatchDiags, Files);
452 // Delete the flushed diagnostics.
453 for (std::vector<const PathDiagnostic *>::iterator it = BatchDiags.begin(),
454 et = BatchDiags.end(); it != et; ++it) {
455 const PathDiagnostic *D = *it;
459 // Clear out the FoldingSet.
463 PathDiagnosticConsumer::FilesMade::~FilesMade() {
464 for (PDFileEntry &Entry : Set)
465 Entry.~PDFileEntry();
468 void PathDiagnosticConsumer::FilesMade::addDiagnostic(const PathDiagnostic &PD,
469 StringRef ConsumerName,
470 StringRef FileName) {
471 llvm::FoldingSetNodeID NodeID;
474 PDFileEntry *Entry = Set.FindNodeOrInsertPos(NodeID, InsertPos);
476 Entry = Alloc.Allocate<PDFileEntry>();
477 Entry = new (Entry) PDFileEntry(NodeID);
478 Set.InsertNode(Entry, InsertPos);
481 // Allocate persistent storage for the file name.
482 char *FileName_cstr = (char*) Alloc.Allocate(FileName.size(), 1);
483 memcpy(FileName_cstr, FileName.data(), FileName.size());
485 Entry->files.push_back(std::make_pair(ConsumerName,
486 StringRef(FileName_cstr,
490 PathDiagnosticConsumer::PDFileEntry::ConsumerFiles *
491 PathDiagnosticConsumer::FilesMade::getFiles(const PathDiagnostic &PD) {
492 llvm::FoldingSetNodeID NodeID;
495 PDFileEntry *Entry = Set.FindNodeOrInsertPos(NodeID, InsertPos);
498 return &Entry->files;
501 //===----------------------------------------------------------------------===//
502 // PathDiagnosticLocation methods.
503 //===----------------------------------------------------------------------===//
505 static SourceLocation getValidSourceLocation(const Stmt* S,
506 LocationOrAnalysisDeclContext LAC,
507 bool UseEnd = false) {
508 SourceLocation L = UseEnd ? S->getLocEnd() : S->getLocStart();
509 assert(!LAC.isNull() && "A valid LocationContext or AnalysisDeclContext should "
510 "be passed to PathDiagnosticLocation upon creation.");
512 // S might be a temporary statement that does not have a location in the
513 // source code, so find an enclosing statement and use its location.
515 AnalysisDeclContext *ADC;
516 if (LAC.is<const LocationContext*>())
517 ADC = LAC.get<const LocationContext*>()->getAnalysisDeclContext();
519 ADC = LAC.get<AnalysisDeclContext*>();
521 ParentMap &PM = ADC->getParentMap();
523 const Stmt *Parent = S;
525 Parent = PM.getParent(Parent);
527 // In rare cases, we have implicit top-level expressions,
528 // such as arguments for implicit member initializers.
529 // In this case, fall back to the start of the body (even if we were
530 // asked for the statement end location).
532 const Stmt *Body = ADC->getBody();
534 L = Body->getLocStart();
536 L = ADC->getDecl()->getLocEnd();
540 L = UseEnd ? Parent->getLocEnd() : Parent->getLocStart();
541 } while (!L.isValid());
547 static PathDiagnosticLocation
548 getLocationForCaller(const StackFrameContext *SFC,
549 const LocationContext *CallerCtx,
550 const SourceManager &SM) {
551 const CFGBlock &Block = *SFC->getCallSiteBlock();
552 CFGElement Source = Block[SFC->getIndex()];
554 switch (Source.getKind()) {
555 case CFGElement::Statement:
556 return PathDiagnosticLocation(Source.castAs<CFGStmt>().getStmt(),
558 case CFGElement::Initializer: {
559 const CFGInitializer &Init = Source.castAs<CFGInitializer>();
560 return PathDiagnosticLocation(Init.getInitializer()->getInit(),
563 case CFGElement::AutomaticObjectDtor: {
564 const CFGAutomaticObjDtor &Dtor = Source.castAs<CFGAutomaticObjDtor>();
565 return PathDiagnosticLocation::createEnd(Dtor.getTriggerStmt(),
568 case CFGElement::DeleteDtor: {
569 const CFGDeleteDtor &Dtor = Source.castAs<CFGDeleteDtor>();
570 return PathDiagnosticLocation(Dtor.getDeleteExpr(), SM, CallerCtx);
572 case CFGElement::BaseDtor:
573 case CFGElement::MemberDtor: {
574 const AnalysisDeclContext *CallerInfo = CallerCtx->getAnalysisDeclContext();
575 if (const Stmt *CallerBody = CallerInfo->getBody())
576 return PathDiagnosticLocation::createEnd(CallerBody, SM, CallerCtx);
577 return PathDiagnosticLocation::create(CallerInfo->getDecl(), SM);
579 case CFGElement::TemporaryDtor:
580 case CFGElement::NewAllocator:
581 llvm_unreachable("not yet implemented!");
582 case CFGElement::LifetimeEnds:
583 case CFGElement::LoopExit:
584 llvm_unreachable("CFGElement kind should not be on callsite!");
587 llvm_unreachable("Unknown CFGElement kind");
590 PathDiagnosticLocation
591 PathDiagnosticLocation::createBegin(const Decl *D,
592 const SourceManager &SM) {
593 return PathDiagnosticLocation(D->getLocStart(), SM, SingleLocK);
596 PathDiagnosticLocation
597 PathDiagnosticLocation::createBegin(const Stmt *S,
598 const SourceManager &SM,
599 LocationOrAnalysisDeclContext LAC) {
600 return PathDiagnosticLocation(getValidSourceLocation(S, LAC),
604 PathDiagnosticLocation
605 PathDiagnosticLocation::createEnd(const Stmt *S,
606 const SourceManager &SM,
607 LocationOrAnalysisDeclContext LAC) {
608 if (const CompoundStmt *CS = dyn_cast<CompoundStmt>(S))
609 return createEndBrace(CS, SM);
610 return PathDiagnosticLocation(getValidSourceLocation(S, LAC, /*End=*/true),
614 PathDiagnosticLocation
615 PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO,
616 const SourceManager &SM) {
617 return PathDiagnosticLocation(BO->getOperatorLoc(), SM, SingleLocK);
620 PathDiagnosticLocation
621 PathDiagnosticLocation::createConditionalColonLoc(
622 const ConditionalOperator *CO,
623 const SourceManager &SM) {
624 return PathDiagnosticLocation(CO->getColonLoc(), SM, SingleLocK);
628 PathDiagnosticLocation
629 PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME,
630 const SourceManager &SM) {
631 return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK);
634 PathDiagnosticLocation
635 PathDiagnosticLocation::createBeginBrace(const CompoundStmt *CS,
636 const SourceManager &SM) {
637 SourceLocation L = CS->getLBracLoc();
638 return PathDiagnosticLocation(L, SM, SingleLocK);
641 PathDiagnosticLocation
642 PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS,
643 const SourceManager &SM) {
644 SourceLocation L = CS->getRBracLoc();
645 return PathDiagnosticLocation(L, SM, SingleLocK);
648 PathDiagnosticLocation
649 PathDiagnosticLocation::createDeclBegin(const LocationContext *LC,
650 const SourceManager &SM) {
651 // FIXME: Should handle CXXTryStmt if analyser starts supporting C++.
652 if (const CompoundStmt *CS =
653 dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody()))
654 if (!CS->body_empty()) {
655 SourceLocation Loc = (*CS->body_begin())->getLocStart();
656 return PathDiagnosticLocation(Loc, SM, SingleLocK);
659 return PathDiagnosticLocation();
662 PathDiagnosticLocation
663 PathDiagnosticLocation::createDeclEnd(const LocationContext *LC,
664 const SourceManager &SM) {
665 SourceLocation L = LC->getDecl()->getBodyRBrace();
666 return PathDiagnosticLocation(L, SM, SingleLocK);
669 PathDiagnosticLocation
670 PathDiagnosticLocation::create(const ProgramPoint& P,
671 const SourceManager &SMng) {
672 const Stmt* S = nullptr;
673 if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
674 const CFGBlock *BSrc = BE->getSrc();
675 S = BSrc->getTerminatorCondition();
676 } else if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) {
678 if (P.getAs<PostStmtPurgeDeadSymbols>())
679 return PathDiagnosticLocation::createEnd(S, SMng, P.getLocationContext());
680 } else if (Optional<PostInitializer> PIP = P.getAs<PostInitializer>()) {
681 return PathDiagnosticLocation(PIP->getInitializer()->getSourceLocation(),
683 } else if (Optional<PostImplicitCall> PIE = P.getAs<PostImplicitCall>()) {
684 return PathDiagnosticLocation(PIE->getLocation(), SMng);
685 } else if (Optional<CallEnter> CE = P.getAs<CallEnter>()) {
686 return getLocationForCaller(CE->getCalleeContext(),
687 CE->getLocationContext(),
689 } else if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) {
690 return getLocationForCaller(CEE->getCalleeContext(),
691 CEE->getLocationContext(),
693 } else if (Optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) {
694 CFGElement BlockFront = BE->getBlock()->front();
695 if (auto StmtElt = BlockFront.getAs<CFGStmt>()) {
696 return PathDiagnosticLocation(StmtElt->getStmt()->getLocStart(), SMng);
697 } else if (auto NewAllocElt = BlockFront.getAs<CFGNewAllocator>()) {
698 return PathDiagnosticLocation(
699 NewAllocElt->getAllocatorExpr()->getLocStart(), SMng);
701 llvm_unreachable("Unexpected CFG element at front of block");
703 llvm_unreachable("Unexpected ProgramPoint");
706 return PathDiagnosticLocation(S, SMng, P.getLocationContext());
709 static const LocationContext *
710 findTopAutosynthesizedParentContext(const LocationContext *LC) {
711 assert(LC->getAnalysisDeclContext()->isBodyAutosynthesized());
712 const LocationContext *ParentLC = LC->getParent();
713 assert(ParentLC && "We don't start analysis from autosynthesized code");
714 while (ParentLC->getAnalysisDeclContext()->isBodyAutosynthesized()) {
716 ParentLC = LC->getParent();
717 assert(ParentLC && "We don't start analysis from autosynthesized code");
722 const Stmt *PathDiagnosticLocation::getStmt(const ExplodedNode *N) {
723 // We cannot place diagnostics on autosynthesized code.
724 // Put them onto the call site through which we jumped into autosynthesized
725 // code for the first time.
726 const LocationContext *LC = N->getLocationContext();
727 if (LC->getAnalysisDeclContext()->isBodyAutosynthesized()) {
728 // It must be a stack frame because we only autosynthesize functions.
729 return cast<StackFrameContext>(findTopAutosynthesizedParentContext(LC))
732 // Otherwise, see if the node's program point directly points to a statement.
733 ProgramPoint P = N->getLocation();
734 if (Optional<StmtPoint> SP = P.getAs<StmtPoint>())
735 return SP->getStmt();
736 if (Optional<BlockEdge> BE = P.getAs<BlockEdge>())
737 return BE->getSrc()->getTerminator();
738 if (Optional<CallEnter> CE = P.getAs<CallEnter>())
739 return CE->getCallExpr();
740 if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>())
741 return CEE->getCalleeContext()->getCallSite();
742 if (Optional<PostInitializer> PIPP = P.getAs<PostInitializer>())
743 return PIPP->getInitializer()->getInit();
748 const Stmt *PathDiagnosticLocation::getNextStmt(const ExplodedNode *N) {
749 for (N = N->getFirstSucc(); N; N = N->getFirstSucc()) {
750 if (const Stmt *S = getStmt(N)) {
751 // Check if the statement is '?' or '&&'/'||'. These are "merges",
752 // not actual statement points.
753 switch (S->getStmtClass()) {
754 case Stmt::ChooseExprClass:
755 case Stmt::BinaryConditionalOperatorClass:
756 case Stmt::ConditionalOperatorClass:
758 case Stmt::BinaryOperatorClass: {
759 BinaryOperatorKind Op = cast<BinaryOperator>(S)->getOpcode();
760 if (Op == BO_LAnd || Op == BO_LOr)
767 // We found the statement, so return it.
775 PathDiagnosticLocation
776 PathDiagnosticLocation::createEndOfPath(const ExplodedNode *N,
777 const SourceManager &SM) {
778 assert(N && "Cannot create a location with a null node.");
779 const Stmt *S = getStmt(N);
782 // If this is an implicit call, return the implicit call point location.
783 if (Optional<PreImplicitCall> PIE = N->getLocationAs<PreImplicitCall>())
784 return PathDiagnosticLocation(PIE->getLocation(), SM);
789 ProgramPoint P = N->getLocation();
790 const LocationContext *LC = N->getLocationContext();
792 // For member expressions, return the location of the '.' or '->'.
793 if (const MemberExpr *ME = dyn_cast<MemberExpr>(S))
794 return PathDiagnosticLocation::createMemberLoc(ME, SM);
796 // For binary operators, return the location of the operator.
797 if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S))
798 return PathDiagnosticLocation::createOperatorLoc(B, SM);
800 if (P.getAs<PostStmtPurgeDeadSymbols>())
801 return PathDiagnosticLocation::createEnd(S, SM, LC);
803 if (S->getLocStart().isValid())
804 return PathDiagnosticLocation(S, SM, LC);
805 return PathDiagnosticLocation(getValidSourceLocation(S, LC), SM);
808 return createDeclEnd(N->getLocationContext(), SM);
811 PathDiagnosticLocation PathDiagnosticLocation::createSingleLocation(
812 const PathDiagnosticLocation &PDL) {
813 FullSourceLoc L = PDL.asLocation();
814 return PathDiagnosticLocation(L, L.getManager(), SingleLocK);
818 PathDiagnosticLocation::genLocation(SourceLocation L,
819 LocationOrAnalysisDeclContext LAC) const {
821 // Note that we want a 'switch' here so that the compiler can warn us in
822 // case we add more cases.
828 // Defensive checking.
831 return FullSourceLoc(getValidSourceLocation(S, LAC),
832 const_cast<SourceManager&>(*SM));
834 // Defensive checking.
837 return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM));
840 return FullSourceLoc(L, const_cast<SourceManager&>(*SM));
844 PathDiagnosticLocation::genRange(LocationOrAnalysisDeclContext LAC) const {
846 // Note that we want a 'switch' here so that the compiler can warn us in
847 // case we add more cases.
850 return PathDiagnosticRange(SourceRange(Loc,Loc), true);
854 const Stmt *S = asStmt();
855 switch (S->getStmtClass()) {
858 case Stmt::DeclStmtClass: {
859 const DeclStmt *DS = cast<DeclStmt>(S);
860 if (DS->isSingleDecl()) {
861 // Should always be the case, but we'll be defensive.
862 return SourceRange(DS->getLocStart(),
863 DS->getSingleDecl()->getLocation());
867 // FIXME: Provide better range information for different
869 case Stmt::IfStmtClass:
870 case Stmt::WhileStmtClass:
871 case Stmt::DoStmtClass:
872 case Stmt::ForStmtClass:
873 case Stmt::ChooseExprClass:
874 case Stmt::IndirectGotoStmtClass:
875 case Stmt::SwitchStmtClass:
876 case Stmt::BinaryConditionalOperatorClass:
877 case Stmt::ConditionalOperatorClass:
878 case Stmt::ObjCForCollectionStmtClass: {
879 SourceLocation L = getValidSourceLocation(S, LAC);
880 return SourceRange(L, L);
883 SourceRange R = S->getSourceRange();
889 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
890 return MD->getSourceRange();
891 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
892 if (Stmt *Body = FD->getBody())
893 return Body->getSourceRange();
896 SourceLocation L = D->getLocation();
897 return PathDiagnosticRange(SourceRange(L, L), true);
901 return SourceRange(Loc,Loc);
904 void PathDiagnosticLocation::flatten() {
910 else if (K == DeclK) {
917 //===----------------------------------------------------------------------===//
918 // Manipulation of PathDiagnosticCallPieces.
919 //===----------------------------------------------------------------------===//
921 std::shared_ptr<PathDiagnosticCallPiece>
922 PathDiagnosticCallPiece::construct(const ExplodedNode *N, const CallExitEnd &CE,
923 const SourceManager &SM) {
924 const Decl *caller = CE.getLocationContext()->getDecl();
925 PathDiagnosticLocation pos = getLocationForCaller(CE.getCalleeContext(),
926 CE.getLocationContext(),
928 return std::shared_ptr<PathDiagnosticCallPiece>(
929 new PathDiagnosticCallPiece(caller, pos));
932 PathDiagnosticCallPiece *
933 PathDiagnosticCallPiece::construct(PathPieces &path,
934 const Decl *caller) {
935 std::shared_ptr<PathDiagnosticCallPiece> C(
936 new PathDiagnosticCallPiece(path, caller));
939 path.push_front(std::move(C));
943 void PathDiagnosticCallPiece::setCallee(const CallEnter &CE,
944 const SourceManager &SM) {
945 const StackFrameContext *CalleeCtx = CE.getCalleeContext();
946 Callee = CalleeCtx->getDecl();
948 callEnterWithin = PathDiagnosticLocation::createBegin(Callee, SM);
949 callEnter = getLocationForCaller(CalleeCtx, CE.getLocationContext(), SM);
951 // Autosynthesized property accessors are special because we'd never
952 // pop back up to non-autosynthesized code until we leave them.
953 // This is not generally true for autosynthesized callees, which may call
954 // non-autosynthesized callbacks.
955 // Unless set here, the IsCalleeAnAutosynthesizedPropertyAccessor flag
956 // defaults to false.
957 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(Callee))
958 IsCalleeAnAutosynthesizedPropertyAccessor = (
959 MD->isPropertyAccessor() &&
960 CalleeCtx->getAnalysisDeclContext()->isBodyAutosynthesized());
963 static inline void describeClass(raw_ostream &Out, const CXXRecordDecl *D,
964 StringRef Prefix = StringRef()) {
965 if (!D->getIdentifier())
967 Out << Prefix << '\'' << *D << '\'';
970 static bool describeCodeDecl(raw_ostream &Out, const Decl *D,
971 bool ExtendedDescription,
972 StringRef Prefix = StringRef()) {
976 if (isa<BlockDecl>(D)) {
977 if (ExtendedDescription)
978 Out << Prefix << "anonymous block";
979 return ExtendedDescription;
982 if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
984 if (ExtendedDescription && !MD->isUserProvided()) {
985 if (MD->isExplicitlyDefaulted())
991 if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(MD)) {
992 if (CD->isDefaultConstructor())
994 else if (CD->isCopyConstructor())
996 else if (CD->isMoveConstructor())
999 Out << "constructor";
1000 describeClass(Out, MD->getParent(), " for ");
1002 } else if (isa<CXXDestructorDecl>(MD)) {
1003 if (!MD->isUserProvided()) {
1004 Out << "destructor";
1005 describeClass(Out, MD->getParent(), " for ");
1007 // Use ~Foo for explicitly-written destructors.
1008 Out << "'" << *MD << "'";
1011 } else if (MD->isCopyAssignmentOperator()) {
1012 Out << "copy assignment operator";
1013 describeClass(Out, MD->getParent(), " for ");
1015 } else if (MD->isMoveAssignmentOperator()) {
1016 Out << "move assignment operator";
1017 describeClass(Out, MD->getParent(), " for ");
1020 if (MD->getParent()->getIdentifier())
1021 Out << "'" << *MD->getParent() << "::" << *MD << "'";
1023 Out << "'" << *MD << "'";
1029 Out << Prefix << '\'' << cast<NamedDecl>(*D) << '\'';
1033 std::shared_ptr<PathDiagnosticEventPiece>
1034 PathDiagnosticCallPiece::getCallEnterEvent() const {
1035 // We do not produce call enters and call exits for autosynthesized property
1036 // accessors. We do generally produce them for other functions coming from
1037 // the body farm because they may call callbacks that bring us back into
1039 if (!Callee || IsCalleeAnAutosynthesizedPropertyAccessor)
1042 SmallString<256> buf;
1043 llvm::raw_svector_ostream Out(buf);
1046 describeCodeDecl(Out, Callee, /*ExtendedDescription=*/true);
1048 assert(callEnter.asLocation().isValid());
1049 return std::make_shared<PathDiagnosticEventPiece>(callEnter, Out.str());
1052 std::shared_ptr<PathDiagnosticEventPiece>
1053 PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const {
1054 if (!callEnterWithin.asLocation().isValid())
1056 if (Callee->isImplicit() || !Callee->hasBody())
1058 if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Callee))
1059 if (MD->isDefaulted())
1062 SmallString<256> buf;
1063 llvm::raw_svector_ostream Out(buf);
1065 Out << "Entered call";
1066 describeCodeDecl(Out, Caller, /*ExtendedDescription=*/false, " from ");
1068 return std::make_shared<PathDiagnosticEventPiece>(callEnterWithin, Out.str());
1071 std::shared_ptr<PathDiagnosticEventPiece>
1072 PathDiagnosticCallPiece::getCallExitEvent() const {
1073 // We do not produce call enters and call exits for autosynthesized property
1074 // accessors. We do generally produce them for other functions coming from
1075 // the body farm because they may call callbacks that bring us back into
1077 if (NoExit || IsCalleeAnAutosynthesizedPropertyAccessor)
1080 SmallString<256> buf;
1081 llvm::raw_svector_ostream Out(buf);
1083 if (!CallStackMessage.empty()) {
1084 Out << CallStackMessage;
1086 bool DidDescribe = describeCodeDecl(Out, Callee,
1087 /*ExtendedDescription=*/false,
1090 Out << "Returning to caller";
1093 assert(callReturn.asLocation().isValid());
1094 return std::make_shared<PathDiagnosticEventPiece>(callReturn, Out.str());
1097 static void compute_path_size(const PathPieces &pieces, unsigned &size) {
1098 for (PathPieces::const_iterator it = pieces.begin(),
1099 et = pieces.end(); it != et; ++it) {
1100 const PathDiagnosticPiece *piece = it->get();
1101 if (const PathDiagnosticCallPiece *cp =
1102 dyn_cast<PathDiagnosticCallPiece>(piece)) {
1103 compute_path_size(cp->path, size);
1110 unsigned PathDiagnostic::full_size() {
1112 compute_path_size(path, size);
1116 //===----------------------------------------------------------------------===//
1117 // FoldingSet profiling methods.
1118 //===----------------------------------------------------------------------===//
1120 void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const {
1121 ID.AddInteger(Range.getBegin().getRawEncoding());
1122 ID.AddInteger(Range.getEnd().getRawEncoding());
1123 ID.AddInteger(Loc.getRawEncoding());
1126 void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1127 ID.AddInteger((unsigned) getKind());
1129 // FIXME: Add profiling support for code hints.
1130 ID.AddInteger((unsigned) getDisplayHint());
1131 ArrayRef<SourceRange> Ranges = getRanges();
1132 for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end();
1134 ID.AddInteger(I->getBegin().getRawEncoding());
1135 ID.AddInteger(I->getEnd().getRawEncoding());
1139 void PathDiagnosticCallPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1140 PathDiagnosticPiece::Profile(ID);
1141 for (PathPieces::const_iterator it = path.begin(),
1142 et = path.end(); it != et; ++it) {
1147 void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1148 PathDiagnosticPiece::Profile(ID);
1152 void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1153 PathDiagnosticPiece::Profile(ID);
1154 for (const_iterator I = begin(), E = end(); I != E; ++I)
1158 void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1159 PathDiagnosticSpotPiece::Profile(ID);
1160 for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end();
1165 void PathDiagnosticNotePiece::Profile(llvm::FoldingSetNodeID &ID) const {
1166 PathDiagnosticSpotPiece::Profile(ID);
1169 void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const {
1170 ID.Add(getLocation());
1171 ID.AddString(BugType);
1172 ID.AddString(VerboseDesc);
1173 ID.AddString(Category);
1176 void PathDiagnostic::FullProfile(llvm::FoldingSetNodeID &ID) const {
1178 for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E; ++I)
1180 for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I)
1184 StackHintGenerator::~StackHintGenerator() {}
1186 std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){
1187 ProgramPoint P = N->getLocation();
1188 CallExitEnd CExit = P.castAs<CallExitEnd>();
1190 // FIXME: Use CallEvent to abstract this over all calls.
1191 const Stmt *CallSite = CExit.getCalleeContext()->getCallSite();
1192 const CallExpr *CE = dyn_cast_or_null<CallExpr>(CallSite);
1197 return getMessageForSymbolNotFound();
1199 // Check if one of the parameters are set to the interesting symbol.
1200 ProgramStateRef State = N->getState();
1201 const LocationContext *LCtx = N->getLocationContext();
1202 unsigned ArgIndex = 0;
1203 for (CallExpr::const_arg_iterator I = CE->arg_begin(),
1204 E = CE->arg_end(); I != E; ++I, ++ArgIndex){
1205 SVal SV = State->getSVal(*I, LCtx);
1207 // Check if the variable corresponding to the symbol is passed by value.
1208 SymbolRef AS = SV.getAsLocSymbol();
1210 return getMessageForArg(*I, ArgIndex);
1213 // Check if the parameter is a pointer to the symbol.
1214 if (Optional<loc::MemRegionVal> Reg = SV.getAs<loc::MemRegionVal>()) {
1215 SVal PSV = State->getSVal(Reg->getRegion());
1216 SymbolRef AS = PSV.getAsLocSymbol();
1218 return getMessageForArg(*I, ArgIndex);
1223 // Check if we are returning the interesting symbol.
1224 SVal SV = State->getSVal(CE, LCtx);
1225 SymbolRef RetSym = SV.getAsLocSymbol();
1226 if (RetSym == Sym) {
1227 return getMessageForReturn(CE);
1230 return getMessageForSymbolNotFound();
1233 std::string StackHintGeneratorForSymbol::getMessageForArg(const Expr *ArgE,
1234 unsigned ArgIndex) {
1235 // Printed parameters start at 1, not 0.
1238 SmallString<200> buf;
1239 llvm::raw_svector_ostream os(buf);
1241 os << Msg << " via " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex)