PathDiagnostic.cpp revision cfa88f893915ceb8ae4ce2f17c46c24a4d67502f
1//===--- PathDiagnostic.cpp - Path-Specific Diagnostic Handling -*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10//  This file defines the PathDiagnostic-related interfaces.
11//
12//===----------------------------------------------------------------------===//
13
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"
26
27using namespace clang;
28using namespace ento;
29
30bool PathDiagnosticMacroPiece::containsEvent() const {
31  for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end();
32       I!=E; ++I) {
33    if (isa<PathDiagnosticEventPiece>(*I))
34      return true;
35    if (PathDiagnosticMacroPiece *MP = dyn_cast<PathDiagnosticMacroPiece>(*I))
36      if (MP->containsEvent())
37        return true;
38  }
39  return false;
40}
41
42static StringRef StripTrailingDots(StringRef s) {
43  for (StringRef::size_type i = s.size(); i != 0; --i)
44    if (s[i - 1] != '.')
45      return s.substr(0, i);
46  return "";
47}
48
49PathDiagnosticPiece::PathDiagnosticPiece(StringRef s,
50                                         Kind k, DisplayHint hint)
51  : str(StripTrailingDots(s)), kind(k), Hint(hint) {}
52
53PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint)
54  : kind(k), Hint(hint) {}
55
56PathDiagnosticPiece::~PathDiagnosticPiece() {}
57PathDiagnosticEventPiece::~PathDiagnosticEventPiece() {}
58PathDiagnosticCallPiece::~PathDiagnosticCallPiece() {}
59PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() {}
60PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() {}
61
62
63PathPieces::~PathPieces() {}
64
65void 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();
69
70    switch (Piece->getKind()) {
71    case PathDiagnosticPiece::Call: {
72      PathDiagnosticCallPiece *Call = cast<PathDiagnosticCallPiece>(Piece);
73      IntrusiveRefCntPtr<PathDiagnosticEventPiece> CallEnter =
74        Call->getCallEnterEvent();
75      if (CallEnter)
76        Current.push_back(CallEnter);
77      Call->path.flattenTo(Primary, Primary, ShouldFlattenMacros);
78      IntrusiveRefCntPtr<PathDiagnosticEventPiece> callExit =
79        Call->getCallExitEvent();
80      if (callExit)
81        Current.push_back(callExit);
82      break;
83    }
84    case PathDiagnosticPiece::Macro: {
85      PathDiagnosticMacroPiece *Macro = cast<PathDiagnosticMacroPiece>(Piece);
86      if (ShouldFlattenMacros) {
87        Macro->subPieces.flattenTo(Primary, Primary, ShouldFlattenMacros);
88      } else {
89        Current.push_back(Piece);
90        PathPieces NewPath;
91        Macro->subPieces.flattenTo(Primary, NewPath, ShouldFlattenMacros);
92        // FIXME: This probably shouldn't mutate the original path piece.
93        Macro->subPieces = NewPath;
94      }
95      break;
96    }
97    case PathDiagnosticPiece::Event:
98    case PathDiagnosticPiece::ControlFlow:
99      Current.push_back(Piece);
100      break;
101    }
102  }
103}
104
105
106PathDiagnostic::~PathDiagnostic() {}
107
108PathDiagnostic::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),
120    path(pathImpl) {}
121
122void PathDiagnosticConsumer::anchor() { }
123
124PathDiagnosticConsumer::~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) {
128    delete &*it;
129  }
130}
131
132void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) {
133  OwningPtr<PathDiagnostic> OwningD(D);
134
135  if (!D || D->path.empty())
136    return;
137
138  // We need to flatten the locations (convert Stmt* to locations) because
139  // the referenced statements may be freed by the time the diagnostics
140  // are emitted.
141  D->flattenLocations();
142
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.
147    FileID FID;
148    const SourceManager &SMgr = (*D->path.begin())->getLocation().getManager();
149    SmallVector<const PathPieces *, 5> WorkList;
150    WorkList.push_back(&D->path);
151
152    while (!WorkList.empty()) {
153      const PathPieces &path = *WorkList.back();
154      WorkList.pop_back();
155
156      for (PathPieces::const_iterator I = path.begin(), E = path.end();
157           I != E; ++I) {
158        const PathDiagnosticPiece *piece = I->getPtr();
159        FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc();
160
161        if (FID.isInvalid()) {
162          FID = SMgr.getFileID(L);
163        } else if (SMgr.getFileID(L) != FID)
164          return; // FIXME: Emit a warning?
165
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?
176        }
177
178        if (const PathDiagnosticCallPiece *call =
179            dyn_cast<PathDiagnosticCallPiece>(piece)) {
180          WorkList.push_back(&call->path);
181        }
182        else if (const PathDiagnosticMacroPiece *macro =
183                 dyn_cast<PathDiagnosticMacroPiece>(piece)) {
184          WorkList.push_back(&macro->subPieces);
185        }
186      }
187    }
188
189    if (FID.isInvalid())
190      return; // FIXME: Emit a warning?
191  }
192
193  // Profile the node to see if we already have something matching it
194  llvm::FoldingSetNodeID profile;
195  D->Profile(profile);
196  void *InsertPos = 0;
197
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)
206      return;
207
208    assert(orig != D);
209    Diags.RemoveNode(orig);
210    delete orig;
211  }
212
213  Diags.InsertNode(OwningD.take());
214}
215
216static llvm::Optional<bool> comparePath(const PathPieces &X,
217                                        const PathPieces &Y);
218static llvm::Optional<bool>
219compareControlFlow(const PathDiagnosticControlFlowPiece &X,
220                   const PathDiagnosticControlFlowPiece &Y) {
221  FullSourceLoc XSL = X.getStartLocation().asLocation();
222  FullSourceLoc YSL = Y.getStartLocation().asLocation();
223  if (XSL != YSL)
224    return XSL.isBeforeInTranslationUnitThan(YSL);
225  FullSourceLoc XEL = X.getEndLocation().asLocation();
226  FullSourceLoc YEL = Y.getEndLocation().asLocation();
227  if (XEL != YEL)
228    return XEL.isBeforeInTranslationUnitThan(YEL);
229  return llvm::Optional<bool>();
230}
231
232static llvm::Optional<bool>
233compareMacro(const PathDiagnosticMacroPiece &X,
234             const PathDiagnosticMacroPiece &Y) {
235  return comparePath(X.subPieces, Y.subPieces);
236}
237
238static llvm::Optional<bool>
239compareCall(const PathDiagnosticCallPiece &X,
240            const PathDiagnosticCallPiece &Y) {
241  FullSourceLoc X_CEL = X.callEnter.asLocation();
242  FullSourceLoc Y_CEL = Y.callEnter.asLocation();
243  if (X_CEL != Y_CEL)
244    return X_CEL.isBeforeInTranslationUnitThan(Y_CEL);
245  FullSourceLoc X_CEWL = X.callEnterWithin.asLocation();
246  FullSourceLoc Y_CEWL = Y.callEnterWithin.asLocation();
247  if (X_CEWL != Y_CEWL)
248    return X_CEWL.isBeforeInTranslationUnitThan(Y_CEWL);
249  FullSourceLoc X_CRL = X.callReturn.asLocation();
250  FullSourceLoc Y_CRL = Y.callReturn.asLocation();
251  if (X_CRL != Y_CRL)
252    return X_CRL.isBeforeInTranslationUnitThan(Y_CRL);
253  return comparePath(X.path, Y.path);
254}
255
256static llvm::Optional<bool> comparePiece(const PathDiagnosticPiece &X,
257                                         const PathDiagnosticPiece &Y) {
258  if (X.getKind() != Y.getKind())
259    return X.getKind() < Y.getKind();
260
261  FullSourceLoc XL = X.getLocation().asLocation();
262  FullSourceLoc YL = Y.getLocation().asLocation();
263  if (XL != YL)
264    return XL.isBeforeInTranslationUnitThan(YL);
265
266  if (X.getString() != Y.getString())
267    return X.getString() < Y.getString();
268
269  if (X.getRanges().size() != Y.getRanges().size())
270    return X.getRanges().size() < Y.getRanges().size();
271
272  const SourceManager &SM = XL.getManager();
273
274  for (unsigned i = 0, n = X.getRanges().size(); i < n; ++i) {
275    SourceRange XR = X.getRanges()[i];
276    SourceRange YR = Y.getRanges()[i];
277    if (XR != YR) {
278      if (XR.getBegin() != YR.getBegin())
279        return SM.isBeforeInTranslationUnit(XR.getBegin(), YR.getBegin());
280      return SM.isBeforeInTranslationUnit(XR.getEnd(), YR.getEnd());
281    }
282  }
283
284  switch (X.getKind()) {
285    case clang::ento::PathDiagnosticPiece::ControlFlow:
286      return compareControlFlow(cast<PathDiagnosticControlFlowPiece>(X),
287                                cast<PathDiagnosticControlFlowPiece>(Y));
288    case clang::ento::PathDiagnosticPiece::Event:
289      return llvm::Optional<bool>();
290    case clang::ento::PathDiagnosticPiece::Macro:
291      return compareMacro(cast<PathDiagnosticMacroPiece>(X),
292                          cast<PathDiagnosticMacroPiece>(Y));
293    case clang::ento::PathDiagnosticPiece::Call:
294      return compareCall(cast<PathDiagnosticCallPiece>(X),
295                         cast<PathDiagnosticCallPiece>(Y));
296  }
297  llvm_unreachable("all cases handled");
298}
299
300static llvm::Optional<bool> comparePath(const PathPieces &X,
301                                        const PathPieces &Y) {
302  if (X.size() != Y.size())
303    return X.size() < Y.size();
304  for (unsigned i = 0, n = X.size(); i != n; ++i) {
305    llvm::Optional<bool> b = comparePiece(*X[i], *Y[i]);
306    if (b.hasValue())
307      return b.getValue();
308  }
309  return llvm::Optional<bool>();
310}
311
312static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) {
313  FullSourceLoc XL = X.getLocation().asLocation();
314  FullSourceLoc YL = Y.getLocation().asLocation();
315  if (XL != YL)
316    return XL.isBeforeInTranslationUnitThan(YL);
317  if (X.getBugType() != Y.getBugType())
318    return X.getBugType() < Y.getBugType();
319  if (X.getCategory() != Y.getCategory())
320    return X.getCategory() < Y.getCategory();
321  if (X.getVerboseDescription() != Y.getVerboseDescription())
322    return X.getVerboseDescription() < Y.getVerboseDescription();
323  if (X.getShortDescription() != Y.getShortDescription())
324    return X.getShortDescription() < Y.getShortDescription();
325  if (X.getDeclWithIssue() != Y.getDeclWithIssue()) {
326    const Decl *XD = X.getDeclWithIssue();
327    if (!XD)
328      return true;
329    const Decl *YD = Y.getDeclWithIssue();
330    if (!YD)
331      return false;
332    SourceLocation XDL = XD->getLocation();
333    SourceLocation YDL = YD->getLocation();
334    if (XDL != YDL) {
335      const SourceManager &SM = XL.getManager();
336      return SM.isBeforeInTranslationUnit(XDL, YDL);
337    }
338  }
339  PathDiagnostic::meta_iterator XI = X.meta_begin(), XE = X.meta_end();
340  PathDiagnostic::meta_iterator YI = Y.meta_begin(), YE = Y.meta_end();
341  if (XE - XI != YE - YI)
342    return (XE - XI) < (YE - YI);
343  for ( ; XI != XE ; ++XI, ++YI) {
344    if (*XI != *YI)
345      return (*XI) < (*YI);
346  }
347  llvm::Optional<bool> b = comparePath(X.path, Y.path);
348  assert(b.hasValue());
349  return b.getValue();
350}
351
352namespace {
353struct CompareDiagnostics {
354  // Compare if 'X' is "<" than 'Y'.
355  bool operator()(const PathDiagnostic *X, const PathDiagnostic *Y) const {
356    if (X == Y)
357      return false;
358    return compare(*X, *Y);
359  }
360};
361}
362
363void PathDiagnosticConsumer::FlushDiagnostics(
364                                     PathDiagnosticConsumer::FilesMade *Files) {
365  if (flushed)
366    return;
367
368  flushed = true;
369
370  std::vector<const PathDiagnostic *> BatchDiags;
371  for (llvm::FoldingSet<PathDiagnostic>::iterator it = Diags.begin(),
372       et = Diags.end(); it != et; ++it) {
373    const PathDiagnostic *D = &*it;
374    BatchDiags.push_back(D);
375  }
376
377  // Sort the diagnostics so that they are always emitted in a deterministic
378  // order.
379  if (!BatchDiags.empty())
380    std::sort(BatchDiags.begin(), BatchDiags.end(), CompareDiagnostics());
381
382  FlushDiagnosticsImpl(BatchDiags, Files);
383
384  // Delete the flushed diagnostics.
385  for (std::vector<const PathDiagnostic *>::iterator it = BatchDiags.begin(),
386       et = BatchDiags.end(); it != et; ++it) {
387    const PathDiagnostic *D = *it;
388    delete D;
389  }
390
391  // Clear out the FoldingSet.
392  Diags.clear();
393}
394
395void PathDiagnosticConsumer::FilesMade::addDiagnostic(const PathDiagnostic &PD,
396                                                      StringRef ConsumerName,
397                                                      StringRef FileName) {
398  llvm::FoldingSetNodeID NodeID;
399  NodeID.Add(PD);
400  void *InsertPos;
401  PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos);
402  if (!Entry) {
403    Entry = Alloc.Allocate<PDFileEntry>();
404    Entry = new (Entry) PDFileEntry(NodeID);
405    InsertNode(Entry, InsertPos);
406  }
407
408  // Allocate persistent storage for the file name.
409  char *FileName_cstr = (char*) Alloc.Allocate(FileName.size(), 1);
410  memcpy(FileName_cstr, FileName.data(), FileName.size());
411
412  Entry->files.push_back(std::make_pair(ConsumerName,
413                                        StringRef(FileName_cstr,
414                                                  FileName.size())));
415}
416
417PathDiagnosticConsumer::PDFileEntry::ConsumerFiles *
418PathDiagnosticConsumer::FilesMade::getFiles(const PathDiagnostic &PD) {
419  llvm::FoldingSetNodeID NodeID;
420  NodeID.Add(PD);
421  void *InsertPos;
422  PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos);
423  if (!Entry)
424    return 0;
425  return &Entry->files;
426}
427
428//===----------------------------------------------------------------------===//
429// PathDiagnosticLocation methods.
430//===----------------------------------------------------------------------===//
431
432static SourceLocation getValidSourceLocation(const Stmt* S,
433                                             LocationOrAnalysisDeclContext LAC,
434                                             bool UseEnd = false) {
435  SourceLocation L = UseEnd ? S->getLocEnd() : S->getLocStart();
436  assert(!LAC.isNull() && "A valid LocationContext or AnalysisDeclContext should "
437                          "be passed to PathDiagnosticLocation upon creation.");
438
439  // S might be a temporary statement that does not have a location in the
440  // source code, so find an enclosing statement and use its location.
441  if (!L.isValid()) {
442
443    AnalysisDeclContext *ADC;
444    if (LAC.is<const LocationContext*>())
445      ADC = LAC.get<const LocationContext*>()->getAnalysisDeclContext();
446    else
447      ADC = LAC.get<AnalysisDeclContext*>();
448
449    ParentMap &PM = ADC->getParentMap();
450
451    const Stmt *Parent = S;
452    do {
453      Parent = PM.getParent(Parent);
454
455      // In rare cases, we have implicit top-level expressions,
456      // such as arguments for implicit member initializers.
457      // In this case, fall back to the start of the body (even if we were
458      // asked for the statement end location).
459      if (!Parent) {
460        const Stmt *Body = ADC->getBody();
461        if (Body)
462          L = Body->getLocStart();
463        else
464          L = ADC->getDecl()->getLocEnd();
465        break;
466      }
467
468      L = UseEnd ? Parent->getLocEnd() : Parent->getLocStart();
469    } while (!L.isValid());
470  }
471
472  return L;
473}
474
475static PathDiagnosticLocation
476getLocationForCaller(const StackFrameContext *SFC,
477                     const LocationContext *CallerCtx,
478                     const SourceManager &SM) {
479  const CFGBlock &Block = *SFC->getCallSiteBlock();
480  CFGElement Source = Block[SFC->getIndex()];
481
482  switch (Source.getKind()) {
483  case CFGElement::Invalid:
484    llvm_unreachable("Invalid CFGElement");
485  case CFGElement::Statement:
486    return PathDiagnosticLocation(cast<CFGStmt>(Source).getStmt(),
487                                  SM, CallerCtx);
488  case CFGElement::Initializer: {
489    const CFGInitializer &Init = cast<CFGInitializer>(Source);
490    return PathDiagnosticLocation(Init.getInitializer()->getInit(),
491                                  SM, CallerCtx);
492  }
493  case CFGElement::AutomaticObjectDtor: {
494    const CFGAutomaticObjDtor &Dtor = cast<CFGAutomaticObjDtor>(Source);
495    return PathDiagnosticLocation::createEnd(Dtor.getTriggerStmt(),
496                                             SM, CallerCtx);
497  }
498  case CFGElement::BaseDtor:
499  case CFGElement::MemberDtor: {
500    const AnalysisDeclContext *CallerInfo = CallerCtx->getAnalysisDeclContext();
501    if (const Stmt *CallerBody = CallerInfo->getBody())
502      return PathDiagnosticLocation::createEnd(CallerBody, SM, CallerCtx);
503    return PathDiagnosticLocation::create(CallerInfo->getDecl(), SM);
504  }
505  case CFGElement::TemporaryDtor:
506    llvm_unreachable("not yet implemented!");
507  }
508
509  llvm_unreachable("Unknown CFGElement kind");
510}
511
512
513PathDiagnosticLocation
514  PathDiagnosticLocation::createBegin(const Decl *D,
515                                      const SourceManager &SM) {
516  return PathDiagnosticLocation(D->getLocStart(), SM, SingleLocK);
517}
518
519PathDiagnosticLocation
520  PathDiagnosticLocation::createBegin(const Stmt *S,
521                                      const SourceManager &SM,
522                                      LocationOrAnalysisDeclContext LAC) {
523  return PathDiagnosticLocation(getValidSourceLocation(S, LAC),
524                                SM, SingleLocK);
525}
526
527
528PathDiagnosticLocation
529PathDiagnosticLocation::createEnd(const Stmt *S,
530                                  const SourceManager &SM,
531                                  LocationOrAnalysisDeclContext LAC) {
532  if (const CompoundStmt *CS = dyn_cast<CompoundStmt>(S))
533    return createEndBrace(CS, SM);
534  return PathDiagnosticLocation(getValidSourceLocation(S, LAC, /*End=*/true),
535                                SM, SingleLocK);
536}
537
538PathDiagnosticLocation
539  PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO,
540                                            const SourceManager &SM) {
541  return PathDiagnosticLocation(BO->getOperatorLoc(), SM, SingleLocK);
542}
543
544PathDiagnosticLocation
545  PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME,
546                                          const SourceManager &SM) {
547  return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK);
548}
549
550PathDiagnosticLocation
551  PathDiagnosticLocation::createBeginBrace(const CompoundStmt *CS,
552                                           const SourceManager &SM) {
553  SourceLocation L = CS->getLBracLoc();
554  return PathDiagnosticLocation(L, SM, SingleLocK);
555}
556
557PathDiagnosticLocation
558  PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS,
559                                         const SourceManager &SM) {
560  SourceLocation L = CS->getRBracLoc();
561  return PathDiagnosticLocation(L, SM, SingleLocK);
562}
563
564PathDiagnosticLocation
565  PathDiagnosticLocation::createDeclBegin(const LocationContext *LC,
566                                          const SourceManager &SM) {
567  // FIXME: Should handle CXXTryStmt if analyser starts supporting C++.
568  if (const CompoundStmt *CS =
569        dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody()))
570    if (!CS->body_empty()) {
571      SourceLocation Loc = (*CS->body_begin())->getLocStart();
572      return PathDiagnosticLocation(Loc, SM, SingleLocK);
573    }
574
575  return PathDiagnosticLocation();
576}
577
578PathDiagnosticLocation
579  PathDiagnosticLocation::createDeclEnd(const LocationContext *LC,
580                                        const SourceManager &SM) {
581  SourceLocation L = LC->getDecl()->getBodyRBrace();
582  return PathDiagnosticLocation(L, SM, SingleLocK);
583}
584
585PathDiagnosticLocation
586  PathDiagnosticLocation::create(const ProgramPoint& P,
587                                 const SourceManager &SMng) {
588
589  const Stmt* S = 0;
590  if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
591    const CFGBlock *BSrc = BE->getSrc();
592    S = BSrc->getTerminatorCondition();
593  }
594  else if (const StmtPoint *SP = dyn_cast<StmtPoint>(&P)) {
595    S = SP->getStmt();
596    if (isa<PostStmtPurgeDeadSymbols>(P))
597      return PathDiagnosticLocation::createEnd(S, SMng, P.getLocationContext());
598  }
599  else if (const PostImplicitCall *PIE = dyn_cast<PostImplicitCall>(&P)) {
600    return PathDiagnosticLocation(PIE->getLocation(), SMng);
601  }
602  else if (const CallEnter *CE = dyn_cast<CallEnter>(&P)) {
603    return getLocationForCaller(CE->getCalleeContext(),
604                                CE->getLocationContext(),
605                                SMng);
606  }
607  else if (const CallExitEnd *CEE = dyn_cast<CallExitEnd>(&P)) {
608    return getLocationForCaller(CEE->getCalleeContext(),
609                                CEE->getLocationContext(),
610                                SMng);
611  }
612  else {
613    llvm_unreachable("Unexpected ProgramPoint");
614  }
615
616  return PathDiagnosticLocation(S, SMng, P.getLocationContext());
617}
618
619PathDiagnosticLocation
620  PathDiagnosticLocation::createEndOfPath(const ExplodedNode* N,
621                                          const SourceManager &SM) {
622  assert(N && "Cannot create a location with a null node.");
623
624  const ExplodedNode *NI = N;
625  const Stmt *S = 0;
626
627  while (NI) {
628    ProgramPoint P = NI->getLocation();
629    if (const StmtPoint *PS = dyn_cast<StmtPoint>(&P)) {
630      S = PS->getStmt();
631      if (isa<PostStmtPurgeDeadSymbols>(P))
632        return PathDiagnosticLocation::createEnd(S, SM,
633                                                 NI->getLocationContext());
634      break;
635    } else if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
636      S = BE->getSrc()->getTerminator();
637      break;
638    }
639    NI = NI->succ_empty() ? 0 : *(NI->succ_begin());
640  }
641
642  if (S) {
643    const LocationContext *LC = NI->getLocationContext();
644    if (S->getLocStart().isValid())
645      return PathDiagnosticLocation(S, SM, LC);
646    return PathDiagnosticLocation(getValidSourceLocation(S, LC), SM);
647  }
648
649  return createDeclEnd(N->getLocationContext(), SM);
650}
651
652PathDiagnosticLocation PathDiagnosticLocation::createSingleLocation(
653                                           const PathDiagnosticLocation &PDL) {
654  FullSourceLoc L = PDL.asLocation();
655  return PathDiagnosticLocation(L, L.getManager(), SingleLocK);
656}
657
658FullSourceLoc
659  PathDiagnosticLocation::genLocation(SourceLocation L,
660                                      LocationOrAnalysisDeclContext LAC) const {
661  assert(isValid());
662  // Note that we want a 'switch' here so that the compiler can warn us in
663  // case we add more cases.
664  switch (K) {
665    case SingleLocK:
666    case RangeK:
667      break;
668    case StmtK:
669      // Defensive checking.
670      if (!S)
671        break;
672      return FullSourceLoc(getValidSourceLocation(S, LAC),
673                           const_cast<SourceManager&>(*SM));
674    case DeclK:
675      // Defensive checking.
676      if (!D)
677        break;
678      return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM));
679  }
680
681  return FullSourceLoc(L, const_cast<SourceManager&>(*SM));
682}
683
684PathDiagnosticRange
685  PathDiagnosticLocation::genRange(LocationOrAnalysisDeclContext LAC) const {
686  assert(isValid());
687  // Note that we want a 'switch' here so that the compiler can warn us in
688  // case we add more cases.
689  switch (K) {
690    case SingleLocK:
691      return PathDiagnosticRange(SourceRange(Loc,Loc), true);
692    case RangeK:
693      break;
694    case StmtK: {
695      const Stmt *S = asStmt();
696      switch (S->getStmtClass()) {
697        default:
698          break;
699        case Stmt::DeclStmtClass: {
700          const DeclStmt *DS = cast<DeclStmt>(S);
701          if (DS->isSingleDecl()) {
702            // Should always be the case, but we'll be defensive.
703            return SourceRange(DS->getLocStart(),
704                               DS->getSingleDecl()->getLocation());
705          }
706          break;
707        }
708          // FIXME: Provide better range information for different
709          //  terminators.
710        case Stmt::IfStmtClass:
711        case Stmt::WhileStmtClass:
712        case Stmt::DoStmtClass:
713        case Stmt::ForStmtClass:
714        case Stmt::ChooseExprClass:
715        case Stmt::IndirectGotoStmtClass:
716        case Stmt::SwitchStmtClass:
717        case Stmt::BinaryConditionalOperatorClass:
718        case Stmt::ConditionalOperatorClass:
719        case Stmt::ObjCForCollectionStmtClass: {
720          SourceLocation L = getValidSourceLocation(S, LAC);
721          return SourceRange(L, L);
722        }
723      }
724      SourceRange R = S->getSourceRange();
725      if (R.isValid())
726        return R;
727      break;
728    }
729    case DeclK:
730      if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
731        return MD->getSourceRange();
732      if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
733        if (Stmt *Body = FD->getBody())
734          return Body->getSourceRange();
735      }
736      else {
737        SourceLocation L = D->getLocation();
738        return PathDiagnosticRange(SourceRange(L, L), true);
739      }
740  }
741
742  return SourceRange(Loc,Loc);
743}
744
745void PathDiagnosticLocation::flatten() {
746  if (K == StmtK) {
747    K = RangeK;
748    S = 0;
749    D = 0;
750  }
751  else if (K == DeclK) {
752    K = SingleLocK;
753    S = 0;
754    D = 0;
755  }
756}
757
758//===----------------------------------------------------------------------===//
759// Manipulation of PathDiagnosticCallPieces.
760//===----------------------------------------------------------------------===//
761
762PathDiagnosticCallPiece *
763PathDiagnosticCallPiece::construct(const ExplodedNode *N,
764                                   const CallExitEnd &CE,
765                                   const SourceManager &SM) {
766  const Decl *caller = CE.getLocationContext()->getDecl();
767  PathDiagnosticLocation pos = getLocationForCaller(CE.getCalleeContext(),
768                                                    CE.getLocationContext(),
769                                                    SM);
770  return new PathDiagnosticCallPiece(caller, pos);
771}
772
773PathDiagnosticCallPiece *
774PathDiagnosticCallPiece::construct(PathPieces &path,
775                                   const Decl *caller) {
776  PathDiagnosticCallPiece *C = new PathDiagnosticCallPiece(path, caller);
777  path.clear();
778  path.push_front(C);
779  return C;
780}
781
782void PathDiagnosticCallPiece::setCallee(const CallEnter &CE,
783                                        const SourceManager &SM) {
784  const StackFrameContext *CalleeCtx = CE.getCalleeContext();
785  Callee = CalleeCtx->getDecl();
786
787  callEnterWithin = PathDiagnosticLocation::createBegin(Callee, SM);
788  callEnter = getLocationForCaller(CalleeCtx, CE.getLocationContext(), SM);
789}
790
791IntrusiveRefCntPtr<PathDiagnosticEventPiece>
792PathDiagnosticCallPiece::getCallEnterEvent() const {
793  if (!Callee)
794    return 0;
795  SmallString<256> buf;
796  llvm::raw_svector_ostream Out(buf);
797  if (isa<BlockDecl>(Callee))
798    Out << "Calling anonymous block";
799  else if (const NamedDecl *ND = dyn_cast<NamedDecl>(Callee))
800    Out << "Calling '" << *ND << "'";
801  StringRef msg = Out.str();
802  if (msg.empty())
803    return 0;
804  assert(callEnter.asLocation().isValid());
805  return new PathDiagnosticEventPiece(callEnter, msg);
806}
807
808IntrusiveRefCntPtr<PathDiagnosticEventPiece>
809PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const {
810  if (!callEnterWithin.asLocation().isValid())
811    return 0;
812  SmallString<256> buf;
813  llvm::raw_svector_ostream Out(buf);
814  if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Caller))
815    Out << "Entered call from '" << *ND << "'";
816  else
817    Out << "Entered call";
818  StringRef msg = Out.str();
819  if (msg.empty())
820    return 0;
821  return new PathDiagnosticEventPiece(callEnterWithin, msg);
822}
823
824IntrusiveRefCntPtr<PathDiagnosticEventPiece>
825PathDiagnosticCallPiece::getCallExitEvent() const {
826  if (NoExit)
827    return 0;
828  SmallString<256> buf;
829  llvm::raw_svector_ostream Out(buf);
830  if (!CallStackMessage.empty())
831    Out << CallStackMessage;
832  else if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Callee))
833    Out << "Returning from '" << *ND << "'";
834  else
835    Out << "Returning to caller";
836  assert(callReturn.asLocation().isValid());
837  return new PathDiagnosticEventPiece(callReturn, Out.str());
838}
839
840static void compute_path_size(const PathPieces &pieces, unsigned &size) {
841  for (PathPieces::const_iterator it = pieces.begin(),
842                                  et = pieces.end(); it != et; ++it) {
843    const PathDiagnosticPiece *piece = it->getPtr();
844    if (const PathDiagnosticCallPiece *cp =
845        dyn_cast<PathDiagnosticCallPiece>(piece)) {
846      compute_path_size(cp->path, size);
847    }
848    else
849      ++size;
850  }
851}
852
853unsigned PathDiagnostic::full_size() {
854  unsigned size = 0;
855  compute_path_size(path, size);
856  return size;
857}
858
859//===----------------------------------------------------------------------===//
860// FoldingSet profiling methods.
861//===----------------------------------------------------------------------===//
862
863void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const {
864  ID.AddInteger(Range.getBegin().getRawEncoding());
865  ID.AddInteger(Range.getEnd().getRawEncoding());
866  ID.AddInteger(Loc.getRawEncoding());
867  return;
868}
869
870void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const {
871  ID.AddInteger((unsigned) getKind());
872  ID.AddString(str);
873  // FIXME: Add profiling support for code hints.
874  ID.AddInteger((unsigned) getDisplayHint());
875  ArrayRef<SourceRange> Ranges = getRanges();
876  for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end();
877                                        I != E; ++I) {
878    ID.AddInteger(I->getBegin().getRawEncoding());
879    ID.AddInteger(I->getEnd().getRawEncoding());
880  }
881}
882
883void PathDiagnosticCallPiece::Profile(llvm::FoldingSetNodeID &ID) const {
884  PathDiagnosticPiece::Profile(ID);
885  for (PathPieces::const_iterator it = path.begin(),
886       et = path.end(); it != et; ++it) {
887    ID.Add(**it);
888  }
889}
890
891void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const {
892  PathDiagnosticPiece::Profile(ID);
893  ID.Add(Pos);
894}
895
896void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const {
897  PathDiagnosticPiece::Profile(ID);
898  for (const_iterator I = begin(), E = end(); I != E; ++I)
899    ID.Add(*I);
900}
901
902void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const {
903  PathDiagnosticSpotPiece::Profile(ID);
904  for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end();
905       I != E; ++I)
906    ID.Add(**I);
907}
908
909void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const {
910  ID.Add(getLocation());
911  ID.AddString(BugType);
912  ID.AddString(VerboseDesc);
913  ID.AddString(Category);
914}
915
916void PathDiagnostic::FullProfile(llvm::FoldingSetNodeID &ID) const {
917  Profile(ID);
918  for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E; ++I)
919    ID.Add(**I);
920  for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I)
921    ID.AddString(*I);
922}
923
924StackHintGenerator::~StackHintGenerator() {}
925
926std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){
927  ProgramPoint P = N->getLocation();
928  const CallExitEnd *CExit = dyn_cast<CallExitEnd>(&P);
929  assert(CExit && "Stack Hints should be constructed at CallExitEnd points.");
930
931  // FIXME: Use CallEvent to abstract this over all calls.
932  const Stmt *CallSite = CExit->getCalleeContext()->getCallSite();
933  const CallExpr *CE = dyn_cast_or_null<CallExpr>(CallSite);
934  if (!CE)
935    return "";
936
937  if (!N)
938    return getMessageForSymbolNotFound();
939
940  // Check if one of the parameters are set to the interesting symbol.
941  ProgramStateRef State = N->getState();
942  const LocationContext *LCtx = N->getLocationContext();
943  unsigned ArgIndex = 0;
944  for (CallExpr::const_arg_iterator I = CE->arg_begin(),
945                                    E = CE->arg_end(); I != E; ++I, ++ArgIndex){
946    SVal SV = State->getSVal(*I, LCtx);
947
948    // Check if the variable corresponding to the symbol is passed by value.
949    SymbolRef AS = SV.getAsLocSymbol();
950    if (AS == Sym) {
951      return getMessageForArg(*I, ArgIndex);
952    }
953
954    // Check if the parameter is a pointer to the symbol.
955    if (const loc::MemRegionVal *Reg = dyn_cast<loc::MemRegionVal>(&SV)) {
956      SVal PSV = State->getSVal(Reg->getRegion());
957      SymbolRef AS = PSV.getAsLocSymbol();
958      if (AS == Sym) {
959        return getMessageForArg(*I, ArgIndex);
960      }
961    }
962  }
963
964  // Check if we are returning the interesting symbol.
965  SVal SV = State->getSVal(CE, LCtx);
966  SymbolRef RetSym = SV.getAsLocSymbol();
967  if (RetSym == Sym) {
968    return getMessageForReturn(CE);
969  }
970
971  return getMessageForSymbolNotFound();
972}
973
974std::string StackHintGeneratorForSymbol::getMessageForArg(const Expr *ArgE,
975                                                          unsigned ArgIndex) {
976  // Printed parameters start at 1, not 0.
977  ++ArgIndex;
978
979  SmallString<200> buf;
980  llvm::raw_svector_ostream os(buf);
981
982  os << Msg << " via " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex)
983     << " parameter";
984
985  return os.str();
986}
987