clang API Documentation

PathDiagnostic.cpp
Go to the documentation of this file.
00001 //===--- PathDiagnostic.cpp - Path-Specific Diagnostic Handling -*- C++ -*-===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 //  This file defines the PathDiagnostic-related interfaces.
00011 //
00012 //===----------------------------------------------------------------------===//
00013 
00014 #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
00015 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
00016 #include "clang/Basic/SourceManager.h"
00017 #include "clang/AST/Expr.h"
00018 #include "clang/AST/Decl.h"
00019 #include "clang/AST/DeclObjC.h"
00020 #include "clang/AST/ParentMap.h"
00021 #include "clang/AST/StmtCXX.h"
00022 #include "llvm/ADT/SmallString.h"
00023 
00024 using namespace clang;
00025 using namespace ento;
00026 
00027 bool PathDiagnosticMacroPiece::containsEvent() const {
00028   for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end();
00029        I!=E; ++I) {
00030     if (isa<PathDiagnosticEventPiece>(*I))
00031       return true;
00032     if (PathDiagnosticMacroPiece *MP = dyn_cast<PathDiagnosticMacroPiece>(*I))
00033       if (MP->containsEvent())
00034         return true;
00035   }
00036   return false;
00037 }
00038 
00039 static StringRef StripTrailingDots(StringRef s) {
00040   for (StringRef::size_type i = s.size(); i != 0; --i)
00041     if (s[i - 1] != '.')
00042       return s.substr(0, i);
00043   return "";
00044 }
00045 
00046 PathDiagnosticPiece::PathDiagnosticPiece(StringRef s,
00047                                          Kind k, DisplayHint hint)
00048   : str(StripTrailingDots(s)), kind(k), Hint(hint) {}
00049 
00050 PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint)
00051   : kind(k), Hint(hint) {}
00052 
00053 PathDiagnosticPiece::~PathDiagnosticPiece() {}
00054 PathDiagnosticEventPiece::~PathDiagnosticEventPiece() {}
00055 PathDiagnosticCallPiece::~PathDiagnosticCallPiece() {}
00056 PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() {}
00057 PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() {}
00058 
00059 
00060 PathPieces::~PathPieces() {}
00061 PathDiagnostic::~PathDiagnostic() {}
00062 
00063 PathDiagnostic::PathDiagnostic(const Decl *declWithIssue,
00064                                StringRef bugtype, StringRef desc,
00065                                StringRef category)
00066   : DeclWithIssue(declWithIssue),
00067     BugType(StripTrailingDots(bugtype)),
00068     Desc(StripTrailingDots(desc)),
00069     Category(StripTrailingDots(category)),
00070     path(pathImpl) {}
00071 
00072 void PathDiagnosticConsumer::anchor() { }
00073 
00074 PathDiagnosticConsumer::~PathDiagnosticConsumer() {
00075   // Delete the contents of the FoldingSet if it isn't empty already.
00076   for (llvm::FoldingSet<PathDiagnostic>::iterator it =
00077        Diags.begin(), et = Diags.end() ; it != et ; ++it) {
00078     delete &*it;
00079   }
00080 }
00081 
00082 void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) {
00083   llvm::OwningPtr<PathDiagnostic> OwningD(D);
00084   
00085   if (!D || D->path.empty())
00086     return;
00087   
00088   // We need to flatten the locations (convert Stmt* to locations) because
00089   // the referenced statements may be freed by the time the diagnostics
00090   // are emitted.
00091   D->flattenLocations();
00092 
00093   // If the PathDiagnosticConsumer does not support diagnostics that
00094   // cross file boundaries, prune out such diagnostics now.
00095   if (!supportsCrossFileDiagnostics()) {
00096     // Verify that the entire path is from the same FileID.
00097     FileID FID;
00098     const SourceManager &SMgr = (*D->path.begin())->getLocation().getManager();
00099     llvm::SmallVector<const PathPieces *, 5> WorkList;
00100     WorkList.push_back(&D->path);
00101 
00102     while (!WorkList.empty()) {
00103       const PathPieces &path = *WorkList.back();
00104       WorkList.pop_back();
00105 
00106       for (PathPieces::const_iterator I = path.begin(), E = path.end();
00107            I != E; ++I) {
00108         const PathDiagnosticPiece *piece = I->getPtr();
00109         FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc();
00110       
00111         if (FID.isInvalid()) {
00112           FID = SMgr.getFileID(L);
00113         } else if (SMgr.getFileID(L) != FID)
00114           return; // FIXME: Emit a warning?
00115       
00116         // Check the source ranges.
00117         for (PathDiagnosticPiece::range_iterator RI = piece->ranges_begin(),
00118              RE = piece->ranges_end();
00119              RI != RE; ++RI) {
00120           SourceLocation L = SMgr.getExpansionLoc(RI->getBegin());
00121           if (!L.isFileID() || SMgr.getFileID(L) != FID)
00122             return; // FIXME: Emit a warning?
00123           L = SMgr.getExpansionLoc(RI->getEnd());
00124           if (!L.isFileID() || SMgr.getFileID(L) != FID)
00125             return; // FIXME: Emit a warning?
00126         }
00127         
00128         if (const PathDiagnosticCallPiece *call =
00129             dyn_cast<PathDiagnosticCallPiece>(piece)) {
00130           WorkList.push_back(&call->path);
00131         }
00132         else if (const PathDiagnosticMacroPiece *macro =
00133                  dyn_cast<PathDiagnosticMacroPiece>(piece)) {
00134           WorkList.push_back(&macro->subPieces);
00135         }
00136       }
00137     }
00138     
00139     if (FID.isInvalid())
00140       return; // FIXME: Emit a warning?
00141   }  
00142 
00143   // Profile the node to see if we already have something matching it
00144   llvm::FoldingSetNodeID profile;
00145   D->Profile(profile);
00146   void *InsertPos = 0;
00147 
00148   if (PathDiagnostic *orig = Diags.FindNodeOrInsertPos(profile, InsertPos)) {
00149     // Keep the PathDiagnostic with the shorter path.
00150     const unsigned orig_size = orig->full_size();
00151     const unsigned new_size = D->full_size();
00152     
00153     if (orig_size <= new_size) {
00154       bool shouldKeepOriginal = true;
00155       if (orig_size == new_size) {
00156         // Here we break ties in a fairly arbitrary, but deterministic, way.
00157         llvm::FoldingSetNodeID fullProfile, fullProfileOrig;
00158         D->FullProfile(fullProfile);
00159         orig->FullProfile(fullProfileOrig);
00160         if (fullProfile.ComputeHash() < fullProfileOrig.ComputeHash())
00161           shouldKeepOriginal = false;
00162       }
00163 
00164       if (shouldKeepOriginal)
00165         return;
00166     }
00167     Diags.RemoveNode(orig);
00168     delete orig;
00169   }
00170   
00171   Diags.InsertNode(OwningD.take());
00172 }
00173 
00174 
00175 namespace {
00176 struct CompareDiagnostics {
00177   // Compare if 'X' is "<" than 'Y'.
00178   bool operator()(const PathDiagnostic *X, const PathDiagnostic *Y) const {
00179     // First compare by location
00180     const FullSourceLoc &XLoc = X->getLocation().asLocation();
00181     const FullSourceLoc &YLoc = Y->getLocation().asLocation();
00182     if (XLoc < YLoc)
00183       return true;
00184     if (XLoc != YLoc)
00185       return false;
00186     
00187     // Next, compare by bug type.
00188     StringRef XBugType = X->getBugType();
00189     StringRef YBugType = Y->getBugType();
00190     if (XBugType < YBugType)
00191       return true;
00192     if (XBugType != YBugType)
00193       return false;
00194     
00195     // Next, compare by bug description.
00196     StringRef XDesc = X->getDescription();
00197     StringRef YDesc = Y->getDescription();
00198     if (XDesc < YDesc)
00199       return true;
00200     if (XDesc != YDesc)
00201       return false;
00202     
00203     // FIXME: Further refine by comparing PathDiagnosticPieces?
00204     return false;    
00205   }  
00206 };  
00207 }
00208 
00209 void
00210 PathDiagnosticConsumer::FlushDiagnostics(SmallVectorImpl<std::string> *Files) {
00211   if (flushed)
00212     return;
00213   
00214   flushed = true;
00215   
00216   std::vector<const PathDiagnostic *> BatchDiags;
00217   for (llvm::FoldingSet<PathDiagnostic>::iterator it = Diags.begin(),
00218        et = Diags.end(); it != et; ++it) {
00219     BatchDiags.push_back(&*it);
00220   }
00221   
00222   // Clear out the FoldingSet.
00223   Diags.clear();
00224 
00225   // Sort the diagnostics so that they are always emitted in a deterministic
00226   // order.
00227   if (!BatchDiags.empty())
00228     std::sort(BatchDiags.begin(), BatchDiags.end(), CompareDiagnostics());
00229   
00230   FlushDiagnosticsImpl(BatchDiags, Files);
00231 
00232   // Delete the flushed diagnostics.
00233   for (std::vector<const PathDiagnostic *>::iterator it = BatchDiags.begin(),
00234        et = BatchDiags.end(); it != et; ++it) {
00235     const PathDiagnostic *D = *it;
00236     delete D;
00237   }
00238 }
00239 
00240 //===----------------------------------------------------------------------===//
00241 // PathDiagnosticLocation methods.
00242 //===----------------------------------------------------------------------===//
00243 
00244 static SourceLocation getValidSourceLocation(const Stmt* S,
00245                                              LocationOrAnalysisDeclContext LAC) {
00246   SourceLocation L = S->getLocStart();
00247   assert(!LAC.isNull() && "A valid LocationContext or AnalysisDeclContext should "
00248                           "be passed to PathDiagnosticLocation upon creation.");
00249 
00250   // S might be a temporary statement that does not have a location in the
00251   // source code, so find an enclosing statement and use it's location.
00252   if (!L.isValid()) {
00253 
00254     ParentMap *PM = 0;
00255     if (LAC.is<const LocationContext*>())
00256       PM = &LAC.get<const LocationContext*>()->getParentMap();
00257     else
00258       PM = &LAC.get<AnalysisDeclContext*>()->getParentMap();
00259 
00260     while (!L.isValid()) {
00261       S = PM->getParent(S);
00262       L = S->getLocStart();
00263     }
00264   }
00265 
00266   return L;
00267 }
00268 
00269 PathDiagnosticLocation
00270   PathDiagnosticLocation::createBegin(const Decl *D,
00271                                       const SourceManager &SM) {
00272   return PathDiagnosticLocation(D->getLocStart(), SM, SingleLocK);
00273 }
00274 
00275 PathDiagnosticLocation
00276   PathDiagnosticLocation::createBegin(const Stmt *S,
00277                                       const SourceManager &SM,
00278                                       LocationOrAnalysisDeclContext LAC) {
00279   return PathDiagnosticLocation(getValidSourceLocation(S, LAC),
00280                                 SM, SingleLocK);
00281 }
00282 
00283 PathDiagnosticLocation
00284   PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO,
00285                                             const SourceManager &SM) {
00286   return PathDiagnosticLocation(BO->getOperatorLoc(), SM, SingleLocK);
00287 }
00288 
00289 PathDiagnosticLocation
00290   PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME,
00291                                           const SourceManager &SM) {
00292   return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK);
00293 }
00294 
00295 PathDiagnosticLocation
00296   PathDiagnosticLocation::createBeginBrace(const CompoundStmt *CS,
00297                                            const SourceManager &SM) {
00298   SourceLocation L = CS->getLBracLoc();
00299   return PathDiagnosticLocation(L, SM, SingleLocK);
00300 }
00301 
00302 PathDiagnosticLocation
00303   PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS,
00304                                          const SourceManager &SM) {
00305   SourceLocation L = CS->getRBracLoc();
00306   return PathDiagnosticLocation(L, SM, SingleLocK);
00307 }
00308 
00309 PathDiagnosticLocation
00310   PathDiagnosticLocation::createDeclBegin(const LocationContext *LC,
00311                                           const SourceManager &SM) {
00312   // FIXME: Should handle CXXTryStmt if analyser starts supporting C++.
00313   if (const CompoundStmt *CS =
00314         dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody()))
00315     if (!CS->body_empty()) {
00316       SourceLocation Loc = (*CS->body_begin())->getLocStart();
00317       return PathDiagnosticLocation(Loc, SM, SingleLocK);
00318     }
00319 
00320   return PathDiagnosticLocation();
00321 }
00322 
00323 PathDiagnosticLocation
00324   PathDiagnosticLocation::createDeclEnd(const LocationContext *LC,
00325                                         const SourceManager &SM) {
00326   SourceLocation L = LC->getDecl()->getBodyRBrace();
00327   return PathDiagnosticLocation(L, SM, SingleLocK);
00328 }
00329 
00330 PathDiagnosticLocation
00331   PathDiagnosticLocation::create(const ProgramPoint& P,
00332                                  const SourceManager &SMng) {
00333 
00334   const Stmt* S = 0;
00335   if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
00336     const CFGBlock *BSrc = BE->getSrc();
00337     S = BSrc->getTerminatorCondition();
00338   }
00339   else if (const PostStmt *PS = dyn_cast<PostStmt>(&P)) {
00340     S = PS->getStmt();
00341   }
00342 
00343   return PathDiagnosticLocation(S, SMng, P.getLocationContext());
00344 }
00345 
00346 PathDiagnosticLocation
00347   PathDiagnosticLocation::createEndOfPath(const ExplodedNode* N,
00348                                           const SourceManager &SM) {
00349   assert(N && "Cannot create a location with a null node.");
00350 
00351   const ExplodedNode *NI = N;
00352 
00353   while (NI) {
00354     ProgramPoint P = NI->getLocation();
00355     const LocationContext *LC = P.getLocationContext();
00356     if (const StmtPoint *PS = dyn_cast<StmtPoint>(&P))
00357       return PathDiagnosticLocation(PS->getStmt(), SM, LC);
00358     else if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
00359       const Stmt *Term = BE->getSrc()->getTerminator();
00360       if (Term) {
00361         return PathDiagnosticLocation(Term, SM, LC);
00362       }
00363     }
00364     NI = NI->succ_empty() ? 0 : *(NI->succ_begin());
00365   }
00366 
00367   return createDeclEnd(N->getLocationContext(), SM);
00368 }
00369 
00370 PathDiagnosticLocation PathDiagnosticLocation::createSingleLocation(
00371                                            const PathDiagnosticLocation &PDL) {
00372   FullSourceLoc L = PDL.asLocation();
00373   return PathDiagnosticLocation(L, L.getManager(), SingleLocK);
00374 }
00375 
00376 FullSourceLoc
00377   PathDiagnosticLocation::genLocation(SourceLocation L,
00378                                       LocationOrAnalysisDeclContext LAC) const {
00379   assert(isValid());
00380   // Note that we want a 'switch' here so that the compiler can warn us in
00381   // case we add more cases.
00382   switch (K) {
00383     case SingleLocK:
00384     case RangeK:
00385       break;
00386     case StmtK:
00387       // Defensive checking.
00388       if (!S)
00389         break;
00390       return FullSourceLoc(getValidSourceLocation(S, LAC),
00391                            const_cast<SourceManager&>(*SM));
00392     case DeclK:
00393       // Defensive checking.
00394       if (!D)
00395         break;
00396       return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM));
00397   }
00398 
00399   return FullSourceLoc(L, const_cast<SourceManager&>(*SM));
00400 }
00401 
00402 PathDiagnosticRange
00403   PathDiagnosticLocation::genRange(LocationOrAnalysisDeclContext LAC) const {
00404   assert(isValid());
00405   // Note that we want a 'switch' here so that the compiler can warn us in
00406   // case we add more cases.
00407   switch (K) {
00408     case SingleLocK:
00409       return PathDiagnosticRange(SourceRange(Loc,Loc), true);
00410     case RangeK:
00411       break;
00412     case StmtK: {
00413       const Stmt *S = asStmt();
00414       switch (S->getStmtClass()) {
00415         default:
00416           break;
00417         case Stmt::DeclStmtClass: {
00418           const DeclStmt *DS = cast<DeclStmt>(S);
00419           if (DS->isSingleDecl()) {
00420             // Should always be the case, but we'll be defensive.
00421             return SourceRange(DS->getLocStart(),
00422                                DS->getSingleDecl()->getLocation());
00423           }
00424           break;
00425         }
00426           // FIXME: Provide better range information for different
00427           //  terminators.
00428         case Stmt::IfStmtClass:
00429         case Stmt::WhileStmtClass:
00430         case Stmt::DoStmtClass:
00431         case Stmt::ForStmtClass:
00432         case Stmt::ChooseExprClass:
00433         case Stmt::IndirectGotoStmtClass:
00434         case Stmt::SwitchStmtClass:
00435         case Stmt::BinaryConditionalOperatorClass:
00436         case Stmt::ConditionalOperatorClass:
00437         case Stmt::ObjCForCollectionStmtClass: {
00438           SourceLocation L = getValidSourceLocation(S, LAC);
00439           return SourceRange(L, L);
00440         }
00441       }
00442       SourceRange R = S->getSourceRange();
00443       if (R.isValid())
00444         return R;
00445       break;  
00446     }
00447     case DeclK:
00448       if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
00449         return MD->getSourceRange();
00450       if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
00451         if (Stmt *Body = FD->getBody())
00452           return Body->getSourceRange();
00453       }
00454       else {
00455         SourceLocation L = D->getLocation();
00456         return PathDiagnosticRange(SourceRange(L, L), true);
00457       }
00458   }
00459 
00460   return SourceRange(Loc,Loc);
00461 }
00462 
00463 void PathDiagnosticLocation::flatten() {
00464   if (K == StmtK) {
00465     K = RangeK;
00466     S = 0;
00467     D = 0;
00468   }
00469   else if (K == DeclK) {
00470     K = SingleLocK;
00471     S = 0;
00472     D = 0;
00473   }
00474 }
00475 
00476 PathDiagnosticLocation PathDiagnostic::getLocation() const {
00477   assert(path.size() > 0 &&
00478          "getLocation() requires a non-empty PathDiagnostic.");
00479   
00480   PathDiagnosticPiece *p = path.rbegin()->getPtr();
00481   
00482   while (true) {
00483     if (PathDiagnosticCallPiece *cp = dyn_cast<PathDiagnosticCallPiece>(p)) {
00484       assert(!cp->path.empty());
00485       p = cp->path.rbegin()->getPtr();
00486       continue;
00487     }
00488     break;
00489   }
00490   
00491   return p->getLocation();
00492 }
00493 
00494 //===----------------------------------------------------------------------===//
00495 // Manipulation of PathDiagnosticCallPieces.
00496 //===----------------------------------------------------------------------===//
00497 
00498 static PathDiagnosticLocation getLastStmtLoc(const ExplodedNode *N,
00499                                              const SourceManager &SM) {
00500   while (N) {
00501     ProgramPoint PP = N->getLocation();
00502     if (const StmtPoint *SP = dyn_cast<StmtPoint>(&PP))
00503       return PathDiagnosticLocation(SP->getStmt(), SM, PP.getLocationContext());
00504     if (N->pred_empty())
00505       break;
00506     N = *N->pred_begin();
00507   }
00508   return PathDiagnosticLocation();
00509 }
00510 
00511 PathDiagnosticCallPiece *
00512 PathDiagnosticCallPiece::construct(const ExplodedNode *N,
00513                                    const CallExitEnd &CE,
00514                                    const SourceManager &SM) {
00515   const Decl *caller = CE.getLocationContext()->getDecl();
00516   PathDiagnosticLocation pos = getLastStmtLoc(N, SM);
00517   return new PathDiagnosticCallPiece(caller, pos);
00518 }
00519 
00520 PathDiagnosticCallPiece *
00521 PathDiagnosticCallPiece::construct(PathPieces &path,
00522                                    const Decl *caller) {
00523   PathDiagnosticCallPiece *C = new PathDiagnosticCallPiece(path, caller);
00524   path.clear();
00525   path.push_front(C);
00526   return C;
00527 }
00528 
00529 void PathDiagnosticCallPiece::setCallee(const CallEnter &CE,
00530                                         const SourceManager &SM) {
00531   const Decl *D = CE.getCalleeContext()->getDecl();
00532   Callee = D;
00533   callEnter = PathDiagnosticLocation(CE.getCallExpr(), SM,
00534                                      CE.getLocationContext());
00535   callEnterWithin = PathDiagnosticLocation::createBegin(D, SM);
00536 }
00537 
00538 IntrusiveRefCntPtr<PathDiagnosticEventPiece>
00539 PathDiagnosticCallPiece::getCallEnterEvent() const {
00540   if (!Callee)
00541     return 0;  
00542   SmallString<256> buf;
00543   llvm::raw_svector_ostream Out(buf);
00544   if (isa<BlockDecl>(Callee))
00545     Out << "Calling anonymous block";
00546   else if (const NamedDecl *ND = dyn_cast<NamedDecl>(Callee))
00547     Out << "Calling '" << *ND << "'";
00548   StringRef msg = Out.str();
00549   if (msg.empty())
00550     return 0;
00551   return new PathDiagnosticEventPiece(callEnter, msg);
00552 }
00553 
00554 IntrusiveRefCntPtr<PathDiagnosticEventPiece>
00555 PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const {
00556   SmallString<256> buf;
00557   llvm::raw_svector_ostream Out(buf);
00558   if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Caller))
00559     Out << "Entered call from '" << *ND << "'";
00560   else
00561     Out << "Entered call";
00562   StringRef msg = Out.str();
00563   if (msg.empty())
00564     return 0;
00565   return new PathDiagnosticEventPiece(callEnterWithin, msg);
00566 }
00567 
00568 IntrusiveRefCntPtr<PathDiagnosticEventPiece>
00569 PathDiagnosticCallPiece::getCallExitEvent() const {
00570   if (NoExit)
00571     return 0;
00572   SmallString<256> buf;
00573   llvm::raw_svector_ostream Out(buf);
00574   if (!CallStackMessage.empty())
00575     Out << CallStackMessage;
00576   else if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Callee))
00577     Out << "Returning from '" << *ND << "'";
00578   else
00579     Out << "Returning to caller";
00580   return new PathDiagnosticEventPiece(callReturn, Out.str());
00581 }
00582 
00583 static void compute_path_size(const PathPieces &pieces, unsigned &size) {
00584   for (PathPieces::const_iterator it = pieces.begin(),
00585                                   et = pieces.end(); it != et; ++it) {
00586     const PathDiagnosticPiece *piece = it->getPtr();
00587     if (const PathDiagnosticCallPiece *cp = 
00588         dyn_cast<PathDiagnosticCallPiece>(piece)) {
00589       compute_path_size(cp->path, size);
00590     }
00591     else
00592       ++size;
00593   }
00594 }
00595 
00596 unsigned PathDiagnostic::full_size() {
00597   unsigned size = 0;
00598   compute_path_size(path, size);
00599   return size;
00600 }
00601 
00602 //===----------------------------------------------------------------------===//
00603 // FoldingSet profiling methods.
00604 //===----------------------------------------------------------------------===//
00605 
00606 void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const {
00607   ID.AddInteger(Range.getBegin().getRawEncoding());
00608   ID.AddInteger(Range.getEnd().getRawEncoding());
00609   ID.AddInteger(Loc.getRawEncoding());
00610   return;
00611 }
00612 
00613 void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const {
00614   ID.AddInteger((unsigned) getKind());
00615   ID.AddString(str);
00616   // FIXME: Add profiling support for code hints.
00617   ID.AddInteger((unsigned) getDisplayHint());
00618   for (range_iterator I = ranges_begin(), E = ranges_end(); I != E; ++I) {
00619     ID.AddInteger(I->getBegin().getRawEncoding());
00620     ID.AddInteger(I->getEnd().getRawEncoding());
00621   }  
00622 }
00623 
00624 void PathDiagnosticCallPiece::Profile(llvm::FoldingSetNodeID &ID) const {
00625   PathDiagnosticPiece::Profile(ID);
00626   for (PathPieces::const_iterator it = path.begin(), 
00627        et = path.end(); it != et; ++it) {
00628     ID.Add(**it);
00629   }
00630 }
00631 
00632 void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const {
00633   PathDiagnosticPiece::Profile(ID);
00634   ID.Add(Pos);
00635 }
00636 
00637 void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const {
00638   PathDiagnosticPiece::Profile(ID);
00639   for (const_iterator I = begin(), E = end(); I != E; ++I)
00640     ID.Add(*I);
00641 }
00642 
00643 void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const {
00644   PathDiagnosticSpotPiece::Profile(ID);
00645   for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end();
00646        I != E; ++I)
00647     ID.Add(**I);
00648 }
00649 
00650 void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const {
00651   if (!path.empty())
00652     getLocation().Profile(ID);
00653   ID.AddString(BugType);
00654   ID.AddString(Desc);
00655   ID.AddString(Category);
00656 }
00657 
00658 void PathDiagnostic::FullProfile(llvm::FoldingSetNodeID &ID) const {
00659   Profile(ID);
00660   for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E; ++I)
00661     ID.Add(**I);
00662   for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I)
00663     ID.AddString(*I);
00664 }
00665 
00666 StackHintGenerator::~StackHintGenerator() {}
00667 
00668 std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){
00669   ProgramPoint P = N->getLocation();
00670   const CallExitEnd *CExit = dyn_cast<CallExitEnd>(&P);
00671   assert(CExit && "Stack Hints should be constructed at CallExitEnd points.");
00672 
00673   const CallExpr *CE = dyn_cast_or_null<CallExpr>(CExit->getStmt());
00674   if (!CE)
00675     return "";
00676 
00677   if (!N)
00678     return getMessageForSymbolNotFound();
00679 
00680   // Check if one of the parameters are set to the interesting symbol.
00681   ProgramStateRef State = N->getState();
00682   const LocationContext *LCtx = N->getLocationContext();
00683   unsigned ArgIndex = 0;
00684   for (CallExpr::const_arg_iterator I = CE->arg_begin(),
00685                                     E = CE->arg_end(); I != E; ++I, ++ArgIndex){
00686     SVal SV = State->getSVal(*I, LCtx);
00687 
00688     // Check if the variable corresponding to the symbol is passed by value.
00689     SymbolRef AS = SV.getAsLocSymbol();
00690     if (AS == Sym) {
00691       return getMessageForArg(*I, ArgIndex);
00692     }
00693 
00694     // Check if the parameter is a pointer to the symbol.
00695     if (const loc::MemRegionVal *Reg = dyn_cast<loc::MemRegionVal>(&SV)) {
00696       SVal PSV = State->getSVal(Reg->getRegion());
00697       SymbolRef AS = PSV.getAsLocSymbol();
00698       if (AS == Sym) {
00699         return getMessageForArg(*I, ArgIndex);
00700       }
00701     }
00702   }
00703 
00704   // Check if we are returning the interesting symbol.
00705   SVal SV = State->getSVal(CE, LCtx);
00706   SymbolRef RetSym = SV.getAsLocSymbol();
00707   if (RetSym == Sym) {
00708     return getMessageForReturn(CE);
00709   }
00710 
00711   return getMessageForSymbolNotFound();
00712 }
00713 
00714 /// TODO: This is copied from clang diagnostics. Maybe we could just move it to
00715 /// some common place. (Same as HandleOrdinalModifier.)
00716 void StackHintGeneratorForSymbol::printOrdinal(unsigned ValNo,
00717                                                llvm::raw_svector_ostream &Out) {
00718   assert(ValNo != 0 && "ValNo must be strictly positive!");
00719 
00720   // We could use text forms for the first N ordinals, but the numeric
00721   // forms are actually nicer in diagnostics because they stand out.
00722   Out << ValNo;
00723 
00724   // It is critically important that we do this perfectly for
00725   // user-written sequences with over 100 elements.
00726   switch (ValNo % 100) {
00727   case 11:
00728   case 12:
00729   case 13:
00730     Out << "th"; return;
00731   default:
00732     switch (ValNo % 10) {
00733     case 1: Out << "st"; return;
00734     case 2: Out << "nd"; return;
00735     case 3: Out << "rd"; return;
00736     default: Out << "th"; return;
00737     }
00738   }
00739 }
00740 
00741 std::string StackHintGeneratorForSymbol::getMessageForArg(const Expr *ArgE,
00742                                                         unsigned ArgIndex) {
00743   SmallString<200> buf;
00744   llvm::raw_svector_ostream os(buf);
00745 
00746   os << Msg << " via ";
00747   // Printed parameters start at 1, not 0.
00748   printOrdinal(++ArgIndex, os);
00749   os << " parameter";
00750 
00751   return os.str();
00752 }