PathDiagnostic.cpp revision 183ba8e19d49ab1ae25d3cdd0a19591369c5ab9f
103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)//===--- PathDiagnostic.cpp - Path-Specific Diagnostic Handling -*- C++ -*-===//
203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)//
303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)//                     The LLVM Compiler Infrastructure
403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)//
503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// This file is distributed under the University of Illinois Open Source
603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// License. See LICENSE.TXT for details.
703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)//
803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)//===----------------------------------------------------------------------===//
903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)//
1003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)//  This file defines the PathDiagnostic-related interfaces.
1103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)//
1203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)//===----------------------------------------------------------------------===//
1303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
1403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
1503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
1603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "clang/Basic/SourceManager.h"
1703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "clang/AST/Expr.h"
1803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "clang/AST/Decl.h"
1903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "clang/AST/DeclCXX.h"
2003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "clang/AST/DeclObjC.h"
2103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "clang/AST/ParentMap.h"
2203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "clang/AST/StmtCXX.h"
2303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "llvm/ADT/SmallString.h"
2403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
2503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)using namespace clang;
2603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)using namespace ento;
2703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
2803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)bool PathDiagnosticMacroPiece::containsEvent() const {
2903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end();
3003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)       I!=E; ++I) {
3103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (isa<PathDiagnosticEventPiece>(*I))
3203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      return true;
3303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (PathDiagnosticMacroPiece *MP = dyn_cast<PathDiagnosticMacroPiece>(*I))
34      if (MP->containsEvent())
35        return true;
36  }
37  return false;
38}
39
40static StringRef StripTrailingDots(StringRef s) {
41  for (StringRef::size_type i = s.size(); i != 0; --i)
42    if (s[i - 1] != '.')
43      return s.substr(0, i);
44  return "";
45}
46
47PathDiagnosticPiece::PathDiagnosticPiece(StringRef s,
48                                         Kind k, DisplayHint hint)
49  : str(StripTrailingDots(s)), kind(k), Hint(hint) {}
50
51PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint)
52  : kind(k), Hint(hint) {}
53
54PathDiagnosticPiece::~PathDiagnosticPiece() {}
55PathDiagnosticEventPiece::~PathDiagnosticEventPiece() {}
56PathDiagnosticCallPiece::~PathDiagnosticCallPiece() {}
57PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() {}
58PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() {}
59
60
61PathPieces::~PathPieces() {}
62PathDiagnostic::~PathDiagnostic() {}
63
64PathDiagnostic::PathDiagnostic(const Decl *declWithIssue,
65                               StringRef bugtype, StringRef desc,
66                               StringRef category)
67  : DeclWithIssue(declWithIssue),
68    BugType(StripTrailingDots(bugtype)),
69    Desc(StripTrailingDots(desc)),
70    Category(StripTrailingDots(category)),
71    path(pathImpl) {}
72
73void PathDiagnosticConsumer::anchor() { }
74
75PathDiagnosticConsumer::~PathDiagnosticConsumer() {
76  // Delete the contents of the FoldingSet if it isn't empty already.
77  for (llvm::FoldingSet<PathDiagnostic>::iterator it =
78       Diags.begin(), et = Diags.end() ; it != et ; ++it) {
79    delete &*it;
80  }
81}
82
83void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) {
84  llvm::OwningPtr<PathDiagnostic> OwningD(D);
85
86  if (!D || D->path.empty())
87    return;
88
89  // We need to flatten the locations (convert Stmt* to locations) because
90  // the referenced statements may be freed by the time the diagnostics
91  // are emitted.
92  D->flattenLocations();
93
94  // If the PathDiagnosticConsumer does not support diagnostics that
95  // cross file boundaries, prune out such diagnostics now.
96  if (!supportsCrossFileDiagnostics()) {
97    // Verify that the entire path is from the same FileID.
98    FileID FID;
99    const SourceManager &SMgr = (*D->path.begin())->getLocation().getManager();
100    llvm::SmallVector<const PathPieces *, 5> WorkList;
101    WorkList.push_back(&D->path);
102
103    while (!WorkList.empty()) {
104      const PathPieces &path = *WorkList.back();
105      WorkList.pop_back();
106
107      for (PathPieces::const_iterator I = path.begin(), E = path.end();
108           I != E; ++I) {
109        const PathDiagnosticPiece *piece = I->getPtr();
110        FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc();
111
112        if (FID.isInvalid()) {
113          FID = SMgr.getFileID(L);
114        } else if (SMgr.getFileID(L) != FID)
115          return; // FIXME: Emit a warning?
116
117        // Check the source ranges.
118        for (PathDiagnosticPiece::range_iterator RI = piece->ranges_begin(),
119             RE = piece->ranges_end();
120             RI != RE; ++RI) {
121          SourceLocation L = SMgr.getExpansionLoc(RI->getBegin());
122          if (!L.isFileID() || SMgr.getFileID(L) != FID)
123            return; // FIXME: Emit a warning?
124          L = SMgr.getExpansionLoc(RI->getEnd());
125          if (!L.isFileID() || SMgr.getFileID(L) != FID)
126            return; // FIXME: Emit a warning?
127        }
128
129        if (const PathDiagnosticCallPiece *call =
130            dyn_cast<PathDiagnosticCallPiece>(piece)) {
131          WorkList.push_back(&call->path);
132        }
133        else if (const PathDiagnosticMacroPiece *macro =
134                 dyn_cast<PathDiagnosticMacroPiece>(piece)) {
135          WorkList.push_back(&macro->subPieces);
136        }
137      }
138    }
139
140    if (FID.isInvalid())
141      return; // FIXME: Emit a warning?
142  }
143
144  // Profile the node to see if we already have something matching it
145  llvm::FoldingSetNodeID profile;
146  D->Profile(profile);
147  void *InsertPos = 0;
148
149  if (PathDiagnostic *orig = Diags.FindNodeOrInsertPos(profile, InsertPos)) {
150    // Keep the PathDiagnostic with the shorter path.
151    const unsigned orig_size = orig->full_size();
152    const unsigned new_size = D->full_size();
153
154    if (orig_size <= new_size) {
155      bool shouldKeepOriginal = true;
156      if (orig_size == new_size) {
157        // Here we break ties in a fairly arbitrary, but deterministic, way.
158        llvm::FoldingSetNodeID fullProfile, fullProfileOrig;
159        D->FullProfile(fullProfile);
160        orig->FullProfile(fullProfileOrig);
161        if (fullProfile.ComputeHash() < fullProfileOrig.ComputeHash())
162          shouldKeepOriginal = false;
163      }
164
165      if (shouldKeepOriginal)
166        return;
167    }
168    Diags.RemoveNode(orig);
169    delete orig;
170  }
171
172  Diags.InsertNode(OwningD.take());
173}
174
175
176namespace {
177struct CompareDiagnostics {
178  // Compare if 'X' is "<" than 'Y'.
179  bool operator()(const PathDiagnostic *X, const PathDiagnostic *Y) const {
180    // First compare by location
181    const FullSourceLoc &XLoc = X->getLocation().asLocation();
182    const FullSourceLoc &YLoc = Y->getLocation().asLocation();
183    if (XLoc < YLoc)
184      return true;
185    if (XLoc != YLoc)
186      return false;
187
188    // Next, compare by bug type.
189    StringRef XBugType = X->getBugType();
190    StringRef YBugType = Y->getBugType();
191    if (XBugType < YBugType)
192      return true;
193    if (XBugType != YBugType)
194      return false;
195
196    // Next, compare by bug description.
197    StringRef XDesc = X->getDescription();
198    StringRef YDesc = Y->getDescription();
199    if (XDesc < YDesc)
200      return true;
201    if (XDesc != YDesc)
202      return false;
203
204    // FIXME: Further refine by comparing PathDiagnosticPieces?
205    return false;
206  }
207};
208}
209
210void
211PathDiagnosticConsumer::FlushDiagnostics(SmallVectorImpl<std::string> *Files) {
212  if (flushed)
213    return;
214
215  flushed = true;
216
217  std::vector<const PathDiagnostic *> BatchDiags;
218  for (llvm::FoldingSet<PathDiagnostic>::iterator it = Diags.begin(),
219       et = Diags.end(); it != et; ++it) {
220    BatchDiags.push_back(&*it);
221  }
222
223  // Clear out the FoldingSet.
224  Diags.clear();
225
226  // Sort the diagnostics so that they are always emitted in a deterministic
227  // order.
228  if (!BatchDiags.empty())
229    std::sort(BatchDiags.begin(), BatchDiags.end(), CompareDiagnostics());
230
231  FlushDiagnosticsImpl(BatchDiags, Files);
232
233  // Delete the flushed diagnostics.
234  for (std::vector<const PathDiagnostic *>::iterator it = BatchDiags.begin(),
235       et = BatchDiags.end(); it != et; ++it) {
236    const PathDiagnostic *D = *it;
237    delete D;
238  }
239}
240
241//===----------------------------------------------------------------------===//
242// PathDiagnosticLocation methods.
243//===----------------------------------------------------------------------===//
244
245static SourceLocation getValidSourceLocation(const Stmt* S,
246                                             LocationOrAnalysisDeclContext LAC,
247                                             bool UseEnd = false) {
248  SourceLocation L = UseEnd ? S->getLocEnd() : S->getLocStart();
249  assert(!LAC.isNull() && "A valid LocationContext or AnalysisDeclContext should "
250                          "be passed to PathDiagnosticLocation upon creation.");
251
252  // S might be a temporary statement that does not have a location in the
253  // source code, so find an enclosing statement and use its location.
254  if (!L.isValid()) {
255
256    ParentMap *PM = 0;
257    if (LAC.is<const LocationContext*>())
258      PM = &LAC.get<const LocationContext*>()->getParentMap();
259    else
260      PM = &LAC.get<AnalysisDeclContext*>()->getParentMap();
261
262    while (!L.isValid()) {
263      S = PM->getParent(S);
264      L = UseEnd ? S->getLocEnd() : S->getLocStart();
265    }
266  }
267
268  return L;
269}
270
271PathDiagnosticLocation
272  PathDiagnosticLocation::createBegin(const Decl *D,
273                                      const SourceManager &SM) {
274  return PathDiagnosticLocation(D->getLocStart(), SM, SingleLocK);
275}
276
277PathDiagnosticLocation
278  PathDiagnosticLocation::createBegin(const Stmt *S,
279                                      const SourceManager &SM,
280                                      LocationOrAnalysisDeclContext LAC) {
281  return PathDiagnosticLocation(getValidSourceLocation(S, LAC),
282                                SM, SingleLocK);
283}
284
285
286PathDiagnosticLocation
287PathDiagnosticLocation::createEnd(const Stmt *S,
288                                  const SourceManager &SM,
289                                  LocationOrAnalysisDeclContext LAC) {
290  if (const CompoundStmt *CS = dyn_cast<CompoundStmt>(S))
291    return createEndBrace(CS, SM);
292  return PathDiagnosticLocation(getValidSourceLocation(S, LAC, /*End=*/true),
293                                SM, SingleLocK);
294}
295
296PathDiagnosticLocation
297  PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO,
298                                            const SourceManager &SM) {
299  return PathDiagnosticLocation(BO->getOperatorLoc(), SM, SingleLocK);
300}
301
302PathDiagnosticLocation
303  PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME,
304                                          const SourceManager &SM) {
305  return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK);
306}
307
308PathDiagnosticLocation
309  PathDiagnosticLocation::createBeginBrace(const CompoundStmt *CS,
310                                           const SourceManager &SM) {
311  SourceLocation L = CS->getLBracLoc();
312  return PathDiagnosticLocation(L, SM, SingleLocK);
313}
314
315PathDiagnosticLocation
316  PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS,
317                                         const SourceManager &SM) {
318  SourceLocation L = CS->getRBracLoc();
319  return PathDiagnosticLocation(L, SM, SingleLocK);
320}
321
322PathDiagnosticLocation
323  PathDiagnosticLocation::createDeclBegin(const LocationContext *LC,
324                                          const SourceManager &SM) {
325  // FIXME: Should handle CXXTryStmt if analyser starts supporting C++.
326  if (const CompoundStmt *CS =
327        dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody()))
328    if (!CS->body_empty()) {
329      SourceLocation Loc = (*CS->body_begin())->getLocStart();
330      return PathDiagnosticLocation(Loc, SM, SingleLocK);
331    }
332
333  return PathDiagnosticLocation();
334}
335
336PathDiagnosticLocation
337  PathDiagnosticLocation::createDeclEnd(const LocationContext *LC,
338                                        const SourceManager &SM) {
339  SourceLocation L = LC->getDecl()->getBodyRBrace();
340  return PathDiagnosticLocation(L, SM, SingleLocK);
341}
342
343PathDiagnosticLocation
344  PathDiagnosticLocation::create(const ProgramPoint& P,
345                                 const SourceManager &SMng) {
346
347  const Stmt* S = 0;
348  if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
349    const CFGBlock *BSrc = BE->getSrc();
350    S = BSrc->getTerminatorCondition();
351  }
352  else if (const PostStmt *PS = dyn_cast<PostStmt>(&P)) {
353    S = PS->getStmt();
354  }
355
356  return PathDiagnosticLocation(S, SMng, P.getLocationContext());
357}
358
359PathDiagnosticLocation
360  PathDiagnosticLocation::createEndOfPath(const ExplodedNode* N,
361                                          const SourceManager &SM) {
362  assert(N && "Cannot create a location with a null node.");
363
364  const ExplodedNode *NI = N;
365
366  while (NI) {
367    ProgramPoint P = NI->getLocation();
368    const LocationContext *LC = P.getLocationContext();
369    if (const StmtPoint *PS = dyn_cast<StmtPoint>(&P))
370      return PathDiagnosticLocation(PS->getStmt(), SM, LC);
371    else if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
372      const Stmt *Term = BE->getSrc()->getTerminator();
373      if (Term) {
374        return PathDiagnosticLocation(Term, SM, LC);
375      }
376    }
377    NI = NI->succ_empty() ? 0 : *(NI->succ_begin());
378  }
379
380  return createDeclEnd(N->getLocationContext(), SM);
381}
382
383PathDiagnosticLocation PathDiagnosticLocation::createSingleLocation(
384                                           const PathDiagnosticLocation &PDL) {
385  FullSourceLoc L = PDL.asLocation();
386  return PathDiagnosticLocation(L, L.getManager(), SingleLocK);
387}
388
389FullSourceLoc
390  PathDiagnosticLocation::genLocation(SourceLocation L,
391                                      LocationOrAnalysisDeclContext LAC) const {
392  assert(isValid());
393  // Note that we want a 'switch' here so that the compiler can warn us in
394  // case we add more cases.
395  switch (K) {
396    case SingleLocK:
397    case RangeK:
398      break;
399    case StmtK:
400      // Defensive checking.
401      if (!S)
402        break;
403      return FullSourceLoc(getValidSourceLocation(S, LAC),
404                           const_cast<SourceManager&>(*SM));
405    case DeclK:
406      // Defensive checking.
407      if (!D)
408        break;
409      return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM));
410  }
411
412  return FullSourceLoc(L, const_cast<SourceManager&>(*SM));
413}
414
415PathDiagnosticRange
416  PathDiagnosticLocation::genRange(LocationOrAnalysisDeclContext LAC) const {
417  assert(isValid());
418  // Note that we want a 'switch' here so that the compiler can warn us in
419  // case we add more cases.
420  switch (K) {
421    case SingleLocK:
422      return PathDiagnosticRange(SourceRange(Loc,Loc), true);
423    case RangeK:
424      break;
425    case StmtK: {
426      const Stmt *S = asStmt();
427      switch (S->getStmtClass()) {
428        default:
429          break;
430        case Stmt::DeclStmtClass: {
431          const DeclStmt *DS = cast<DeclStmt>(S);
432          if (DS->isSingleDecl()) {
433            // Should always be the case, but we'll be defensive.
434            return SourceRange(DS->getLocStart(),
435                               DS->getSingleDecl()->getLocation());
436          }
437          break;
438        }
439          // FIXME: Provide better range information for different
440          //  terminators.
441        case Stmt::IfStmtClass:
442        case Stmt::WhileStmtClass:
443        case Stmt::DoStmtClass:
444        case Stmt::ForStmtClass:
445        case Stmt::ChooseExprClass:
446        case Stmt::IndirectGotoStmtClass:
447        case Stmt::SwitchStmtClass:
448        case Stmt::BinaryConditionalOperatorClass:
449        case Stmt::ConditionalOperatorClass:
450        case Stmt::ObjCForCollectionStmtClass: {
451          SourceLocation L = getValidSourceLocation(S, LAC);
452          return SourceRange(L, L);
453        }
454      }
455      SourceRange R = S->getSourceRange();
456      if (R.isValid())
457        return R;
458      break;
459    }
460    case DeclK:
461      if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
462        return MD->getSourceRange();
463      if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
464        if (Stmt *Body = FD->getBody())
465          return Body->getSourceRange();
466      }
467      else {
468        SourceLocation L = D->getLocation();
469        return PathDiagnosticRange(SourceRange(L, L), true);
470      }
471  }
472
473  return SourceRange(Loc,Loc);
474}
475
476void PathDiagnosticLocation::flatten() {
477  if (K == StmtK) {
478    K = RangeK;
479    S = 0;
480    D = 0;
481  }
482  else if (K == DeclK) {
483    K = SingleLocK;
484    S = 0;
485    D = 0;
486  }
487}
488
489PathDiagnosticLocation PathDiagnostic::getLocation() const {
490  assert(path.size() > 0 &&
491         "getLocation() requires a non-empty PathDiagnostic.");
492
493  PathDiagnosticPiece *p = path.rbegin()->getPtr();
494
495  while (true) {
496    if (PathDiagnosticCallPiece *cp = dyn_cast<PathDiagnosticCallPiece>(p)) {
497      assert(!cp->path.empty());
498      p = cp->path.rbegin()->getPtr();
499      continue;
500    }
501    break;
502  }
503
504  return p->getLocation();
505}
506
507//===----------------------------------------------------------------------===//
508// Manipulation of PathDiagnosticCallPieces.
509//===----------------------------------------------------------------------===//
510
511static PathDiagnosticLocation
512getLocationForCaller(const StackFrameContext *SFC,
513                     const LocationContext *CallerCtx,
514                     const SourceManager &SM) {
515  const CFGBlock &Block = *SFC->getCallSiteBlock();
516  CFGElement Source = Block[SFC->getIndex()];
517
518  switch (Source.getKind()) {
519  case CFGElement::Invalid:
520    llvm_unreachable("Invalid CFGElement");
521  case CFGElement::Statement:
522    return PathDiagnosticLocation(cast<CFGStmt>(Source).getStmt(),
523                                  SM, CallerCtx);
524  case CFGElement::Initializer: {
525    const CFGInitializer &Init = cast<CFGInitializer>(Source);
526    return PathDiagnosticLocation(Init.getInitializer()->getInit(),
527                                  SM, CallerCtx);
528  }
529  case CFGElement::AutomaticObjectDtor: {
530    const CFGAutomaticObjDtor &Dtor = cast<CFGAutomaticObjDtor>(Source);
531    return PathDiagnosticLocation::createEnd(Dtor.getTriggerStmt(),
532                                             SM, CallerCtx);
533  }
534  case CFGElement::BaseDtor:
535  case CFGElement::MemberDtor:
536  case CFGElement::TemporaryDtor:
537    llvm_unreachable("not yet implemented!");
538  }
539
540  llvm_unreachable("Unknown CFGElement kind");
541}
542
543PathDiagnosticCallPiece *
544PathDiagnosticCallPiece::construct(const ExplodedNode *N,
545                                   const CallExitEnd &CE,
546                                   const SourceManager &SM) {
547  const Decl *caller = CE.getLocationContext()->getDecl();
548  PathDiagnosticLocation pos = getLocationForCaller(CE.getCalleeContext(),
549                                                    CE.getLocationContext(),
550                                                    SM);
551  return new PathDiagnosticCallPiece(caller, pos);
552}
553
554PathDiagnosticCallPiece *
555PathDiagnosticCallPiece::construct(PathPieces &path,
556                                   const Decl *caller) {
557  PathDiagnosticCallPiece *C = new PathDiagnosticCallPiece(path, caller);
558  path.clear();
559  path.push_front(C);
560  return C;
561}
562
563void PathDiagnosticCallPiece::setCallee(const CallEnter &CE,
564                                        const SourceManager &SM) {
565  const StackFrameContext *CalleeCtx = CE.getCalleeContext();
566  Callee = CalleeCtx->getDecl();
567
568  callEnterWithin = PathDiagnosticLocation::createBegin(Callee, SM);
569  callEnter = getLocationForCaller(CalleeCtx, CE.getLocationContext(), SM);
570}
571
572IntrusiveRefCntPtr<PathDiagnosticEventPiece>
573PathDiagnosticCallPiece::getCallEnterEvent() const {
574  if (!Callee)
575    return 0;
576  SmallString<256> buf;
577  llvm::raw_svector_ostream Out(buf);
578  if (isa<BlockDecl>(Callee))
579    Out << "Calling anonymous block";
580  else if (const NamedDecl *ND = dyn_cast<NamedDecl>(Callee))
581    Out << "Calling '" << *ND << "'";
582  StringRef msg = Out.str();
583  if (msg.empty())
584    return 0;
585  return new PathDiagnosticEventPiece(callEnter, msg);
586}
587
588IntrusiveRefCntPtr<PathDiagnosticEventPiece>
589PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const {
590  SmallString<256> buf;
591  llvm::raw_svector_ostream Out(buf);
592  if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Caller))
593    Out << "Entered call from '" << *ND << "'";
594  else
595    Out << "Entered call";
596  StringRef msg = Out.str();
597  if (msg.empty())
598    return 0;
599  return new PathDiagnosticEventPiece(callEnterWithin, msg);
600}
601
602IntrusiveRefCntPtr<PathDiagnosticEventPiece>
603PathDiagnosticCallPiece::getCallExitEvent() const {
604  if (NoExit)
605    return 0;
606  SmallString<256> buf;
607  llvm::raw_svector_ostream Out(buf);
608  if (!CallStackMessage.empty())
609    Out << CallStackMessage;
610  else if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Callee))
611    Out << "Returning from '" << *ND << "'";
612  else
613    Out << "Returning to caller";
614  return new PathDiagnosticEventPiece(callReturn, Out.str());
615}
616
617static void compute_path_size(const PathPieces &pieces, unsigned &size) {
618  for (PathPieces::const_iterator it = pieces.begin(),
619                                  et = pieces.end(); it != et; ++it) {
620    const PathDiagnosticPiece *piece = it->getPtr();
621    if (const PathDiagnosticCallPiece *cp =
622        dyn_cast<PathDiagnosticCallPiece>(piece)) {
623      compute_path_size(cp->path, size);
624    }
625    else
626      ++size;
627  }
628}
629
630unsigned PathDiagnostic::full_size() {
631  unsigned size = 0;
632  compute_path_size(path, size);
633  return size;
634}
635
636//===----------------------------------------------------------------------===//
637// FoldingSet profiling methods.
638//===----------------------------------------------------------------------===//
639
640void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const {
641  ID.AddInteger(Range.getBegin().getRawEncoding());
642  ID.AddInteger(Range.getEnd().getRawEncoding());
643  ID.AddInteger(Loc.getRawEncoding());
644  return;
645}
646
647void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const {
648  ID.AddInteger((unsigned) getKind());
649  ID.AddString(str);
650  // FIXME: Add profiling support for code hints.
651  ID.AddInteger((unsigned) getDisplayHint());
652  for (range_iterator I = ranges_begin(), E = ranges_end(); I != E; ++I) {
653    ID.AddInteger(I->getBegin().getRawEncoding());
654    ID.AddInteger(I->getEnd().getRawEncoding());
655  }
656}
657
658void PathDiagnosticCallPiece::Profile(llvm::FoldingSetNodeID &ID) const {
659  PathDiagnosticPiece::Profile(ID);
660  for (PathPieces::const_iterator it = path.begin(),
661       et = path.end(); it != et; ++it) {
662    ID.Add(**it);
663  }
664}
665
666void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const {
667  PathDiagnosticPiece::Profile(ID);
668  ID.Add(Pos);
669}
670
671void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const {
672  PathDiagnosticPiece::Profile(ID);
673  for (const_iterator I = begin(), E = end(); I != E; ++I)
674    ID.Add(*I);
675}
676
677void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const {
678  PathDiagnosticSpotPiece::Profile(ID);
679  for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end();
680       I != E; ++I)
681    ID.Add(**I);
682}
683
684void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const {
685  if (!path.empty())
686    getLocation().Profile(ID);
687  ID.AddString(BugType);
688  ID.AddString(Desc);
689  ID.AddString(Category);
690}
691
692void PathDiagnostic::FullProfile(llvm::FoldingSetNodeID &ID) const {
693  Profile(ID);
694  for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E; ++I)
695    ID.Add(**I);
696  for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I)
697    ID.AddString(*I);
698}
699
700StackHintGenerator::~StackHintGenerator() {}
701
702std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){
703  ProgramPoint P = N->getLocation();
704  const CallExitEnd *CExit = dyn_cast<CallExitEnd>(&P);
705  assert(CExit && "Stack Hints should be constructed at CallExitEnd points.");
706
707  // FIXME: Use CallEvent to abstract this over all calls.
708  const Stmt *CallSite = CExit->getCalleeContext()->getCallSite();
709  const CallExpr *CE = dyn_cast_or_null<CallExpr>(CallSite);
710  if (!CE)
711    return "";
712
713  if (!N)
714    return getMessageForSymbolNotFound();
715
716  // Check if one of the parameters are set to the interesting symbol.
717  ProgramStateRef State = N->getState();
718  const LocationContext *LCtx = N->getLocationContext();
719  unsigned ArgIndex = 0;
720  for (CallExpr::const_arg_iterator I = CE->arg_begin(),
721                                    E = CE->arg_end(); I != E; ++I, ++ArgIndex){
722    SVal SV = State->getSVal(*I, LCtx);
723
724    // Check if the variable corresponding to the symbol is passed by value.
725    SymbolRef AS = SV.getAsLocSymbol();
726    if (AS == Sym) {
727      return getMessageForArg(*I, ArgIndex);
728    }
729
730    // Check if the parameter is a pointer to the symbol.
731    if (const loc::MemRegionVal *Reg = dyn_cast<loc::MemRegionVal>(&SV)) {
732      SVal PSV = State->getSVal(Reg->getRegion());
733      SymbolRef AS = PSV.getAsLocSymbol();
734      if (AS == Sym) {
735        return getMessageForArg(*I, ArgIndex);
736      }
737    }
738  }
739
740  // Check if we are returning the interesting symbol.
741  SVal SV = State->getSVal(CE, LCtx);
742  SymbolRef RetSym = SV.getAsLocSymbol();
743  if (RetSym == Sym) {
744    return getMessageForReturn(CE);
745  }
746
747  return getMessageForSymbolNotFound();
748}
749
750/// TODO: This is copied from clang diagnostics. Maybe we could just move it to
751/// some common place. (Same as HandleOrdinalModifier.)
752void StackHintGeneratorForSymbol::printOrdinal(unsigned ValNo,
753                                               llvm::raw_svector_ostream &Out) {
754  assert(ValNo != 0 && "ValNo must be strictly positive!");
755
756  // We could use text forms for the first N ordinals, but the numeric
757  // forms are actually nicer in diagnostics because they stand out.
758  Out << ValNo;
759
760  // It is critically important that we do this perfectly for
761  // user-written sequences with over 100 elements.
762  switch (ValNo % 100) {
763  case 11:
764  case 12:
765  case 13:
766    Out << "th"; return;
767  default:
768    switch (ValNo % 10) {
769    case 1: Out << "st"; return;
770    case 2: Out << "nd"; return;
771    case 3: Out << "rd"; return;
772    default: Out << "th"; return;
773    }
774  }
775}
776
777std::string StackHintGeneratorForSymbol::getMessageForArg(const Expr *ArgE,
778                                                        unsigned ArgIndex) {
779  SmallString<200> buf;
780  llvm::raw_svector_ostream os(buf);
781
782  os << Msg << " via ";
783  // Printed parameters start at 1, not 0.
784  printOrdinal(++ArgIndex, os);
785  os << " parameter";
786
787  return os.str();
788}
789