PathDiagnostic.cpp revision 1d3ca251f9891623fac0dbe70eece42564e274ed
1//===--- PathDiagnostic.cpp - Path-Specific Diagnostic Handling -*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10//  This file defines the PathDiagnostic-related interfaces.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
15#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
16#include "clang/Basic/SourceManager.h"
17#include "clang/AST/Expr.h"
18#include "clang/AST/Decl.h"
19#include "clang/AST/DeclCXX.h"
20#include "clang/AST/DeclObjC.h"
21#include "clang/AST/ParentMap.h"
22#include "clang/AST/StmtCXX.h"
23#include "llvm/ADT/SmallString.h"
24
25using namespace clang;
26using namespace ento;
27
28bool PathDiagnosticMacroPiece::containsEvent() const {
29  for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end();
30       I!=E; ++I) {
31    if (isa<PathDiagnosticEventPiece>(*I))
32      return true;
33    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    AnalysisDeclContext *ADC;
257    if (LAC.is<const LocationContext*>())
258      ADC = LAC.get<const LocationContext*>()->getAnalysisDeclContext();
259    else
260      ADC = LAC.get<AnalysisDeclContext*>();
261
262    ParentMap &PM = ADC->getParentMap();
263
264    const Stmt *Parent = S;
265    do {
266      Parent = PM.getParent(Parent);
267
268      // In rare cases, we have implicit top-level expressions,
269      // such as arguments for implicit member initializers.
270      // In this case, fall back to the start of the body (even if we were
271      // asked for the statement end location).
272      if (!Parent) {
273        const Stmt *Body = ADC->getBody();
274        if (Body)
275          L = Body->getLocStart();
276        else
277          L = ADC->getDecl()->getLocEnd();
278        break;
279      }
280
281      L = UseEnd ? Parent->getLocEnd() : Parent->getLocStart();
282    } while (!L.isValid());
283  }
284
285  return L;
286}
287
288PathDiagnosticLocation
289  PathDiagnosticLocation::createBegin(const Decl *D,
290                                      const SourceManager &SM) {
291  return PathDiagnosticLocation(D->getLocStart(), SM, SingleLocK);
292}
293
294PathDiagnosticLocation
295  PathDiagnosticLocation::createBegin(const Stmt *S,
296                                      const SourceManager &SM,
297                                      LocationOrAnalysisDeclContext LAC) {
298  return PathDiagnosticLocation(getValidSourceLocation(S, LAC),
299                                SM, SingleLocK);
300}
301
302
303PathDiagnosticLocation
304PathDiagnosticLocation::createEnd(const Stmt *S,
305                                  const SourceManager &SM,
306                                  LocationOrAnalysisDeclContext LAC) {
307  if (const CompoundStmt *CS = dyn_cast<CompoundStmt>(S))
308    return createEndBrace(CS, SM);
309  return PathDiagnosticLocation(getValidSourceLocation(S, LAC, /*End=*/true),
310                                SM, SingleLocK);
311}
312
313PathDiagnosticLocation
314  PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO,
315                                            const SourceManager &SM) {
316  return PathDiagnosticLocation(BO->getOperatorLoc(), SM, SingleLocK);
317}
318
319PathDiagnosticLocation
320  PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME,
321                                          const SourceManager &SM) {
322  return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK);
323}
324
325PathDiagnosticLocation
326  PathDiagnosticLocation::createBeginBrace(const CompoundStmt *CS,
327                                           const SourceManager &SM) {
328  SourceLocation L = CS->getLBracLoc();
329  return PathDiagnosticLocation(L, SM, SingleLocK);
330}
331
332PathDiagnosticLocation
333  PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS,
334                                         const SourceManager &SM) {
335  SourceLocation L = CS->getRBracLoc();
336  return PathDiagnosticLocation(L, SM, SingleLocK);
337}
338
339PathDiagnosticLocation
340  PathDiagnosticLocation::createDeclBegin(const LocationContext *LC,
341                                          const SourceManager &SM) {
342  // FIXME: Should handle CXXTryStmt if analyser starts supporting C++.
343  if (const CompoundStmt *CS =
344        dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody()))
345    if (!CS->body_empty()) {
346      SourceLocation Loc = (*CS->body_begin())->getLocStart();
347      return PathDiagnosticLocation(Loc, SM, SingleLocK);
348    }
349
350  return PathDiagnosticLocation();
351}
352
353PathDiagnosticLocation
354  PathDiagnosticLocation::createDeclEnd(const LocationContext *LC,
355                                        const SourceManager &SM) {
356  SourceLocation L = LC->getDecl()->getBodyRBrace();
357  return PathDiagnosticLocation(L, SM, SingleLocK);
358}
359
360PathDiagnosticLocation
361  PathDiagnosticLocation::create(const ProgramPoint& P,
362                                 const SourceManager &SMng) {
363
364  const Stmt* S = 0;
365  if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
366    const CFGBlock *BSrc = BE->getSrc();
367    S = BSrc->getTerminatorCondition();
368  }
369  else if (const PostStmt *PS = dyn_cast<PostStmt>(&P)) {
370    S = PS->getStmt();
371  }
372
373  return PathDiagnosticLocation(S, SMng, P.getLocationContext());
374}
375
376PathDiagnosticLocation
377  PathDiagnosticLocation::createEndOfPath(const ExplodedNode* N,
378                                          const SourceManager &SM) {
379  assert(N && "Cannot create a location with a null node.");
380
381  const ExplodedNode *NI = N;
382
383  while (NI) {
384    ProgramPoint P = NI->getLocation();
385    const LocationContext *LC = P.getLocationContext();
386    if (const StmtPoint *PS = dyn_cast<StmtPoint>(&P))
387      return PathDiagnosticLocation(PS->getStmt(), SM, LC);
388    else if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
389      const Stmt *Term = BE->getSrc()->getTerminator();
390      if (Term) {
391        return PathDiagnosticLocation(Term, SM, LC);
392      }
393    }
394    NI = NI->succ_empty() ? 0 : *(NI->succ_begin());
395  }
396
397  return createDeclEnd(N->getLocationContext(), SM);
398}
399
400PathDiagnosticLocation PathDiagnosticLocation::createSingleLocation(
401                                           const PathDiagnosticLocation &PDL) {
402  FullSourceLoc L = PDL.asLocation();
403  return PathDiagnosticLocation(L, L.getManager(), SingleLocK);
404}
405
406FullSourceLoc
407  PathDiagnosticLocation::genLocation(SourceLocation L,
408                                      LocationOrAnalysisDeclContext LAC) const {
409  assert(isValid());
410  // Note that we want a 'switch' here so that the compiler can warn us in
411  // case we add more cases.
412  switch (K) {
413    case SingleLocK:
414    case RangeK:
415      break;
416    case StmtK:
417      // Defensive checking.
418      if (!S)
419        break;
420      return FullSourceLoc(getValidSourceLocation(S, LAC),
421                           const_cast<SourceManager&>(*SM));
422    case DeclK:
423      // Defensive checking.
424      if (!D)
425        break;
426      return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM));
427  }
428
429  return FullSourceLoc(L, const_cast<SourceManager&>(*SM));
430}
431
432PathDiagnosticRange
433  PathDiagnosticLocation::genRange(LocationOrAnalysisDeclContext LAC) const {
434  assert(isValid());
435  // Note that we want a 'switch' here so that the compiler can warn us in
436  // case we add more cases.
437  switch (K) {
438    case SingleLocK:
439      return PathDiagnosticRange(SourceRange(Loc,Loc), true);
440    case RangeK:
441      break;
442    case StmtK: {
443      const Stmt *S = asStmt();
444      switch (S->getStmtClass()) {
445        default:
446          break;
447        case Stmt::DeclStmtClass: {
448          const DeclStmt *DS = cast<DeclStmt>(S);
449          if (DS->isSingleDecl()) {
450            // Should always be the case, but we'll be defensive.
451            return SourceRange(DS->getLocStart(),
452                               DS->getSingleDecl()->getLocation());
453          }
454          break;
455        }
456          // FIXME: Provide better range information for different
457          //  terminators.
458        case Stmt::IfStmtClass:
459        case Stmt::WhileStmtClass:
460        case Stmt::DoStmtClass:
461        case Stmt::ForStmtClass:
462        case Stmt::ChooseExprClass:
463        case Stmt::IndirectGotoStmtClass:
464        case Stmt::SwitchStmtClass:
465        case Stmt::BinaryConditionalOperatorClass:
466        case Stmt::ConditionalOperatorClass:
467        case Stmt::ObjCForCollectionStmtClass: {
468          SourceLocation L = getValidSourceLocation(S, LAC);
469          return SourceRange(L, L);
470        }
471      }
472      SourceRange R = S->getSourceRange();
473      if (R.isValid())
474        return R;
475      break;
476    }
477    case DeclK:
478      if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
479        return MD->getSourceRange();
480      if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
481        if (Stmt *Body = FD->getBody())
482          return Body->getSourceRange();
483      }
484      else {
485        SourceLocation L = D->getLocation();
486        return PathDiagnosticRange(SourceRange(L, L), true);
487      }
488  }
489
490  return SourceRange(Loc,Loc);
491}
492
493void PathDiagnosticLocation::flatten() {
494  if (K == StmtK) {
495    K = RangeK;
496    S = 0;
497    D = 0;
498  }
499  else if (K == DeclK) {
500    K = SingleLocK;
501    S = 0;
502    D = 0;
503  }
504}
505
506PathDiagnosticLocation PathDiagnostic::getLocation() const {
507  assert(path.size() > 0 &&
508         "getLocation() requires a non-empty PathDiagnostic.");
509
510  PathDiagnosticPiece *p = path.rbegin()->getPtr();
511
512  while (true) {
513    if (PathDiagnosticCallPiece *cp = dyn_cast<PathDiagnosticCallPiece>(p)) {
514      assert(!cp->path.empty());
515      p = cp->path.rbegin()->getPtr();
516      continue;
517    }
518    break;
519  }
520
521  return p->getLocation();
522}
523
524//===----------------------------------------------------------------------===//
525// Manipulation of PathDiagnosticCallPieces.
526//===----------------------------------------------------------------------===//
527
528static PathDiagnosticLocation
529getLocationForCaller(const StackFrameContext *SFC,
530                     const LocationContext *CallerCtx,
531                     const SourceManager &SM) {
532  const CFGBlock &Block = *SFC->getCallSiteBlock();
533  CFGElement Source = Block[SFC->getIndex()];
534
535  switch (Source.getKind()) {
536  case CFGElement::Invalid:
537    llvm_unreachable("Invalid CFGElement");
538  case CFGElement::Statement:
539    return PathDiagnosticLocation(cast<CFGStmt>(Source).getStmt(),
540                                  SM, CallerCtx);
541  case CFGElement::Initializer: {
542    const CFGInitializer &Init = cast<CFGInitializer>(Source);
543    return PathDiagnosticLocation(Init.getInitializer()->getInit(),
544                                  SM, CallerCtx);
545  }
546  case CFGElement::AutomaticObjectDtor: {
547    const CFGAutomaticObjDtor &Dtor = cast<CFGAutomaticObjDtor>(Source);
548    return PathDiagnosticLocation::createEnd(Dtor.getTriggerStmt(),
549                                             SM, CallerCtx);
550  }
551  case CFGElement::BaseDtor:
552  case CFGElement::MemberDtor: {
553    const AnalysisDeclContext *CallerInfo = CallerCtx->getAnalysisDeclContext();
554    if (const Stmt *CallerBody = CallerInfo->getBody())
555      return PathDiagnosticLocation::createEnd(CallerBody, SM, CallerCtx);
556    return PathDiagnosticLocation::create(CallerInfo->getDecl(), SM);
557  }
558  case CFGElement::TemporaryDtor:
559    llvm_unreachable("not yet implemented!");
560  }
561
562  llvm_unreachable("Unknown CFGElement kind");
563}
564
565PathDiagnosticCallPiece *
566PathDiagnosticCallPiece::construct(const ExplodedNode *N,
567                                   const CallExitEnd &CE,
568                                   const SourceManager &SM) {
569  const Decl *caller = CE.getLocationContext()->getDecl();
570  PathDiagnosticLocation pos = getLocationForCaller(CE.getCalleeContext(),
571                                                    CE.getLocationContext(),
572                                                    SM);
573  return new PathDiagnosticCallPiece(caller, pos);
574}
575
576PathDiagnosticCallPiece *
577PathDiagnosticCallPiece::construct(PathPieces &path,
578                                   const Decl *caller) {
579  PathDiagnosticCallPiece *C = new PathDiagnosticCallPiece(path, caller);
580  path.clear();
581  path.push_front(C);
582  return C;
583}
584
585void PathDiagnosticCallPiece::setCallee(const CallEnter &CE,
586                                        const SourceManager &SM) {
587  const StackFrameContext *CalleeCtx = CE.getCalleeContext();
588  Callee = CalleeCtx->getDecl();
589
590  callEnterWithin = PathDiagnosticLocation::createBegin(Callee, SM);
591  callEnter = getLocationForCaller(CalleeCtx, CE.getLocationContext(), SM);
592}
593
594IntrusiveRefCntPtr<PathDiagnosticEventPiece>
595PathDiagnosticCallPiece::getCallEnterEvent() const {
596  if (!Callee)
597    return 0;
598  SmallString<256> buf;
599  llvm::raw_svector_ostream Out(buf);
600  if (isa<BlockDecl>(Callee))
601    Out << "Calling anonymous block";
602  else if (const NamedDecl *ND = dyn_cast<NamedDecl>(Callee))
603    Out << "Calling '" << *ND << "'";
604  StringRef msg = Out.str();
605  if (msg.empty())
606    return 0;
607  return new PathDiagnosticEventPiece(callEnter, msg);
608}
609
610IntrusiveRefCntPtr<PathDiagnosticEventPiece>
611PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const {
612  SmallString<256> buf;
613  llvm::raw_svector_ostream Out(buf);
614  if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Caller))
615    Out << "Entered call from '" << *ND << "'";
616  else
617    Out << "Entered call";
618  StringRef msg = Out.str();
619  if (msg.empty())
620    return 0;
621  return new PathDiagnosticEventPiece(callEnterWithin, msg);
622}
623
624IntrusiveRefCntPtr<PathDiagnosticEventPiece>
625PathDiagnosticCallPiece::getCallExitEvent() const {
626  if (NoExit)
627    return 0;
628  SmallString<256> buf;
629  llvm::raw_svector_ostream Out(buf);
630  if (!CallStackMessage.empty())
631    Out << CallStackMessage;
632  else if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Callee))
633    Out << "Returning from '" << *ND << "'";
634  else
635    Out << "Returning to caller";
636  return new PathDiagnosticEventPiece(callReturn, Out.str());
637}
638
639static void compute_path_size(const PathPieces &pieces, unsigned &size) {
640  for (PathPieces::const_iterator it = pieces.begin(),
641                                  et = pieces.end(); it != et; ++it) {
642    const PathDiagnosticPiece *piece = it->getPtr();
643    if (const PathDiagnosticCallPiece *cp =
644        dyn_cast<PathDiagnosticCallPiece>(piece)) {
645      compute_path_size(cp->path, size);
646    }
647    else
648      ++size;
649  }
650}
651
652unsigned PathDiagnostic::full_size() {
653  unsigned size = 0;
654  compute_path_size(path, size);
655  return size;
656}
657
658//===----------------------------------------------------------------------===//
659// FoldingSet profiling methods.
660//===----------------------------------------------------------------------===//
661
662void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const {
663  ID.AddInteger(Range.getBegin().getRawEncoding());
664  ID.AddInteger(Range.getEnd().getRawEncoding());
665  ID.AddInteger(Loc.getRawEncoding());
666  return;
667}
668
669void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const {
670  ID.AddInteger((unsigned) getKind());
671  ID.AddString(str);
672  // FIXME: Add profiling support for code hints.
673  ID.AddInteger((unsigned) getDisplayHint());
674  for (range_iterator I = ranges_begin(), E = ranges_end(); I != E; ++I) {
675    ID.AddInteger(I->getBegin().getRawEncoding());
676    ID.AddInteger(I->getEnd().getRawEncoding());
677  }
678}
679
680void PathDiagnosticCallPiece::Profile(llvm::FoldingSetNodeID &ID) const {
681  PathDiagnosticPiece::Profile(ID);
682  for (PathPieces::const_iterator it = path.begin(),
683       et = path.end(); it != et; ++it) {
684    ID.Add(**it);
685  }
686}
687
688void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const {
689  PathDiagnosticPiece::Profile(ID);
690  ID.Add(Pos);
691}
692
693void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const {
694  PathDiagnosticPiece::Profile(ID);
695  for (const_iterator I = begin(), E = end(); I != E; ++I)
696    ID.Add(*I);
697}
698
699void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const {
700  PathDiagnosticSpotPiece::Profile(ID);
701  for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end();
702       I != E; ++I)
703    ID.Add(**I);
704}
705
706void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const {
707  if (!path.empty())
708    getLocation().Profile(ID);
709  ID.AddString(BugType);
710  ID.AddString(Desc);
711  ID.AddString(Category);
712}
713
714void PathDiagnostic::FullProfile(llvm::FoldingSetNodeID &ID) const {
715  Profile(ID);
716  for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E; ++I)
717    ID.Add(**I);
718  for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I)
719    ID.AddString(*I);
720}
721
722StackHintGenerator::~StackHintGenerator() {}
723
724std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){
725  ProgramPoint P = N->getLocation();
726  const CallExitEnd *CExit = dyn_cast<CallExitEnd>(&P);
727  assert(CExit && "Stack Hints should be constructed at CallExitEnd points.");
728
729  // FIXME: Use CallEvent to abstract this over all calls.
730  const Stmt *CallSite = CExit->getCalleeContext()->getCallSite();
731  const CallExpr *CE = dyn_cast_or_null<CallExpr>(CallSite);
732  if (!CE)
733    return "";
734
735  if (!N)
736    return getMessageForSymbolNotFound();
737
738  // Check if one of the parameters are set to the interesting symbol.
739  ProgramStateRef State = N->getState();
740  const LocationContext *LCtx = N->getLocationContext();
741  unsigned ArgIndex = 0;
742  for (CallExpr::const_arg_iterator I = CE->arg_begin(),
743                                    E = CE->arg_end(); I != E; ++I, ++ArgIndex){
744    SVal SV = State->getSVal(*I, LCtx);
745
746    // Check if the variable corresponding to the symbol is passed by value.
747    SymbolRef AS = SV.getAsLocSymbol();
748    if (AS == Sym) {
749      return getMessageForArg(*I, ArgIndex);
750    }
751
752    // Check if the parameter is a pointer to the symbol.
753    if (const loc::MemRegionVal *Reg = dyn_cast<loc::MemRegionVal>(&SV)) {
754      SVal PSV = State->getSVal(Reg->getRegion());
755      SymbolRef AS = PSV.getAsLocSymbol();
756      if (AS == Sym) {
757        return getMessageForArg(*I, ArgIndex);
758      }
759    }
760  }
761
762  // Check if we are returning the interesting symbol.
763  SVal SV = State->getSVal(CE, LCtx);
764  SymbolRef RetSym = SV.getAsLocSymbol();
765  if (RetSym == Sym) {
766    return getMessageForReturn(CE);
767  }
768
769  return getMessageForSymbolNotFound();
770}
771
772/// TODO: This is copied from clang diagnostics. Maybe we could just move it to
773/// some common place. (Same as HandleOrdinalModifier.)
774void StackHintGeneratorForSymbol::printOrdinal(unsigned ValNo,
775                                               llvm::raw_svector_ostream &Out) {
776  assert(ValNo != 0 && "ValNo must be strictly positive!");
777
778  // We could use text forms for the first N ordinals, but the numeric
779  // forms are actually nicer in diagnostics because they stand out.
780  Out << ValNo;
781
782  // It is critically important that we do this perfectly for
783  // user-written sequences with over 100 elements.
784  switch (ValNo % 100) {
785  case 11:
786  case 12:
787  case 13:
788    Out << "th"; return;
789  default:
790    switch (ValNo % 10) {
791    case 1: Out << "st"; return;
792    case 2: Out << "nd"; return;
793    case 3: Out << "rd"; return;
794    default: Out << "th"; return;
795    }
796  }
797}
798
799std::string StackHintGeneratorForSymbol::getMessageForArg(const Expr *ArgE,
800                                                        unsigned ArgIndex) {
801  SmallString<200> buf;
802  llvm::raw_svector_ostream os(buf);
803
804  os << Msg << " via ";
805  // Printed parameters start at 1, not 0.
806  printOrdinal(++ArgIndex, os);
807  os << " parameter";
808
809  return os.str();
810}
811