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)
51263508Sdim  : str(StripTrailingDots(s)), kind(k), Hint(hint),
52263508Sdim    LastInMainSourceFile(false) {}
53218887Sdim
54218887SdimPathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint)
55263508Sdim  : kind(k), Hint(hint), LastInMainSourceFile(false) {}
56218887Sdim
57218887SdimPathDiagnosticPiece::~PathDiagnosticPiece() {}
58218887SdimPathDiagnosticEventPiece::~PathDiagnosticEventPiece() {}
59234353SdimPathDiagnosticCallPiece::~PathDiagnosticCallPiece() {}
60218887SdimPathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() {}
61234353SdimPathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() {}
62218887Sdim
63218887Sdim
64234353SdimPathPieces::~PathPieces() {}
65239462Sdim
66239462Sdimvoid PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current,
67239462Sdim                           bool ShouldFlattenMacros) const {
68239462Sdim  for (PathPieces::const_iterator I = begin(), E = end(); I != E; ++I) {
69239462Sdim    PathDiagnosticPiece *Piece = I->getPtr();
70239462Sdim
71239462Sdim    switch (Piece->getKind()) {
72239462Sdim    case PathDiagnosticPiece::Call: {
73239462Sdim      PathDiagnosticCallPiece *Call = cast<PathDiagnosticCallPiece>(Piece);
74239462Sdim      IntrusiveRefCntPtr<PathDiagnosticEventPiece> CallEnter =
75239462Sdim        Call->getCallEnterEvent();
76239462Sdim      if (CallEnter)
77239462Sdim        Current.push_back(CallEnter);
78239462Sdim      Call->path.flattenTo(Primary, Primary, ShouldFlattenMacros);
79239462Sdim      IntrusiveRefCntPtr<PathDiagnosticEventPiece> callExit =
80239462Sdim        Call->getCallExitEvent();
81239462Sdim      if (callExit)
82239462Sdim        Current.push_back(callExit);
83239462Sdim      break;
84239462Sdim    }
85239462Sdim    case PathDiagnosticPiece::Macro: {
86239462Sdim      PathDiagnosticMacroPiece *Macro = cast<PathDiagnosticMacroPiece>(Piece);
87239462Sdim      if (ShouldFlattenMacros) {
88239462Sdim        Macro->subPieces.flattenTo(Primary, Primary, ShouldFlattenMacros);
89239462Sdim      } else {
90239462Sdim        Current.push_back(Piece);
91239462Sdim        PathPieces NewPath;
92239462Sdim        Macro->subPieces.flattenTo(Primary, NewPath, ShouldFlattenMacros);
93239462Sdim        // FIXME: This probably shouldn't mutate the original path piece.
94239462Sdim        Macro->subPieces = NewPath;
95239462Sdim      }
96239462Sdim      break;
97239462Sdim    }
98239462Sdim    case PathDiagnosticPiece::Event:
99239462Sdim    case PathDiagnosticPiece::ControlFlow:
100239462Sdim      Current.push_back(Piece);
101239462Sdim      break;
102239462Sdim    }
103239462Sdim  }
104239462Sdim}
105239462Sdim
106239462Sdim
107234353SdimPathDiagnostic::~PathDiagnostic() {}
108218887Sdim
109234353SdimPathDiagnostic::PathDiagnostic(const Decl *declWithIssue,
110243830Sdim                               StringRef bugtype, StringRef verboseDesc,
111249423Sdim                               StringRef shortDesc, StringRef category,
112249423Sdim                               PathDiagnosticLocation LocationToUnique,
113249423Sdim                               const Decl *DeclToUnique)
114234353Sdim  : DeclWithIssue(declWithIssue),
115234353Sdim    BugType(StripTrailingDots(bugtype)),
116243830Sdim    VerboseDesc(StripTrailingDots(verboseDesc)),
117243830Sdim    ShortDesc(StripTrailingDots(shortDesc)),
118234353Sdim    Category(StripTrailingDots(category)),
119249423Sdim    UniqueingLoc(LocationToUnique),
120249423Sdim    UniqueingDecl(DeclToUnique),
121234353Sdim    path(pathImpl) {}
122234353Sdim
123263508Sdimstatic PathDiagnosticCallPiece *
124263508SdimgetFirstStackedCallToHeaderFile(PathDiagnosticCallPiece *CP,
125263508Sdim                                const SourceManager &SMgr) {
126263508Sdim  SourceLocation CallLoc = CP->callEnter.asLocation();
127263508Sdim
128263508Sdim  // If the call is within a macro, don't do anything (for now).
129263508Sdim  if (CallLoc.isMacroID())
130263508Sdim    return 0;
131263508Sdim
132263508Sdim  assert(SMgr.isInMainFile(CallLoc) &&
133263508Sdim         "The call piece should be in the main file.");
134263508Sdim
135263508Sdim  // Check if CP represents a path through a function outside of the main file.
136263508Sdim  if (!SMgr.isInMainFile(CP->callEnterWithin.asLocation()))
137263508Sdim    return CP;
138263508Sdim
139263508Sdim  const PathPieces &Path = CP->path;
140263508Sdim  if (Path.empty())
141263508Sdim    return 0;
142263508Sdim
143263508Sdim  // Check if the last piece in the callee path is a call to a function outside
144263508Sdim  // of the main file.
145263508Sdim  if (PathDiagnosticCallPiece *CPInner =
146263508Sdim      dyn_cast<PathDiagnosticCallPiece>(Path.back())) {
147263508Sdim    return getFirstStackedCallToHeaderFile(CPInner, SMgr);
148263508Sdim  }
149263508Sdim
150263508Sdim  // Otherwise, the last piece is in the main file.
151263508Sdim  return 0;
152263508Sdim}
153263508Sdim
154263508Sdimvoid PathDiagnostic::resetDiagnosticLocationToMainFile() {
155263508Sdim  if (path.empty())
156263508Sdim    return;
157263508Sdim
158263508Sdim  PathDiagnosticPiece *LastP = path.back().getPtr();
159263508Sdim  assert(LastP);
160263508Sdim  const SourceManager &SMgr = LastP->getLocation().getManager();
161263508Sdim
162263508Sdim  // We only need to check if the report ends inside headers, if the last piece
163263508Sdim  // is a call piece.
164263508Sdim  if (PathDiagnosticCallPiece *CP = dyn_cast<PathDiagnosticCallPiece>(LastP)) {
165263508Sdim    CP = getFirstStackedCallToHeaderFile(CP, SMgr);
166263508Sdim    if (CP) {
167263508Sdim      // Mark the piece.
168263508Sdim       CP->setAsLastInMainSourceFile();
169263508Sdim
170263508Sdim      // Update the path diagnostic message.
171263508Sdim      const NamedDecl *ND = dyn_cast<NamedDecl>(CP->getCallee());
172263508Sdim      if (ND) {
173263508Sdim        SmallString<200> buf;
174263508Sdim        llvm::raw_svector_ostream os(buf);
175263508Sdim        os << " (within a call to '" << ND->getDeclName() << "')";
176263508Sdim        appendToDesc(os.str());
177263508Sdim      }
178263508Sdim
179263508Sdim      // Reset the report containing declaration and location.
180263508Sdim      DeclWithIssue = CP->getCaller();
181263508Sdim      Loc = CP->getLocation();
182263508Sdim
183263508Sdim      return;
184263508Sdim    }
185263508Sdim  }
186263508Sdim}
187263508Sdim
188234353Sdimvoid PathDiagnosticConsumer::anchor() { }
189234353Sdim
190234353SdimPathDiagnosticConsumer::~PathDiagnosticConsumer() {
191234353Sdim  // Delete the contents of the FoldingSet if it isn't empty already.
192234353Sdim  for (llvm::FoldingSet<PathDiagnostic>::iterator it =
193234353Sdim       Diags.begin(), et = Diags.end() ; it != et ; ++it) {
194234353Sdim    delete &*it;
195234353Sdim  }
196218887Sdim}
197218887Sdim
198234353Sdimvoid PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) {
199249423Sdim  OwningPtr<PathDiagnostic> OwningD(D);
200234353Sdim
201234353Sdim  if (!D || D->path.empty())
202234353Sdim    return;
203234353Sdim
204234353Sdim  // We need to flatten the locations (convert Stmt* to locations) because
205234353Sdim  // the referenced statements may be freed by the time the diagnostics
206234353Sdim  // are emitted.
207234353Sdim  D->flattenLocations();
208218887Sdim
209234353Sdim  // If the PathDiagnosticConsumer does not support diagnostics that
210234353Sdim  // cross file boundaries, prune out such diagnostics now.
211234353Sdim  if (!supportsCrossFileDiagnostics()) {
212234353Sdim    // Verify that the entire path is from the same FileID.
213234353Sdim    FileID FID;
214234353Sdim    const SourceManager &SMgr = (*D->path.begin())->getLocation().getManager();
215249423Sdim    SmallVector<const PathPieces *, 5> WorkList;
216234353Sdim    WorkList.push_back(&D->path);
217218887Sdim
218234353Sdim    while (!WorkList.empty()) {
219263508Sdim      const PathPieces &path = *WorkList.pop_back_val();
220234353Sdim
221263508Sdim      for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E;
222263508Sdim           ++I) {
223234353Sdim        const PathDiagnosticPiece *piece = I->getPtr();
224234353Sdim        FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc();
225234353Sdim
226234353Sdim        if (FID.isInvalid()) {
227234353Sdim          FID = SMgr.getFileID(L);
228234353Sdim        } else if (SMgr.getFileID(L) != FID)
229234353Sdim          return; // FIXME: Emit a warning?
230234353Sdim
231234353Sdim        // Check the source ranges.
232239462Sdim        ArrayRef<SourceRange> Ranges = piece->getRanges();
233239462Sdim        for (ArrayRef<SourceRange>::iterator I = Ranges.begin(),
234239462Sdim                                             E = Ranges.end(); I != E; ++I) {
235239462Sdim          SourceLocation L = SMgr.getExpansionLoc(I->getBegin());
236234353Sdim          if (!L.isFileID() || SMgr.getFileID(L) != FID)
237234353Sdim            return; // FIXME: Emit a warning?
238239462Sdim          L = SMgr.getExpansionLoc(I->getEnd());
239234353Sdim          if (!L.isFileID() || SMgr.getFileID(L) != FID)
240234353Sdim            return; // FIXME: Emit a warning?
241234353Sdim        }
242234353Sdim
243234353Sdim        if (const PathDiagnosticCallPiece *call =
244234353Sdim            dyn_cast<PathDiagnosticCallPiece>(piece)) {
245234353Sdim          WorkList.push_back(&call->path);
246234353Sdim        }
247234353Sdim        else if (const PathDiagnosticMacroPiece *macro =
248234353Sdim                 dyn_cast<PathDiagnosticMacroPiece>(piece)) {
249234353Sdim          WorkList.push_back(&macro->subPieces);
250234353Sdim        }
251234353Sdim      }
252234353Sdim    }
253234353Sdim
254234353Sdim    if (FID.isInvalid())
255234353Sdim      return; // FIXME: Emit a warning?
256234353Sdim  }
257234353Sdim
258234353Sdim  // Profile the node to see if we already have something matching it
259234353Sdim  llvm::FoldingSetNodeID profile;
260234353Sdim  D->Profile(profile);
261234353Sdim  void *InsertPos = 0;
262234353Sdim
263234353Sdim  if (PathDiagnostic *orig = Diags.FindNodeOrInsertPos(profile, InsertPos)) {
264234353Sdim    // Keep the PathDiagnostic with the shorter path.
265239462Sdim    // Note, the enclosing routine is called in deterministic order, so the
266239462Sdim    // results will be consistent between runs (no reason to break ties if the
267239462Sdim    // size is the same).
268234353Sdim    const unsigned orig_size = orig->full_size();
269234353Sdim    const unsigned new_size = D->full_size();
270239462Sdim    if (orig_size <= new_size)
271239462Sdim      return;
272234353Sdim
273243830Sdim    assert(orig != D);
274234353Sdim    Diags.RemoveNode(orig);
275234353Sdim    delete orig;
276234353Sdim  }
277234353Sdim
278234353Sdim  Diags.InsertNode(OwningD.take());
279218887Sdim}
280218887Sdim
281249423Sdimstatic Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y);
282249423Sdimstatic Optional<bool>
283243830SdimcompareControlFlow(const PathDiagnosticControlFlowPiece &X,
284243830Sdim                   const PathDiagnosticControlFlowPiece &Y) {
285243830Sdim  FullSourceLoc XSL = X.getStartLocation().asLocation();
286243830Sdim  FullSourceLoc YSL = Y.getStartLocation().asLocation();
287243830Sdim  if (XSL != YSL)
288243830Sdim    return XSL.isBeforeInTranslationUnitThan(YSL);
289243830Sdim  FullSourceLoc XEL = X.getEndLocation().asLocation();
290243830Sdim  FullSourceLoc YEL = Y.getEndLocation().asLocation();
291243830Sdim  if (XEL != YEL)
292243830Sdim    return XEL.isBeforeInTranslationUnitThan(YEL);
293249423Sdim  return None;
294243830Sdim}
295218887Sdim
296249423Sdimstatic Optional<bool> compareMacro(const PathDiagnosticMacroPiece &X,
297249423Sdim                                   const PathDiagnosticMacroPiece &Y) {
298243830Sdim  return comparePath(X.subPieces, Y.subPieces);
299243830Sdim}
300243830Sdim
301249423Sdimstatic Optional<bool> compareCall(const PathDiagnosticCallPiece &X,
302249423Sdim                                  const PathDiagnosticCallPiece &Y) {
303243830Sdim  FullSourceLoc X_CEL = X.callEnter.asLocation();
304243830Sdim  FullSourceLoc Y_CEL = Y.callEnter.asLocation();
305243830Sdim  if (X_CEL != Y_CEL)
306243830Sdim    return X_CEL.isBeforeInTranslationUnitThan(Y_CEL);
307243830Sdim  FullSourceLoc X_CEWL = X.callEnterWithin.asLocation();
308243830Sdim  FullSourceLoc Y_CEWL = Y.callEnterWithin.asLocation();
309243830Sdim  if (X_CEWL != Y_CEWL)
310243830Sdim    return X_CEWL.isBeforeInTranslationUnitThan(Y_CEWL);
311243830Sdim  FullSourceLoc X_CRL = X.callReturn.asLocation();
312243830Sdim  FullSourceLoc Y_CRL = Y.callReturn.asLocation();
313243830Sdim  if (X_CRL != Y_CRL)
314243830Sdim    return X_CRL.isBeforeInTranslationUnitThan(Y_CRL);
315243830Sdim  return comparePath(X.path, Y.path);
316243830Sdim}
317243830Sdim
318249423Sdimstatic Optional<bool> comparePiece(const PathDiagnosticPiece &X,
319249423Sdim                                   const PathDiagnosticPiece &Y) {
320243830Sdim  if (X.getKind() != Y.getKind())
321243830Sdim    return X.getKind() < Y.getKind();
322243830Sdim
323243830Sdim  FullSourceLoc XL = X.getLocation().asLocation();
324243830Sdim  FullSourceLoc YL = Y.getLocation().asLocation();
325243830Sdim  if (XL != YL)
326243830Sdim    return XL.isBeforeInTranslationUnitThan(YL);
327243830Sdim
328243830Sdim  if (X.getString() != Y.getString())
329243830Sdim    return X.getString() < Y.getString();
330243830Sdim
331243830Sdim  if (X.getRanges().size() != Y.getRanges().size())
332243830Sdim    return X.getRanges().size() < Y.getRanges().size();
333243830Sdim
334243830Sdim  const SourceManager &SM = XL.getManager();
335243830Sdim
336243830Sdim  for (unsigned i = 0, n = X.getRanges().size(); i < n; ++i) {
337243830Sdim    SourceRange XR = X.getRanges()[i];
338243830Sdim    SourceRange YR = Y.getRanges()[i];
339243830Sdim    if (XR != YR) {
340243830Sdim      if (XR.getBegin() != YR.getBegin())
341243830Sdim        return SM.isBeforeInTranslationUnit(XR.getBegin(), YR.getBegin());
342243830Sdim      return SM.isBeforeInTranslationUnit(XR.getEnd(), YR.getEnd());
343243830Sdim    }
344243830Sdim  }
345243830Sdim
346243830Sdim  switch (X.getKind()) {
347243830Sdim    case clang::ento::PathDiagnosticPiece::ControlFlow:
348243830Sdim      return compareControlFlow(cast<PathDiagnosticControlFlowPiece>(X),
349243830Sdim                                cast<PathDiagnosticControlFlowPiece>(Y));
350243830Sdim    case clang::ento::PathDiagnosticPiece::Event:
351249423Sdim      return None;
352243830Sdim    case clang::ento::PathDiagnosticPiece::Macro:
353243830Sdim      return compareMacro(cast<PathDiagnosticMacroPiece>(X),
354243830Sdim                          cast<PathDiagnosticMacroPiece>(Y));
355243830Sdim    case clang::ento::PathDiagnosticPiece::Call:
356243830Sdim      return compareCall(cast<PathDiagnosticCallPiece>(X),
357243830Sdim                         cast<PathDiagnosticCallPiece>(Y));
358243830Sdim  }
359243830Sdim  llvm_unreachable("all cases handled");
360243830Sdim}
361243830Sdim
362249423Sdimstatic Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y) {
363243830Sdim  if (X.size() != Y.size())
364243830Sdim    return X.size() < Y.size();
365251662Sdim
366251662Sdim  PathPieces::const_iterator X_I = X.begin(), X_end = X.end();
367251662Sdim  PathPieces::const_iterator Y_I = Y.begin(), Y_end = Y.end();
368251662Sdim
369251662Sdim  for ( ; X_I != X_end && Y_I != Y_end; ++X_I, ++Y_I) {
370251662Sdim    Optional<bool> b = comparePiece(**X_I, **Y_I);
371243830Sdim    if (b.hasValue())
372243830Sdim      return b.getValue();
373243830Sdim  }
374251662Sdim
375249423Sdim  return None;
376243830Sdim}
377243830Sdim
378243830Sdimstatic bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) {
379243830Sdim  FullSourceLoc XL = X.getLocation().asLocation();
380243830Sdim  FullSourceLoc YL = Y.getLocation().asLocation();
381243830Sdim  if (XL != YL)
382243830Sdim    return XL.isBeforeInTranslationUnitThan(YL);
383243830Sdim  if (X.getBugType() != Y.getBugType())
384243830Sdim    return X.getBugType() < Y.getBugType();
385243830Sdim  if (X.getCategory() != Y.getCategory())
386243830Sdim    return X.getCategory() < Y.getCategory();
387243830Sdim  if (X.getVerboseDescription() != Y.getVerboseDescription())
388243830Sdim    return X.getVerboseDescription() < Y.getVerboseDescription();
389243830Sdim  if (X.getShortDescription() != Y.getShortDescription())
390243830Sdim    return X.getShortDescription() < Y.getShortDescription();
391243830Sdim  if (X.getDeclWithIssue() != Y.getDeclWithIssue()) {
392243830Sdim    const Decl *XD = X.getDeclWithIssue();
393243830Sdim    if (!XD)
394243830Sdim      return true;
395243830Sdim    const Decl *YD = Y.getDeclWithIssue();
396243830Sdim    if (!YD)
397243830Sdim      return false;
398243830Sdim    SourceLocation XDL = XD->getLocation();
399243830Sdim    SourceLocation YDL = YD->getLocation();
400243830Sdim    if (XDL != YDL) {
401243830Sdim      const SourceManager &SM = XL.getManager();
402243830Sdim      return SM.isBeforeInTranslationUnit(XDL, YDL);
403243830Sdim    }
404243830Sdim  }
405243830Sdim  PathDiagnostic::meta_iterator XI = X.meta_begin(), XE = X.meta_end();
406243830Sdim  PathDiagnostic::meta_iterator YI = Y.meta_begin(), YE = Y.meta_end();
407243830Sdim  if (XE - XI != YE - YI)
408243830Sdim    return (XE - XI) < (YE - YI);
409243830Sdim  for ( ; XI != XE ; ++XI, ++YI) {
410243830Sdim    if (*XI != *YI)
411243830Sdim      return (*XI) < (*YI);
412243830Sdim  }
413249423Sdim  Optional<bool> b = comparePath(X.path, Y.path);
414243830Sdim  assert(b.hasValue());
415243830Sdim  return b.getValue();
416243830Sdim}
417243830Sdim
418234353Sdimnamespace {
419234353Sdimstruct CompareDiagnostics {
420234353Sdim  // Compare if 'X' is "<" than 'Y'.
421234353Sdim  bool operator()(const PathDiagnostic *X, const PathDiagnostic *Y) const {
422243830Sdim    if (X == Y)
423234353Sdim      return false;
424243830Sdim    return compare(*X, *Y);
425243830Sdim  }
426243830Sdim};
427234353Sdim}
428218887Sdim
429239462Sdimvoid PathDiagnosticConsumer::FlushDiagnostics(
430239462Sdim                                     PathDiagnosticConsumer::FilesMade *Files) {
431234353Sdim  if (flushed)
432234353Sdim    return;
433234353Sdim
434234353Sdim  flushed = true;
435234353Sdim
436234353Sdim  std::vector<const PathDiagnostic *> BatchDiags;
437234353Sdim  for (llvm::FoldingSet<PathDiagnostic>::iterator it = Diags.begin(),
438234353Sdim       et = Diags.end(); it != et; ++it) {
439243830Sdim    const PathDiagnostic *D = &*it;
440243830Sdim    BatchDiags.push_back(D);
441234353Sdim  }
442234353Sdim
443234353Sdim  // Sort the diagnostics so that they are always emitted in a deterministic
444234353Sdim  // order.
445234353Sdim  if (!BatchDiags.empty())
446234353Sdim    std::sort(BatchDiags.begin(), BatchDiags.end(), CompareDiagnostics());
447234353Sdim
448234353Sdim  FlushDiagnosticsImpl(BatchDiags, Files);
449234353Sdim
450234353Sdim  // Delete the flushed diagnostics.
451234353Sdim  for (std::vector<const PathDiagnostic *>::iterator it = BatchDiags.begin(),
452234353Sdim       et = BatchDiags.end(); it != et; ++it) {
453234353Sdim    const PathDiagnostic *D = *it;
454234353Sdim    delete D;
455234353Sdim  }
456243830Sdim
457243830Sdim  // Clear out the FoldingSet.
458243830Sdim  Diags.clear();
459226633Sdim}
460218887Sdim
461243830Sdimvoid PathDiagnosticConsumer::FilesMade::addDiagnostic(const PathDiagnostic &PD,
462243830Sdim                                                      StringRef ConsumerName,
463243830Sdim                                                      StringRef FileName) {
464243830Sdim  llvm::FoldingSetNodeID NodeID;
465243830Sdim  NodeID.Add(PD);
466243830Sdim  void *InsertPos;
467243830Sdim  PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos);
468243830Sdim  if (!Entry) {
469243830Sdim    Entry = Alloc.Allocate<PDFileEntry>();
470243830Sdim    Entry = new (Entry) PDFileEntry(NodeID);
471243830Sdim    InsertNode(Entry, InsertPos);
472243830Sdim  }
473243830Sdim
474243830Sdim  // Allocate persistent storage for the file name.
475243830Sdim  char *FileName_cstr = (char*) Alloc.Allocate(FileName.size(), 1);
476243830Sdim  memcpy(FileName_cstr, FileName.data(), FileName.size());
477243830Sdim
478243830Sdim  Entry->files.push_back(std::make_pair(ConsumerName,
479243830Sdim                                        StringRef(FileName_cstr,
480243830Sdim                                                  FileName.size())));
481243830Sdim}
482243830Sdim
483243830SdimPathDiagnosticConsumer::PDFileEntry::ConsumerFiles *
484243830SdimPathDiagnosticConsumer::FilesMade::getFiles(const PathDiagnostic &PD) {
485243830Sdim  llvm::FoldingSetNodeID NodeID;
486243830Sdim  NodeID.Add(PD);
487243830Sdim  void *InsertPos;
488243830Sdim  PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos);
489243830Sdim  if (!Entry)
490243830Sdim    return 0;
491243830Sdim  return &Entry->files;
492243830Sdim}
493243830Sdim
494226633Sdim//===----------------------------------------------------------------------===//
495226633Sdim// PathDiagnosticLocation methods.
496226633Sdim//===----------------------------------------------------------------------===//
497218887Sdim
498226633Sdimstatic SourceLocation getValidSourceLocation(const Stmt* S,
499239462Sdim                                             LocationOrAnalysisDeclContext LAC,
500239462Sdim                                             bool UseEnd = false) {
501239462Sdim  SourceLocation L = UseEnd ? S->getLocEnd() : S->getLocStart();
502234353Sdim  assert(!LAC.isNull() && "A valid LocationContext or AnalysisDeclContext should "
503226633Sdim                          "be passed to PathDiagnosticLocation upon creation.");
504218887Sdim
505226633Sdim  // S might be a temporary statement that does not have a location in the
506239462Sdim  // source code, so find an enclosing statement and use its location.
507226633Sdim  if (!L.isValid()) {
508226633Sdim
509239462Sdim    AnalysisDeclContext *ADC;
510226633Sdim    if (LAC.is<const LocationContext*>())
511239462Sdim      ADC = LAC.get<const LocationContext*>()->getAnalysisDeclContext();
512226633Sdim    else
513239462Sdim      ADC = LAC.get<AnalysisDeclContext*>();
514226633Sdim
515239462Sdim    ParentMap &PM = ADC->getParentMap();
516239462Sdim
517239462Sdim    const Stmt *Parent = S;
518239462Sdim    do {
519239462Sdim      Parent = PM.getParent(Parent);
520239462Sdim
521239462Sdim      // In rare cases, we have implicit top-level expressions,
522239462Sdim      // such as arguments for implicit member initializers.
523239462Sdim      // In this case, fall back to the start of the body (even if we were
524239462Sdim      // asked for the statement end location).
525239462Sdim      if (!Parent) {
526239462Sdim        const Stmt *Body = ADC->getBody();
527239462Sdim        if (Body)
528239462Sdim          L = Body->getLocStart();
529239462Sdim        else
530239462Sdim          L = ADC->getDecl()->getLocEnd();
531239462Sdim        break;
532239462Sdim      }
533239462Sdim
534239462Sdim      L = UseEnd ? Parent->getLocEnd() : Parent->getLocStart();
535239462Sdim    } while (!L.isValid());
536218887Sdim  }
537218887Sdim
538226633Sdim  return L;
539226633Sdim}
540218887Sdim
541239462Sdimstatic PathDiagnosticLocation
542239462SdimgetLocationForCaller(const StackFrameContext *SFC,
543239462Sdim                     const LocationContext *CallerCtx,
544239462Sdim                     const SourceManager &SM) {
545239462Sdim  const CFGBlock &Block = *SFC->getCallSiteBlock();
546239462Sdim  CFGElement Source = Block[SFC->getIndex()];
547239462Sdim
548239462Sdim  switch (Source.getKind()) {
549239462Sdim  case CFGElement::Statement:
550249423Sdim    return PathDiagnosticLocation(Source.castAs<CFGStmt>().getStmt(),
551239462Sdim                                  SM, CallerCtx);
552239462Sdim  case CFGElement::Initializer: {
553249423Sdim    const CFGInitializer &Init = Source.castAs<CFGInitializer>();
554239462Sdim    return PathDiagnosticLocation(Init.getInitializer()->getInit(),
555239462Sdim                                  SM, CallerCtx);
556239462Sdim  }
557239462Sdim  case CFGElement::AutomaticObjectDtor: {
558249423Sdim    const CFGAutomaticObjDtor &Dtor = Source.castAs<CFGAutomaticObjDtor>();
559239462Sdim    return PathDiagnosticLocation::createEnd(Dtor.getTriggerStmt(),
560239462Sdim                                             SM, CallerCtx);
561239462Sdim  }
562263508Sdim  case CFGElement::DeleteDtor: {
563263508Sdim    const CFGDeleteDtor &Dtor = Source.castAs<CFGDeleteDtor>();
564263508Sdim    return PathDiagnosticLocation(Dtor.getDeleteExpr(), SM, CallerCtx);
565263508Sdim  }
566239462Sdim  case CFGElement::BaseDtor:
567239462Sdim  case CFGElement::MemberDtor: {
568239462Sdim    const AnalysisDeclContext *CallerInfo = CallerCtx->getAnalysisDeclContext();
569239462Sdim    if (const Stmt *CallerBody = CallerInfo->getBody())
570239462Sdim      return PathDiagnosticLocation::createEnd(CallerBody, SM, CallerCtx);
571239462Sdim    return PathDiagnosticLocation::create(CallerInfo->getDecl(), SM);
572239462Sdim  }
573239462Sdim  case CFGElement::TemporaryDtor:
574239462Sdim    llvm_unreachable("not yet implemented!");
575239462Sdim  }
576239462Sdim
577239462Sdim  llvm_unreachable("Unknown CFGElement kind");
578239462Sdim}
579239462Sdim
580239462Sdim
581226633SdimPathDiagnosticLocation
582226633Sdim  PathDiagnosticLocation::createBegin(const Decl *D,
583226633Sdim                                      const SourceManager &SM) {
584226633Sdim  return PathDiagnosticLocation(D->getLocStart(), SM, SingleLocK);
585226633Sdim}
586218887Sdim
587226633SdimPathDiagnosticLocation
588226633Sdim  PathDiagnosticLocation::createBegin(const Stmt *S,
589226633Sdim                                      const SourceManager &SM,
590234353Sdim                                      LocationOrAnalysisDeclContext LAC) {
591226633Sdim  return PathDiagnosticLocation(getValidSourceLocation(S, LAC),
592226633Sdim                                SM, SingleLocK);
593226633Sdim}
594218887Sdim
595239462Sdim
596226633SdimPathDiagnosticLocation
597239462SdimPathDiagnosticLocation::createEnd(const Stmt *S,
598239462Sdim                                  const SourceManager &SM,
599239462Sdim                                  LocationOrAnalysisDeclContext LAC) {
600239462Sdim  if (const CompoundStmt *CS = dyn_cast<CompoundStmt>(S))
601239462Sdim    return createEndBrace(CS, SM);
602239462Sdim  return PathDiagnosticLocation(getValidSourceLocation(S, LAC, /*End=*/true),
603239462Sdim                                SM, SingleLocK);
604239462Sdim}
605239462Sdim
606239462SdimPathDiagnosticLocation
607226633Sdim  PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO,
608226633Sdim                                            const SourceManager &SM) {
609226633Sdim  return PathDiagnosticLocation(BO->getOperatorLoc(), SM, SingleLocK);
610218887Sdim}
611218887Sdim
612226633SdimPathDiagnosticLocation
613226633Sdim  PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME,
614226633Sdim                                          const SourceManager &SM) {
615226633Sdim  return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK);
616226633Sdim}
617218887Sdim
618226633SdimPathDiagnosticLocation
619226633Sdim  PathDiagnosticLocation::createBeginBrace(const CompoundStmt *CS,
620226633Sdim                                           const SourceManager &SM) {
621226633Sdim  SourceLocation L = CS->getLBracLoc();
622226633Sdim  return PathDiagnosticLocation(L, SM, SingleLocK);
623226633Sdim}
624226633Sdim
625226633SdimPathDiagnosticLocation
626226633Sdim  PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS,
627226633Sdim                                         const SourceManager &SM) {
628226633Sdim  SourceLocation L = CS->getRBracLoc();
629226633Sdim  return PathDiagnosticLocation(L, SM, SingleLocK);
630226633Sdim}
631226633Sdim
632226633SdimPathDiagnosticLocation
633226633Sdim  PathDiagnosticLocation::createDeclBegin(const LocationContext *LC,
634226633Sdim                                          const SourceManager &SM) {
635226633Sdim  // FIXME: Should handle CXXTryStmt if analyser starts supporting C++.
636226633Sdim  if (const CompoundStmt *CS =
637226633Sdim        dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody()))
638226633Sdim    if (!CS->body_empty()) {
639226633Sdim      SourceLocation Loc = (*CS->body_begin())->getLocStart();
640226633Sdim      return PathDiagnosticLocation(Loc, SM, SingleLocK);
641226633Sdim    }
642226633Sdim
643226633Sdim  return PathDiagnosticLocation();
644226633Sdim}
645226633Sdim
646226633SdimPathDiagnosticLocation
647226633Sdim  PathDiagnosticLocation::createDeclEnd(const LocationContext *LC,
648226633Sdim                                        const SourceManager &SM) {
649226633Sdim  SourceLocation L = LC->getDecl()->getBodyRBrace();
650226633Sdim  return PathDiagnosticLocation(L, SM, SingleLocK);
651226633Sdim}
652226633Sdim
653226633SdimPathDiagnosticLocation
654226633Sdim  PathDiagnosticLocation::create(const ProgramPoint& P,
655226633Sdim                                 const SourceManager &SMng) {
656226633Sdim
657226633Sdim  const Stmt* S = 0;
658249423Sdim  if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
659226633Sdim    const CFGBlock *BSrc = BE->getSrc();
660226633Sdim    S = BSrc->getTerminatorCondition();
661249423Sdim  } else if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) {
662243830Sdim    S = SP->getStmt();
663249423Sdim    if (P.getAs<PostStmtPurgeDeadSymbols>())
664249423Sdim      return PathDiagnosticLocation::createEnd(S, SMng, P.getLocationContext());
665249423Sdim  } else if (Optional<PostInitializer> PIP = P.getAs<PostInitializer>()) {
666249423Sdim    return PathDiagnosticLocation(PIP->getInitializer()->getSourceLocation(),
667249423Sdim                                  SMng);
668249423Sdim  } else if (Optional<PostImplicitCall> PIE = P.getAs<PostImplicitCall>()) {
669239462Sdim    return PathDiagnosticLocation(PIE->getLocation(), SMng);
670249423Sdim  } else if (Optional<CallEnter> CE = P.getAs<CallEnter>()) {
671239462Sdim    return getLocationForCaller(CE->getCalleeContext(),
672239462Sdim                                CE->getLocationContext(),
673239462Sdim                                SMng);
674249423Sdim  } else if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) {
675239462Sdim    return getLocationForCaller(CEE->getCalleeContext(),
676239462Sdim                                CEE->getLocationContext(),
677239462Sdim                                SMng);
678249423Sdim  } else {
679243830Sdim    llvm_unreachable("Unexpected ProgramPoint");
680243830Sdim  }
681226633Sdim
682226633Sdim  return PathDiagnosticLocation(S, SMng, P.getLocationContext());
683226633Sdim}
684226633Sdim
685251662Sdimconst Stmt *PathDiagnosticLocation::getStmt(const ExplodedNode *N) {
686251662Sdim  ProgramPoint P = N->getLocation();
687251662Sdim  if (Optional<StmtPoint> SP = P.getAs<StmtPoint>())
688251662Sdim    return SP->getStmt();
689251662Sdim  if (Optional<BlockEdge> BE = P.getAs<BlockEdge>())
690251662Sdim    return BE->getSrc()->getTerminator();
691251662Sdim  if (Optional<CallEnter> CE = P.getAs<CallEnter>())
692251662Sdim    return CE->getCallExpr();
693251662Sdim  if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>())
694251662Sdim    return CEE->getCalleeContext()->getCallSite();
695251662Sdim  if (Optional<PostInitializer> PIPP = P.getAs<PostInitializer>())
696251662Sdim    return PIPP->getInitializer()->getInit();
697251662Sdim
698251662Sdim  return 0;
699251662Sdim}
700251662Sdim
701251662Sdimconst Stmt *PathDiagnosticLocation::getNextStmt(const ExplodedNode *N) {
702251662Sdim  for (N = N->getFirstSucc(); N; N = N->getFirstSucc()) {
703251662Sdim    if (const Stmt *S = getStmt(N)) {
704251662Sdim      // Check if the statement is '?' or '&&'/'||'.  These are "merges",
705251662Sdim      // not actual statement points.
706251662Sdim      switch (S->getStmtClass()) {
707251662Sdim        case Stmt::ChooseExprClass:
708251662Sdim        case Stmt::BinaryConditionalOperatorClass:
709251662Sdim        case Stmt::ConditionalOperatorClass:
710251662Sdim          continue;
711251662Sdim        case Stmt::BinaryOperatorClass: {
712251662Sdim          BinaryOperatorKind Op = cast<BinaryOperator>(S)->getOpcode();
713251662Sdim          if (Op == BO_LAnd || Op == BO_LOr)
714251662Sdim            continue;
715251662Sdim          break;
716251662Sdim        }
717251662Sdim        default:
718251662Sdim          break;
719251662Sdim      }
720251662Sdim      // We found the statement, so return it.
721251662Sdim      return S;
722251662Sdim    }
723251662Sdim  }
724251662Sdim
725251662Sdim  return 0;
726251662Sdim}
727251662Sdim
728226633SdimPathDiagnosticLocation
729251662Sdim  PathDiagnosticLocation::createEndOfPath(const ExplodedNode *N,
730226633Sdim                                          const SourceManager &SM) {
731226633Sdim  assert(N && "Cannot create a location with a null node.");
732251662Sdim  const Stmt *S = getStmt(N);
733226633Sdim
734251662Sdim  if (!S)
735251662Sdim    S = getNextStmt(N);
736226633Sdim
737251662Sdim  if (S) {
738251662Sdim    ProgramPoint P = N->getLocation();
739251662Sdim    const LocationContext *LC = N->getLocationContext();
740226633Sdim
741251662Sdim    // For member expressions, return the location of the '.' or '->'.
742251662Sdim    if (const MemberExpr *ME = dyn_cast<MemberExpr>(S))
743251662Sdim      return PathDiagnosticLocation::createMemberLoc(ME, SM);
744251662Sdim
745251662Sdim    // For binary operators, return the location of the operator.
746251662Sdim    if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S))
747251662Sdim      return PathDiagnosticLocation::createOperatorLoc(B, SM);
748251662Sdim
749251662Sdim    if (P.getAs<PostStmtPurgeDeadSymbols>())
750251662Sdim      return PathDiagnosticLocation::createEnd(S, SM, LC);
751251662Sdim
752243830Sdim    if (S->getLocStart().isValid())
753243830Sdim      return PathDiagnosticLocation(S, SM, LC);
754243830Sdim    return PathDiagnosticLocation(getValidSourceLocation(S, LC), SM);
755243830Sdim  }
756243830Sdim
757226633Sdim  return createDeclEnd(N->getLocationContext(), SM);
758226633Sdim}
759226633Sdim
760226633SdimPathDiagnosticLocation PathDiagnosticLocation::createSingleLocation(
761226633Sdim                                           const PathDiagnosticLocation &PDL) {
762226633Sdim  FullSourceLoc L = PDL.asLocation();
763226633Sdim  return PathDiagnosticLocation(L, L.getManager(), SingleLocK);
764226633Sdim}
765226633Sdim
766226633SdimFullSourceLoc
767226633Sdim  PathDiagnosticLocation::genLocation(SourceLocation L,
768234353Sdim                                      LocationOrAnalysisDeclContext LAC) const {
769218887Sdim  assert(isValid());
770218887Sdim  // Note that we want a 'switch' here so that the compiler can warn us in
771218887Sdim  // case we add more cases.
772218887Sdim  switch (K) {
773218887Sdim    case SingleLocK:
774218887Sdim    case RangeK:
775218887Sdim      break;
776218887Sdim    case StmtK:
777234353Sdim      // Defensive checking.
778234353Sdim      if (!S)
779234353Sdim        break;
780226633Sdim      return FullSourceLoc(getValidSourceLocation(S, LAC),
781226633Sdim                           const_cast<SourceManager&>(*SM));
782218887Sdim    case DeclK:
783234353Sdim      // Defensive checking.
784234353Sdim      if (!D)
785234353Sdim        break;
786218887Sdim      return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM));
787218887Sdim  }
788218887Sdim
789226633Sdim  return FullSourceLoc(L, const_cast<SourceManager&>(*SM));
790218887Sdim}
791218887Sdim
792226633SdimPathDiagnosticRange
793234353Sdim  PathDiagnosticLocation::genRange(LocationOrAnalysisDeclContext LAC) const {
794218887Sdim  assert(isValid());
795218887Sdim  // Note that we want a 'switch' here so that the compiler can warn us in
796218887Sdim  // case we add more cases.
797218887Sdim  switch (K) {
798218887Sdim    case SingleLocK:
799226633Sdim      return PathDiagnosticRange(SourceRange(Loc,Loc), true);
800218887Sdim    case RangeK:
801218887Sdim      break;
802218887Sdim    case StmtK: {
803218887Sdim      const Stmt *S = asStmt();
804218887Sdim      switch (S->getStmtClass()) {
805218887Sdim        default:
806218887Sdim          break;
807218887Sdim        case Stmt::DeclStmtClass: {
808218887Sdim          const DeclStmt *DS = cast<DeclStmt>(S);
809218887Sdim          if (DS->isSingleDecl()) {
810218887Sdim            // Should always be the case, but we'll be defensive.
811218887Sdim            return SourceRange(DS->getLocStart(),
812218887Sdim                               DS->getSingleDecl()->getLocation());
813218887Sdim          }
814218887Sdim          break;
815218887Sdim        }
816218887Sdim          // FIXME: Provide better range information for different
817218887Sdim          //  terminators.
818218887Sdim        case Stmt::IfStmtClass:
819218887Sdim        case Stmt::WhileStmtClass:
820218887Sdim        case Stmt::DoStmtClass:
821218887Sdim        case Stmt::ForStmtClass:
822218887Sdim        case Stmt::ChooseExprClass:
823218887Sdim        case Stmt::IndirectGotoStmtClass:
824218887Sdim        case Stmt::SwitchStmtClass:
825218887Sdim        case Stmt::BinaryConditionalOperatorClass:
826218887Sdim        case Stmt::ConditionalOperatorClass:
827218887Sdim        case Stmt::ObjCForCollectionStmtClass: {
828226633Sdim          SourceLocation L = getValidSourceLocation(S, LAC);
829218887Sdim          return SourceRange(L, L);
830218887Sdim        }
831218887Sdim      }
832226633Sdim      SourceRange R = S->getSourceRange();
833226633Sdim      if (R.isValid())
834226633Sdim        return R;
835226633Sdim      break;
836218887Sdim    }
837218887Sdim    case DeclK:
838218887Sdim      if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
839218887Sdim        return MD->getSourceRange();
840218887Sdim      if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
841218887Sdim        if (Stmt *Body = FD->getBody())
842218887Sdim          return Body->getSourceRange();
843218887Sdim      }
844218887Sdim      else {
845218887Sdim        SourceLocation L = D->getLocation();
846218887Sdim        return PathDiagnosticRange(SourceRange(L, L), true);
847218887Sdim      }
848218887Sdim  }
849218887Sdim
850226633Sdim  return SourceRange(Loc,Loc);
851218887Sdim}
852218887Sdim
853218887Sdimvoid PathDiagnosticLocation::flatten() {
854218887Sdim  if (K == StmtK) {
855218887Sdim    K = RangeK;
856218887Sdim    S = 0;
857218887Sdim    D = 0;
858218887Sdim  }
859218887Sdim  else if (K == DeclK) {
860218887Sdim    K = SingleLocK;
861218887Sdim    S = 0;
862218887Sdim    D = 0;
863218887Sdim  }
864218887Sdim}
865218887Sdim
866218887Sdim//===----------------------------------------------------------------------===//
867234353Sdim// Manipulation of PathDiagnosticCallPieces.
868234353Sdim//===----------------------------------------------------------------------===//
869234353Sdim
870234353SdimPathDiagnosticCallPiece *
871234353SdimPathDiagnosticCallPiece::construct(const ExplodedNode *N,
872239462Sdim                                   const CallExitEnd &CE,
873234353Sdim                                   const SourceManager &SM) {
874239462Sdim  const Decl *caller = CE.getLocationContext()->getDecl();
875239462Sdim  PathDiagnosticLocation pos = getLocationForCaller(CE.getCalleeContext(),
876239462Sdim                                                    CE.getLocationContext(),
877239462Sdim                                                    SM);
878234353Sdim  return new PathDiagnosticCallPiece(caller, pos);
879234353Sdim}
880234353Sdim
881234353SdimPathDiagnosticCallPiece *
882234353SdimPathDiagnosticCallPiece::construct(PathPieces &path,
883234353Sdim                                   const Decl *caller) {
884234353Sdim  PathDiagnosticCallPiece *C = new PathDiagnosticCallPiece(path, caller);
885234353Sdim  path.clear();
886234353Sdim  path.push_front(C);
887234353Sdim  return C;
888234353Sdim}
889234353Sdim
890234353Sdimvoid PathDiagnosticCallPiece::setCallee(const CallEnter &CE,
891234353Sdim                                        const SourceManager &SM) {
892239462Sdim  const StackFrameContext *CalleeCtx = CE.getCalleeContext();
893239462Sdim  Callee = CalleeCtx->getDecl();
894239462Sdim
895239462Sdim  callEnterWithin = PathDiagnosticLocation::createBegin(Callee, SM);
896239462Sdim  callEnter = getLocationForCaller(CalleeCtx, CE.getLocationContext(), SM);
897234353Sdim}
898234353Sdim
899249423Sdimstatic inline void describeClass(raw_ostream &Out, const CXXRecordDecl *D,
900249423Sdim                                 StringRef Prefix = StringRef()) {
901249423Sdim  if (!D->getIdentifier())
902249423Sdim    return;
903249423Sdim  Out << Prefix << '\'' << *D << '\'';
904249423Sdim}
905249423Sdim
906249423Sdimstatic bool describeCodeDecl(raw_ostream &Out, const Decl *D,
907249423Sdim                             bool ExtendedDescription,
908249423Sdim                             StringRef Prefix = StringRef()) {
909249423Sdim  if (!D)
910249423Sdim    return false;
911249423Sdim
912249423Sdim  if (isa<BlockDecl>(D)) {
913249423Sdim    if (ExtendedDescription)
914249423Sdim      Out << Prefix << "anonymous block";
915249423Sdim    return ExtendedDescription;
916249423Sdim  }
917249423Sdim
918249423Sdim  if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
919249423Sdim    Out << Prefix;
920249423Sdim    if (ExtendedDescription && !MD->isUserProvided()) {
921249423Sdim      if (MD->isExplicitlyDefaulted())
922249423Sdim        Out << "defaulted ";
923249423Sdim      else
924249423Sdim        Out << "implicit ";
925249423Sdim    }
926249423Sdim
927249423Sdim    if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(MD)) {
928249423Sdim      if (CD->isDefaultConstructor())
929249423Sdim        Out << "default ";
930249423Sdim      else if (CD->isCopyConstructor())
931249423Sdim        Out << "copy ";
932249423Sdim      else if (CD->isMoveConstructor())
933249423Sdim        Out << "move ";
934249423Sdim
935249423Sdim      Out << "constructor";
936249423Sdim      describeClass(Out, MD->getParent(), " for ");
937249423Sdim
938249423Sdim    } else if (isa<CXXDestructorDecl>(MD)) {
939249423Sdim      if (!MD->isUserProvided()) {
940249423Sdim        Out << "destructor";
941249423Sdim        describeClass(Out, MD->getParent(), " for ");
942249423Sdim      } else {
943249423Sdim        // Use ~Foo for explicitly-written destructors.
944249423Sdim        Out << "'" << *MD << "'";
945249423Sdim      }
946249423Sdim
947249423Sdim    } else if (MD->isCopyAssignmentOperator()) {
948249423Sdim        Out << "copy assignment operator";
949249423Sdim        describeClass(Out, MD->getParent(), " for ");
950249423Sdim
951249423Sdim    } else if (MD->isMoveAssignmentOperator()) {
952249423Sdim        Out << "move assignment operator";
953249423Sdim        describeClass(Out, MD->getParent(), " for ");
954249423Sdim
955249423Sdim    } else {
956249423Sdim      if (MD->getParent()->getIdentifier())
957249423Sdim        Out << "'" << *MD->getParent() << "::" << *MD << "'";
958249423Sdim      else
959249423Sdim        Out << "'" << *MD << "'";
960249423Sdim    }
961249423Sdim
962249423Sdim    return true;
963249423Sdim  }
964249423Sdim
965249423Sdim  Out << Prefix << '\'' << cast<NamedDecl>(*D) << '\'';
966249423Sdim  return true;
967249423Sdim}
968249423Sdim
969234353SdimIntrusiveRefCntPtr<PathDiagnosticEventPiece>
970234353SdimPathDiagnosticCallPiece::getCallEnterEvent() const {
971234353Sdim  if (!Callee)
972234353Sdim    return 0;
973249423Sdim
974234353Sdim  SmallString<256> buf;
975234353Sdim  llvm::raw_svector_ostream Out(buf);
976249423Sdim
977249423Sdim  Out << "Calling ";
978249423Sdim  describeCodeDecl(Out, Callee, /*ExtendedDescription=*/true);
979249423Sdim
980249423Sdim  assert(callEnter.asLocation().isValid());
981249423Sdim  return new PathDiagnosticEventPiece(callEnter, Out.str());
982234353Sdim}
983234353Sdim
984234353SdimIntrusiveRefCntPtr<PathDiagnosticEventPiece>
985234353SdimPathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const {
986249423Sdim  if (!callEnterWithin.asLocation().isValid())
987249423Sdim    return 0;
988263508Sdim  if (Callee->isImplicit() || !Callee->hasBody())
989249423Sdim    return 0;
990249423Sdim  if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Callee))
991249423Sdim    if (MD->isDefaulted())
992249423Sdim      return 0;
993249423Sdim
994234353Sdim  SmallString<256> buf;
995234353Sdim  llvm::raw_svector_ostream Out(buf);
996249423Sdim
997249423Sdim  Out << "Entered call";
998249423Sdim  describeCodeDecl(Out, Caller, /*ExtendedDescription=*/false, " from ");
999249423Sdim
1000249423Sdim  return new PathDiagnosticEventPiece(callEnterWithin, Out.str());
1001234353Sdim}
1002234353Sdim
1003234353SdimIntrusiveRefCntPtr<PathDiagnosticEventPiece>
1004234353SdimPathDiagnosticCallPiece::getCallExitEvent() const {
1005234353Sdim  if (NoExit)
1006234353Sdim    return 0;
1007249423Sdim
1008234353Sdim  SmallString<256> buf;
1009234353Sdim  llvm::raw_svector_ostream Out(buf);
1010249423Sdim
1011249423Sdim  if (!CallStackMessage.empty()) {
1012234353Sdim    Out << CallStackMessage;
1013249423Sdim  } else {
1014249423Sdim    bool DidDescribe = describeCodeDecl(Out, Callee,
1015249423Sdim                                        /*ExtendedDescription=*/false,
1016249423Sdim                                        "Returning from ");
1017249423Sdim    if (!DidDescribe)
1018249423Sdim      Out << "Returning to caller";
1019249423Sdim  }
1020249423Sdim
1021249423Sdim  assert(callReturn.asLocation().isValid());
1022234353Sdim  return new PathDiagnosticEventPiece(callReturn, Out.str());
1023234353Sdim}
1024234353Sdim
1025234353Sdimstatic void compute_path_size(const PathPieces &pieces, unsigned &size) {
1026234353Sdim  for (PathPieces::const_iterator it = pieces.begin(),
1027234353Sdim                                  et = pieces.end(); it != et; ++it) {
1028234353Sdim    const PathDiagnosticPiece *piece = it->getPtr();
1029234353Sdim    if (const PathDiagnosticCallPiece *cp =
1030234353Sdim        dyn_cast<PathDiagnosticCallPiece>(piece)) {
1031234353Sdim      compute_path_size(cp->path, size);
1032234353Sdim    }
1033234353Sdim    else
1034234353Sdim      ++size;
1035234353Sdim  }
1036234353Sdim}
1037234353Sdim
1038234353Sdimunsigned PathDiagnostic::full_size() {
1039234353Sdim  unsigned size = 0;
1040234353Sdim  compute_path_size(path, size);
1041234353Sdim  return size;
1042234353Sdim}
1043234353Sdim
1044234353Sdim//===----------------------------------------------------------------------===//
1045218887Sdim// FoldingSet profiling methods.
1046218887Sdim//===----------------------------------------------------------------------===//
1047218887Sdim
1048218887Sdimvoid PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const {
1049226633Sdim  ID.AddInteger(Range.getBegin().getRawEncoding());
1050226633Sdim  ID.AddInteger(Range.getEnd().getRawEncoding());
1051226633Sdim  ID.AddInteger(Loc.getRawEncoding());
1052218887Sdim  return;
1053218887Sdim}
1054218887Sdim
1055218887Sdimvoid PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1056218887Sdim  ID.AddInteger((unsigned) getKind());
1057218887Sdim  ID.AddString(str);
1058218887Sdim  // FIXME: Add profiling support for code hints.
1059218887Sdim  ID.AddInteger((unsigned) getDisplayHint());
1060239462Sdim  ArrayRef<SourceRange> Ranges = getRanges();
1061239462Sdim  for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end();
1062239462Sdim                                        I != E; ++I) {
1063218887Sdim    ID.AddInteger(I->getBegin().getRawEncoding());
1064218887Sdim    ID.AddInteger(I->getEnd().getRawEncoding());
1065218887Sdim  }
1066218887Sdim}
1067218887Sdim
1068234353Sdimvoid PathDiagnosticCallPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1069234353Sdim  PathDiagnosticPiece::Profile(ID);
1070234353Sdim  for (PathPieces::const_iterator it = path.begin(),
1071234353Sdim       et = path.end(); it != et; ++it) {
1072234353Sdim    ID.Add(**it);
1073234353Sdim  }
1074234353Sdim}
1075234353Sdim
1076218887Sdimvoid PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1077218887Sdim  PathDiagnosticPiece::Profile(ID);
1078218887Sdim  ID.Add(Pos);
1079218887Sdim}
1080218887Sdim
1081218887Sdimvoid PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1082218887Sdim  PathDiagnosticPiece::Profile(ID);
1083218887Sdim  for (const_iterator I = begin(), E = end(); I != E; ++I)
1084218887Sdim    ID.Add(*I);
1085218887Sdim}
1086218887Sdim
1087218887Sdimvoid PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1088218887Sdim  PathDiagnosticSpotPiece::Profile(ID);
1089234353Sdim  for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end();
1090234353Sdim       I != E; ++I)
1091218887Sdim    ID.Add(**I);
1092218887Sdim}
1093218887Sdim
1094218887Sdimvoid PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const {
1095243830Sdim  ID.Add(getLocation());
1096218887Sdim  ID.AddString(BugType);
1097243830Sdim  ID.AddString(VerboseDesc);
1098218887Sdim  ID.AddString(Category);
1099234353Sdim}
1100234353Sdim
1101234353Sdimvoid PathDiagnostic::FullProfile(llvm::FoldingSetNodeID &ID) const {
1102234353Sdim  Profile(ID);
1103234353Sdim  for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E; ++I)
1104234353Sdim    ID.Add(**I);
1105218887Sdim  for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I)
1106218887Sdim    ID.AddString(*I);
1107218887Sdim}
1108234353Sdim
1109234353SdimStackHintGenerator::~StackHintGenerator() {}
1110234353Sdim
1111234353Sdimstd::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){
1112234353Sdim  ProgramPoint P = N->getLocation();
1113249423Sdim  CallExitEnd CExit = P.castAs<CallExitEnd>();
1114234353Sdim
1115239462Sdim  // FIXME: Use CallEvent to abstract this over all calls.
1116249423Sdim  const Stmt *CallSite = CExit.getCalleeContext()->getCallSite();
1117239462Sdim  const CallExpr *CE = dyn_cast_or_null<CallExpr>(CallSite);
1118234353Sdim  if (!CE)
1119234353Sdim    return "";
1120234353Sdim
1121234353Sdim  if (!N)
1122234353Sdim    return getMessageForSymbolNotFound();
1123234353Sdim
1124234353Sdim  // Check if one of the parameters are set to the interesting symbol.
1125234353Sdim  ProgramStateRef State = N->getState();
1126234353Sdim  const LocationContext *LCtx = N->getLocationContext();
1127234353Sdim  unsigned ArgIndex = 0;
1128234353Sdim  for (CallExpr::const_arg_iterator I = CE->arg_begin(),
1129234353Sdim                                    E = CE->arg_end(); I != E; ++I, ++ArgIndex){
1130234353Sdim    SVal SV = State->getSVal(*I, LCtx);
1131234353Sdim
1132234353Sdim    // Check if the variable corresponding to the symbol is passed by value.
1133234353Sdim    SymbolRef AS = SV.getAsLocSymbol();
1134234353Sdim    if (AS == Sym) {
1135234353Sdim      return getMessageForArg(*I, ArgIndex);
1136234353Sdim    }
1137234353Sdim
1138234353Sdim    // Check if the parameter is a pointer to the symbol.
1139249423Sdim    if (Optional<loc::MemRegionVal> Reg = SV.getAs<loc::MemRegionVal>()) {
1140234353Sdim      SVal PSV = State->getSVal(Reg->getRegion());
1141234353Sdim      SymbolRef AS = PSV.getAsLocSymbol();
1142234353Sdim      if (AS == Sym) {
1143234353Sdim        return getMessageForArg(*I, ArgIndex);
1144234353Sdim      }
1145234353Sdim    }
1146234353Sdim  }
1147234353Sdim
1148234353Sdim  // Check if we are returning the interesting symbol.
1149234353Sdim  SVal SV = State->getSVal(CE, LCtx);
1150234353Sdim  SymbolRef RetSym = SV.getAsLocSymbol();
1151234353Sdim  if (RetSym == Sym) {
1152234353Sdim    return getMessageForReturn(CE);
1153234353Sdim  }
1154234353Sdim
1155234353Sdim  return getMessageForSymbolNotFound();
1156234353Sdim}
1157234353Sdim
1158243830Sdimstd::string StackHintGeneratorForSymbol::getMessageForArg(const Expr *ArgE,
1159243830Sdim                                                          unsigned ArgIndex) {
1160243830Sdim  // Printed parameters start at 1, not 0.
1161243830Sdim  ++ArgIndex;
1162234353Sdim
1163234353Sdim  SmallString<200> buf;
1164234353Sdim  llvm::raw_svector_ostream os(buf);
1165234353Sdim
1166243830Sdim  os << Msg << " via " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex)
1167243830Sdim     << " parameter";
1168234353Sdim
1169234353Sdim  return os.str();
1170234353Sdim}
1171