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) {}
53 PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint)
54 : kind(k), Hint(hint) {}
56 PathDiagnosticPiece::~PathDiagnosticPiece() {}
57 PathDiagnosticEventPiece::~PathDiagnosticEventPiece() {}
58 PathDiagnosticCallPiece::~PathDiagnosticCallPiece() {}
59 PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() {}
60 PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() {}
63 PathPieces::~PathPieces() {}
65 void PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current,
66 bool ShouldFlattenMacros) const {
67 for (PathPieces::const_iterator I = begin(), E = end(); I != E; ++I) {
68 PathDiagnosticPiece *Piece = I->getPtr();
70 switch (Piece->getKind()) {
71 case PathDiagnosticPiece::Call: {
72 PathDiagnosticCallPiece *Call = cast<PathDiagnosticCallPiece>(Piece);
73 IntrusiveRefCntPtr<PathDiagnosticEventPiece> CallEnter =
74 Call->getCallEnterEvent();
76 Current.push_back(CallEnter);
77 Call->path.flattenTo(Primary, Primary, ShouldFlattenMacros);
78 IntrusiveRefCntPtr<PathDiagnosticEventPiece> callExit =
79 Call->getCallExitEvent();
81 Current.push_back(callExit);
84 case PathDiagnosticPiece::Macro: {
85 PathDiagnosticMacroPiece *Macro = cast<PathDiagnosticMacroPiece>(Piece);
86 if (ShouldFlattenMacros) {
87 Macro->subPieces.flattenTo(Primary, Primary, ShouldFlattenMacros);
89 Current.push_back(Piece);
91 Macro->subPieces.flattenTo(Primary, NewPath, ShouldFlattenMacros);
92 // FIXME: This probably shouldn't mutate the original path piece.
93 Macro->subPieces = NewPath;
97 case PathDiagnosticPiece::Event:
98 case PathDiagnosticPiece::ControlFlow:
99 Current.push_back(Piece);
106 PathDiagnostic::~PathDiagnostic() {}
108 PathDiagnostic::PathDiagnostic(const Decl *declWithIssue,
109 StringRef bugtype, StringRef verboseDesc,
110 StringRef shortDesc, StringRef category,
111 PathDiagnosticLocation LocationToUnique,
112 const Decl *DeclToUnique)
113 : DeclWithIssue(declWithIssue),
114 BugType(StripTrailingDots(bugtype)),
115 VerboseDesc(StripTrailingDots(verboseDesc)),
116 ShortDesc(StripTrailingDots(shortDesc)),
117 Category(StripTrailingDots(category)),
118 UniqueingLoc(LocationToUnique),
119 UniqueingDecl(DeclToUnique),
122 void PathDiagnosticConsumer::anchor() { }
124 PathDiagnosticConsumer::~PathDiagnosticConsumer() {
125 // Delete the contents of the FoldingSet if it isn't empty already.
126 for (llvm::FoldingSet<PathDiagnostic>::iterator it =
127 Diags.begin(), et = Diags.end() ; it != et ; ++it) {
132 void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) {
133 OwningPtr<PathDiagnostic> OwningD(D);
135 if (!D || D->path.empty())
138 // We need to flatten the locations (convert Stmt* to locations) because
139 // the referenced statements may be freed by the time the diagnostics
141 D->flattenLocations();
143 // If the PathDiagnosticConsumer does not support diagnostics that
144 // cross file boundaries, prune out such diagnostics now.
145 if (!supportsCrossFileDiagnostics()) {
146 // Verify that the entire path is from the same FileID.
148 const SourceManager &SMgr = (*D->path.begin())->getLocation().getManager();
149 SmallVector<const PathPieces *, 5> WorkList;
150 WorkList.push_back(&D->path);
152 while (!WorkList.empty()) {
153 const PathPieces &path = *WorkList.back();
156 for (PathPieces::const_iterator I = path.begin(), E = path.end();
158 const PathDiagnosticPiece *piece = I->getPtr();
159 FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc();
161 if (FID.isInvalid()) {
162 FID = SMgr.getFileID(L);
163 } else if (SMgr.getFileID(L) != FID)
164 return; // FIXME: Emit a warning?
166 // Check the source ranges.
167 ArrayRef<SourceRange> Ranges = piece->getRanges();
168 for (ArrayRef<SourceRange>::iterator I = Ranges.begin(),
169 E = Ranges.end(); I != E; ++I) {
170 SourceLocation L = SMgr.getExpansionLoc(I->getBegin());
171 if (!L.isFileID() || SMgr.getFileID(L) != FID)
172 return; // FIXME: Emit a warning?
173 L = SMgr.getExpansionLoc(I->getEnd());
174 if (!L.isFileID() || SMgr.getFileID(L) != FID)
175 return; // FIXME: Emit a warning?
178 if (const PathDiagnosticCallPiece *call =
179 dyn_cast<PathDiagnosticCallPiece>(piece)) {
180 WorkList.push_back(&call->path);
182 else if (const PathDiagnosticMacroPiece *macro =
183 dyn_cast<PathDiagnosticMacroPiece>(piece)) {
184 WorkList.push_back(¯o->subPieces);
190 return; // FIXME: Emit a warning?
193 // Profile the node to see if we already have something matching it
194 llvm::FoldingSetNodeID profile;
198 if (PathDiagnostic *orig = Diags.FindNodeOrInsertPos(profile, InsertPos)) {
199 // Keep the PathDiagnostic with the shorter path.
200 // Note, the enclosing routine is called in deterministic order, so the
201 // results will be consistent between runs (no reason to break ties if the
202 // size is the same).
203 const unsigned orig_size = orig->full_size();
204 const unsigned new_size = D->full_size();
205 if (orig_size <= new_size)
209 Diags.RemoveNode(orig);
213 Diags.InsertNode(OwningD.take());
216 static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y);
217 static Optional<bool>
218 compareControlFlow(const PathDiagnosticControlFlowPiece &X,
219 const PathDiagnosticControlFlowPiece &Y) {
220 FullSourceLoc XSL = X.getStartLocation().asLocation();
221 FullSourceLoc YSL = Y.getStartLocation().asLocation();
223 return XSL.isBeforeInTranslationUnitThan(YSL);
224 FullSourceLoc XEL = X.getEndLocation().asLocation();
225 FullSourceLoc YEL = Y.getEndLocation().asLocation();
227 return XEL.isBeforeInTranslationUnitThan(YEL);
231 static Optional<bool> compareMacro(const PathDiagnosticMacroPiece &X,
232 const PathDiagnosticMacroPiece &Y) {
233 return comparePath(X.subPieces, Y.subPieces);
236 static Optional<bool> compareCall(const PathDiagnosticCallPiece &X,
237 const PathDiagnosticCallPiece &Y) {
238 FullSourceLoc X_CEL = X.callEnter.asLocation();
239 FullSourceLoc Y_CEL = Y.callEnter.asLocation();
241 return X_CEL.isBeforeInTranslationUnitThan(Y_CEL);
242 FullSourceLoc X_CEWL = X.callEnterWithin.asLocation();
243 FullSourceLoc Y_CEWL = Y.callEnterWithin.asLocation();
244 if (X_CEWL != Y_CEWL)
245 return X_CEWL.isBeforeInTranslationUnitThan(Y_CEWL);
246 FullSourceLoc X_CRL = X.callReturn.asLocation();
247 FullSourceLoc Y_CRL = Y.callReturn.asLocation();
249 return X_CRL.isBeforeInTranslationUnitThan(Y_CRL);
250 return comparePath(X.path, Y.path);
253 static Optional<bool> comparePiece(const PathDiagnosticPiece &X,
254 const PathDiagnosticPiece &Y) {
255 if (X.getKind() != Y.getKind())
256 return X.getKind() < Y.getKind();
258 FullSourceLoc XL = X.getLocation().asLocation();
259 FullSourceLoc YL = Y.getLocation().asLocation();
261 return XL.isBeforeInTranslationUnitThan(YL);
263 if (X.getString() != Y.getString())
264 return X.getString() < Y.getString();
266 if (X.getRanges().size() != Y.getRanges().size())
267 return X.getRanges().size() < Y.getRanges().size();
269 const SourceManager &SM = XL.getManager();
271 for (unsigned i = 0, n = X.getRanges().size(); i < n; ++i) {
272 SourceRange XR = X.getRanges()[i];
273 SourceRange YR = Y.getRanges()[i];
275 if (XR.getBegin() != YR.getBegin())
276 return SM.isBeforeInTranslationUnit(XR.getBegin(), YR.getBegin());
277 return SM.isBeforeInTranslationUnit(XR.getEnd(), YR.getEnd());
281 switch (X.getKind()) {
282 case clang::ento::PathDiagnosticPiece::ControlFlow:
283 return compareControlFlow(cast<PathDiagnosticControlFlowPiece>(X),
284 cast<PathDiagnosticControlFlowPiece>(Y));
285 case clang::ento::PathDiagnosticPiece::Event:
287 case clang::ento::PathDiagnosticPiece::Macro:
288 return compareMacro(cast<PathDiagnosticMacroPiece>(X),
289 cast<PathDiagnosticMacroPiece>(Y));
290 case clang::ento::PathDiagnosticPiece::Call:
291 return compareCall(cast<PathDiagnosticCallPiece>(X),
292 cast<PathDiagnosticCallPiece>(Y));
294 llvm_unreachable("all cases handled");
297 static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y) {
298 if (X.size() != Y.size())
299 return X.size() < Y.size();
301 PathPieces::const_iterator X_I = X.begin(), X_end = X.end();
302 PathPieces::const_iterator Y_I = Y.begin(), Y_end = Y.end();
304 for ( ; X_I != X_end && Y_I != Y_end; ++X_I, ++Y_I) {
305 Optional<bool> b = comparePiece(**X_I, **Y_I);
313 static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) {
314 FullSourceLoc XL = X.getLocation().asLocation();
315 FullSourceLoc YL = Y.getLocation().asLocation();
317 return XL.isBeforeInTranslationUnitThan(YL);
318 if (X.getBugType() != Y.getBugType())
319 return X.getBugType() < Y.getBugType();
320 if (X.getCategory() != Y.getCategory())
321 return X.getCategory() < Y.getCategory();
322 if (X.getVerboseDescription() != Y.getVerboseDescription())
323 return X.getVerboseDescription() < Y.getVerboseDescription();
324 if (X.getShortDescription() != Y.getShortDescription())
325 return X.getShortDescription() < Y.getShortDescription();
326 if (X.getDeclWithIssue() != Y.getDeclWithIssue()) {
327 const Decl *XD = X.getDeclWithIssue();
330 const Decl *YD = Y.getDeclWithIssue();
333 SourceLocation XDL = XD->getLocation();
334 SourceLocation YDL = YD->getLocation();
336 const SourceManager &SM = XL.getManager();
337 return SM.isBeforeInTranslationUnit(XDL, YDL);
340 PathDiagnostic::meta_iterator XI = X.meta_begin(), XE = X.meta_end();
341 PathDiagnostic::meta_iterator YI = Y.meta_begin(), YE = Y.meta_end();
342 if (XE - XI != YE - YI)
343 return (XE - XI) < (YE - YI);
344 for ( ; XI != XE ; ++XI, ++YI) {
346 return (*XI) < (*YI);
348 Optional<bool> b = comparePath(X.path, Y.path);
349 assert(b.hasValue());
354 struct CompareDiagnostics {
355 // Compare if 'X' is "<" than 'Y'.
356 bool operator()(const PathDiagnostic *X, const PathDiagnostic *Y) const {
359 return compare(*X, *Y);
364 void PathDiagnosticConsumer::FlushDiagnostics(
365 PathDiagnosticConsumer::FilesMade *Files) {
371 std::vector<const PathDiagnostic *> BatchDiags;
372 for (llvm::FoldingSet<PathDiagnostic>::iterator it = Diags.begin(),
373 et = Diags.end(); it != et; ++it) {
374 const PathDiagnostic *D = &*it;
375 BatchDiags.push_back(D);
378 // Sort the diagnostics so that they are always emitted in a deterministic
380 if (!BatchDiags.empty())
381 std::sort(BatchDiags.begin(), BatchDiags.end(), CompareDiagnostics());
383 FlushDiagnosticsImpl(BatchDiags, Files);
385 // Delete the flushed diagnostics.
386 for (std::vector<const PathDiagnostic *>::iterator it = BatchDiags.begin(),
387 et = BatchDiags.end(); it != et; ++it) {
388 const PathDiagnostic *D = *it;
392 // Clear out the FoldingSet.
396 void PathDiagnosticConsumer::FilesMade::addDiagnostic(const PathDiagnostic &PD,
397 StringRef ConsumerName,
398 StringRef FileName) {
399 llvm::FoldingSetNodeID NodeID;
402 PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos);
404 Entry = Alloc.Allocate<PDFileEntry>();
405 Entry = new (Entry) PDFileEntry(NodeID);
406 InsertNode(Entry, InsertPos);
409 // Allocate persistent storage for the file name.
410 char *FileName_cstr = (char*) Alloc.Allocate(FileName.size(), 1);
411 memcpy(FileName_cstr, FileName.data(), FileName.size());
413 Entry->files.push_back(std::make_pair(ConsumerName,
414 StringRef(FileName_cstr,
418 PathDiagnosticConsumer::PDFileEntry::ConsumerFiles *
419 PathDiagnosticConsumer::FilesMade::getFiles(const PathDiagnostic &PD) {
420 llvm::FoldingSetNodeID NodeID;
423 PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos);
426 return &Entry->files;
429 //===----------------------------------------------------------------------===//
430 // PathDiagnosticLocation methods.
431 //===----------------------------------------------------------------------===//
433 static SourceLocation getValidSourceLocation(const Stmt* S,
434 LocationOrAnalysisDeclContext LAC,
435 bool UseEnd = false) {
436 SourceLocation L = UseEnd ? S->getLocEnd() : S->getLocStart();
437 assert(!LAC.isNull() && "A valid LocationContext or AnalysisDeclContext should "
438 "be passed to PathDiagnosticLocation upon creation.");
440 // S might be a temporary statement that does not have a location in the
441 // source code, so find an enclosing statement and use its location.
444 AnalysisDeclContext *ADC;
445 if (LAC.is<const LocationContext*>())
446 ADC = LAC.get<const LocationContext*>()->getAnalysisDeclContext();
448 ADC = LAC.get<AnalysisDeclContext*>();
450 ParentMap &PM = ADC->getParentMap();
452 const Stmt *Parent = S;
454 Parent = PM.getParent(Parent);
456 // In rare cases, we have implicit top-level expressions,
457 // such as arguments for implicit member initializers.
458 // In this case, fall back to the start of the body (even if we were
459 // asked for the statement end location).
461 const Stmt *Body = ADC->getBody();
463 L = Body->getLocStart();
465 L = ADC->getDecl()->getLocEnd();
469 L = UseEnd ? Parent->getLocEnd() : Parent->getLocStart();
470 } while (!L.isValid());
476 static PathDiagnosticLocation
477 getLocationForCaller(const StackFrameContext *SFC,
478 const LocationContext *CallerCtx,
479 const SourceManager &SM) {
480 const CFGBlock &Block = *SFC->getCallSiteBlock();
481 CFGElement Source = Block[SFC->getIndex()];
483 switch (Source.getKind()) {
484 case CFGElement::Statement:
485 return PathDiagnosticLocation(Source.castAs<CFGStmt>().getStmt(),
487 case CFGElement::Initializer: {
488 const CFGInitializer &Init = Source.castAs<CFGInitializer>();
489 return PathDiagnosticLocation(Init.getInitializer()->getInit(),
492 case CFGElement::AutomaticObjectDtor: {
493 const CFGAutomaticObjDtor &Dtor = Source.castAs<CFGAutomaticObjDtor>();
494 return PathDiagnosticLocation::createEnd(Dtor.getTriggerStmt(),
497 case CFGElement::BaseDtor:
498 case CFGElement::MemberDtor: {
499 const AnalysisDeclContext *CallerInfo = CallerCtx->getAnalysisDeclContext();
500 if (const Stmt *CallerBody = CallerInfo->getBody())
501 return PathDiagnosticLocation::createEnd(CallerBody, SM, CallerCtx);
502 return PathDiagnosticLocation::create(CallerInfo->getDecl(), SM);
504 case CFGElement::TemporaryDtor:
505 llvm_unreachable("not yet implemented!");
508 llvm_unreachable("Unknown CFGElement kind");
512 PathDiagnosticLocation
513 PathDiagnosticLocation::createBegin(const Decl *D,
514 const SourceManager &SM) {
515 return PathDiagnosticLocation(D->getLocStart(), SM, SingleLocK);
518 PathDiagnosticLocation
519 PathDiagnosticLocation::createBegin(const Stmt *S,
520 const SourceManager &SM,
521 LocationOrAnalysisDeclContext LAC) {
522 return PathDiagnosticLocation(getValidSourceLocation(S, LAC),
527 PathDiagnosticLocation
528 PathDiagnosticLocation::createEnd(const Stmt *S,
529 const SourceManager &SM,
530 LocationOrAnalysisDeclContext LAC) {
531 if (const CompoundStmt *CS = dyn_cast<CompoundStmt>(S))
532 return createEndBrace(CS, SM);
533 return PathDiagnosticLocation(getValidSourceLocation(S, LAC, /*End=*/true),
537 PathDiagnosticLocation
538 PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO,
539 const SourceManager &SM) {
540 return PathDiagnosticLocation(BO->getOperatorLoc(), SM, SingleLocK);
543 PathDiagnosticLocation
544 PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME,
545 const SourceManager &SM) {
546 return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK);
549 PathDiagnosticLocation
550 PathDiagnosticLocation::createBeginBrace(const CompoundStmt *CS,
551 const SourceManager &SM) {
552 SourceLocation L = CS->getLBracLoc();
553 return PathDiagnosticLocation(L, SM, SingleLocK);
556 PathDiagnosticLocation
557 PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS,
558 const SourceManager &SM) {
559 SourceLocation L = CS->getRBracLoc();
560 return PathDiagnosticLocation(L, SM, SingleLocK);
563 PathDiagnosticLocation
564 PathDiagnosticLocation::createDeclBegin(const LocationContext *LC,
565 const SourceManager &SM) {
566 // FIXME: Should handle CXXTryStmt if analyser starts supporting C++.
567 if (const CompoundStmt *CS =
568 dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody()))
569 if (!CS->body_empty()) {
570 SourceLocation Loc = (*CS->body_begin())->getLocStart();
571 return PathDiagnosticLocation(Loc, SM, SingleLocK);
574 return PathDiagnosticLocation();
577 PathDiagnosticLocation
578 PathDiagnosticLocation::createDeclEnd(const LocationContext *LC,
579 const SourceManager &SM) {
580 SourceLocation L = LC->getDecl()->getBodyRBrace();
581 return PathDiagnosticLocation(L, SM, SingleLocK);
584 PathDiagnosticLocation
585 PathDiagnosticLocation::create(const ProgramPoint& P,
586 const SourceManager &SMng) {
589 if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
590 const CFGBlock *BSrc = BE->getSrc();
591 S = BSrc->getTerminatorCondition();
592 } else if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) {
594 if (P.getAs<PostStmtPurgeDeadSymbols>())
595 return PathDiagnosticLocation::createEnd(S, SMng, P.getLocationContext());
596 } else if (Optional<PostInitializer> PIP = P.getAs<PostInitializer>()) {
597 return PathDiagnosticLocation(PIP->getInitializer()->getSourceLocation(),
599 } else if (Optional<PostImplicitCall> PIE = P.getAs<PostImplicitCall>()) {
600 return PathDiagnosticLocation(PIE->getLocation(), SMng);
601 } else if (Optional<CallEnter> CE = P.getAs<CallEnter>()) {
602 return getLocationForCaller(CE->getCalleeContext(),
603 CE->getLocationContext(),
605 } else if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) {
606 return getLocationForCaller(CEE->getCalleeContext(),
607 CEE->getLocationContext(),
610 llvm_unreachable("Unexpected ProgramPoint");
613 return PathDiagnosticLocation(S, SMng, P.getLocationContext());
616 const Stmt *PathDiagnosticLocation::getStmt(const ExplodedNode *N) {
617 ProgramPoint P = N->getLocation();
618 if (Optional<StmtPoint> SP = P.getAs<StmtPoint>())
619 return SP->getStmt();
620 if (Optional<BlockEdge> BE = P.getAs<BlockEdge>())
621 return BE->getSrc()->getTerminator();
622 if (Optional<CallEnter> CE = P.getAs<CallEnter>())
623 return CE->getCallExpr();
624 if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>())
625 return CEE->getCalleeContext()->getCallSite();
626 if (Optional<PostInitializer> PIPP = P.getAs<PostInitializer>())
627 return PIPP->getInitializer()->getInit();
632 const Stmt *PathDiagnosticLocation::getNextStmt(const ExplodedNode *N) {
633 for (N = N->getFirstSucc(); N; N = N->getFirstSucc()) {
634 if (const Stmt *S = getStmt(N)) {
635 // Check if the statement is '?' or '&&'/'||'. These are "merges",
636 // not actual statement points.
637 switch (S->getStmtClass()) {
638 case Stmt::ChooseExprClass:
639 case Stmt::BinaryConditionalOperatorClass:
640 case Stmt::ConditionalOperatorClass:
642 case Stmt::BinaryOperatorClass: {
643 BinaryOperatorKind Op = cast<BinaryOperator>(S)->getOpcode();
644 if (Op == BO_LAnd || Op == BO_LOr)
651 // We found the statement, so return it.
659 PathDiagnosticLocation
660 PathDiagnosticLocation::createEndOfPath(const ExplodedNode *N,
661 const SourceManager &SM) {
662 assert(N && "Cannot create a location with a null node.");
663 const Stmt *S = getStmt(N);
669 ProgramPoint P = N->getLocation();
670 const LocationContext *LC = N->getLocationContext();
672 // For member expressions, return the location of the '.' or '->'.
673 if (const MemberExpr *ME = dyn_cast<MemberExpr>(S))
674 return PathDiagnosticLocation::createMemberLoc(ME, SM);
676 // For binary operators, return the location of the operator.
677 if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S))
678 return PathDiagnosticLocation::createOperatorLoc(B, SM);
680 if (P.getAs<PostStmtPurgeDeadSymbols>())
681 return PathDiagnosticLocation::createEnd(S, SM, LC);
683 if (S->getLocStart().isValid())
684 return PathDiagnosticLocation(S, SM, LC);
685 return PathDiagnosticLocation(getValidSourceLocation(S, LC), SM);
688 return createDeclEnd(N->getLocationContext(), SM);
691 PathDiagnosticLocation PathDiagnosticLocation::createSingleLocation(
692 const PathDiagnosticLocation &PDL) {
693 FullSourceLoc L = PDL.asLocation();
694 return PathDiagnosticLocation(L, L.getManager(), SingleLocK);
698 PathDiagnosticLocation::genLocation(SourceLocation L,
699 LocationOrAnalysisDeclContext LAC) const {
701 // Note that we want a 'switch' here so that the compiler can warn us in
702 // case we add more cases.
708 // Defensive checking.
711 return FullSourceLoc(getValidSourceLocation(S, LAC),
712 const_cast<SourceManager&>(*SM));
714 // Defensive checking.
717 return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM));
720 return FullSourceLoc(L, const_cast<SourceManager&>(*SM));
724 PathDiagnosticLocation::genRange(LocationOrAnalysisDeclContext LAC) const {
726 // Note that we want a 'switch' here so that the compiler can warn us in
727 // case we add more cases.
730 return PathDiagnosticRange(SourceRange(Loc,Loc), true);
734 const Stmt *S = asStmt();
735 switch (S->getStmtClass()) {
738 case Stmt::DeclStmtClass: {
739 const DeclStmt *DS = cast<DeclStmt>(S);
740 if (DS->isSingleDecl()) {
741 // Should always be the case, but we'll be defensive.
742 return SourceRange(DS->getLocStart(),
743 DS->getSingleDecl()->getLocation());
747 // FIXME: Provide better range information for different
749 case Stmt::IfStmtClass:
750 case Stmt::WhileStmtClass:
751 case Stmt::DoStmtClass:
752 case Stmt::ForStmtClass:
753 case Stmt::ChooseExprClass:
754 case Stmt::IndirectGotoStmtClass:
755 case Stmt::SwitchStmtClass:
756 case Stmt::BinaryConditionalOperatorClass:
757 case Stmt::ConditionalOperatorClass:
758 case Stmt::ObjCForCollectionStmtClass: {
759 SourceLocation L = getValidSourceLocation(S, LAC);
760 return SourceRange(L, L);
763 SourceRange R = S->getSourceRange();
769 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
770 return MD->getSourceRange();
771 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
772 if (Stmt *Body = FD->getBody())
773 return Body->getSourceRange();
776 SourceLocation L = D->getLocation();
777 return PathDiagnosticRange(SourceRange(L, L), true);
781 return SourceRange(Loc,Loc);
784 void PathDiagnosticLocation::flatten() {
790 else if (K == DeclK) {
797 //===----------------------------------------------------------------------===//
798 // Manipulation of PathDiagnosticCallPieces.
799 //===----------------------------------------------------------------------===//
801 PathDiagnosticCallPiece *
802 PathDiagnosticCallPiece::construct(const ExplodedNode *N,
803 const CallExitEnd &CE,
804 const SourceManager &SM) {
805 const Decl *caller = CE.getLocationContext()->getDecl();
806 PathDiagnosticLocation pos = getLocationForCaller(CE.getCalleeContext(),
807 CE.getLocationContext(),
809 return new PathDiagnosticCallPiece(caller, pos);
812 PathDiagnosticCallPiece *
813 PathDiagnosticCallPiece::construct(PathPieces &path,
814 const Decl *caller) {
815 PathDiagnosticCallPiece *C = new PathDiagnosticCallPiece(path, caller);
821 void PathDiagnosticCallPiece::setCallee(const CallEnter &CE,
822 const SourceManager &SM) {
823 const StackFrameContext *CalleeCtx = CE.getCalleeContext();
824 Callee = CalleeCtx->getDecl();
826 callEnterWithin = PathDiagnosticLocation::createBegin(Callee, SM);
827 callEnter = getLocationForCaller(CalleeCtx, CE.getLocationContext(), SM);
830 static inline void describeClass(raw_ostream &Out, const CXXRecordDecl *D,
831 StringRef Prefix = StringRef()) {
832 if (!D->getIdentifier())
834 Out << Prefix << '\'' << *D << '\'';
837 static bool describeCodeDecl(raw_ostream &Out, const Decl *D,
838 bool ExtendedDescription,
839 StringRef Prefix = StringRef()) {
843 if (isa<BlockDecl>(D)) {
844 if (ExtendedDescription)
845 Out << Prefix << "anonymous block";
846 return ExtendedDescription;
849 if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
851 if (ExtendedDescription && !MD->isUserProvided()) {
852 if (MD->isExplicitlyDefaulted())
858 if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(MD)) {
859 if (CD->isDefaultConstructor())
861 else if (CD->isCopyConstructor())
863 else if (CD->isMoveConstructor())
866 Out << "constructor";
867 describeClass(Out, MD->getParent(), " for ");
869 } else if (isa<CXXDestructorDecl>(MD)) {
870 if (!MD->isUserProvided()) {
872 describeClass(Out, MD->getParent(), " for ");
874 // Use ~Foo for explicitly-written destructors.
875 Out << "'" << *MD << "'";
878 } else if (MD->isCopyAssignmentOperator()) {
879 Out << "copy assignment operator";
880 describeClass(Out, MD->getParent(), " for ");
882 } else if (MD->isMoveAssignmentOperator()) {
883 Out << "move assignment operator";
884 describeClass(Out, MD->getParent(), " for ");
887 if (MD->getParent()->getIdentifier())
888 Out << "'" << *MD->getParent() << "::" << *MD << "'";
890 Out << "'" << *MD << "'";
896 Out << Prefix << '\'' << cast<NamedDecl>(*D) << '\'';
900 IntrusiveRefCntPtr<PathDiagnosticEventPiece>
901 PathDiagnosticCallPiece::getCallEnterEvent() const {
905 SmallString<256> buf;
906 llvm::raw_svector_ostream Out(buf);
909 describeCodeDecl(Out, Callee, /*ExtendedDescription=*/true);
911 assert(callEnter.asLocation().isValid());
912 return new PathDiagnosticEventPiece(callEnter, Out.str());
915 IntrusiveRefCntPtr<PathDiagnosticEventPiece>
916 PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const {
917 if (!callEnterWithin.asLocation().isValid())
919 if (Callee->isImplicit())
921 if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Callee))
922 if (MD->isDefaulted())
925 SmallString<256> buf;
926 llvm::raw_svector_ostream Out(buf);
928 Out << "Entered call";
929 describeCodeDecl(Out, Caller, /*ExtendedDescription=*/false, " from ");
931 return new PathDiagnosticEventPiece(callEnterWithin, Out.str());
934 IntrusiveRefCntPtr<PathDiagnosticEventPiece>
935 PathDiagnosticCallPiece::getCallExitEvent() const {
939 SmallString<256> buf;
940 llvm::raw_svector_ostream Out(buf);
942 if (!CallStackMessage.empty()) {
943 Out << CallStackMessage;
945 bool DidDescribe = describeCodeDecl(Out, Callee,
946 /*ExtendedDescription=*/false,
949 Out << "Returning to caller";
952 assert(callReturn.asLocation().isValid());
953 return new PathDiagnosticEventPiece(callReturn, Out.str());
956 static void compute_path_size(const PathPieces &pieces, unsigned &size) {
957 for (PathPieces::const_iterator it = pieces.begin(),
958 et = pieces.end(); it != et; ++it) {
959 const PathDiagnosticPiece *piece = it->getPtr();
960 if (const PathDiagnosticCallPiece *cp =
961 dyn_cast<PathDiagnosticCallPiece>(piece)) {
962 compute_path_size(cp->path, size);
969 unsigned PathDiagnostic::full_size() {
971 compute_path_size(path, size);
975 //===----------------------------------------------------------------------===//
976 // FoldingSet profiling methods.
977 //===----------------------------------------------------------------------===//
979 void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const {
980 ID.AddInteger(Range.getBegin().getRawEncoding());
981 ID.AddInteger(Range.getEnd().getRawEncoding());
982 ID.AddInteger(Loc.getRawEncoding());
986 void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const {
987 ID.AddInteger((unsigned) getKind());
989 // FIXME: Add profiling support for code hints.
990 ID.AddInteger((unsigned) getDisplayHint());
991 ArrayRef<SourceRange> Ranges = getRanges();
992 for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end();
994 ID.AddInteger(I->getBegin().getRawEncoding());
995 ID.AddInteger(I->getEnd().getRawEncoding());
999 void PathDiagnosticCallPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1000 PathDiagnosticPiece::Profile(ID);
1001 for (PathPieces::const_iterator it = path.begin(),
1002 et = path.end(); it != et; ++it) {
1007 void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1008 PathDiagnosticPiece::Profile(ID);
1012 void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1013 PathDiagnosticPiece::Profile(ID);
1014 for (const_iterator I = begin(), E = end(); I != E; ++I)
1018 void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1019 PathDiagnosticSpotPiece::Profile(ID);
1020 for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end();
1025 void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const {
1026 ID.Add(getLocation());
1027 ID.AddString(BugType);
1028 ID.AddString(VerboseDesc);
1029 ID.AddString(Category);
1032 void PathDiagnostic::FullProfile(llvm::FoldingSetNodeID &ID) const {
1034 for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E; ++I)
1036 for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I)
1040 StackHintGenerator::~StackHintGenerator() {}
1042 std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){
1043 ProgramPoint P = N->getLocation();
1044 CallExitEnd CExit = P.castAs<CallExitEnd>();
1046 // FIXME: Use CallEvent to abstract this over all calls.
1047 const Stmt *CallSite = CExit.getCalleeContext()->getCallSite();
1048 const CallExpr *CE = dyn_cast_or_null<CallExpr>(CallSite);
1053 return getMessageForSymbolNotFound();
1055 // Check if one of the parameters are set to the interesting symbol.
1056 ProgramStateRef State = N->getState();
1057 const LocationContext *LCtx = N->getLocationContext();
1058 unsigned ArgIndex = 0;
1059 for (CallExpr::const_arg_iterator I = CE->arg_begin(),
1060 E = CE->arg_end(); I != E; ++I, ++ArgIndex){
1061 SVal SV = State->getSVal(*I, LCtx);
1063 // Check if the variable corresponding to the symbol is passed by value.
1064 SymbolRef AS = SV.getAsLocSymbol();
1066 return getMessageForArg(*I, ArgIndex);
1069 // Check if the parameter is a pointer to the symbol.
1070 if (Optional<loc::MemRegionVal> Reg = SV.getAs<loc::MemRegionVal>()) {
1071 SVal PSV = State->getSVal(Reg->getRegion());
1072 SymbolRef AS = PSV.getAsLocSymbol();
1074 return getMessageForArg(*I, ArgIndex);
1079 // Check if we are returning the interesting symbol.
1080 SVal SV = State->getSVal(CE, LCtx);
1081 SymbolRef RetSym = SV.getAsLocSymbol();
1082 if (RetSym == Sym) {
1083 return getMessageForReturn(CE);
1086 return getMessageForSymbolNotFound();
1089 std::string StackHintGeneratorForSymbol::getMessageForArg(const Expr *ArgE,
1090 unsigned ArgIndex) {
1091 // Printed parameters start at 1, not 0.
1094 SmallString<200> buf;
1095 llvm::raw_svector_ostream os(buf);
1097 os << Msg << " via " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex)