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