1218887Sdim//===--- PathDiagnostic.cpp - Path-Specific Diagnostic Handling -*- C++ -*-===//
2218887Sdim//
3218887Sdim//                     The LLVM Compiler Infrastructure
4218887Sdim//
5218887Sdim// This file is distributed under the University of Illinois Open Source
6218887Sdim// License. See LICENSE.TXT for details.
7218887Sdim//
8218887Sdim//===----------------------------------------------------------------------===//
9218887Sdim//
10218887Sdim//  This file defines the PathDiagnostic-related interfaces.
11218887Sdim//
12218887Sdim//===----------------------------------------------------------------------===//
13218887Sdim
14218887Sdim#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
15218887Sdim#include "clang/AST/Decl.h"
16239462Sdim#include "clang/AST/DeclCXX.h"
17218887Sdim#include "clang/AST/DeclObjC.h"
18249423Sdim#include "clang/AST/Expr.h"
19226633Sdim#include "clang/AST/ParentMap.h"
20218887Sdim#include "clang/AST/StmtCXX.h"
21249423Sdim#include "clang/Basic/SourceManager.h"
22249423Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
23218887Sdim#include "llvm/ADT/SmallString.h"
24243830Sdim#include "llvm/ADT/StringExtras.h"
25249423Sdim#include "llvm/Support/raw_ostream.h"
26218887Sdim
27218887Sdimusing namespace clang;
28218887Sdimusing namespace ento;
29218887Sdim
30218887Sdimbool PathDiagnosticMacroPiece::containsEvent() const {
31234353Sdim  for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end();
32234353Sdim       I!=E; ++I) {
33218887Sdim    if (isa<PathDiagnosticEventPiece>(*I))
34218887Sdim      return true;
35218887Sdim    if (PathDiagnosticMacroPiece *MP = dyn_cast<PathDiagnosticMacroPiece>(*I))
36218887Sdim      if (MP->containsEvent())
37218887Sdim        return true;
38218887Sdim  }
39218887Sdim  return false;
40218887Sdim}
41218887Sdim
42226633Sdimstatic StringRef StripTrailingDots(StringRef s) {
43226633Sdim  for (StringRef::size_type i = s.size(); i != 0; --i)
44218887Sdim    if (s[i - 1] != '.')
45218887Sdim      return s.substr(0, i);
46218887Sdim  return "";
47218887Sdim}
48218887Sdim
49226633SdimPathDiagnosticPiece::PathDiagnosticPiece(StringRef s,
50218887Sdim                                         Kind k, DisplayHint hint)
51218887Sdim  : str(StripTrailingDots(s)), kind(k), Hint(hint) {}
52218887Sdim
53218887SdimPathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint)
54218887Sdim  : kind(k), Hint(hint) {}
55218887Sdim
56218887SdimPathDiagnosticPiece::~PathDiagnosticPiece() {}
57218887SdimPathDiagnosticEventPiece::~PathDiagnosticEventPiece() {}
58234353SdimPathDiagnosticCallPiece::~PathDiagnosticCallPiece() {}
59218887SdimPathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() {}
60234353SdimPathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() {}
61218887Sdim
62218887Sdim
63234353SdimPathPieces::~PathPieces() {}
64239462Sdim
65239462Sdimvoid PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current,
66239462Sdim                           bool ShouldFlattenMacros) const {
67239462Sdim  for (PathPieces::const_iterator I = begin(), E = end(); I != E; ++I) {
68239462Sdim    PathDiagnosticPiece *Piece = I->getPtr();
69239462Sdim
70239462Sdim    switch (Piece->getKind()) {
71239462Sdim    case PathDiagnosticPiece::Call: {
72239462Sdim      PathDiagnosticCallPiece *Call = cast<PathDiagnosticCallPiece>(Piece);
73239462Sdim      IntrusiveRefCntPtr<PathDiagnosticEventPiece> CallEnter =
74239462Sdim        Call->getCallEnterEvent();
75239462Sdim      if (CallEnter)
76239462Sdim        Current.push_back(CallEnter);
77239462Sdim      Call->path.flattenTo(Primary, Primary, ShouldFlattenMacros);
78239462Sdim      IntrusiveRefCntPtr<PathDiagnosticEventPiece> callExit =
79239462Sdim        Call->getCallExitEvent();
80239462Sdim      if (callExit)
81239462Sdim        Current.push_back(callExit);
82239462Sdim      break;
83239462Sdim    }
84239462Sdim    case PathDiagnosticPiece::Macro: {
85239462Sdim      PathDiagnosticMacroPiece *Macro = cast<PathDiagnosticMacroPiece>(Piece);
86239462Sdim      if (ShouldFlattenMacros) {
87239462Sdim        Macro->subPieces.flattenTo(Primary, Primary, ShouldFlattenMacros);
88239462Sdim      } else {
89239462Sdim        Current.push_back(Piece);
90239462Sdim        PathPieces NewPath;
91239462Sdim        Macro->subPieces.flattenTo(Primary, NewPath, ShouldFlattenMacros);
92239462Sdim        // FIXME: This probably shouldn't mutate the original path piece.
93239462Sdim        Macro->subPieces = NewPath;
94239462Sdim      }
95239462Sdim      break;
96239462Sdim    }
97239462Sdim    case PathDiagnosticPiece::Event:
98239462Sdim    case PathDiagnosticPiece::ControlFlow:
99239462Sdim      Current.push_back(Piece);
100239462Sdim      break;
101239462Sdim    }
102239462Sdim  }
103239462Sdim}
104239462Sdim
105239462Sdim
106234353SdimPathDiagnostic::~PathDiagnostic() {}
107218887Sdim
108234353SdimPathDiagnostic::PathDiagnostic(const Decl *declWithIssue,
109243830Sdim                               StringRef bugtype, StringRef verboseDesc,
110249423Sdim                               StringRef shortDesc, StringRef category,
111249423Sdim                               PathDiagnosticLocation LocationToUnique,
112249423Sdim                               const Decl *DeclToUnique)
113234353Sdim  : DeclWithIssue(declWithIssue),
114234353Sdim    BugType(StripTrailingDots(bugtype)),
115243830Sdim    VerboseDesc(StripTrailingDots(verboseDesc)),
116243830Sdim    ShortDesc(StripTrailingDots(shortDesc)),
117234353Sdim    Category(StripTrailingDots(category)),
118249423Sdim    UniqueingLoc(LocationToUnique),
119249423Sdim    UniqueingDecl(DeclToUnique),
120234353Sdim    path(pathImpl) {}
121234353Sdim
122234353Sdimvoid PathDiagnosticConsumer::anchor() { }
123234353Sdim
124234353SdimPathDiagnosticConsumer::~PathDiagnosticConsumer() {
125234353Sdim  // Delete the contents of the FoldingSet if it isn't empty already.
126234353Sdim  for (llvm::FoldingSet<PathDiagnostic>::iterator it =
127234353Sdim       Diags.begin(), et = Diags.end() ; it != et ; ++it) {
128234353Sdim    delete &*it;
129234353Sdim  }
130218887Sdim}
131218887Sdim
132234353Sdimvoid PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) {
133249423Sdim  OwningPtr<PathDiagnostic> OwningD(D);
134234353Sdim
135234353Sdim  if (!D || D->path.empty())
136234353Sdim    return;
137234353Sdim
138234353Sdim  // We need to flatten the locations (convert Stmt* to locations) because
139234353Sdim  // the referenced statements may be freed by the time the diagnostics
140234353Sdim  // are emitted.
141234353Sdim  D->flattenLocations();
142218887Sdim
143234353Sdim  // If the PathDiagnosticConsumer does not support diagnostics that
144234353Sdim  // cross file boundaries, prune out such diagnostics now.
145234353Sdim  if (!supportsCrossFileDiagnostics()) {
146234353Sdim    // Verify that the entire path is from the same FileID.
147234353Sdim    FileID FID;
148234353Sdim    const SourceManager &SMgr = (*D->path.begin())->getLocation().getManager();
149249423Sdim    SmallVector<const PathPieces *, 5> WorkList;
150234353Sdim    WorkList.push_back(&D->path);
151218887Sdim
152234353Sdim    while (!WorkList.empty()) {
153234353Sdim      const PathPieces &path = *WorkList.back();
154234353Sdim      WorkList.pop_back();
155234353Sdim
156234353Sdim      for (PathPieces::const_iterator I = path.begin(), E = path.end();
157234353Sdim           I != E; ++I) {
158234353Sdim        const PathDiagnosticPiece *piece = I->getPtr();
159234353Sdim        FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc();
160234353Sdim
161234353Sdim        if (FID.isInvalid()) {
162234353Sdim          FID = SMgr.getFileID(L);
163234353Sdim        } else if (SMgr.getFileID(L) != FID)
164234353Sdim          return; // FIXME: Emit a warning?
165234353Sdim
166234353Sdim        // Check the source ranges.
167239462Sdim        ArrayRef<SourceRange> Ranges = piece->getRanges();
168239462Sdim        for (ArrayRef<SourceRange>::iterator I = Ranges.begin(),
169239462Sdim                                             E = Ranges.end(); I != E; ++I) {
170239462Sdim          SourceLocation L = SMgr.getExpansionLoc(I->getBegin());
171234353Sdim          if (!L.isFileID() || SMgr.getFileID(L) != FID)
172234353Sdim            return; // FIXME: Emit a warning?
173239462Sdim          L = SMgr.getExpansionLoc(I->getEnd());
174234353Sdim          if (!L.isFileID() || SMgr.getFileID(L) != FID)
175234353Sdim            return; // FIXME: Emit a warning?
176234353Sdim        }
177234353Sdim
178234353Sdim        if (const PathDiagnosticCallPiece *call =
179234353Sdim            dyn_cast<PathDiagnosticCallPiece>(piece)) {
180234353Sdim          WorkList.push_back(&call->path);
181234353Sdim        }
182234353Sdim        else if (const PathDiagnosticMacroPiece *macro =
183234353Sdim                 dyn_cast<PathDiagnosticMacroPiece>(piece)) {
184234353Sdim          WorkList.push_back(&macro->subPieces);
185234353Sdim        }
186234353Sdim      }
187234353Sdim    }
188234353Sdim
189234353Sdim    if (FID.isInvalid())
190234353Sdim      return; // FIXME: Emit a warning?
191234353Sdim  }
192234353Sdim
193234353Sdim  // Profile the node to see if we already have something matching it
194234353Sdim  llvm::FoldingSetNodeID profile;
195234353Sdim  D->Profile(profile);
196234353Sdim  void *InsertPos = 0;
197234353Sdim
198234353Sdim  if (PathDiagnostic *orig = Diags.FindNodeOrInsertPos(profile, InsertPos)) {
199234353Sdim    // Keep the PathDiagnostic with the shorter path.
200239462Sdim    // Note, the enclosing routine is called in deterministic order, so the
201239462Sdim    // results will be consistent between runs (no reason to break ties if the
202239462Sdim    // size is the same).
203234353Sdim    const unsigned orig_size = orig->full_size();
204234353Sdim    const unsigned new_size = D->full_size();
205239462Sdim    if (orig_size <= new_size)
206239462Sdim      return;
207234353Sdim
208243830Sdim    assert(orig != D);
209234353Sdim    Diags.RemoveNode(orig);
210234353Sdim    delete orig;
211234353Sdim  }
212234353Sdim
213234353Sdim  Diags.InsertNode(OwningD.take());
214218887Sdim}
215218887Sdim
216249423Sdimstatic Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y);
217249423Sdimstatic Optional<bool>
218243830SdimcompareControlFlow(const PathDiagnosticControlFlowPiece &X,
219243830Sdim                   const PathDiagnosticControlFlowPiece &Y) {
220243830Sdim  FullSourceLoc XSL = X.getStartLocation().asLocation();
221243830Sdim  FullSourceLoc YSL = Y.getStartLocation().asLocation();
222243830Sdim  if (XSL != YSL)
223243830Sdim    return XSL.isBeforeInTranslationUnitThan(YSL);
224243830Sdim  FullSourceLoc XEL = X.getEndLocation().asLocation();
225243830Sdim  FullSourceLoc YEL = Y.getEndLocation().asLocation();
226243830Sdim  if (XEL != YEL)
227243830Sdim    return XEL.isBeforeInTranslationUnitThan(YEL);
228249423Sdim  return None;
229243830Sdim}
230218887Sdim
231249423Sdimstatic Optional<bool> compareMacro(const PathDiagnosticMacroPiece &X,
232249423Sdim                                   const PathDiagnosticMacroPiece &Y) {
233243830Sdim  return comparePath(X.subPieces, Y.subPieces);
234243830Sdim}
235243830Sdim
236249423Sdimstatic Optional<bool> compareCall(const PathDiagnosticCallPiece &X,
237249423Sdim                                  const PathDiagnosticCallPiece &Y) {
238243830Sdim  FullSourceLoc X_CEL = X.callEnter.asLocation();
239243830Sdim  FullSourceLoc Y_CEL = Y.callEnter.asLocation();
240243830Sdim  if (X_CEL != Y_CEL)
241243830Sdim    return X_CEL.isBeforeInTranslationUnitThan(Y_CEL);
242243830Sdim  FullSourceLoc X_CEWL = X.callEnterWithin.asLocation();
243243830Sdim  FullSourceLoc Y_CEWL = Y.callEnterWithin.asLocation();
244243830Sdim  if (X_CEWL != Y_CEWL)
245243830Sdim    return X_CEWL.isBeforeInTranslationUnitThan(Y_CEWL);
246243830Sdim  FullSourceLoc X_CRL = X.callReturn.asLocation();
247243830Sdim  FullSourceLoc Y_CRL = Y.callReturn.asLocation();
248243830Sdim  if (X_CRL != Y_CRL)
249243830Sdim    return X_CRL.isBeforeInTranslationUnitThan(Y_CRL);
250243830Sdim  return comparePath(X.path, Y.path);
251243830Sdim}
252243830Sdim
253249423Sdimstatic Optional<bool> comparePiece(const PathDiagnosticPiece &X,
254249423Sdim                                   const PathDiagnosticPiece &Y) {
255243830Sdim  if (X.getKind() != Y.getKind())
256243830Sdim    return X.getKind() < Y.getKind();
257243830Sdim
258243830Sdim  FullSourceLoc XL = X.getLocation().asLocation();
259243830Sdim  FullSourceLoc YL = Y.getLocation().asLocation();
260243830Sdim  if (XL != YL)
261243830Sdim    return XL.isBeforeInTranslationUnitThan(YL);
262243830Sdim
263243830Sdim  if (X.getString() != Y.getString())
264243830Sdim    return X.getString() < Y.getString();
265243830Sdim
266243830Sdim  if (X.getRanges().size() != Y.getRanges().size())
267243830Sdim    return X.getRanges().size() < Y.getRanges().size();
268243830Sdim
269243830Sdim  const SourceManager &SM = XL.getManager();
270243830Sdim
271243830Sdim  for (unsigned i = 0, n = X.getRanges().size(); i < n; ++i) {
272243830Sdim    SourceRange XR = X.getRanges()[i];
273243830Sdim    SourceRange YR = Y.getRanges()[i];
274243830Sdim    if (XR != YR) {
275243830Sdim      if (XR.getBegin() != YR.getBegin())
276243830Sdim        return SM.isBeforeInTranslationUnit(XR.getBegin(), YR.getBegin());
277243830Sdim      return SM.isBeforeInTranslationUnit(XR.getEnd(), YR.getEnd());
278243830Sdim    }
279243830Sdim  }
280243830Sdim
281243830Sdim  switch (X.getKind()) {
282243830Sdim    case clang::ento::PathDiagnosticPiece::ControlFlow:
283243830Sdim      return compareControlFlow(cast<PathDiagnosticControlFlowPiece>(X),
284243830Sdim                                cast<PathDiagnosticControlFlowPiece>(Y));
285243830Sdim    case clang::ento::PathDiagnosticPiece::Event:
286249423Sdim      return None;
287243830Sdim    case clang::ento::PathDiagnosticPiece::Macro:
288243830Sdim      return compareMacro(cast<PathDiagnosticMacroPiece>(X),
289243830Sdim                          cast<PathDiagnosticMacroPiece>(Y));
290243830Sdim    case clang::ento::PathDiagnosticPiece::Call:
291243830Sdim      return compareCall(cast<PathDiagnosticCallPiece>(X),
292243830Sdim                         cast<PathDiagnosticCallPiece>(Y));
293243830Sdim  }
294243830Sdim  llvm_unreachable("all cases handled");
295243830Sdim}
296243830Sdim
297249423Sdimstatic Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y) {
298243830Sdim  if (X.size() != Y.size())
299243830Sdim    return X.size() < Y.size();
300251662Sdim
301251662Sdim  PathPieces::const_iterator X_I = X.begin(), X_end = X.end();
302251662Sdim  PathPieces::const_iterator Y_I = Y.begin(), Y_end = Y.end();
303251662Sdim
304251662Sdim  for ( ; X_I != X_end && Y_I != Y_end; ++X_I, ++Y_I) {
305251662Sdim    Optional<bool> b = comparePiece(**X_I, **Y_I);
306243830Sdim    if (b.hasValue())
307243830Sdim      return b.getValue();
308243830Sdim  }
309251662Sdim
310249423Sdim  return None;
311243830Sdim}
312243830Sdim
313243830Sdimstatic bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) {
314243830Sdim  FullSourceLoc XL = X.getLocation().asLocation();
315243830Sdim  FullSourceLoc YL = Y.getLocation().asLocation();
316243830Sdim  if (XL != YL)
317243830Sdim    return XL.isBeforeInTranslationUnitThan(YL);
318243830Sdim  if (X.getBugType() != Y.getBugType())
319243830Sdim    return X.getBugType() < Y.getBugType();
320243830Sdim  if (X.getCategory() != Y.getCategory())
321243830Sdim    return X.getCategory() < Y.getCategory();
322243830Sdim  if (X.getVerboseDescription() != Y.getVerboseDescription())
323243830Sdim    return X.getVerboseDescription() < Y.getVerboseDescription();
324243830Sdim  if (X.getShortDescription() != Y.getShortDescription())
325243830Sdim    return X.getShortDescription() < Y.getShortDescription();
326243830Sdim  if (X.getDeclWithIssue() != Y.getDeclWithIssue()) {
327243830Sdim    const Decl *XD = X.getDeclWithIssue();
328243830Sdim    if (!XD)
329243830Sdim      return true;
330243830Sdim    const Decl *YD = Y.getDeclWithIssue();
331243830Sdim    if (!YD)
332243830Sdim      return false;
333243830Sdim    SourceLocation XDL = XD->getLocation();
334243830Sdim    SourceLocation YDL = YD->getLocation();
335243830Sdim    if (XDL != YDL) {
336243830Sdim      const SourceManager &SM = XL.getManager();
337243830Sdim      return SM.isBeforeInTranslationUnit(XDL, YDL);
338243830Sdim    }
339243830Sdim  }
340243830Sdim  PathDiagnostic::meta_iterator XI = X.meta_begin(), XE = X.meta_end();
341243830Sdim  PathDiagnostic::meta_iterator YI = Y.meta_begin(), YE = Y.meta_end();
342243830Sdim  if (XE - XI != YE - YI)
343243830Sdim    return (XE - XI) < (YE - YI);
344243830Sdim  for ( ; XI != XE ; ++XI, ++YI) {
345243830Sdim    if (*XI != *YI)
346243830Sdim      return (*XI) < (*YI);
347243830Sdim  }
348249423Sdim  Optional<bool> b = comparePath(X.path, Y.path);
349243830Sdim  assert(b.hasValue());
350243830Sdim  return b.getValue();
351243830Sdim}
352243830Sdim
353234353Sdimnamespace {
354234353Sdimstruct CompareDiagnostics {
355234353Sdim  // Compare if 'X' is "<" than 'Y'.
356234353Sdim  bool operator()(const PathDiagnostic *X, const PathDiagnostic *Y) const {
357243830Sdim    if (X == Y)
358234353Sdim      return false;
359243830Sdim    return compare(*X, *Y);
360243830Sdim  }
361243830Sdim};
362234353Sdim}
363218887Sdim
364239462Sdimvoid PathDiagnosticConsumer::FlushDiagnostics(
365239462Sdim                                     PathDiagnosticConsumer::FilesMade *Files) {
366234353Sdim  if (flushed)
367234353Sdim    return;
368234353Sdim
369234353Sdim  flushed = true;
370234353Sdim
371234353Sdim  std::vector<const PathDiagnostic *> BatchDiags;
372234353Sdim  for (llvm::FoldingSet<PathDiagnostic>::iterator it = Diags.begin(),
373234353Sdim       et = Diags.end(); it != et; ++it) {
374243830Sdim    const PathDiagnostic *D = &*it;
375243830Sdim    BatchDiags.push_back(D);
376234353Sdim  }
377234353Sdim
378234353Sdim  // Sort the diagnostics so that they are always emitted in a deterministic
379234353Sdim  // order.
380234353Sdim  if (!BatchDiags.empty())
381234353Sdim    std::sort(BatchDiags.begin(), BatchDiags.end(), CompareDiagnostics());
382234353Sdim
383234353Sdim  FlushDiagnosticsImpl(BatchDiags, Files);
384234353Sdim
385234353Sdim  // Delete the flushed diagnostics.
386234353Sdim  for (std::vector<const PathDiagnostic *>::iterator it = BatchDiags.begin(),
387234353Sdim       et = BatchDiags.end(); it != et; ++it) {
388234353Sdim    const PathDiagnostic *D = *it;
389234353Sdim    delete D;
390234353Sdim  }
391243830Sdim
392243830Sdim  // Clear out the FoldingSet.
393243830Sdim  Diags.clear();
394226633Sdim}
395218887Sdim
396243830Sdimvoid PathDiagnosticConsumer::FilesMade::addDiagnostic(const PathDiagnostic &PD,
397243830Sdim                                                      StringRef ConsumerName,
398243830Sdim                                                      StringRef FileName) {
399243830Sdim  llvm::FoldingSetNodeID NodeID;
400243830Sdim  NodeID.Add(PD);
401243830Sdim  void *InsertPos;
402243830Sdim  PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos);
403243830Sdim  if (!Entry) {
404243830Sdim    Entry = Alloc.Allocate<PDFileEntry>();
405243830Sdim    Entry = new (Entry) PDFileEntry(NodeID);
406243830Sdim    InsertNode(Entry, InsertPos);
407243830Sdim  }
408243830Sdim
409243830Sdim  // Allocate persistent storage for the file name.
410243830Sdim  char *FileName_cstr = (char*) Alloc.Allocate(FileName.size(), 1);
411243830Sdim  memcpy(FileName_cstr, FileName.data(), FileName.size());
412243830Sdim
413243830Sdim  Entry->files.push_back(std::make_pair(ConsumerName,
414243830Sdim                                        StringRef(FileName_cstr,
415243830Sdim                                                  FileName.size())));
416243830Sdim}
417243830Sdim
418243830SdimPathDiagnosticConsumer::PDFileEntry::ConsumerFiles *
419243830SdimPathDiagnosticConsumer::FilesMade::getFiles(const PathDiagnostic &PD) {
420243830Sdim  llvm::FoldingSetNodeID NodeID;
421243830Sdim  NodeID.Add(PD);
422243830Sdim  void *InsertPos;
423243830Sdim  PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos);
424243830Sdim  if (!Entry)
425243830Sdim    return 0;
426243830Sdim  return &Entry->files;
427243830Sdim}
428243830Sdim
429226633Sdim//===----------------------------------------------------------------------===//
430226633Sdim// PathDiagnosticLocation methods.
431226633Sdim//===----------------------------------------------------------------------===//
432218887Sdim
433226633Sdimstatic SourceLocation getValidSourceLocation(const Stmt* S,
434239462Sdim                                             LocationOrAnalysisDeclContext LAC,
435239462Sdim                                             bool UseEnd = false) {
436239462Sdim  SourceLocation L = UseEnd ? S->getLocEnd() : S->getLocStart();
437234353Sdim  assert(!LAC.isNull() && "A valid LocationContext or AnalysisDeclContext should "
438226633Sdim                          "be passed to PathDiagnosticLocation upon creation.");
439218887Sdim
440226633Sdim  // S might be a temporary statement that does not have a location in the
441239462Sdim  // source code, so find an enclosing statement and use its location.
442226633Sdim  if (!L.isValid()) {
443226633Sdim
444239462Sdim    AnalysisDeclContext *ADC;
445226633Sdim    if (LAC.is<const LocationContext*>())
446239462Sdim      ADC = LAC.get<const LocationContext*>()->getAnalysisDeclContext();
447226633Sdim    else
448239462Sdim      ADC = LAC.get<AnalysisDeclContext*>();
449226633Sdim
450239462Sdim    ParentMap &PM = ADC->getParentMap();
451239462Sdim
452239462Sdim    const Stmt *Parent = S;
453239462Sdim    do {
454239462Sdim      Parent = PM.getParent(Parent);
455239462Sdim
456239462Sdim      // In rare cases, we have implicit top-level expressions,
457239462Sdim      // such as arguments for implicit member initializers.
458239462Sdim      // In this case, fall back to the start of the body (even if we were
459239462Sdim      // asked for the statement end location).
460239462Sdim      if (!Parent) {
461239462Sdim        const Stmt *Body = ADC->getBody();
462239462Sdim        if (Body)
463239462Sdim          L = Body->getLocStart();
464239462Sdim        else
465239462Sdim          L = ADC->getDecl()->getLocEnd();
466239462Sdim        break;
467239462Sdim      }
468239462Sdim
469239462Sdim      L = UseEnd ? Parent->getLocEnd() : Parent->getLocStart();
470239462Sdim    } while (!L.isValid());
471218887Sdim  }
472218887Sdim
473226633Sdim  return L;
474226633Sdim}
475218887Sdim
476239462Sdimstatic PathDiagnosticLocation
477239462SdimgetLocationForCaller(const StackFrameContext *SFC,
478239462Sdim                     const LocationContext *CallerCtx,
479239462Sdim                     const SourceManager &SM) {
480239462Sdim  const CFGBlock &Block = *SFC->getCallSiteBlock();
481239462Sdim  CFGElement Source = Block[SFC->getIndex()];
482239462Sdim
483239462Sdim  switch (Source.getKind()) {
484239462Sdim  case CFGElement::Statement:
485249423Sdim    return PathDiagnosticLocation(Source.castAs<CFGStmt>().getStmt(),
486239462Sdim                                  SM, CallerCtx);
487239462Sdim  case CFGElement::Initializer: {
488249423Sdim    const CFGInitializer &Init = Source.castAs<CFGInitializer>();
489239462Sdim    return PathDiagnosticLocation(Init.getInitializer()->getInit(),
490239462Sdim                                  SM, CallerCtx);
491239462Sdim  }
492239462Sdim  case CFGElement::AutomaticObjectDtor: {
493249423Sdim    const CFGAutomaticObjDtor &Dtor = Source.castAs<CFGAutomaticObjDtor>();
494239462Sdim    return PathDiagnosticLocation::createEnd(Dtor.getTriggerStmt(),
495239462Sdim                                             SM, CallerCtx);
496239462Sdim  }
497239462Sdim  case CFGElement::BaseDtor:
498239462Sdim  case CFGElement::MemberDtor: {
499239462Sdim    const AnalysisDeclContext *CallerInfo = CallerCtx->getAnalysisDeclContext();
500239462Sdim    if (const Stmt *CallerBody = CallerInfo->getBody())
501239462Sdim      return PathDiagnosticLocation::createEnd(CallerBody, SM, CallerCtx);
502239462Sdim    return PathDiagnosticLocation::create(CallerInfo->getDecl(), SM);
503239462Sdim  }
504239462Sdim  case CFGElement::TemporaryDtor:
505239462Sdim    llvm_unreachable("not yet implemented!");
506239462Sdim  }
507239462Sdim
508239462Sdim  llvm_unreachable("Unknown CFGElement kind");
509239462Sdim}
510239462Sdim
511239462Sdim
512226633SdimPathDiagnosticLocation
513226633Sdim  PathDiagnosticLocation::createBegin(const Decl *D,
514226633Sdim                                      const SourceManager &SM) {
515226633Sdim  return PathDiagnosticLocation(D->getLocStart(), SM, SingleLocK);
516226633Sdim}
517218887Sdim
518226633SdimPathDiagnosticLocation
519226633Sdim  PathDiagnosticLocation::createBegin(const Stmt *S,
520226633Sdim                                      const SourceManager &SM,
521234353Sdim                                      LocationOrAnalysisDeclContext LAC) {
522226633Sdim  return PathDiagnosticLocation(getValidSourceLocation(S, LAC),
523226633Sdim                                SM, SingleLocK);
524226633Sdim}
525218887Sdim
526239462Sdim
527226633SdimPathDiagnosticLocation
528239462SdimPathDiagnosticLocation::createEnd(const Stmt *S,
529239462Sdim                                  const SourceManager &SM,
530239462Sdim                                  LocationOrAnalysisDeclContext LAC) {
531239462Sdim  if (const CompoundStmt *CS = dyn_cast<CompoundStmt>(S))
532239462Sdim    return createEndBrace(CS, SM);
533239462Sdim  return PathDiagnosticLocation(getValidSourceLocation(S, LAC, /*End=*/true),
534239462Sdim                                SM, SingleLocK);
535239462Sdim}
536239462Sdim
537239462SdimPathDiagnosticLocation
538226633Sdim  PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO,
539226633Sdim                                            const SourceManager &SM) {
540226633Sdim  return PathDiagnosticLocation(BO->getOperatorLoc(), SM, SingleLocK);
541218887Sdim}
542218887Sdim
543226633SdimPathDiagnosticLocation
544226633Sdim  PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME,
545226633Sdim                                          const SourceManager &SM) {
546226633Sdim  return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK);
547226633Sdim}
548218887Sdim
549226633SdimPathDiagnosticLocation
550226633Sdim  PathDiagnosticLocation::createBeginBrace(const CompoundStmt *CS,
551226633Sdim                                           const SourceManager &SM) {
552226633Sdim  SourceLocation L = CS->getLBracLoc();
553226633Sdim  return PathDiagnosticLocation(L, SM, SingleLocK);
554226633Sdim}
555226633Sdim
556226633SdimPathDiagnosticLocation
557226633Sdim  PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS,
558226633Sdim                                         const SourceManager &SM) {
559226633Sdim  SourceLocation L = CS->getRBracLoc();
560226633Sdim  return PathDiagnosticLocation(L, SM, SingleLocK);
561226633Sdim}
562226633Sdim
563226633SdimPathDiagnosticLocation
564226633Sdim  PathDiagnosticLocation::createDeclBegin(const LocationContext *LC,
565226633Sdim                                          const SourceManager &SM) {
566226633Sdim  // FIXME: Should handle CXXTryStmt if analyser starts supporting C++.
567226633Sdim  if (const CompoundStmt *CS =
568226633Sdim        dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody()))
569226633Sdim    if (!CS->body_empty()) {
570226633Sdim      SourceLocation Loc = (*CS->body_begin())->getLocStart();
571226633Sdim      return PathDiagnosticLocation(Loc, SM, SingleLocK);
572226633Sdim    }
573226633Sdim
574226633Sdim  return PathDiagnosticLocation();
575226633Sdim}
576226633Sdim
577226633SdimPathDiagnosticLocation
578226633Sdim  PathDiagnosticLocation::createDeclEnd(const LocationContext *LC,
579226633Sdim                                        const SourceManager &SM) {
580226633Sdim  SourceLocation L = LC->getDecl()->getBodyRBrace();
581226633Sdim  return PathDiagnosticLocation(L, SM, SingleLocK);
582226633Sdim}
583226633Sdim
584226633SdimPathDiagnosticLocation
585226633Sdim  PathDiagnosticLocation::create(const ProgramPoint& P,
586226633Sdim                                 const SourceManager &SMng) {
587226633Sdim
588226633Sdim  const Stmt* S = 0;
589249423Sdim  if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
590226633Sdim    const CFGBlock *BSrc = BE->getSrc();
591226633Sdim    S = BSrc->getTerminatorCondition();
592249423Sdim  } else if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) {
593243830Sdim    S = SP->getStmt();
594249423Sdim    if (P.getAs<PostStmtPurgeDeadSymbols>())
595249423Sdim      return PathDiagnosticLocation::createEnd(S, SMng, P.getLocationContext());
596249423Sdim  } else if (Optional<PostInitializer> PIP = P.getAs<PostInitializer>()) {
597249423Sdim    return PathDiagnosticLocation(PIP->getInitializer()->getSourceLocation(),
598249423Sdim                                  SMng);
599249423Sdim  } else if (Optional<PostImplicitCall> PIE = P.getAs<PostImplicitCall>()) {
600239462Sdim    return PathDiagnosticLocation(PIE->getLocation(), SMng);
601249423Sdim  } else if (Optional<CallEnter> CE = P.getAs<CallEnter>()) {
602239462Sdim    return getLocationForCaller(CE->getCalleeContext(),
603239462Sdim                                CE->getLocationContext(),
604239462Sdim                                SMng);
605249423Sdim  } else if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) {
606239462Sdim    return getLocationForCaller(CEE->getCalleeContext(),
607239462Sdim                                CEE->getLocationContext(),
608239462Sdim                                SMng);
609249423Sdim  } else {
610243830Sdim    llvm_unreachable("Unexpected ProgramPoint");
611243830Sdim  }
612226633Sdim
613226633Sdim  return PathDiagnosticLocation(S, SMng, P.getLocationContext());
614226633Sdim}
615226633Sdim
616251662Sdimconst Stmt *PathDiagnosticLocation::getStmt(const ExplodedNode *N) {
617251662Sdim  ProgramPoint P = N->getLocation();
618251662Sdim  if (Optional<StmtPoint> SP = P.getAs<StmtPoint>())
619251662Sdim    return SP->getStmt();
620251662Sdim  if (Optional<BlockEdge> BE = P.getAs<BlockEdge>())
621251662Sdim    return BE->getSrc()->getTerminator();
622251662Sdim  if (Optional<CallEnter> CE = P.getAs<CallEnter>())
623251662Sdim    return CE->getCallExpr();
624251662Sdim  if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>())
625251662Sdim    return CEE->getCalleeContext()->getCallSite();
626251662Sdim  if (Optional<PostInitializer> PIPP = P.getAs<PostInitializer>())
627251662Sdim    return PIPP->getInitializer()->getInit();
628251662Sdim
629251662Sdim  return 0;
630251662Sdim}
631251662Sdim
632251662Sdimconst Stmt *PathDiagnosticLocation::getNextStmt(const ExplodedNode *N) {
633251662Sdim  for (N = N->getFirstSucc(); N; N = N->getFirstSucc()) {
634251662Sdim    if (const Stmt *S = getStmt(N)) {
635251662Sdim      // Check if the statement is '?' or '&&'/'||'.  These are "merges",
636251662Sdim      // not actual statement points.
637251662Sdim      switch (S->getStmtClass()) {
638251662Sdim        case Stmt::ChooseExprClass:
639251662Sdim        case Stmt::BinaryConditionalOperatorClass:
640251662Sdim        case Stmt::ConditionalOperatorClass:
641251662Sdim          continue;
642251662Sdim        case Stmt::BinaryOperatorClass: {
643251662Sdim          BinaryOperatorKind Op = cast<BinaryOperator>(S)->getOpcode();
644251662Sdim          if (Op == BO_LAnd || Op == BO_LOr)
645251662Sdim            continue;
646251662Sdim          break;
647251662Sdim        }
648251662Sdim        default:
649251662Sdim          break;
650251662Sdim      }
651251662Sdim      // We found the statement, so return it.
652251662Sdim      return S;
653251662Sdim    }
654251662Sdim  }
655251662Sdim
656251662Sdim  return 0;
657251662Sdim}
658251662Sdim
659226633SdimPathDiagnosticLocation
660251662Sdim  PathDiagnosticLocation::createEndOfPath(const ExplodedNode *N,
661226633Sdim                                          const SourceManager &SM) {
662226633Sdim  assert(N && "Cannot create a location with a null node.");
663251662Sdim  const Stmt *S = getStmt(N);
664226633Sdim
665251662Sdim  if (!S)
666251662Sdim    S = getNextStmt(N);
667226633Sdim
668251662Sdim  if (S) {
669251662Sdim    ProgramPoint P = N->getLocation();
670251662Sdim    const LocationContext *LC = N->getLocationContext();
671226633Sdim
672251662Sdim    // For member expressions, return the location of the '.' or '->'.
673251662Sdim    if (const MemberExpr *ME = dyn_cast<MemberExpr>(S))
674251662Sdim      return PathDiagnosticLocation::createMemberLoc(ME, SM);
675251662Sdim
676251662Sdim    // For binary operators, return the location of the operator.
677251662Sdim    if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S))
678251662Sdim      return PathDiagnosticLocation::createOperatorLoc(B, SM);
679251662Sdim
680251662Sdim    if (P.getAs<PostStmtPurgeDeadSymbols>())
681251662Sdim      return PathDiagnosticLocation::createEnd(S, SM, LC);
682251662Sdim
683243830Sdim    if (S->getLocStart().isValid())
684243830Sdim      return PathDiagnosticLocation(S, SM, LC);
685243830Sdim    return PathDiagnosticLocation(getValidSourceLocation(S, LC), SM);
686243830Sdim  }
687243830Sdim
688226633Sdim  return createDeclEnd(N->getLocationContext(), SM);
689226633Sdim}
690226633Sdim
691226633SdimPathDiagnosticLocation PathDiagnosticLocation::createSingleLocation(
692226633Sdim                                           const PathDiagnosticLocation &PDL) {
693226633Sdim  FullSourceLoc L = PDL.asLocation();
694226633Sdim  return PathDiagnosticLocation(L, L.getManager(), SingleLocK);
695226633Sdim}
696226633Sdim
697226633SdimFullSourceLoc
698226633Sdim  PathDiagnosticLocation::genLocation(SourceLocation L,
699234353Sdim                                      LocationOrAnalysisDeclContext LAC) const {
700218887Sdim  assert(isValid());
701218887Sdim  // Note that we want a 'switch' here so that the compiler can warn us in
702218887Sdim  // case we add more cases.
703218887Sdim  switch (K) {
704218887Sdim    case SingleLocK:
705218887Sdim    case RangeK:
706218887Sdim      break;
707218887Sdim    case StmtK:
708234353Sdim      // Defensive checking.
709234353Sdim      if (!S)
710234353Sdim        break;
711226633Sdim      return FullSourceLoc(getValidSourceLocation(S, LAC),
712226633Sdim                           const_cast<SourceManager&>(*SM));
713218887Sdim    case DeclK:
714234353Sdim      // Defensive checking.
715234353Sdim      if (!D)
716234353Sdim        break;
717218887Sdim      return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM));
718218887Sdim  }
719218887Sdim
720226633Sdim  return FullSourceLoc(L, const_cast<SourceManager&>(*SM));
721218887Sdim}
722218887Sdim
723226633SdimPathDiagnosticRange
724234353Sdim  PathDiagnosticLocation::genRange(LocationOrAnalysisDeclContext LAC) const {
725218887Sdim  assert(isValid());
726218887Sdim  // Note that we want a 'switch' here so that the compiler can warn us in
727218887Sdim  // case we add more cases.
728218887Sdim  switch (K) {
729218887Sdim    case SingleLocK:
730226633Sdim      return PathDiagnosticRange(SourceRange(Loc,Loc), true);
731218887Sdim    case RangeK:
732218887Sdim      break;
733218887Sdim    case StmtK: {
734218887Sdim      const Stmt *S = asStmt();
735218887Sdim      switch (S->getStmtClass()) {
736218887Sdim        default:
737218887Sdim          break;
738218887Sdim        case Stmt::DeclStmtClass: {
739218887Sdim          const DeclStmt *DS = cast<DeclStmt>(S);
740218887Sdim          if (DS->isSingleDecl()) {
741218887Sdim            // Should always be the case, but we'll be defensive.
742218887Sdim            return SourceRange(DS->getLocStart(),
743218887Sdim                               DS->getSingleDecl()->getLocation());
744218887Sdim          }
745218887Sdim          break;
746218887Sdim        }
747218887Sdim          // FIXME: Provide better range information for different
748218887Sdim          //  terminators.
749218887Sdim        case Stmt::IfStmtClass:
750218887Sdim        case Stmt::WhileStmtClass:
751218887Sdim        case Stmt::DoStmtClass:
752218887Sdim        case Stmt::ForStmtClass:
753218887Sdim        case Stmt::ChooseExprClass:
754218887Sdim        case Stmt::IndirectGotoStmtClass:
755218887Sdim        case Stmt::SwitchStmtClass:
756218887Sdim        case Stmt::BinaryConditionalOperatorClass:
757218887Sdim        case Stmt::ConditionalOperatorClass:
758218887Sdim        case Stmt::ObjCForCollectionStmtClass: {
759226633Sdim          SourceLocation L = getValidSourceLocation(S, LAC);
760218887Sdim          return SourceRange(L, L);
761218887Sdim        }
762218887Sdim      }
763226633Sdim      SourceRange R = S->getSourceRange();
764226633Sdim      if (R.isValid())
765226633Sdim        return R;
766226633Sdim      break;
767218887Sdim    }
768218887Sdim    case DeclK:
769218887Sdim      if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
770218887Sdim        return MD->getSourceRange();
771218887Sdim      if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
772218887Sdim        if (Stmt *Body = FD->getBody())
773218887Sdim          return Body->getSourceRange();
774218887Sdim      }
775218887Sdim      else {
776218887Sdim        SourceLocation L = D->getLocation();
777218887Sdim        return PathDiagnosticRange(SourceRange(L, L), true);
778218887Sdim      }
779218887Sdim  }
780218887Sdim
781226633Sdim  return SourceRange(Loc,Loc);
782218887Sdim}
783218887Sdim
784218887Sdimvoid PathDiagnosticLocation::flatten() {
785218887Sdim  if (K == StmtK) {
786218887Sdim    K = RangeK;
787218887Sdim    S = 0;
788218887Sdim    D = 0;
789218887Sdim  }
790218887Sdim  else if (K == DeclK) {
791218887Sdim    K = SingleLocK;
792218887Sdim    S = 0;
793218887Sdim    D = 0;
794218887Sdim  }
795218887Sdim}
796218887Sdim
797218887Sdim//===----------------------------------------------------------------------===//
798234353Sdim// Manipulation of PathDiagnosticCallPieces.
799234353Sdim//===----------------------------------------------------------------------===//
800234353Sdim
801234353SdimPathDiagnosticCallPiece *
802234353SdimPathDiagnosticCallPiece::construct(const ExplodedNode *N,
803239462Sdim                                   const CallExitEnd &CE,
804234353Sdim                                   const SourceManager &SM) {
805239462Sdim  const Decl *caller = CE.getLocationContext()->getDecl();
806239462Sdim  PathDiagnosticLocation pos = getLocationForCaller(CE.getCalleeContext(),
807239462Sdim                                                    CE.getLocationContext(),
808239462Sdim                                                    SM);
809234353Sdim  return new PathDiagnosticCallPiece(caller, pos);
810234353Sdim}
811234353Sdim
812234353SdimPathDiagnosticCallPiece *
813234353SdimPathDiagnosticCallPiece::construct(PathPieces &path,
814234353Sdim                                   const Decl *caller) {
815234353Sdim  PathDiagnosticCallPiece *C = new PathDiagnosticCallPiece(path, caller);
816234353Sdim  path.clear();
817234353Sdim  path.push_front(C);
818234353Sdim  return C;
819234353Sdim}
820234353Sdim
821234353Sdimvoid PathDiagnosticCallPiece::setCallee(const CallEnter &CE,
822234353Sdim                                        const SourceManager &SM) {
823239462Sdim  const StackFrameContext *CalleeCtx = CE.getCalleeContext();
824239462Sdim  Callee = CalleeCtx->getDecl();
825239462Sdim
826239462Sdim  callEnterWithin = PathDiagnosticLocation::createBegin(Callee, SM);
827239462Sdim  callEnter = getLocationForCaller(CalleeCtx, CE.getLocationContext(), SM);
828234353Sdim}
829234353Sdim
830249423Sdimstatic inline void describeClass(raw_ostream &Out, const CXXRecordDecl *D,
831249423Sdim                                 StringRef Prefix = StringRef()) {
832249423Sdim  if (!D->getIdentifier())
833249423Sdim    return;
834249423Sdim  Out << Prefix << '\'' << *D << '\'';
835249423Sdim}
836249423Sdim
837249423Sdimstatic bool describeCodeDecl(raw_ostream &Out, const Decl *D,
838249423Sdim                             bool ExtendedDescription,
839249423Sdim                             StringRef Prefix = StringRef()) {
840249423Sdim  if (!D)
841249423Sdim    return false;
842249423Sdim
843249423Sdim  if (isa<BlockDecl>(D)) {
844249423Sdim    if (ExtendedDescription)
845249423Sdim      Out << Prefix << "anonymous block";
846249423Sdim    return ExtendedDescription;
847249423Sdim  }
848249423Sdim
849249423Sdim  if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
850249423Sdim    Out << Prefix;
851249423Sdim    if (ExtendedDescription && !MD->isUserProvided()) {
852249423Sdim      if (MD->isExplicitlyDefaulted())
853249423Sdim        Out << "defaulted ";
854249423Sdim      else
855249423Sdim        Out << "implicit ";
856249423Sdim    }
857249423Sdim
858249423Sdim    if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(MD)) {
859249423Sdim      if (CD->isDefaultConstructor())
860249423Sdim        Out << "default ";
861249423Sdim      else if (CD->isCopyConstructor())
862249423Sdim        Out << "copy ";
863249423Sdim      else if (CD->isMoveConstructor())
864249423Sdim        Out << "move ";
865249423Sdim
866249423Sdim      Out << "constructor";
867249423Sdim      describeClass(Out, MD->getParent(), " for ");
868249423Sdim
869249423Sdim    } else if (isa<CXXDestructorDecl>(MD)) {
870249423Sdim      if (!MD->isUserProvided()) {
871249423Sdim        Out << "destructor";
872249423Sdim        describeClass(Out, MD->getParent(), " for ");
873249423Sdim      } else {
874249423Sdim        // Use ~Foo for explicitly-written destructors.
875249423Sdim        Out << "'" << *MD << "'";
876249423Sdim      }
877249423Sdim
878249423Sdim    } else if (MD->isCopyAssignmentOperator()) {
879249423Sdim        Out << "copy assignment operator";
880249423Sdim        describeClass(Out, MD->getParent(), " for ");
881249423Sdim
882249423Sdim    } else if (MD->isMoveAssignmentOperator()) {
883249423Sdim        Out << "move assignment operator";
884249423Sdim        describeClass(Out, MD->getParent(), " for ");
885249423Sdim
886249423Sdim    } else {
887249423Sdim      if (MD->getParent()->getIdentifier())
888249423Sdim        Out << "'" << *MD->getParent() << "::" << *MD << "'";
889249423Sdim      else
890249423Sdim        Out << "'" << *MD << "'";
891249423Sdim    }
892249423Sdim
893249423Sdim    return true;
894249423Sdim  }
895249423Sdim
896249423Sdim  Out << Prefix << '\'' << cast<NamedDecl>(*D) << '\'';
897249423Sdim  return true;
898249423Sdim}
899249423Sdim
900234353SdimIntrusiveRefCntPtr<PathDiagnosticEventPiece>
901234353SdimPathDiagnosticCallPiece::getCallEnterEvent() const {
902234353Sdim  if (!Callee)
903234353Sdim    return 0;
904249423Sdim
905234353Sdim  SmallString<256> buf;
906234353Sdim  llvm::raw_svector_ostream Out(buf);
907249423Sdim
908249423Sdim  Out << "Calling ";
909249423Sdim  describeCodeDecl(Out, Callee, /*ExtendedDescription=*/true);
910249423Sdim
911249423Sdim  assert(callEnter.asLocation().isValid());
912249423Sdim  return new PathDiagnosticEventPiece(callEnter, Out.str());
913234353Sdim}
914234353Sdim
915234353SdimIntrusiveRefCntPtr<PathDiagnosticEventPiece>
916234353SdimPathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const {
917249423Sdim  if (!callEnterWithin.asLocation().isValid())
918249423Sdim    return 0;
919249423Sdim  if (Callee->isImplicit())
920249423Sdim    return 0;
921249423Sdim  if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Callee))
922249423Sdim    if (MD->isDefaulted())
923249423Sdim      return 0;
924249423Sdim
925234353Sdim  SmallString<256> buf;
926234353Sdim  llvm::raw_svector_ostream Out(buf);
927249423Sdim
928249423Sdim  Out << "Entered call";
929249423Sdim  describeCodeDecl(Out, Caller, /*ExtendedDescription=*/false, " from ");
930249423Sdim
931249423Sdim  return new PathDiagnosticEventPiece(callEnterWithin, Out.str());
932234353Sdim}
933234353Sdim
934234353SdimIntrusiveRefCntPtr<PathDiagnosticEventPiece>
935234353SdimPathDiagnosticCallPiece::getCallExitEvent() const {
936234353Sdim  if (NoExit)
937234353Sdim    return 0;
938249423Sdim
939234353Sdim  SmallString<256> buf;
940234353Sdim  llvm::raw_svector_ostream Out(buf);
941249423Sdim
942249423Sdim  if (!CallStackMessage.empty()) {
943234353Sdim    Out << CallStackMessage;
944249423Sdim  } else {
945249423Sdim    bool DidDescribe = describeCodeDecl(Out, Callee,
946249423Sdim                                        /*ExtendedDescription=*/false,
947249423Sdim                                        "Returning from ");
948249423Sdim    if (!DidDescribe)
949249423Sdim      Out << "Returning to caller";
950249423Sdim  }
951249423Sdim
952249423Sdim  assert(callReturn.asLocation().isValid());
953234353Sdim  return new PathDiagnosticEventPiece(callReturn, Out.str());
954234353Sdim}
955234353Sdim
956234353Sdimstatic void compute_path_size(const PathPieces &pieces, unsigned &size) {
957234353Sdim  for (PathPieces::const_iterator it = pieces.begin(),
958234353Sdim                                  et = pieces.end(); it != et; ++it) {
959234353Sdim    const PathDiagnosticPiece *piece = it->getPtr();
960234353Sdim    if (const PathDiagnosticCallPiece *cp =
961234353Sdim        dyn_cast<PathDiagnosticCallPiece>(piece)) {
962234353Sdim      compute_path_size(cp->path, size);
963234353Sdim    }
964234353Sdim    else
965234353Sdim      ++size;
966234353Sdim  }
967234353Sdim}
968234353Sdim
969234353Sdimunsigned PathDiagnostic::full_size() {
970234353Sdim  unsigned size = 0;
971234353Sdim  compute_path_size(path, size);
972234353Sdim  return size;
973234353Sdim}
974234353Sdim
975234353Sdim//===----------------------------------------------------------------------===//
976218887Sdim// FoldingSet profiling methods.
977218887Sdim//===----------------------------------------------------------------------===//
978218887Sdim
979218887Sdimvoid PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const {
980226633Sdim  ID.AddInteger(Range.getBegin().getRawEncoding());
981226633Sdim  ID.AddInteger(Range.getEnd().getRawEncoding());
982226633Sdim  ID.AddInteger(Loc.getRawEncoding());
983218887Sdim  return;
984218887Sdim}
985218887Sdim
986218887Sdimvoid PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const {
987218887Sdim  ID.AddInteger((unsigned) getKind());
988218887Sdim  ID.AddString(str);
989218887Sdim  // FIXME: Add profiling support for code hints.
990218887Sdim  ID.AddInteger((unsigned) getDisplayHint());
991239462Sdim  ArrayRef<SourceRange> Ranges = getRanges();
992239462Sdim  for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end();
993239462Sdim                                        I != E; ++I) {
994218887Sdim    ID.AddInteger(I->getBegin().getRawEncoding());
995218887Sdim    ID.AddInteger(I->getEnd().getRawEncoding());
996218887Sdim  }
997218887Sdim}
998218887Sdim
999234353Sdimvoid PathDiagnosticCallPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1000234353Sdim  PathDiagnosticPiece::Profile(ID);
1001234353Sdim  for (PathPieces::const_iterator it = path.begin(),
1002234353Sdim       et = path.end(); it != et; ++it) {
1003234353Sdim    ID.Add(**it);
1004234353Sdim  }
1005234353Sdim}
1006234353Sdim
1007218887Sdimvoid PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1008218887Sdim  PathDiagnosticPiece::Profile(ID);
1009218887Sdim  ID.Add(Pos);
1010218887Sdim}
1011218887Sdim
1012218887Sdimvoid PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1013218887Sdim  PathDiagnosticPiece::Profile(ID);
1014218887Sdim  for (const_iterator I = begin(), E = end(); I != E; ++I)
1015218887Sdim    ID.Add(*I);
1016218887Sdim}
1017218887Sdim
1018218887Sdimvoid PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1019218887Sdim  PathDiagnosticSpotPiece::Profile(ID);
1020234353Sdim  for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end();
1021234353Sdim       I != E; ++I)
1022218887Sdim    ID.Add(**I);
1023218887Sdim}
1024218887Sdim
1025218887Sdimvoid PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const {
1026243830Sdim  ID.Add(getLocation());
1027218887Sdim  ID.AddString(BugType);
1028243830Sdim  ID.AddString(VerboseDesc);
1029218887Sdim  ID.AddString(Category);
1030234353Sdim}
1031234353Sdim
1032234353Sdimvoid PathDiagnostic::FullProfile(llvm::FoldingSetNodeID &ID) const {
1033234353Sdim  Profile(ID);
1034234353Sdim  for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E; ++I)
1035234353Sdim    ID.Add(**I);
1036218887Sdim  for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I)
1037218887Sdim    ID.AddString(*I);
1038218887Sdim}
1039234353Sdim
1040234353SdimStackHintGenerator::~StackHintGenerator() {}
1041234353Sdim
1042234353Sdimstd::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){
1043234353Sdim  ProgramPoint P = N->getLocation();
1044249423Sdim  CallExitEnd CExit = P.castAs<CallExitEnd>();
1045234353Sdim
1046239462Sdim  // FIXME: Use CallEvent to abstract this over all calls.
1047249423Sdim  const Stmt *CallSite = CExit.getCalleeContext()->getCallSite();
1048239462Sdim  const CallExpr *CE = dyn_cast_or_null<CallExpr>(CallSite);
1049234353Sdim  if (!CE)
1050234353Sdim    return "";
1051234353Sdim
1052234353Sdim  if (!N)
1053234353Sdim    return getMessageForSymbolNotFound();
1054234353Sdim
1055234353Sdim  // Check if one of the parameters are set to the interesting symbol.
1056234353Sdim  ProgramStateRef State = N->getState();
1057234353Sdim  const LocationContext *LCtx = N->getLocationContext();
1058234353Sdim  unsigned ArgIndex = 0;
1059234353Sdim  for (CallExpr::const_arg_iterator I = CE->arg_begin(),
1060234353Sdim                                    E = CE->arg_end(); I != E; ++I, ++ArgIndex){
1061234353Sdim    SVal SV = State->getSVal(*I, LCtx);
1062234353Sdim
1063234353Sdim    // Check if the variable corresponding to the symbol is passed by value.
1064234353Sdim    SymbolRef AS = SV.getAsLocSymbol();
1065234353Sdim    if (AS == Sym) {
1066234353Sdim      return getMessageForArg(*I, ArgIndex);
1067234353Sdim    }
1068234353Sdim
1069234353Sdim    // Check if the parameter is a pointer to the symbol.
1070249423Sdim    if (Optional<loc::MemRegionVal> Reg = SV.getAs<loc::MemRegionVal>()) {
1071234353Sdim      SVal PSV = State->getSVal(Reg->getRegion());
1072234353Sdim      SymbolRef AS = PSV.getAsLocSymbol();
1073234353Sdim      if (AS == Sym) {
1074234353Sdim        return getMessageForArg(*I, ArgIndex);
1075234353Sdim      }
1076234353Sdim    }
1077234353Sdim  }
1078234353Sdim
1079234353Sdim  // Check if we are returning the interesting symbol.
1080234353Sdim  SVal SV = State->getSVal(CE, LCtx);
1081234353Sdim  SymbolRef RetSym = SV.getAsLocSymbol();
1082234353Sdim  if (RetSym == Sym) {
1083234353Sdim    return getMessageForReturn(CE);
1084234353Sdim  }
1085234353Sdim
1086234353Sdim  return getMessageForSymbolNotFound();
1087234353Sdim}
1088234353Sdim
1089243830Sdimstd::string StackHintGeneratorForSymbol::getMessageForArg(const Expr *ArgE,
1090243830Sdim                                                          unsigned ArgIndex) {
1091243830Sdim  // Printed parameters start at 1, not 0.
1092243830Sdim  ++ArgIndex;
1093234353Sdim
1094234353Sdim  SmallString<200> buf;
1095234353Sdim  llvm::raw_svector_ostream os(buf);
1096234353Sdim
1097243830Sdim  os << Msg << " via " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex)
1098243830Sdim     << " parameter";
1099234353Sdim
1100234353Sdim  return os.str();
1101234353Sdim}
1102