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/ParentMap.h"
20 #include "clang/AST/StmtCXX.h"
21 #include "clang/Basic/SourceManager.h"
22 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
23 #include "llvm/ADT/SmallString.h"
24 #include "llvm/ADT/StringExtras.h"
25 #include "llvm/Support/raw_ostream.h"
27 using namespace clang;
30 bool PathDiagnosticMacroPiece::containsEvent() const {
31 for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end();
33 if (isa<PathDiagnosticEventPiece>(*I))
35 if (PathDiagnosticMacroPiece *MP = dyn_cast<PathDiagnosticMacroPiece>(*I))
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() {}
64 PathPieces::~PathPieces() {}
66 void PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current,
67 bool ShouldFlattenMacros) const {
68 for (PathPieces::const_iterator I = begin(), E = end(); I != E; ++I) {
69 PathDiagnosticPiece *Piece = I->getPtr();
71 switch (Piece->getKind()) {
72 case PathDiagnosticPiece::Call: {
73 PathDiagnosticCallPiece *Call = cast<PathDiagnosticCallPiece>(Piece);
74 IntrusiveRefCntPtr<PathDiagnosticEventPiece> CallEnter =
75 Call->getCallEnterEvent();
77 Current.push_back(CallEnter);
78 Call->path.flattenTo(Primary, Primary, ShouldFlattenMacros);
79 IntrusiveRefCntPtr<PathDiagnosticEventPiece> callExit =
80 Call->getCallExitEvent();
82 Current.push_back(callExit);
85 case PathDiagnosticPiece::Macro: {
86 PathDiagnosticMacroPiece *Macro = cast<PathDiagnosticMacroPiece>(Piece);
87 if (ShouldFlattenMacros) {
88 Macro->subPieces.flattenTo(Primary, Primary, ShouldFlattenMacros);
90 Current.push_back(Piece);
92 Macro->subPieces.flattenTo(Primary, NewPath, ShouldFlattenMacros);
93 // FIXME: This probably shouldn't mutate the original path piece.
94 Macro->subPieces = NewPath;
98 case PathDiagnosticPiece::Event:
99 case PathDiagnosticPiece::ControlFlow:
100 Current.push_back(Piece);
107 PathDiagnostic::~PathDiagnostic() {}
109 PathDiagnostic::PathDiagnostic(const Decl *declWithIssue,
110 StringRef bugtype, StringRef verboseDesc,
111 StringRef shortDesc, StringRef category,
112 PathDiagnosticLocation LocationToUnique,
113 const Decl *DeclToUnique)
114 : DeclWithIssue(declWithIssue),
115 BugType(StripTrailingDots(bugtype)),
116 VerboseDesc(StripTrailingDots(verboseDesc)),
117 ShortDesc(StripTrailingDots(shortDesc)),
118 Category(StripTrailingDots(category)),
119 UniqueingLoc(LocationToUnique),
120 UniqueingDecl(DeclToUnique),
123 static PathDiagnosticCallPiece *
124 getFirstStackedCallToHeaderFile(PathDiagnosticCallPiece *CP,
125 const SourceManager &SMgr) {
126 SourceLocation CallLoc = CP->callEnter.asLocation();
128 // If the call is within a macro, don't do anything (for now).
129 if (CallLoc.isMacroID())
132 assert(SMgr.isInMainFile(CallLoc) &&
133 "The call piece should be in the main file.");
135 // Check if CP represents a path through a function outside of the main file.
136 if (!SMgr.isInMainFile(CP->callEnterWithin.asLocation()))
139 const PathPieces &Path = CP->path;
143 // Check if the last piece in the callee path is a call to a function outside
145 if (PathDiagnosticCallPiece *CPInner =
146 dyn_cast<PathDiagnosticCallPiece>(Path.back())) {
147 return getFirstStackedCallToHeaderFile(CPInner, SMgr);
150 // Otherwise, the last piece is in the main file.
154 void PathDiagnostic::resetDiagnosticLocationToMainFile() {
158 PathDiagnosticPiece *LastP = path.back().getPtr();
160 const SourceManager &SMgr = LastP->getLocation().getManager();
162 // We only need to check if the report ends inside headers, if the last piece
164 if (PathDiagnosticCallPiece *CP = dyn_cast<PathDiagnosticCallPiece>(LastP)) {
165 CP = getFirstStackedCallToHeaderFile(CP, SMgr);
168 CP->setAsLastInMainSourceFile();
170 // Update the path diagnostic message.
171 const NamedDecl *ND = dyn_cast<NamedDecl>(CP->getCallee());
173 SmallString<200> buf;
174 llvm::raw_svector_ostream os(buf);
175 os << " (within a call to '" << ND->getDeclName() << "')";
176 appendToDesc(os.str());
179 // Reset the report containing declaration and location.
180 DeclWithIssue = CP->getCaller();
181 Loc = CP->getLocation();
188 void PathDiagnosticConsumer::anchor() { }
190 PathDiagnosticConsumer::~PathDiagnosticConsumer() {
191 // Delete the contents of the FoldingSet if it isn't empty already.
192 for (llvm::FoldingSet<PathDiagnostic>::iterator it =
193 Diags.begin(), et = Diags.end() ; it != et ; ++it) {
198 void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) {
199 OwningPtr<PathDiagnostic> OwningD(D);
201 if (!D || D->path.empty())
204 // We need to flatten the locations (convert Stmt* to locations) because
205 // the referenced statements may be freed by the time the diagnostics
207 D->flattenLocations();
209 // If the PathDiagnosticConsumer does not support diagnostics that
210 // cross file boundaries, prune out such diagnostics now.
211 if (!supportsCrossFileDiagnostics()) {
212 // Verify that the entire path is from the same FileID.
214 const SourceManager &SMgr = (*D->path.begin())->getLocation().getManager();
215 SmallVector<const PathPieces *, 5> WorkList;
216 WorkList.push_back(&D->path);
218 while (!WorkList.empty()) {
219 const PathPieces &path = *WorkList.pop_back_val();
221 for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E;
223 const PathDiagnosticPiece *piece = I->getPtr();
224 FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc();
226 if (FID.isInvalid()) {
227 FID = SMgr.getFileID(L);
228 } else if (SMgr.getFileID(L) != FID)
229 return; // FIXME: Emit a warning?
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 return; // FIXME: Emit a warning?
238 L = SMgr.getExpansionLoc(I->getEnd());
239 if (!L.isFileID() || SMgr.getFileID(L) != FID)
240 return; // FIXME: Emit a warning?
243 if (const PathDiagnosticCallPiece *call =
244 dyn_cast<PathDiagnosticCallPiece>(piece)) {
245 WorkList.push_back(&call->path);
247 else if (const PathDiagnosticMacroPiece *macro =
248 dyn_cast<PathDiagnosticMacroPiece>(piece)) {
249 WorkList.push_back(¯o->subPieces);
255 return; // FIXME: Emit a warning?
258 // Profile the node to see if we already have something matching it
259 llvm::FoldingSetNodeID profile;
263 if (PathDiagnostic *orig = Diags.FindNodeOrInsertPos(profile, InsertPos)) {
264 // Keep the PathDiagnostic with the shorter path.
265 // Note, the enclosing routine is called in deterministic order, so the
266 // results will be consistent between runs (no reason to break ties if the
267 // size is the same).
268 const unsigned orig_size = orig->full_size();
269 const unsigned new_size = D->full_size();
270 if (orig_size <= new_size)
274 Diags.RemoveNode(orig);
278 Diags.InsertNode(OwningD.take());
281 static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y);
282 static Optional<bool>
283 compareControlFlow(const PathDiagnosticControlFlowPiece &X,
284 const PathDiagnosticControlFlowPiece &Y) {
285 FullSourceLoc XSL = X.getStartLocation().asLocation();
286 FullSourceLoc YSL = Y.getStartLocation().asLocation();
288 return XSL.isBeforeInTranslationUnitThan(YSL);
289 FullSourceLoc XEL = X.getEndLocation().asLocation();
290 FullSourceLoc YEL = Y.getEndLocation().asLocation();
292 return XEL.isBeforeInTranslationUnitThan(YEL);
296 static Optional<bool> compareMacro(const PathDiagnosticMacroPiece &X,
297 const PathDiagnosticMacroPiece &Y) {
298 return comparePath(X.subPieces, Y.subPieces);
301 static Optional<bool> compareCall(const PathDiagnosticCallPiece &X,
302 const PathDiagnosticCallPiece &Y) {
303 FullSourceLoc X_CEL = X.callEnter.asLocation();
304 FullSourceLoc Y_CEL = Y.callEnter.asLocation();
306 return X_CEL.isBeforeInTranslationUnitThan(Y_CEL);
307 FullSourceLoc X_CEWL = X.callEnterWithin.asLocation();
308 FullSourceLoc Y_CEWL = Y.callEnterWithin.asLocation();
309 if (X_CEWL != Y_CEWL)
310 return X_CEWL.isBeforeInTranslationUnitThan(Y_CEWL);
311 FullSourceLoc X_CRL = X.callReturn.asLocation();
312 FullSourceLoc Y_CRL = Y.callReturn.asLocation();
314 return X_CRL.isBeforeInTranslationUnitThan(Y_CRL);
315 return comparePath(X.path, Y.path);
318 static Optional<bool> comparePiece(const PathDiagnosticPiece &X,
319 const PathDiagnosticPiece &Y) {
320 if (X.getKind() != Y.getKind())
321 return X.getKind() < Y.getKind();
323 FullSourceLoc XL = X.getLocation().asLocation();
324 FullSourceLoc YL = Y.getLocation().asLocation();
326 return XL.isBeforeInTranslationUnitThan(YL);
328 if (X.getString() != Y.getString())
329 return X.getString() < Y.getString();
331 if (X.getRanges().size() != Y.getRanges().size())
332 return X.getRanges().size() < Y.getRanges().size();
334 const SourceManager &SM = XL.getManager();
336 for (unsigned i = 0, n = X.getRanges().size(); i < n; ++i) {
337 SourceRange XR = X.getRanges()[i];
338 SourceRange YR = Y.getRanges()[i];
340 if (XR.getBegin() != YR.getBegin())
341 return SM.isBeforeInTranslationUnit(XR.getBegin(), YR.getBegin());
342 return SM.isBeforeInTranslationUnit(XR.getEnd(), YR.getEnd());
346 switch (X.getKind()) {
347 case clang::ento::PathDiagnosticPiece::ControlFlow:
348 return compareControlFlow(cast<PathDiagnosticControlFlowPiece>(X),
349 cast<PathDiagnosticControlFlowPiece>(Y));
350 case clang::ento::PathDiagnosticPiece::Event:
352 case clang::ento::PathDiagnosticPiece::Macro:
353 return compareMacro(cast<PathDiagnosticMacroPiece>(X),
354 cast<PathDiagnosticMacroPiece>(Y));
355 case clang::ento::PathDiagnosticPiece::Call:
356 return compareCall(cast<PathDiagnosticCallPiece>(X),
357 cast<PathDiagnosticCallPiece>(Y));
359 llvm_unreachable("all cases handled");
362 static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y) {
363 if (X.size() != Y.size())
364 return X.size() < Y.size();
366 PathPieces::const_iterator X_I = X.begin(), X_end = X.end();
367 PathPieces::const_iterator Y_I = Y.begin(), Y_end = Y.end();
369 for ( ; X_I != X_end && Y_I != Y_end; ++X_I, ++Y_I) {
370 Optional<bool> b = comparePiece(**X_I, **Y_I);
378 static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) {
379 FullSourceLoc XL = X.getLocation().asLocation();
380 FullSourceLoc YL = Y.getLocation().asLocation();
382 return XL.isBeforeInTranslationUnitThan(YL);
383 if (X.getBugType() != Y.getBugType())
384 return X.getBugType() < Y.getBugType();
385 if (X.getCategory() != Y.getCategory())
386 return X.getCategory() < Y.getCategory();
387 if (X.getVerboseDescription() != Y.getVerboseDescription())
388 return X.getVerboseDescription() < Y.getVerboseDescription();
389 if (X.getShortDescription() != Y.getShortDescription())
390 return X.getShortDescription() < Y.getShortDescription();
391 if (X.getDeclWithIssue() != Y.getDeclWithIssue()) {
392 const Decl *XD = X.getDeclWithIssue();
395 const Decl *YD = Y.getDeclWithIssue();
398 SourceLocation XDL = XD->getLocation();
399 SourceLocation YDL = YD->getLocation();
401 const SourceManager &SM = XL.getManager();
402 return SM.isBeforeInTranslationUnit(XDL, YDL);
405 PathDiagnostic::meta_iterator XI = X.meta_begin(), XE = X.meta_end();
406 PathDiagnostic::meta_iterator YI = Y.meta_begin(), YE = Y.meta_end();
407 if (XE - XI != YE - YI)
408 return (XE - XI) < (YE - YI);
409 for ( ; XI != XE ; ++XI, ++YI) {
411 return (*XI) < (*YI);
413 Optional<bool> b = comparePath(X.path, Y.path);
414 assert(b.hasValue());
419 struct CompareDiagnostics {
420 // Compare if 'X' is "<" than 'Y'.
421 bool operator()(const PathDiagnostic *X, const PathDiagnostic *Y) const {
424 return compare(*X, *Y);
429 void PathDiagnosticConsumer::FlushDiagnostics(
430 PathDiagnosticConsumer::FilesMade *Files) {
436 std::vector<const PathDiagnostic *> BatchDiags;
437 for (llvm::FoldingSet<PathDiagnostic>::iterator it = Diags.begin(),
438 et = Diags.end(); it != et; ++it) {
439 const PathDiagnostic *D = &*it;
440 BatchDiags.push_back(D);
443 // Sort the diagnostics so that they are always emitted in a deterministic
445 if (!BatchDiags.empty())
446 std::sort(BatchDiags.begin(), BatchDiags.end(), CompareDiagnostics());
448 FlushDiagnosticsImpl(BatchDiags, Files);
450 // Delete the flushed diagnostics.
451 for (std::vector<const PathDiagnostic *>::iterator it = BatchDiags.begin(),
452 et = BatchDiags.end(); it != et; ++it) {
453 const PathDiagnostic *D = *it;
457 // Clear out the FoldingSet.
461 void PathDiagnosticConsumer::FilesMade::addDiagnostic(const PathDiagnostic &PD,
462 StringRef ConsumerName,
463 StringRef FileName) {
464 llvm::FoldingSetNodeID NodeID;
467 PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos);
469 Entry = Alloc.Allocate<PDFileEntry>();
470 Entry = new (Entry) PDFileEntry(NodeID);
471 InsertNode(Entry, InsertPos);
474 // Allocate persistent storage for the file name.
475 char *FileName_cstr = (char*) Alloc.Allocate(FileName.size(), 1);
476 memcpy(FileName_cstr, FileName.data(), FileName.size());
478 Entry->files.push_back(std::make_pair(ConsumerName,
479 StringRef(FileName_cstr,
483 PathDiagnosticConsumer::PDFileEntry::ConsumerFiles *
484 PathDiagnosticConsumer::FilesMade::getFiles(const PathDiagnostic &PD) {
485 llvm::FoldingSetNodeID NodeID;
488 PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos);
491 return &Entry->files;
494 //===----------------------------------------------------------------------===//
495 // PathDiagnosticLocation methods.
496 //===----------------------------------------------------------------------===//
498 static SourceLocation getValidSourceLocation(const Stmt* S,
499 LocationOrAnalysisDeclContext LAC,
500 bool UseEnd = false) {
501 SourceLocation L = UseEnd ? S->getLocEnd() : S->getLocStart();
502 assert(!LAC.isNull() && "A valid LocationContext or AnalysisDeclContext should "
503 "be passed to PathDiagnosticLocation upon creation.");
505 // S might be a temporary statement that does not have a location in the
506 // source code, so find an enclosing statement and use its location.
509 AnalysisDeclContext *ADC;
510 if (LAC.is<const LocationContext*>())
511 ADC = LAC.get<const LocationContext*>()->getAnalysisDeclContext();
513 ADC = LAC.get<AnalysisDeclContext*>();
515 ParentMap &PM = ADC->getParentMap();
517 const Stmt *Parent = S;
519 Parent = PM.getParent(Parent);
521 // In rare cases, we have implicit top-level expressions,
522 // such as arguments for implicit member initializers.
523 // In this case, fall back to the start of the body (even if we were
524 // asked for the statement end location).
526 const Stmt *Body = ADC->getBody();
528 L = Body->getLocStart();
530 L = ADC->getDecl()->getLocEnd();
534 L = UseEnd ? Parent->getLocEnd() : Parent->getLocStart();
535 } while (!L.isValid());
541 static PathDiagnosticLocation
542 getLocationForCaller(const StackFrameContext *SFC,
543 const LocationContext *CallerCtx,
544 const SourceManager &SM) {
545 const CFGBlock &Block = *SFC->getCallSiteBlock();
546 CFGElement Source = Block[SFC->getIndex()];
548 switch (Source.getKind()) {
549 case CFGElement::Statement:
550 return PathDiagnosticLocation(Source.castAs<CFGStmt>().getStmt(),
552 case CFGElement::Initializer: {
553 const CFGInitializer &Init = Source.castAs<CFGInitializer>();
554 return PathDiagnosticLocation(Init.getInitializer()->getInit(),
557 case CFGElement::AutomaticObjectDtor: {
558 const CFGAutomaticObjDtor &Dtor = Source.castAs<CFGAutomaticObjDtor>();
559 return PathDiagnosticLocation::createEnd(Dtor.getTriggerStmt(),
562 case CFGElement::DeleteDtor: {
563 const CFGDeleteDtor &Dtor = Source.castAs<CFGDeleteDtor>();
564 return PathDiagnosticLocation(Dtor.getDeleteExpr(), SM, CallerCtx);
566 case CFGElement::BaseDtor:
567 case CFGElement::MemberDtor: {
568 const AnalysisDeclContext *CallerInfo = CallerCtx->getAnalysisDeclContext();
569 if (const Stmt *CallerBody = CallerInfo->getBody())
570 return PathDiagnosticLocation::createEnd(CallerBody, SM, CallerCtx);
571 return PathDiagnosticLocation::create(CallerInfo->getDecl(), SM);
573 case CFGElement::TemporaryDtor:
574 llvm_unreachable("not yet implemented!");
577 llvm_unreachable("Unknown CFGElement kind");
581 PathDiagnosticLocation
582 PathDiagnosticLocation::createBegin(const Decl *D,
583 const SourceManager &SM) {
584 return PathDiagnosticLocation(D->getLocStart(), SM, SingleLocK);
587 PathDiagnosticLocation
588 PathDiagnosticLocation::createBegin(const Stmt *S,
589 const SourceManager &SM,
590 LocationOrAnalysisDeclContext LAC) {
591 return PathDiagnosticLocation(getValidSourceLocation(S, LAC),
596 PathDiagnosticLocation
597 PathDiagnosticLocation::createEnd(const Stmt *S,
598 const SourceManager &SM,
599 LocationOrAnalysisDeclContext LAC) {
600 if (const CompoundStmt *CS = dyn_cast<CompoundStmt>(S))
601 return createEndBrace(CS, SM);
602 return PathDiagnosticLocation(getValidSourceLocation(S, LAC, /*End=*/true),
606 PathDiagnosticLocation
607 PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO,
608 const SourceManager &SM) {
609 return PathDiagnosticLocation(BO->getOperatorLoc(), SM, SingleLocK);
612 PathDiagnosticLocation
613 PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME,
614 const SourceManager &SM) {
615 return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK);
618 PathDiagnosticLocation
619 PathDiagnosticLocation::createBeginBrace(const CompoundStmt *CS,
620 const SourceManager &SM) {
621 SourceLocation L = CS->getLBracLoc();
622 return PathDiagnosticLocation(L, SM, SingleLocK);
625 PathDiagnosticLocation
626 PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS,
627 const SourceManager &SM) {
628 SourceLocation L = CS->getRBracLoc();
629 return PathDiagnosticLocation(L, SM, SingleLocK);
632 PathDiagnosticLocation
633 PathDiagnosticLocation::createDeclBegin(const LocationContext *LC,
634 const SourceManager &SM) {
635 // FIXME: Should handle CXXTryStmt if analyser starts supporting C++.
636 if (const CompoundStmt *CS =
637 dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody()))
638 if (!CS->body_empty()) {
639 SourceLocation Loc = (*CS->body_begin())->getLocStart();
640 return PathDiagnosticLocation(Loc, SM, SingleLocK);
643 return PathDiagnosticLocation();
646 PathDiagnosticLocation
647 PathDiagnosticLocation::createDeclEnd(const LocationContext *LC,
648 const SourceManager &SM) {
649 SourceLocation L = LC->getDecl()->getBodyRBrace();
650 return PathDiagnosticLocation(L, SM, SingleLocK);
653 PathDiagnosticLocation
654 PathDiagnosticLocation::create(const ProgramPoint& P,
655 const SourceManager &SMng) {
658 if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
659 const CFGBlock *BSrc = BE->getSrc();
660 S = BSrc->getTerminatorCondition();
661 } else if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) {
663 if (P.getAs<PostStmtPurgeDeadSymbols>())
664 return PathDiagnosticLocation::createEnd(S, SMng, P.getLocationContext());
665 } else if (Optional<PostInitializer> PIP = P.getAs<PostInitializer>()) {
666 return PathDiagnosticLocation(PIP->getInitializer()->getSourceLocation(),
668 } else if (Optional<PostImplicitCall> PIE = P.getAs<PostImplicitCall>()) {
669 return PathDiagnosticLocation(PIE->getLocation(), SMng);
670 } else if (Optional<CallEnter> CE = P.getAs<CallEnter>()) {
671 return getLocationForCaller(CE->getCalleeContext(),
672 CE->getLocationContext(),
674 } else if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) {
675 return getLocationForCaller(CEE->getCalleeContext(),
676 CEE->getLocationContext(),
679 llvm_unreachable("Unexpected ProgramPoint");
682 return PathDiagnosticLocation(S, SMng, P.getLocationContext());
685 const Stmt *PathDiagnosticLocation::getStmt(const ExplodedNode *N) {
686 ProgramPoint P = N->getLocation();
687 if (Optional<StmtPoint> SP = P.getAs<StmtPoint>())
688 return SP->getStmt();
689 if (Optional<BlockEdge> BE = P.getAs<BlockEdge>())
690 return BE->getSrc()->getTerminator();
691 if (Optional<CallEnter> CE = P.getAs<CallEnter>())
692 return CE->getCallExpr();
693 if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>())
694 return CEE->getCalleeContext()->getCallSite();
695 if (Optional<PostInitializer> PIPP = P.getAs<PostInitializer>())
696 return PIPP->getInitializer()->getInit();
701 const Stmt *PathDiagnosticLocation::getNextStmt(const ExplodedNode *N) {
702 for (N = N->getFirstSucc(); N; N = N->getFirstSucc()) {
703 if (const Stmt *S = getStmt(N)) {
704 // Check if the statement is '?' or '&&'/'||'. These are "merges",
705 // not actual statement points.
706 switch (S->getStmtClass()) {
707 case Stmt::ChooseExprClass:
708 case Stmt::BinaryConditionalOperatorClass:
709 case Stmt::ConditionalOperatorClass:
711 case Stmt::BinaryOperatorClass: {
712 BinaryOperatorKind Op = cast<BinaryOperator>(S)->getOpcode();
713 if (Op == BO_LAnd || Op == BO_LOr)
720 // We found the statement, so return it.
728 PathDiagnosticLocation
729 PathDiagnosticLocation::createEndOfPath(const ExplodedNode *N,
730 const SourceManager &SM) {
731 assert(N && "Cannot create a location with a null node.");
732 const Stmt *S = getStmt(N);
738 ProgramPoint P = N->getLocation();
739 const LocationContext *LC = N->getLocationContext();
741 // For member expressions, return the location of the '.' or '->'.
742 if (const MemberExpr *ME = dyn_cast<MemberExpr>(S))
743 return PathDiagnosticLocation::createMemberLoc(ME, SM);
745 // For binary operators, return the location of the operator.
746 if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S))
747 return PathDiagnosticLocation::createOperatorLoc(B, SM);
749 if (P.getAs<PostStmtPurgeDeadSymbols>())
750 return PathDiagnosticLocation::createEnd(S, SM, LC);
752 if (S->getLocStart().isValid())
753 return PathDiagnosticLocation(S, SM, LC);
754 return PathDiagnosticLocation(getValidSourceLocation(S, LC), SM);
757 return createDeclEnd(N->getLocationContext(), SM);
760 PathDiagnosticLocation PathDiagnosticLocation::createSingleLocation(
761 const PathDiagnosticLocation &PDL) {
762 FullSourceLoc L = PDL.asLocation();
763 return PathDiagnosticLocation(L, L.getManager(), SingleLocK);
767 PathDiagnosticLocation::genLocation(SourceLocation L,
768 LocationOrAnalysisDeclContext LAC) const {
770 // Note that we want a 'switch' here so that the compiler can warn us in
771 // case we add more cases.
777 // Defensive checking.
780 return FullSourceLoc(getValidSourceLocation(S, LAC),
781 const_cast<SourceManager&>(*SM));
783 // Defensive checking.
786 return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM));
789 return FullSourceLoc(L, const_cast<SourceManager&>(*SM));
793 PathDiagnosticLocation::genRange(LocationOrAnalysisDeclContext LAC) const {
795 // Note that we want a 'switch' here so that the compiler can warn us in
796 // case we add more cases.
799 return PathDiagnosticRange(SourceRange(Loc,Loc), true);
803 const Stmt *S = asStmt();
804 switch (S->getStmtClass()) {
807 case Stmt::DeclStmtClass: {
808 const DeclStmt *DS = cast<DeclStmt>(S);
809 if (DS->isSingleDecl()) {
810 // Should always be the case, but we'll be defensive.
811 return SourceRange(DS->getLocStart(),
812 DS->getSingleDecl()->getLocation());
816 // FIXME: Provide better range information for different
818 case Stmt::IfStmtClass:
819 case Stmt::WhileStmtClass:
820 case Stmt::DoStmtClass:
821 case Stmt::ForStmtClass:
822 case Stmt::ChooseExprClass:
823 case Stmt::IndirectGotoStmtClass:
824 case Stmt::SwitchStmtClass:
825 case Stmt::BinaryConditionalOperatorClass:
826 case Stmt::ConditionalOperatorClass:
827 case Stmt::ObjCForCollectionStmtClass: {
828 SourceLocation L = getValidSourceLocation(S, LAC);
829 return SourceRange(L, L);
832 SourceRange R = S->getSourceRange();
838 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
839 return MD->getSourceRange();
840 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
841 if (Stmt *Body = FD->getBody())
842 return Body->getSourceRange();
845 SourceLocation L = D->getLocation();
846 return PathDiagnosticRange(SourceRange(L, L), true);
850 return SourceRange(Loc,Loc);
853 void PathDiagnosticLocation::flatten() {
859 else if (K == DeclK) {
866 //===----------------------------------------------------------------------===//
867 // Manipulation of PathDiagnosticCallPieces.
868 //===----------------------------------------------------------------------===//
870 PathDiagnosticCallPiece *
871 PathDiagnosticCallPiece::construct(const ExplodedNode *N,
872 const CallExitEnd &CE,
873 const SourceManager &SM) {
874 const Decl *caller = CE.getLocationContext()->getDecl();
875 PathDiagnosticLocation pos = getLocationForCaller(CE.getCalleeContext(),
876 CE.getLocationContext(),
878 return new PathDiagnosticCallPiece(caller, pos);
881 PathDiagnosticCallPiece *
882 PathDiagnosticCallPiece::construct(PathPieces &path,
883 const Decl *caller) {
884 PathDiagnosticCallPiece *C = new PathDiagnosticCallPiece(path, caller);
890 void PathDiagnosticCallPiece::setCallee(const CallEnter &CE,
891 const SourceManager &SM) {
892 const StackFrameContext *CalleeCtx = CE.getCalleeContext();
893 Callee = CalleeCtx->getDecl();
895 callEnterWithin = PathDiagnosticLocation::createBegin(Callee, SM);
896 callEnter = getLocationForCaller(CalleeCtx, CE.getLocationContext(), SM);
899 static inline void describeClass(raw_ostream &Out, const CXXRecordDecl *D,
900 StringRef Prefix = StringRef()) {
901 if (!D->getIdentifier())
903 Out << Prefix << '\'' << *D << '\'';
906 static bool describeCodeDecl(raw_ostream &Out, const Decl *D,
907 bool ExtendedDescription,
908 StringRef Prefix = StringRef()) {
912 if (isa<BlockDecl>(D)) {
913 if (ExtendedDescription)
914 Out << Prefix << "anonymous block";
915 return ExtendedDescription;
918 if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
920 if (ExtendedDescription && !MD->isUserProvided()) {
921 if (MD->isExplicitlyDefaulted())
927 if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(MD)) {
928 if (CD->isDefaultConstructor())
930 else if (CD->isCopyConstructor())
932 else if (CD->isMoveConstructor())
935 Out << "constructor";
936 describeClass(Out, MD->getParent(), " for ");
938 } else if (isa<CXXDestructorDecl>(MD)) {
939 if (!MD->isUserProvided()) {
941 describeClass(Out, MD->getParent(), " for ");
943 // Use ~Foo for explicitly-written destructors.
944 Out << "'" << *MD << "'";
947 } else if (MD->isCopyAssignmentOperator()) {
948 Out << "copy assignment operator";
949 describeClass(Out, MD->getParent(), " for ");
951 } else if (MD->isMoveAssignmentOperator()) {
952 Out << "move assignment operator";
953 describeClass(Out, MD->getParent(), " for ");
956 if (MD->getParent()->getIdentifier())
957 Out << "'" << *MD->getParent() << "::" << *MD << "'";
959 Out << "'" << *MD << "'";
965 Out << Prefix << '\'' << cast<NamedDecl>(*D) << '\'';
969 IntrusiveRefCntPtr<PathDiagnosticEventPiece>
970 PathDiagnosticCallPiece::getCallEnterEvent() const {
974 SmallString<256> buf;
975 llvm::raw_svector_ostream Out(buf);
978 describeCodeDecl(Out, Callee, /*ExtendedDescription=*/true);
980 assert(callEnter.asLocation().isValid());
981 return new PathDiagnosticEventPiece(callEnter, Out.str());
984 IntrusiveRefCntPtr<PathDiagnosticEventPiece>
985 PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const {
986 if (!callEnterWithin.asLocation().isValid())
988 if (Callee->isImplicit() || !Callee->hasBody())
990 if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Callee))
991 if (MD->isDefaulted())
994 SmallString<256> buf;
995 llvm::raw_svector_ostream Out(buf);
997 Out << "Entered call";
998 describeCodeDecl(Out, Caller, /*ExtendedDescription=*/false, " from ");
1000 return new PathDiagnosticEventPiece(callEnterWithin, Out.str());
1003 IntrusiveRefCntPtr<PathDiagnosticEventPiece>
1004 PathDiagnosticCallPiece::getCallExitEvent() const {
1008 SmallString<256> buf;
1009 llvm::raw_svector_ostream Out(buf);
1011 if (!CallStackMessage.empty()) {
1012 Out << CallStackMessage;
1014 bool DidDescribe = describeCodeDecl(Out, Callee,
1015 /*ExtendedDescription=*/false,
1018 Out << "Returning to caller";
1021 assert(callReturn.asLocation().isValid());
1022 return new PathDiagnosticEventPiece(callReturn, Out.str());
1025 static void compute_path_size(const PathPieces &pieces, unsigned &size) {
1026 for (PathPieces::const_iterator it = pieces.begin(),
1027 et = pieces.end(); it != et; ++it) {
1028 const PathDiagnosticPiece *piece = it->getPtr();
1029 if (const PathDiagnosticCallPiece *cp =
1030 dyn_cast<PathDiagnosticCallPiece>(piece)) {
1031 compute_path_size(cp->path, size);
1038 unsigned PathDiagnostic::full_size() {
1040 compute_path_size(path, size);
1044 //===----------------------------------------------------------------------===//
1045 // FoldingSet profiling methods.
1046 //===----------------------------------------------------------------------===//
1048 void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const {
1049 ID.AddInteger(Range.getBegin().getRawEncoding());
1050 ID.AddInteger(Range.getEnd().getRawEncoding());
1051 ID.AddInteger(Loc.getRawEncoding());
1055 void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1056 ID.AddInteger((unsigned) getKind());
1058 // FIXME: Add profiling support for code hints.
1059 ID.AddInteger((unsigned) getDisplayHint());
1060 ArrayRef<SourceRange> Ranges = getRanges();
1061 for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end();
1063 ID.AddInteger(I->getBegin().getRawEncoding());
1064 ID.AddInteger(I->getEnd().getRawEncoding());
1068 void PathDiagnosticCallPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1069 PathDiagnosticPiece::Profile(ID);
1070 for (PathPieces::const_iterator it = path.begin(),
1071 et = path.end(); it != et; ++it) {
1076 void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1077 PathDiagnosticPiece::Profile(ID);
1081 void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1082 PathDiagnosticPiece::Profile(ID);
1083 for (const_iterator I = begin(), E = end(); I != E; ++I)
1087 void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1088 PathDiagnosticSpotPiece::Profile(ID);
1089 for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end();
1094 void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const {
1095 ID.Add(getLocation());
1096 ID.AddString(BugType);
1097 ID.AddString(VerboseDesc);
1098 ID.AddString(Category);
1101 void PathDiagnostic::FullProfile(llvm::FoldingSetNodeID &ID) const {
1103 for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E; ++I)
1105 for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I)
1109 StackHintGenerator::~StackHintGenerator() {}
1111 std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){
1112 ProgramPoint P = N->getLocation();
1113 CallExitEnd CExit = P.castAs<CallExitEnd>();
1115 // FIXME: Use CallEvent to abstract this over all calls.
1116 const Stmt *CallSite = CExit.getCalleeContext()->getCallSite();
1117 const CallExpr *CE = dyn_cast_or_null<CallExpr>(CallSite);
1122 return getMessageForSymbolNotFound();
1124 // Check if one of the parameters are set to the interesting symbol.
1125 ProgramStateRef State = N->getState();
1126 const LocationContext *LCtx = N->getLocationContext();
1127 unsigned ArgIndex = 0;
1128 for (CallExpr::const_arg_iterator I = CE->arg_begin(),
1129 E = CE->arg_end(); I != E; ++I, ++ArgIndex){
1130 SVal SV = State->getSVal(*I, LCtx);
1132 // Check if the variable corresponding to the symbol is passed by value.
1133 SymbolRef AS = SV.getAsLocSymbol();
1135 return getMessageForArg(*I, ArgIndex);
1138 // Check if the parameter is a pointer to the symbol.
1139 if (Optional<loc::MemRegionVal> Reg = SV.getAs<loc::MemRegionVal>()) {
1140 SVal PSV = State->getSVal(Reg->getRegion());
1141 SymbolRef AS = PSV.getAsLocSymbol();
1143 return getMessageForArg(*I, ArgIndex);
1148 // Check if we are returning the interesting symbol.
1149 SVal SV = State->getSVal(CE, LCtx);
1150 SymbolRef RetSym = SV.getAsLocSymbol();
1151 if (RetSym == Sym) {
1152 return getMessageForReturn(CE);
1155 return getMessageForSymbolNotFound();
1158 std::string StackHintGeneratorForSymbol::getMessageForArg(const Expr *ArgE,
1159 unsigned ArgIndex) {
1160 // Printed parameters start at 1, not 0.
1163 SmallString<200> buf;
1164 llvm::raw_svector_ostream os(buf);
1166 os << Msg << " via " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex)