PathDiagnostic.cpp revision 3a46f5fd1709f6df03bbb8b0abf84052dc0f39ff
1860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root//===--- PathDiagnostic.cpp - Path-Specific Diagnostic Handling -*- C++ -*-===//
2860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root//
3860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root//                     The LLVM Compiler Infrastructure
4860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root//
5860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root// This file is distributed under the University of Illinois Open Source
6860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root// License. See LICENSE.TXT for details.
7860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root//
8860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root//===----------------------------------------------------------------------===//
9860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root//
10860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root//  This file defines the PathDiagnostic-related interfaces.
11860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root//
12860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root//===----------------------------------------------------------------------===//
13860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root
14860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
15860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
16860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root#include "clang/Basic/SourceManager.h"
17860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root#include "clang/AST/Expr.h"
18860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root#include "clang/AST/Decl.h"
19860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root#include "clang/AST/DeclCXX.h"
20860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root#include "clang/AST/DeclObjC.h"
21860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root#include "clang/AST/ParentMap.h"
22860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root#include "clang/AST/StmtCXX.h"
23860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root#include "llvm/ADT/SmallString.h"
24860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root
25860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootusing namespace clang;
26860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootusing namespace ento;
27860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root
28860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootbool PathDiagnosticMacroPiece::containsEvent() const {
29860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root  for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end();
30860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root       I!=E; ++I) {
31860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root    if (isa<PathDiagnosticEventPiece>(*I))
32860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root      return true;
33860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root    if (PathDiagnosticMacroPiece *MP = dyn_cast<PathDiagnosticMacroPiece>(*I))
34860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root      if (MP->containsEvent())
35860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root        return true;
36860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root  }
37860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root  return false;
38860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root}
39860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root
40860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootstatic StringRef StripTrailingDots(StringRef s) {
41860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root  for (StringRef::size_type i = s.size(); i != 0; --i)
42860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root    if (s[i - 1] != '.')
43860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root      return s.substr(0, i);
44860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root  return "";
45860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root}
46860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root
47860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny RootPathDiagnosticPiece::PathDiagnosticPiece(StringRef s,
48860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root                                         Kind k, DisplayHint hint)
49860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root  : str(StripTrailingDots(s)), kind(k), Hint(hint) {}
50860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root
51860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny RootPathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint)
52860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root  : kind(k), Hint(hint) {}
53860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root
54860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny RootPathDiagnosticPiece::~PathDiagnosticPiece() {}
55860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny RootPathDiagnosticEventPiece::~PathDiagnosticEventPiece() {}
56860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny RootPathDiagnosticCallPiece::~PathDiagnosticCallPiece() {}
57860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny RootPathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() {}
58860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny RootPathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() {}
59860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root
60860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root
61860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny RootPathPieces::~PathPieces() {}
62860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root
63860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootvoid PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current,
64860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root                           bool ShouldFlattenMacros) const {
65860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root  for (PathPieces::const_iterator I = begin(), E = end(); I != E; ++I) {
66860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root    PathDiagnosticPiece *Piece = I->getPtr();
67860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root
68860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root    switch (Piece->getKind()) {
69860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root    case PathDiagnosticPiece::Call: {
70860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root      PathDiagnosticCallPiece *Call = cast<PathDiagnosticCallPiece>(Piece);
71860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root      IntrusiveRefCntPtr<PathDiagnosticEventPiece> CallEnter =
72860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root        Call->getCallEnterEvent();
73860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root      if (CallEnter)
74860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root        Current.push_back(CallEnter);
75860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root      Call->path.flattenTo(Primary, Primary, ShouldFlattenMacros);
76860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root      IntrusiveRefCntPtr<PathDiagnosticEventPiece> callExit =
77860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root        Call->getCallExitEvent();
78860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root      if (callExit)
79860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root        Current.push_back(callExit);
80860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root      break;
81860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root    }
82860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root    case PathDiagnosticPiece::Macro: {
83860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root      PathDiagnosticMacroPiece *Macro = cast<PathDiagnosticMacroPiece>(Piece);
84860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root      if (ShouldFlattenMacros) {
85860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root        Macro->subPieces.flattenTo(Primary, Primary, ShouldFlattenMacros);
86860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root      } else {
87860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root        Current.push_back(Piece);
88860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root        PathPieces NewPath;
89860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root        Macro->subPieces.flattenTo(Primary, NewPath, ShouldFlattenMacros);
90860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root        // FIXME: This probably shouldn't mutate the original path piece.
91860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root        Macro->subPieces = NewPath;
92860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root      }
93860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root      break;
94860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root    }
95860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root    case PathDiagnosticPiece::Event:
96860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root    case PathDiagnosticPiece::ControlFlow:
97860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root      Current.push_back(Piece);
98860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root      break;
99860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root    }
100860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root  }
101860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root}
102860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root
103860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root
104860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny RootPathDiagnostic::~PathDiagnostic() {}
105860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root
106860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny RootPathDiagnostic::PathDiagnostic(const Decl *declWithIssue,
107860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root                               StringRef bugtype, StringRef verboseDesc,
108860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root                               StringRef shortDesc, StringRef category)
109860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root  : DeclWithIssue(declWithIssue),
110860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root    BugType(StripTrailingDots(bugtype)),
111860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root    VerboseDesc(StripTrailingDots(verboseDesc)),
112860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root    ShortDesc(StripTrailingDots(shortDesc)),
113860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root    Category(StripTrailingDots(category)),
114860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root    path(pathImpl) {}
115860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root
116860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootvoid PathDiagnosticConsumer::anchor() { }
117860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root
118860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny RootPathDiagnosticConsumer::~PathDiagnosticConsumer() {
119860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root  // Delete the contents of the FoldingSet if it isn't empty already.
120860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Root  for (llvm::FoldingSet<PathDiagnostic>::iterator it =
121       Diags.begin(), et = Diags.end() ; it != et ; ++it) {
122    delete &*it;
123  }
124}
125
126void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) {
127  llvm::OwningPtr<PathDiagnostic> OwningD(D);
128
129  if (!D || D->path.empty())
130    return;
131
132  // We need to flatten the locations (convert Stmt* to locations) because
133  // the referenced statements may be freed by the time the diagnostics
134  // are emitted.
135  D->flattenLocations();
136
137  // If the PathDiagnosticConsumer does not support diagnostics that
138  // cross file boundaries, prune out such diagnostics now.
139  if (!supportsCrossFileDiagnostics()) {
140    // Verify that the entire path is from the same FileID.
141    FileID FID;
142    const SourceManager &SMgr = (*D->path.begin())->getLocation().getManager();
143    llvm::SmallVector<const PathPieces *, 5> WorkList;
144    WorkList.push_back(&D->path);
145
146    while (!WorkList.empty()) {
147      const PathPieces &path = *WorkList.back();
148      WorkList.pop_back();
149
150      for (PathPieces::const_iterator I = path.begin(), E = path.end();
151           I != E; ++I) {
152        const PathDiagnosticPiece *piece = I->getPtr();
153        FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc();
154
155        if (FID.isInvalid()) {
156          FID = SMgr.getFileID(L);
157        } else if (SMgr.getFileID(L) != FID)
158          return; // FIXME: Emit a warning?
159
160        // Check the source ranges.
161        ArrayRef<SourceRange> Ranges = piece->getRanges();
162        for (ArrayRef<SourceRange>::iterator I = Ranges.begin(),
163                                             E = Ranges.end(); I != E; ++I) {
164          SourceLocation L = SMgr.getExpansionLoc(I->getBegin());
165          if (!L.isFileID() || SMgr.getFileID(L) != FID)
166            return; // FIXME: Emit a warning?
167          L = SMgr.getExpansionLoc(I->getEnd());
168          if (!L.isFileID() || SMgr.getFileID(L) != FID)
169            return; // FIXME: Emit a warning?
170        }
171
172        if (const PathDiagnosticCallPiece *call =
173            dyn_cast<PathDiagnosticCallPiece>(piece)) {
174          WorkList.push_back(&call->path);
175        }
176        else if (const PathDiagnosticMacroPiece *macro =
177                 dyn_cast<PathDiagnosticMacroPiece>(piece)) {
178          WorkList.push_back(&macro->subPieces);
179        }
180      }
181    }
182
183    if (FID.isInvalid())
184      return; // FIXME: Emit a warning?
185  }
186
187  // Profile the node to see if we already have something matching it
188  llvm::FoldingSetNodeID profile;
189  D->Profile(profile);
190  void *InsertPos = 0;
191
192  if (PathDiagnostic *orig = Diags.FindNodeOrInsertPos(profile, InsertPos)) {
193    // Keep the PathDiagnostic with the shorter path.
194    // Note, the enclosing routine is called in deterministic order, so the
195    // results will be consistent between runs (no reason to break ties if the
196    // size is the same).
197    const unsigned orig_size = orig->full_size();
198    const unsigned new_size = D->full_size();
199    if (orig_size <= new_size)
200      return;
201
202    Diags.RemoveNode(orig);
203    delete orig;
204  }
205
206  Diags.InsertNode(OwningD.take());
207}
208
209
210namespace {
211struct CompareDiagnostics {
212  // Compare if 'X' is "<" than 'Y'.
213  bool operator()(const PathDiagnostic *X, const PathDiagnostic *Y) const {
214    // First compare by location
215    const FullSourceLoc &XLoc = X->getLocation().asLocation();
216    const FullSourceLoc &YLoc = Y->getLocation().asLocation();
217    if (XLoc < YLoc)
218      return true;
219    if (XLoc != YLoc)
220      return false;
221
222    // Next, compare by bug type.
223    StringRef XBugType = X->getBugType();
224    StringRef YBugType = Y->getBugType();
225    if (XBugType < YBugType)
226      return true;
227    if (XBugType != YBugType)
228      return false;
229
230    // Next, compare by bug description.
231    StringRef XDesc = X->getVerboseDescription();
232    StringRef YDesc = Y->getVerboseDescription();
233    if (XDesc < YDesc)
234      return true;
235    if (XDesc != YDesc)
236      return false;
237
238    // FIXME: Further refine by comparing PathDiagnosticPieces?
239    return false;
240  }
241};
242}
243
244void PathDiagnosticConsumer::FlushDiagnostics(
245                                     PathDiagnosticConsumer::FilesMade *Files) {
246  if (flushed)
247    return;
248
249  flushed = true;
250
251  std::vector<const PathDiagnostic *> BatchDiags;
252  for (llvm::FoldingSet<PathDiagnostic>::iterator it = Diags.begin(),
253       et = Diags.end(); it != et; ++it) {
254    BatchDiags.push_back(&*it);
255  }
256
257  // Clear out the FoldingSet.
258  Diags.clear();
259
260  // Sort the diagnostics so that they are always emitted in a deterministic
261  // order.
262  if (!BatchDiags.empty())
263    std::sort(BatchDiags.begin(), BatchDiags.end(), CompareDiagnostics());
264
265  FlushDiagnosticsImpl(BatchDiags, Files);
266
267  // Delete the flushed diagnostics.
268  for (std::vector<const PathDiagnostic *>::iterator it = BatchDiags.begin(),
269       et = BatchDiags.end(); it != et; ++it) {
270    const PathDiagnostic *D = *it;
271    delete D;
272  }
273}
274
275void PathDiagnosticConsumer::FilesMade::addDiagnostic(const PathDiagnostic &PD,
276                                                      StringRef ConsumerName,
277                                                      StringRef FileName) {
278  llvm::FoldingSetNodeID NodeID;
279  NodeID.Add(PD);
280  void *InsertPos;
281  PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos);
282  if (!Entry) {
283    Entry = Alloc.Allocate<PDFileEntry>();
284    Entry = new (Entry) PDFileEntry(NodeID);
285    InsertNode(Entry, InsertPos);
286  }
287
288  // Allocate persistent storage for the file name.
289  char *FileName_cstr = (char*) Alloc.Allocate(FileName.size(), 1);
290  memcpy(FileName_cstr, FileName.data(), FileName.size());
291
292  Entry->files.push_back(std::make_pair(ConsumerName,
293                                        StringRef(FileName_cstr,
294                                                  FileName.size())));
295}
296
297PathDiagnosticConsumer::PDFileEntry::ConsumerFiles *
298PathDiagnosticConsumer::FilesMade::getFiles(const PathDiagnostic &PD) {
299  llvm::FoldingSetNodeID NodeID;
300  NodeID.Add(PD);
301  void *InsertPos;
302  PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos);
303  if (!Entry)
304    return 0;
305  return &Entry->files;
306}
307
308//===----------------------------------------------------------------------===//
309// PathDiagnosticLocation methods.
310//===----------------------------------------------------------------------===//
311
312static SourceLocation getValidSourceLocation(const Stmt* S,
313                                             LocationOrAnalysisDeclContext LAC,
314                                             bool UseEnd = false) {
315  SourceLocation L = UseEnd ? S->getLocEnd() : S->getLocStart();
316  assert(!LAC.isNull() && "A valid LocationContext or AnalysisDeclContext should "
317                          "be passed to PathDiagnosticLocation upon creation.");
318
319  // S might be a temporary statement that does not have a location in the
320  // source code, so find an enclosing statement and use its location.
321  if (!L.isValid()) {
322
323    AnalysisDeclContext *ADC;
324    if (LAC.is<const LocationContext*>())
325      ADC = LAC.get<const LocationContext*>()->getAnalysisDeclContext();
326    else
327      ADC = LAC.get<AnalysisDeclContext*>();
328
329    ParentMap &PM = ADC->getParentMap();
330
331    const Stmt *Parent = S;
332    do {
333      Parent = PM.getParent(Parent);
334
335      // In rare cases, we have implicit top-level expressions,
336      // such as arguments for implicit member initializers.
337      // In this case, fall back to the start of the body (even if we were
338      // asked for the statement end location).
339      if (!Parent) {
340        const Stmt *Body = ADC->getBody();
341        if (Body)
342          L = Body->getLocStart();
343        else
344          L = ADC->getDecl()->getLocEnd();
345        break;
346      }
347
348      L = UseEnd ? Parent->getLocEnd() : Parent->getLocStart();
349    } while (!L.isValid());
350  }
351
352  return L;
353}
354
355static PathDiagnosticLocation
356getLocationForCaller(const StackFrameContext *SFC,
357                     const LocationContext *CallerCtx,
358                     const SourceManager &SM) {
359  const CFGBlock &Block = *SFC->getCallSiteBlock();
360  CFGElement Source = Block[SFC->getIndex()];
361
362  switch (Source.getKind()) {
363  case CFGElement::Invalid:
364    llvm_unreachable("Invalid CFGElement");
365  case CFGElement::Statement:
366    return PathDiagnosticLocation(cast<CFGStmt>(Source).getStmt(),
367                                  SM, CallerCtx);
368  case CFGElement::Initializer: {
369    const CFGInitializer &Init = cast<CFGInitializer>(Source);
370    return PathDiagnosticLocation(Init.getInitializer()->getInit(),
371                                  SM, CallerCtx);
372  }
373  case CFGElement::AutomaticObjectDtor: {
374    const CFGAutomaticObjDtor &Dtor = cast<CFGAutomaticObjDtor>(Source);
375    return PathDiagnosticLocation::createEnd(Dtor.getTriggerStmt(),
376                                             SM, CallerCtx);
377  }
378  case CFGElement::BaseDtor:
379  case CFGElement::MemberDtor: {
380    const AnalysisDeclContext *CallerInfo = CallerCtx->getAnalysisDeclContext();
381    if (const Stmt *CallerBody = CallerInfo->getBody())
382      return PathDiagnosticLocation::createEnd(CallerBody, SM, CallerCtx);
383    return PathDiagnosticLocation::create(CallerInfo->getDecl(), SM);
384  }
385  case CFGElement::TemporaryDtor:
386    llvm_unreachable("not yet implemented!");
387  }
388
389  llvm_unreachable("Unknown CFGElement kind");
390}
391
392
393PathDiagnosticLocation
394  PathDiagnosticLocation::createBegin(const Decl *D,
395                                      const SourceManager &SM) {
396  return PathDiagnosticLocation(D->getLocStart(), SM, SingleLocK);
397}
398
399PathDiagnosticLocation
400  PathDiagnosticLocation::createBegin(const Stmt *S,
401                                      const SourceManager &SM,
402                                      LocationOrAnalysisDeclContext LAC) {
403  return PathDiagnosticLocation(getValidSourceLocation(S, LAC),
404                                SM, SingleLocK);
405}
406
407
408PathDiagnosticLocation
409PathDiagnosticLocation::createEnd(const Stmt *S,
410                                  const SourceManager &SM,
411                                  LocationOrAnalysisDeclContext LAC) {
412  if (const CompoundStmt *CS = dyn_cast<CompoundStmt>(S))
413    return createEndBrace(CS, SM);
414  return PathDiagnosticLocation(getValidSourceLocation(S, LAC, /*End=*/true),
415                                SM, SingleLocK);
416}
417
418PathDiagnosticLocation
419  PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO,
420                                            const SourceManager &SM) {
421  return PathDiagnosticLocation(BO->getOperatorLoc(), SM, SingleLocK);
422}
423
424PathDiagnosticLocation
425  PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME,
426                                          const SourceManager &SM) {
427  return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK);
428}
429
430PathDiagnosticLocation
431  PathDiagnosticLocation::createBeginBrace(const CompoundStmt *CS,
432                                           const SourceManager &SM) {
433  SourceLocation L = CS->getLBracLoc();
434  return PathDiagnosticLocation(L, SM, SingleLocK);
435}
436
437PathDiagnosticLocation
438  PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS,
439                                         const SourceManager &SM) {
440  SourceLocation L = CS->getRBracLoc();
441  return PathDiagnosticLocation(L, SM, SingleLocK);
442}
443
444PathDiagnosticLocation
445  PathDiagnosticLocation::createDeclBegin(const LocationContext *LC,
446                                          const SourceManager &SM) {
447  // FIXME: Should handle CXXTryStmt if analyser starts supporting C++.
448  if (const CompoundStmt *CS =
449        dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody()))
450    if (!CS->body_empty()) {
451      SourceLocation Loc = (*CS->body_begin())->getLocStart();
452      return PathDiagnosticLocation(Loc, SM, SingleLocK);
453    }
454
455  return PathDiagnosticLocation();
456}
457
458PathDiagnosticLocation
459  PathDiagnosticLocation::createDeclEnd(const LocationContext *LC,
460                                        const SourceManager &SM) {
461  SourceLocation L = LC->getDecl()->getBodyRBrace();
462  return PathDiagnosticLocation(L, SM, SingleLocK);
463}
464
465PathDiagnosticLocation
466  PathDiagnosticLocation::create(const ProgramPoint& P,
467                                 const SourceManager &SMng) {
468
469  const Stmt* S = 0;
470  if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
471    const CFGBlock *BSrc = BE->getSrc();
472    S = BSrc->getTerminatorCondition();
473  }
474  else if (const PostStmt *PS = dyn_cast<PostStmt>(&P)) {
475    S = PS->getStmt();
476  }
477  else if (const PostImplicitCall *PIE = dyn_cast<PostImplicitCall>(&P)) {
478    return PathDiagnosticLocation(PIE->getLocation(), SMng);
479  }
480  else if (const CallEnter *CE = dyn_cast<CallEnter>(&P)) {
481    return getLocationForCaller(CE->getCalleeContext(),
482                                CE->getLocationContext(),
483                                SMng);
484  }
485  else if (const CallExitEnd *CEE = dyn_cast<CallExitEnd>(&P)) {
486    return getLocationForCaller(CEE->getCalleeContext(),
487                                CEE->getLocationContext(),
488                                SMng);
489  }
490
491  return PathDiagnosticLocation(S, SMng, P.getLocationContext());
492}
493
494PathDiagnosticLocation
495  PathDiagnosticLocation::createEndOfPath(const ExplodedNode* N,
496                                          const SourceManager &SM) {
497  assert(N && "Cannot create a location with a null node.");
498
499  const ExplodedNode *NI = N;
500
501  while (NI) {
502    ProgramPoint P = NI->getLocation();
503    const LocationContext *LC = P.getLocationContext();
504    if (const StmtPoint *PS = dyn_cast<StmtPoint>(&P))
505      return PathDiagnosticLocation(PS->getStmt(), SM, LC);
506    else if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
507      const Stmt *Term = BE->getSrc()->getTerminator();
508      if (Term) {
509        return PathDiagnosticLocation(Term, SM, LC);
510      }
511    }
512    NI = NI->succ_empty() ? 0 : *(NI->succ_begin());
513  }
514
515  return createDeclEnd(N->getLocationContext(), SM);
516}
517
518PathDiagnosticLocation PathDiagnosticLocation::createSingleLocation(
519                                           const PathDiagnosticLocation &PDL) {
520  FullSourceLoc L = PDL.asLocation();
521  return PathDiagnosticLocation(L, L.getManager(), SingleLocK);
522}
523
524FullSourceLoc
525  PathDiagnosticLocation::genLocation(SourceLocation L,
526                                      LocationOrAnalysisDeclContext LAC) const {
527  assert(isValid());
528  // Note that we want a 'switch' here so that the compiler can warn us in
529  // case we add more cases.
530  switch (K) {
531    case SingleLocK:
532    case RangeK:
533      break;
534    case StmtK:
535      // Defensive checking.
536      if (!S)
537        break;
538      return FullSourceLoc(getValidSourceLocation(S, LAC),
539                           const_cast<SourceManager&>(*SM));
540    case DeclK:
541      // Defensive checking.
542      if (!D)
543        break;
544      return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM));
545  }
546
547  return FullSourceLoc(L, const_cast<SourceManager&>(*SM));
548}
549
550PathDiagnosticRange
551  PathDiagnosticLocation::genRange(LocationOrAnalysisDeclContext LAC) const {
552  assert(isValid());
553  // Note that we want a 'switch' here so that the compiler can warn us in
554  // case we add more cases.
555  switch (K) {
556    case SingleLocK:
557      return PathDiagnosticRange(SourceRange(Loc,Loc), true);
558    case RangeK:
559      break;
560    case StmtK: {
561      const Stmt *S = asStmt();
562      switch (S->getStmtClass()) {
563        default:
564          break;
565        case Stmt::DeclStmtClass: {
566          const DeclStmt *DS = cast<DeclStmt>(S);
567          if (DS->isSingleDecl()) {
568            // Should always be the case, but we'll be defensive.
569            return SourceRange(DS->getLocStart(),
570                               DS->getSingleDecl()->getLocation());
571          }
572          break;
573        }
574          // FIXME: Provide better range information for different
575          //  terminators.
576        case Stmt::IfStmtClass:
577        case Stmt::WhileStmtClass:
578        case Stmt::DoStmtClass:
579        case Stmt::ForStmtClass:
580        case Stmt::ChooseExprClass:
581        case Stmt::IndirectGotoStmtClass:
582        case Stmt::SwitchStmtClass:
583        case Stmt::BinaryConditionalOperatorClass:
584        case Stmt::ConditionalOperatorClass:
585        case Stmt::ObjCForCollectionStmtClass: {
586          SourceLocation L = getValidSourceLocation(S, LAC);
587          return SourceRange(L, L);
588        }
589      }
590      SourceRange R = S->getSourceRange();
591      if (R.isValid())
592        return R;
593      break;
594    }
595    case DeclK:
596      if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
597        return MD->getSourceRange();
598      if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
599        if (Stmt *Body = FD->getBody())
600          return Body->getSourceRange();
601      }
602      else {
603        SourceLocation L = D->getLocation();
604        return PathDiagnosticRange(SourceRange(L, L), true);
605      }
606  }
607
608  return SourceRange(Loc,Loc);
609}
610
611void PathDiagnosticLocation::flatten() {
612  if (K == StmtK) {
613    K = RangeK;
614    S = 0;
615    D = 0;
616  }
617  else if (K == DeclK) {
618    K = SingleLocK;
619    S = 0;
620    D = 0;
621  }
622}
623
624//===----------------------------------------------------------------------===//
625// Manipulation of PathDiagnosticCallPieces.
626//===----------------------------------------------------------------------===//
627
628PathDiagnosticCallPiece *
629PathDiagnosticCallPiece::construct(const ExplodedNode *N,
630                                   const CallExitEnd &CE,
631                                   const SourceManager &SM) {
632  const Decl *caller = CE.getLocationContext()->getDecl();
633  PathDiagnosticLocation pos = getLocationForCaller(CE.getCalleeContext(),
634                                                    CE.getLocationContext(),
635                                                    SM);
636  return new PathDiagnosticCallPiece(caller, pos);
637}
638
639PathDiagnosticCallPiece *
640PathDiagnosticCallPiece::construct(PathPieces &path,
641                                   const Decl *caller) {
642  PathDiagnosticCallPiece *C = new PathDiagnosticCallPiece(path, caller);
643  path.clear();
644  path.push_front(C);
645  return C;
646}
647
648void PathDiagnosticCallPiece::setCallee(const CallEnter &CE,
649                                        const SourceManager &SM) {
650  const StackFrameContext *CalleeCtx = CE.getCalleeContext();
651  Callee = CalleeCtx->getDecl();
652
653  callEnterWithin = PathDiagnosticLocation::createBegin(Callee, SM);
654  callEnter = getLocationForCaller(CalleeCtx, CE.getLocationContext(), SM);
655}
656
657IntrusiveRefCntPtr<PathDiagnosticEventPiece>
658PathDiagnosticCallPiece::getCallEnterEvent() const {
659  if (!Callee)
660    return 0;
661  SmallString<256> buf;
662  llvm::raw_svector_ostream Out(buf);
663  if (isa<BlockDecl>(Callee))
664    Out << "Calling anonymous block";
665  else if (const NamedDecl *ND = dyn_cast<NamedDecl>(Callee))
666    Out << "Calling '" << *ND << "'";
667  StringRef msg = Out.str();
668  if (msg.empty())
669    return 0;
670  return new PathDiagnosticEventPiece(callEnter, msg);
671}
672
673IntrusiveRefCntPtr<PathDiagnosticEventPiece>
674PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const {
675  SmallString<256> buf;
676  llvm::raw_svector_ostream Out(buf);
677  if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Caller))
678    Out << "Entered call from '" << *ND << "'";
679  else
680    Out << "Entered call";
681  StringRef msg = Out.str();
682  if (msg.empty())
683    return 0;
684  return new PathDiagnosticEventPiece(callEnterWithin, msg);
685}
686
687IntrusiveRefCntPtr<PathDiagnosticEventPiece>
688PathDiagnosticCallPiece::getCallExitEvent() const {
689  if (NoExit)
690    return 0;
691  SmallString<256> buf;
692  llvm::raw_svector_ostream Out(buf);
693  if (!CallStackMessage.empty())
694    Out << CallStackMessage;
695  else if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Callee))
696    Out << "Returning from '" << *ND << "'";
697  else
698    Out << "Returning to caller";
699  return new PathDiagnosticEventPiece(callReturn, Out.str());
700}
701
702static void compute_path_size(const PathPieces &pieces, unsigned &size) {
703  for (PathPieces::const_iterator it = pieces.begin(),
704                                  et = pieces.end(); it != et; ++it) {
705    const PathDiagnosticPiece *piece = it->getPtr();
706    if (const PathDiagnosticCallPiece *cp =
707        dyn_cast<PathDiagnosticCallPiece>(piece)) {
708      compute_path_size(cp->path, size);
709    }
710    else
711      ++size;
712  }
713}
714
715unsigned PathDiagnostic::full_size() {
716  unsigned size = 0;
717  compute_path_size(path, size);
718  return size;
719}
720
721//===----------------------------------------------------------------------===//
722// FoldingSet profiling methods.
723//===----------------------------------------------------------------------===//
724
725void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const {
726  ID.AddInteger(Range.getBegin().getRawEncoding());
727  ID.AddInteger(Range.getEnd().getRawEncoding());
728  ID.AddInteger(Loc.getRawEncoding());
729  return;
730}
731
732void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const {
733  ID.AddInteger((unsigned) getKind());
734  ID.AddString(str);
735  // FIXME: Add profiling support for code hints.
736  ID.AddInteger((unsigned) getDisplayHint());
737  ArrayRef<SourceRange> Ranges = getRanges();
738  for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end();
739                                        I != E; ++I) {
740    ID.AddInteger(I->getBegin().getRawEncoding());
741    ID.AddInteger(I->getEnd().getRawEncoding());
742  }
743}
744
745void PathDiagnosticCallPiece::Profile(llvm::FoldingSetNodeID &ID) const {
746  PathDiagnosticPiece::Profile(ID);
747  for (PathPieces::const_iterator it = path.begin(),
748       et = path.end(); it != et; ++it) {
749    ID.Add(**it);
750  }
751}
752
753void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const {
754  PathDiagnosticPiece::Profile(ID);
755  ID.Add(Pos);
756}
757
758void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const {
759  PathDiagnosticPiece::Profile(ID);
760  for (const_iterator I = begin(), E = end(); I != E; ++I)
761    ID.Add(*I);
762}
763
764void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const {
765  PathDiagnosticSpotPiece::Profile(ID);
766  for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end();
767       I != E; ++I)
768    ID.Add(**I);
769}
770
771void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const {
772  ID.Add(getLocation());
773  ID.AddString(BugType);
774  ID.AddString(VerboseDesc);
775  ID.AddString(Category);
776}
777
778void PathDiagnostic::FullProfile(llvm::FoldingSetNodeID &ID) const {
779  Profile(ID);
780  for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E; ++I)
781    ID.Add(**I);
782  for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I)
783    ID.AddString(*I);
784}
785
786StackHintGenerator::~StackHintGenerator() {}
787
788std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){
789  ProgramPoint P = N->getLocation();
790  const CallExitEnd *CExit = dyn_cast<CallExitEnd>(&P);
791  assert(CExit && "Stack Hints should be constructed at CallExitEnd points.");
792
793  // FIXME: Use CallEvent to abstract this over all calls.
794  const Stmt *CallSite = CExit->getCalleeContext()->getCallSite();
795  const CallExpr *CE = dyn_cast_or_null<CallExpr>(CallSite);
796  if (!CE)
797    return "";
798
799  if (!N)
800    return getMessageForSymbolNotFound();
801
802  // Check if one of the parameters are set to the interesting symbol.
803  ProgramStateRef State = N->getState();
804  const LocationContext *LCtx = N->getLocationContext();
805  unsigned ArgIndex = 0;
806  for (CallExpr::const_arg_iterator I = CE->arg_begin(),
807                                    E = CE->arg_end(); I != E; ++I, ++ArgIndex){
808    SVal SV = State->getSVal(*I, LCtx);
809
810    // Check if the variable corresponding to the symbol is passed by value.
811    SymbolRef AS = SV.getAsLocSymbol();
812    if (AS == Sym) {
813      return getMessageForArg(*I, ArgIndex);
814    }
815
816    // Check if the parameter is a pointer to the symbol.
817    if (const loc::MemRegionVal *Reg = dyn_cast<loc::MemRegionVal>(&SV)) {
818      SVal PSV = State->getSVal(Reg->getRegion());
819      SymbolRef AS = PSV.getAsLocSymbol();
820      if (AS == Sym) {
821        return getMessageForArg(*I, ArgIndex);
822      }
823    }
824  }
825
826  // Check if we are returning the interesting symbol.
827  SVal SV = State->getSVal(CE, LCtx);
828  SymbolRef RetSym = SV.getAsLocSymbol();
829  if (RetSym == Sym) {
830    return getMessageForReturn(CE);
831  }
832
833  return getMessageForSymbolNotFound();
834}
835
836/// TODO: This is copied from clang diagnostics. Maybe we could just move it to
837/// some common place. (Same as HandleOrdinalModifier.)
838void StackHintGeneratorForSymbol::printOrdinal(unsigned ValNo,
839                                               llvm::raw_svector_ostream &Out) {
840  assert(ValNo != 0 && "ValNo must be strictly positive!");
841
842  // We could use text forms for the first N ordinals, but the numeric
843  // forms are actually nicer in diagnostics because they stand out.
844  Out << ValNo;
845
846  // It is critically important that we do this perfectly for
847  // user-written sequences with over 100 elements.
848  switch (ValNo % 100) {
849  case 11:
850  case 12:
851  case 13:
852    Out << "th"; return;
853  default:
854    switch (ValNo % 10) {
855    case 1: Out << "st"; return;
856    case 2: Out << "nd"; return;
857    case 3: Out << "rd"; return;
858    default: Out << "th"; return;
859    }
860  }
861}
862
863std::string StackHintGeneratorForSymbol::getMessageForArg(const Expr *ArgE,
864                                                        unsigned ArgIndex) {
865  SmallString<200> buf;
866  llvm::raw_svector_ostream os(buf);
867
868  os << Msg << " via ";
869  // Printed parameters start at 1, not 0.
870  printOrdinal(++ArgIndex, os);
871  os << " parameter";
872
873  return os.str();
874}
875