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