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/AST/Decl.h"
     16 #include "clang/AST/DeclCXX.h"
     17 #include "clang/AST/DeclObjC.h"
     18 #include "clang/AST/Expr.h"
     19 #include "clang/AST/ParentMap.h"
     20 #include "clang/AST/StmtCXX.h"
     21 #include "clang/Basic/SourceManager.h"
     22 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
     23 #include "llvm/ADT/SmallString.h"
     24 #include "llvm/ADT/StringExtras.h"
     25 #include "llvm/Support/raw_ostream.h"
     26 
     27 using namespace clang;
     28 using namespace ento;
     29 
     30 bool PathDiagnosticMacroPiece::containsEvent() const {
     31   for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end();
     32        I!=E; ++I) {
     33     if (isa<PathDiagnosticEventPiece>(*I))
     34       return true;
     35     if (PathDiagnosticMacroPiece *MP = dyn_cast<PathDiagnosticMacroPiece>(*I))
     36       if (MP->containsEvent())
     37         return true;
     38   }
     39   return false;
     40 }
     41 
     42 static StringRef StripTrailingDots(StringRef s) {
     43   for (StringRef::size_type i = s.size(); i != 0; --i)
     44     if (s[i - 1] != '.')
     45       return s.substr(0, i);
     46   return "";
     47 }
     48 
     49 PathDiagnosticPiece::PathDiagnosticPiece(StringRef s,
     50                                          Kind k, DisplayHint hint)
     51   : str(StripTrailingDots(s)), kind(k), Hint(hint),
     52     LastInMainSourceFile(false) {}
     53 
     54 PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint)
     55   : kind(k), Hint(hint), LastInMainSourceFile(false) {}
     56 
     57 PathDiagnosticPiece::~PathDiagnosticPiece() {}
     58 PathDiagnosticEventPiece::~PathDiagnosticEventPiece() {}
     59 PathDiagnosticCallPiece::~PathDiagnosticCallPiece() {}
     60 PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() {}
     61 PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() {}
     62 
     63 
     64 PathPieces::~PathPieces() {}
     65 
     66 void PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current,
     67                            bool ShouldFlattenMacros) const {
     68   for (PathPieces::const_iterator I = begin(), E = end(); I != E; ++I) {
     69     PathDiagnosticPiece *Piece = I->getPtr();
     70 
     71     switch (Piece->getKind()) {
     72     case PathDiagnosticPiece::Call: {
     73       PathDiagnosticCallPiece *Call = cast<PathDiagnosticCallPiece>(Piece);
     74       IntrusiveRefCntPtr<PathDiagnosticEventPiece> CallEnter =
     75         Call->getCallEnterEvent();
     76       if (CallEnter)
     77         Current.push_back(CallEnter);
     78       Call->path.flattenTo(Primary, Primary, ShouldFlattenMacros);
     79       IntrusiveRefCntPtr<PathDiagnosticEventPiece> callExit =
     80         Call->getCallExitEvent();
     81       if (callExit)
     82         Current.push_back(callExit);
     83       break;
     84     }
     85     case PathDiagnosticPiece::Macro: {
     86       PathDiagnosticMacroPiece *Macro = cast<PathDiagnosticMacroPiece>(Piece);
     87       if (ShouldFlattenMacros) {
     88         Macro->subPieces.flattenTo(Primary, Primary, ShouldFlattenMacros);
     89       } else {
     90         Current.push_back(Piece);
     91         PathPieces NewPath;
     92         Macro->subPieces.flattenTo(Primary, NewPath, ShouldFlattenMacros);
     93         // FIXME: This probably shouldn't mutate the original path piece.
     94         Macro->subPieces = NewPath;
     95       }
     96       break;
     97     }
     98     case PathDiagnosticPiece::Event:
     99     case PathDiagnosticPiece::ControlFlow:
    100       Current.push_back(Piece);
    101       break;
    102     }
    103   }
    104 }
    105 
    106 
    107 PathDiagnostic::~PathDiagnostic() {}
    108 
    109 PathDiagnostic::PathDiagnostic(const Decl *declWithIssue,
    110                                StringRef bugtype, StringRef verboseDesc,
    111                                StringRef shortDesc, StringRef category,
    112                                PathDiagnosticLocation LocationToUnique,
    113                                const Decl *DeclToUnique)
    114   : DeclWithIssue(declWithIssue),
    115     BugType(StripTrailingDots(bugtype)),
    116     VerboseDesc(StripTrailingDots(verboseDesc)),
    117     ShortDesc(StripTrailingDots(shortDesc)),
    118     Category(StripTrailingDots(category)),
    119     UniqueingLoc(LocationToUnique),
    120     UniqueingDecl(DeclToUnique),
    121     path(pathImpl) {}
    122 
    123 static PathDiagnosticCallPiece *
    124 getFirstStackedCallToHeaderFile(PathDiagnosticCallPiece *CP,
    125                                 const SourceManager &SMgr) {
    126   SourceLocation CallLoc = CP->callEnter.asLocation();
    127 
    128   // If the call is within a macro, don't do anything (for now).
    129   if (CallLoc.isMacroID())
    130     return 0;
    131 
    132   assert(SMgr.isFromMainFile(CallLoc) &&
    133          "The call piece should be in the main file.");
    134 
    135   // Check if CP represents a path through a function outside of the main file.
    136   if (!SMgr.isFromMainFile(CP->callEnterWithin.asLocation()))
    137     return CP;
    138 
    139   const PathPieces &Path = CP->path;
    140   if (Path.empty())
    141     return 0;
    142 
    143   // Check if the last piece in the callee path is a call to a function outside
    144   // of the main file.
    145   if (PathDiagnosticCallPiece *CPInner =
    146       dyn_cast<PathDiagnosticCallPiece>(Path.back())) {
    147     return getFirstStackedCallToHeaderFile(CPInner, SMgr);
    148   }
    149 
    150   // Otherwise, the last piece is in the main file.
    151   return 0;
    152 }
    153 
    154 void PathDiagnostic::resetDiagnosticLocationToMainFile() {
    155   if (path.empty())
    156     return;
    157 
    158   PathDiagnosticPiece *LastP = path.back().getPtr();
    159   assert(LastP);
    160   const SourceManager &SMgr = LastP->getLocation().getManager();
    161 
    162   // We only need to check if the report ends inside headers, if the last piece
    163   // is a call piece.
    164   if (PathDiagnosticCallPiece *CP = dyn_cast<PathDiagnosticCallPiece>(LastP)) {
    165     CP = getFirstStackedCallToHeaderFile(CP, SMgr);
    166     if (CP) {
    167       // Mark the piece.
    168        CP->setAsLastInMainSourceFile();
    169 
    170       // Update the path diagnostic message.
    171       const NamedDecl *ND = dyn_cast<NamedDecl>(CP->getCallee());
    172       if (ND) {
    173         SmallString<200> buf;
    174         llvm::raw_svector_ostream os(buf);
    175         os << " (within a call to '" << ND->getDeclName() << "')";
    176         appendToDesc(os.str());
    177       }
    178 
    179       // Reset the report containing declaration and location.
    180       DeclWithIssue = CP->getCaller();
    181       Loc = CP->getLocation();
    182 
    183       return;
    184     }
    185   }
    186 }
    187 
    188 void PathDiagnosticConsumer::anchor() { }
    189 
    190 PathDiagnosticConsumer::~PathDiagnosticConsumer() {
    191   // Delete the contents of the FoldingSet if it isn't empty already.
    192   for (llvm::FoldingSet<PathDiagnostic>::iterator it =
    193        Diags.begin(), et = Diags.end() ; it != et ; ++it) {
    194     delete &*it;
    195   }
    196 }
    197 
    198 void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) {
    199   OwningPtr<PathDiagnostic> OwningD(D);
    200 
    201   if (!D || D->path.empty())
    202     return;
    203 
    204   // We need to flatten the locations (convert Stmt* to locations) because
    205   // the referenced statements may be freed by the time the diagnostics
    206   // are emitted.
    207   D->flattenLocations();
    208 
    209   // If the PathDiagnosticConsumer does not support diagnostics that
    210   // cross file boundaries, prune out such diagnostics now.
    211   if (!supportsCrossFileDiagnostics()) {
    212     // Verify that the entire path is from the same FileID.
    213     FileID FID;
    214     const SourceManager &SMgr = (*D->path.begin())->getLocation().getManager();
    215     SmallVector<const PathPieces *, 5> WorkList;
    216     WorkList.push_back(&D->path);
    217 
    218     while (!WorkList.empty()) {
    219       const PathPieces &path = *WorkList.back();
    220       WorkList.pop_back();
    221 
    222       for (PathPieces::const_iterator I = path.begin(), E = path.end();
    223            I != E; ++I) {
    224         const PathDiagnosticPiece *piece = I->getPtr();
    225         FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc();
    226 
    227         if (FID.isInvalid()) {
    228           FID = SMgr.getFileID(L);
    229         } else if (SMgr.getFileID(L) != FID)
    230           return; // FIXME: Emit a warning?
    231 
    232         // Check the source ranges.
    233         ArrayRef<SourceRange> Ranges = piece->getRanges();
    234         for (ArrayRef<SourceRange>::iterator I = Ranges.begin(),
    235                                              E = Ranges.end(); I != E; ++I) {
    236           SourceLocation L = SMgr.getExpansionLoc(I->getBegin());
    237           if (!L.isFileID() || SMgr.getFileID(L) != FID)
    238             return; // FIXME: Emit a warning?
    239           L = SMgr.getExpansionLoc(I->getEnd());
    240           if (!L.isFileID() || SMgr.getFileID(L) != FID)
    241             return; // FIXME: Emit a warning?
    242         }
    243 
    244         if (const PathDiagnosticCallPiece *call =
    245             dyn_cast<PathDiagnosticCallPiece>(piece)) {
    246           WorkList.push_back(&call->path);
    247         }
    248         else if (const PathDiagnosticMacroPiece *macro =
    249                  dyn_cast<PathDiagnosticMacroPiece>(piece)) {
    250           WorkList.push_back(&macro->subPieces);
    251         }
    252       }
    253     }
    254 
    255     if (FID.isInvalid())
    256       return; // FIXME: Emit a warning?
    257   }
    258 
    259   // Profile the node to see if we already have something matching it
    260   llvm::FoldingSetNodeID profile;
    261   D->Profile(profile);
    262   void *InsertPos = 0;
    263 
    264   if (PathDiagnostic *orig = Diags.FindNodeOrInsertPos(profile, InsertPos)) {
    265     // Keep the PathDiagnostic with the shorter path.
    266     // Note, the enclosing routine is called in deterministic order, so the
    267     // results will be consistent between runs (no reason to break ties if the
    268     // size is the same).
    269     const unsigned orig_size = orig->full_size();
    270     const unsigned new_size = D->full_size();
    271     if (orig_size <= new_size)
    272       return;
    273 
    274     assert(orig != D);
    275     Diags.RemoveNode(orig);
    276     delete orig;
    277   }
    278 
    279   Diags.InsertNode(OwningD.take());
    280 }
    281 
    282 static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y);
    283 static Optional<bool>
    284 compareControlFlow(const PathDiagnosticControlFlowPiece &X,
    285                    const PathDiagnosticControlFlowPiece &Y) {
    286   FullSourceLoc XSL = X.getStartLocation().asLocation();
    287   FullSourceLoc YSL = Y.getStartLocation().asLocation();
    288   if (XSL != YSL)
    289     return XSL.isBeforeInTranslationUnitThan(YSL);
    290   FullSourceLoc XEL = X.getEndLocation().asLocation();
    291   FullSourceLoc YEL = Y.getEndLocation().asLocation();
    292   if (XEL != YEL)
    293     return XEL.isBeforeInTranslationUnitThan(YEL);
    294   return None;
    295 }
    296 
    297 static Optional<bool> compareMacro(const PathDiagnosticMacroPiece &X,
    298                                    const PathDiagnosticMacroPiece &Y) {
    299   return comparePath(X.subPieces, Y.subPieces);
    300 }
    301 
    302 static Optional<bool> compareCall(const PathDiagnosticCallPiece &X,
    303                                   const PathDiagnosticCallPiece &Y) {
    304   FullSourceLoc X_CEL = X.callEnter.asLocation();
    305   FullSourceLoc Y_CEL = Y.callEnter.asLocation();
    306   if (X_CEL != Y_CEL)
    307     return X_CEL.isBeforeInTranslationUnitThan(Y_CEL);
    308   FullSourceLoc X_CEWL = X.callEnterWithin.asLocation();
    309   FullSourceLoc Y_CEWL = Y.callEnterWithin.asLocation();
    310   if (X_CEWL != Y_CEWL)
    311     return X_CEWL.isBeforeInTranslationUnitThan(Y_CEWL);
    312   FullSourceLoc X_CRL = X.callReturn.asLocation();
    313   FullSourceLoc Y_CRL = Y.callReturn.asLocation();
    314   if (X_CRL != Y_CRL)
    315     return X_CRL.isBeforeInTranslationUnitThan(Y_CRL);
    316   return comparePath(X.path, Y.path);
    317 }
    318 
    319 static Optional<bool> comparePiece(const PathDiagnosticPiece &X,
    320                                    const PathDiagnosticPiece &Y) {
    321   if (X.getKind() != Y.getKind())
    322     return X.getKind() < Y.getKind();
    323 
    324   FullSourceLoc XL = X.getLocation().asLocation();
    325   FullSourceLoc YL = Y.getLocation().asLocation();
    326   if (XL != YL)
    327     return XL.isBeforeInTranslationUnitThan(YL);
    328 
    329   if (X.getString() != Y.getString())
    330     return X.getString() < Y.getString();
    331 
    332   if (X.getRanges().size() != Y.getRanges().size())
    333     return X.getRanges().size() < Y.getRanges().size();
    334 
    335   const SourceManager &SM = XL.getManager();
    336 
    337   for (unsigned i = 0, n = X.getRanges().size(); i < n; ++i) {
    338     SourceRange XR = X.getRanges()[i];
    339     SourceRange YR = Y.getRanges()[i];
    340     if (XR != YR) {
    341       if (XR.getBegin() != YR.getBegin())
    342         return SM.isBeforeInTranslationUnit(XR.getBegin(), YR.getBegin());
    343       return SM.isBeforeInTranslationUnit(XR.getEnd(), YR.getEnd());
    344     }
    345   }
    346 
    347   switch (X.getKind()) {
    348     case clang::ento::PathDiagnosticPiece::ControlFlow:
    349       return compareControlFlow(cast<PathDiagnosticControlFlowPiece>(X),
    350                                 cast<PathDiagnosticControlFlowPiece>(Y));
    351     case clang::ento::PathDiagnosticPiece::Event:
    352       return None;
    353     case clang::ento::PathDiagnosticPiece::Macro:
    354       return compareMacro(cast<PathDiagnosticMacroPiece>(X),
    355                           cast<PathDiagnosticMacroPiece>(Y));
    356     case clang::ento::PathDiagnosticPiece::Call:
    357       return compareCall(cast<PathDiagnosticCallPiece>(X),
    358                          cast<PathDiagnosticCallPiece>(Y));
    359   }
    360   llvm_unreachable("all cases handled");
    361 }
    362 
    363 static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y) {
    364   if (X.size() != Y.size())
    365     return X.size() < Y.size();
    366 
    367   PathPieces::const_iterator X_I = X.begin(), X_end = X.end();
    368   PathPieces::const_iterator Y_I = Y.begin(), Y_end = Y.end();
    369 
    370   for ( ; X_I != X_end && Y_I != Y_end; ++X_I, ++Y_I) {
    371     Optional<bool> b = comparePiece(**X_I, **Y_I);
    372     if (b.hasValue())
    373       return b.getValue();
    374   }
    375 
    376   return None;
    377 }
    378 
    379 static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) {
    380   FullSourceLoc XL = X.getLocation().asLocation();
    381   FullSourceLoc YL = Y.getLocation().asLocation();
    382   if (XL != YL)
    383     return XL.isBeforeInTranslationUnitThan(YL);
    384   if (X.getBugType() != Y.getBugType())
    385     return X.getBugType() < Y.getBugType();
    386   if (X.getCategory() != Y.getCategory())
    387     return X.getCategory() < Y.getCategory();
    388   if (X.getVerboseDescription() != Y.getVerboseDescription())
    389     return X.getVerboseDescription() < Y.getVerboseDescription();
    390   if (X.getShortDescription() != Y.getShortDescription())
    391     return X.getShortDescription() < Y.getShortDescription();
    392   if (X.getDeclWithIssue() != Y.getDeclWithIssue()) {
    393     const Decl *XD = X.getDeclWithIssue();
    394     if (!XD)
    395       return true;
    396     const Decl *YD = Y.getDeclWithIssue();
    397     if (!YD)
    398       return false;
    399     SourceLocation XDL = XD->getLocation();
    400     SourceLocation YDL = YD->getLocation();
    401     if (XDL != YDL) {
    402       const SourceManager &SM = XL.getManager();
    403       return SM.isBeforeInTranslationUnit(XDL, YDL);
    404     }
    405   }
    406   PathDiagnostic::meta_iterator XI = X.meta_begin(), XE = X.meta_end();
    407   PathDiagnostic::meta_iterator YI = Y.meta_begin(), YE = Y.meta_end();
    408   if (XE - XI != YE - YI)
    409     return (XE - XI) < (YE - YI);
    410   for ( ; XI != XE ; ++XI, ++YI) {
    411     if (*XI != *YI)
    412       return (*XI) < (*YI);
    413   }
    414   Optional<bool> b = comparePath(X.path, Y.path);
    415   assert(b.hasValue());
    416   return b.getValue();
    417 }
    418 
    419 namespace {
    420 struct CompareDiagnostics {
    421   // Compare if 'X' is "<" than 'Y'.
    422   bool operator()(const PathDiagnostic *X, const PathDiagnostic *Y) const {
    423     if (X == Y)
    424       return false;
    425     return compare(*X, *Y);
    426   }
    427 };
    428 }
    429 
    430 void PathDiagnosticConsumer::FlushDiagnostics(
    431                                      PathDiagnosticConsumer::FilesMade *Files) {
    432   if (flushed)
    433     return;
    434 
    435   flushed = true;
    436 
    437   std::vector<const PathDiagnostic *> BatchDiags;
    438   for (llvm::FoldingSet<PathDiagnostic>::iterator it = Diags.begin(),
    439        et = Diags.end(); it != et; ++it) {
    440     const PathDiagnostic *D = &*it;
    441     BatchDiags.push_back(D);
    442   }
    443 
    444   // Sort the diagnostics so that they are always emitted in a deterministic
    445   // order.
    446   if (!BatchDiags.empty())
    447     std::sort(BatchDiags.begin(), BatchDiags.end(), CompareDiagnostics());
    448 
    449   FlushDiagnosticsImpl(BatchDiags, Files);
    450 
    451   // Delete the flushed diagnostics.
    452   for (std::vector<const PathDiagnostic *>::iterator it = BatchDiags.begin(),
    453        et = BatchDiags.end(); it != et; ++it) {
    454     const PathDiagnostic *D = *it;
    455     delete D;
    456   }
    457 
    458   // Clear out the FoldingSet.
    459   Diags.clear();
    460 }
    461 
    462 void PathDiagnosticConsumer::FilesMade::addDiagnostic(const PathDiagnostic &PD,
    463                                                       StringRef ConsumerName,
    464                                                       StringRef FileName) {
    465   llvm::FoldingSetNodeID NodeID;
    466   NodeID.Add(PD);
    467   void *InsertPos;
    468   PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos);
    469   if (!Entry) {
    470     Entry = Alloc.Allocate<PDFileEntry>();
    471     Entry = new (Entry) PDFileEntry(NodeID);
    472     InsertNode(Entry, InsertPos);
    473   }
    474 
    475   // Allocate persistent storage for the file name.
    476   char *FileName_cstr = (char*) Alloc.Allocate(FileName.size(), 1);
    477   memcpy(FileName_cstr, FileName.data(), FileName.size());
    478 
    479   Entry->files.push_back(std::make_pair(ConsumerName,
    480                                         StringRef(FileName_cstr,
    481                                                   FileName.size())));
    482 }
    483 
    484 PathDiagnosticConsumer::PDFileEntry::ConsumerFiles *
    485 PathDiagnosticConsumer::FilesMade::getFiles(const PathDiagnostic &PD) {
    486   llvm::FoldingSetNodeID NodeID;
    487   NodeID.Add(PD);
    488   void *InsertPos;
    489   PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos);
    490   if (!Entry)
    491     return 0;
    492   return &Entry->files;
    493 }
    494 
    495 //===----------------------------------------------------------------------===//
    496 // PathDiagnosticLocation methods.
    497 //===----------------------------------------------------------------------===//
    498 
    499 static SourceLocation getValidSourceLocation(const Stmt* S,
    500                                              LocationOrAnalysisDeclContext LAC,
    501                                              bool UseEnd = false) {
    502   SourceLocation L = UseEnd ? S->getLocEnd() : S->getLocStart();
    503   assert(!LAC.isNull() && "A valid LocationContext or AnalysisDeclContext should "
    504                           "be passed to PathDiagnosticLocation upon creation.");
    505 
    506   // S might be a temporary statement that does not have a location in the
    507   // source code, so find an enclosing statement and use its location.
    508   if (!L.isValid()) {
    509 
    510     AnalysisDeclContext *ADC;
    511     if (LAC.is<const LocationContext*>())
    512       ADC = LAC.get<const LocationContext*>()->getAnalysisDeclContext();
    513     else
    514       ADC = LAC.get<AnalysisDeclContext*>();
    515 
    516     ParentMap &PM = ADC->getParentMap();
    517 
    518     const Stmt *Parent = S;
    519     do {
    520       Parent = PM.getParent(Parent);
    521 
    522       // In rare cases, we have implicit top-level expressions,
    523       // such as arguments for implicit member initializers.
    524       // In this case, fall back to the start of the body (even if we were
    525       // asked for the statement end location).
    526       if (!Parent) {
    527         const Stmt *Body = ADC->getBody();
    528         if (Body)
    529           L = Body->getLocStart();
    530         else
    531           L = ADC->getDecl()->getLocEnd();
    532         break;
    533       }
    534 
    535       L = UseEnd ? Parent->getLocEnd() : Parent->getLocStart();
    536     } while (!L.isValid());
    537   }
    538 
    539   return L;
    540 }
    541 
    542 static PathDiagnosticLocation
    543 getLocationForCaller(const StackFrameContext *SFC,
    544                      const LocationContext *CallerCtx,
    545                      const SourceManager &SM) {
    546   const CFGBlock &Block = *SFC->getCallSiteBlock();
    547   CFGElement Source = Block[SFC->getIndex()];
    548 
    549   switch (Source.getKind()) {
    550   case CFGElement::Statement:
    551     return PathDiagnosticLocation(Source.castAs<CFGStmt>().getStmt(),
    552                                   SM, CallerCtx);
    553   case CFGElement::Initializer: {
    554     const CFGInitializer &Init = Source.castAs<CFGInitializer>();
    555     return PathDiagnosticLocation(Init.getInitializer()->getInit(),
    556                                   SM, CallerCtx);
    557   }
    558   case CFGElement::AutomaticObjectDtor: {
    559     const CFGAutomaticObjDtor &Dtor = Source.castAs<CFGAutomaticObjDtor>();
    560     return PathDiagnosticLocation::createEnd(Dtor.getTriggerStmt(),
    561                                              SM, CallerCtx);
    562   }
    563   case CFGElement::BaseDtor:
    564   case CFGElement::MemberDtor: {
    565     const AnalysisDeclContext *CallerInfo = CallerCtx->getAnalysisDeclContext();
    566     if (const Stmt *CallerBody = CallerInfo->getBody())
    567       return PathDiagnosticLocation::createEnd(CallerBody, SM, CallerCtx);
    568     return PathDiagnosticLocation::create(CallerInfo->getDecl(), SM);
    569   }
    570   case CFGElement::TemporaryDtor:
    571     llvm_unreachable("not yet implemented!");
    572   }
    573 
    574   llvm_unreachable("Unknown CFGElement kind");
    575 }
    576 
    577 
    578 PathDiagnosticLocation
    579   PathDiagnosticLocation::createBegin(const Decl *D,
    580                                       const SourceManager &SM) {
    581   return PathDiagnosticLocation(D->getLocStart(), SM, SingleLocK);
    582 }
    583 
    584 PathDiagnosticLocation
    585   PathDiagnosticLocation::createBegin(const Stmt *S,
    586                                       const SourceManager &SM,
    587                                       LocationOrAnalysisDeclContext LAC) {
    588   return PathDiagnosticLocation(getValidSourceLocation(S, LAC),
    589                                 SM, SingleLocK);
    590 }
    591 
    592 
    593 PathDiagnosticLocation
    594 PathDiagnosticLocation::createEnd(const Stmt *S,
    595                                   const SourceManager &SM,
    596                                   LocationOrAnalysisDeclContext LAC) {
    597   if (const CompoundStmt *CS = dyn_cast<CompoundStmt>(S))
    598     return createEndBrace(CS, SM);
    599   return PathDiagnosticLocation(getValidSourceLocation(S, LAC, /*End=*/true),
    600                                 SM, SingleLocK);
    601 }
    602 
    603 PathDiagnosticLocation
    604   PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO,
    605                                             const SourceManager &SM) {
    606   return PathDiagnosticLocation(BO->getOperatorLoc(), SM, SingleLocK);
    607 }
    608 
    609 PathDiagnosticLocation
    610   PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME,
    611                                           const SourceManager &SM) {
    612   return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK);
    613 }
    614 
    615 PathDiagnosticLocation
    616   PathDiagnosticLocation::createBeginBrace(const CompoundStmt *CS,
    617                                            const SourceManager &SM) {
    618   SourceLocation L = CS->getLBracLoc();
    619   return PathDiagnosticLocation(L, SM, SingleLocK);
    620 }
    621 
    622 PathDiagnosticLocation
    623   PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS,
    624                                          const SourceManager &SM) {
    625   SourceLocation L = CS->getRBracLoc();
    626   return PathDiagnosticLocation(L, SM, SingleLocK);
    627 }
    628 
    629 PathDiagnosticLocation
    630   PathDiagnosticLocation::createDeclBegin(const LocationContext *LC,
    631                                           const SourceManager &SM) {
    632   // FIXME: Should handle CXXTryStmt if analyser starts supporting C++.
    633   if (const CompoundStmt *CS =
    634         dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody()))
    635     if (!CS->body_empty()) {
    636       SourceLocation Loc = (*CS->body_begin())->getLocStart();
    637       return PathDiagnosticLocation(Loc, SM, SingleLocK);
    638     }
    639 
    640   return PathDiagnosticLocation();
    641 }
    642 
    643 PathDiagnosticLocation
    644   PathDiagnosticLocation::createDeclEnd(const LocationContext *LC,
    645                                         const SourceManager &SM) {
    646   SourceLocation L = LC->getDecl()->getBodyRBrace();
    647   return PathDiagnosticLocation(L, SM, SingleLocK);
    648 }
    649 
    650 PathDiagnosticLocation
    651   PathDiagnosticLocation::create(const ProgramPoint& P,
    652                                  const SourceManager &SMng) {
    653 
    654   const Stmt* S = 0;
    655   if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
    656     const CFGBlock *BSrc = BE->getSrc();
    657     S = BSrc->getTerminatorCondition();
    658   } else if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) {
    659     S = SP->getStmt();
    660     if (P.getAs<PostStmtPurgeDeadSymbols>())
    661       return PathDiagnosticLocation::createEnd(S, SMng, P.getLocationContext());
    662   } else if (Optional<PostInitializer> PIP = P.getAs<PostInitializer>()) {
    663     return PathDiagnosticLocation(PIP->getInitializer()->getSourceLocation(),
    664                                   SMng);
    665   } else if (Optional<PostImplicitCall> PIE = P.getAs<PostImplicitCall>()) {
    666     return PathDiagnosticLocation(PIE->getLocation(), SMng);
    667   } else if (Optional<CallEnter> CE = P.getAs<CallEnter>()) {
    668     return getLocationForCaller(CE->getCalleeContext(),
    669                                 CE->getLocationContext(),
    670                                 SMng);
    671   } else if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) {
    672     return getLocationForCaller(CEE->getCalleeContext(),
    673                                 CEE->getLocationContext(),
    674                                 SMng);
    675   } else {
    676     llvm_unreachable("Unexpected ProgramPoint");
    677   }
    678 
    679   return PathDiagnosticLocation(S, SMng, P.getLocationContext());
    680 }
    681 
    682 const Stmt *PathDiagnosticLocation::getStmt(const ExplodedNode *N) {
    683   ProgramPoint P = N->getLocation();
    684   if (Optional<StmtPoint> SP = P.getAs<StmtPoint>())
    685     return SP->getStmt();
    686   if (Optional<BlockEdge> BE = P.getAs<BlockEdge>())
    687     return BE->getSrc()->getTerminator();
    688   if (Optional<CallEnter> CE = P.getAs<CallEnter>())
    689     return CE->getCallExpr();
    690   if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>())
    691     return CEE->getCalleeContext()->getCallSite();
    692   if (Optional<PostInitializer> PIPP = P.getAs<PostInitializer>())
    693     return PIPP->getInitializer()->getInit();
    694 
    695   return 0;
    696 }
    697 
    698 const Stmt *PathDiagnosticLocation::getNextStmt(const ExplodedNode *N) {
    699   for (N = N->getFirstSucc(); N; N = N->getFirstSucc()) {
    700     if (const Stmt *S = getStmt(N)) {
    701       // Check if the statement is '?' or '&&'/'||'.  These are "merges",
    702       // not actual statement points.
    703       switch (S->getStmtClass()) {
    704         case Stmt::ChooseExprClass:
    705         case Stmt::BinaryConditionalOperatorClass:
    706         case Stmt::ConditionalOperatorClass:
    707           continue;
    708         case Stmt::BinaryOperatorClass: {
    709           BinaryOperatorKind Op = cast<BinaryOperator>(S)->getOpcode();
    710           if (Op == BO_LAnd || Op == BO_LOr)
    711             continue;
    712           break;
    713         }
    714         default:
    715           break;
    716       }
    717       // We found the statement, so return it.
    718       return S;
    719     }
    720   }
    721 
    722   return 0;
    723 }
    724 
    725 PathDiagnosticLocation
    726   PathDiagnosticLocation::createEndOfPath(const ExplodedNode *N,
    727                                           const SourceManager &SM) {
    728   assert(N && "Cannot create a location with a null node.");
    729   const Stmt *S = getStmt(N);
    730 
    731   if (!S)
    732     S = getNextStmt(N);
    733 
    734   if (S) {
    735     ProgramPoint P = N->getLocation();
    736     const LocationContext *LC = N->getLocationContext();
    737 
    738     // For member expressions, return the location of the '.' or '->'.
    739     if (const MemberExpr *ME = dyn_cast<MemberExpr>(S))
    740       return PathDiagnosticLocation::createMemberLoc(ME, SM);
    741 
    742     // For binary operators, return the location of the operator.
    743     if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S))
    744       return PathDiagnosticLocation::createOperatorLoc(B, SM);
    745 
    746     if (P.getAs<PostStmtPurgeDeadSymbols>())
    747       return PathDiagnosticLocation::createEnd(S, SM, LC);
    748 
    749     if (S->getLocStart().isValid())
    750       return PathDiagnosticLocation(S, SM, LC);
    751     return PathDiagnosticLocation(getValidSourceLocation(S, LC), SM);
    752   }
    753 
    754   return createDeclEnd(N->getLocationContext(), SM);
    755 }
    756 
    757 PathDiagnosticLocation PathDiagnosticLocation::createSingleLocation(
    758                                            const PathDiagnosticLocation &PDL) {
    759   FullSourceLoc L = PDL.asLocation();
    760   return PathDiagnosticLocation(L, L.getManager(), SingleLocK);
    761 }
    762 
    763 FullSourceLoc
    764   PathDiagnosticLocation::genLocation(SourceLocation L,
    765                                       LocationOrAnalysisDeclContext LAC) const {
    766   assert(isValid());
    767   // Note that we want a 'switch' here so that the compiler can warn us in
    768   // case we add more cases.
    769   switch (K) {
    770     case SingleLocK:
    771     case RangeK:
    772       break;
    773     case StmtK:
    774       // Defensive checking.
    775       if (!S)
    776         break;
    777       return FullSourceLoc(getValidSourceLocation(S, LAC),
    778                            const_cast<SourceManager&>(*SM));
    779     case DeclK:
    780       // Defensive checking.
    781       if (!D)
    782         break;
    783       return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM));
    784   }
    785 
    786   return FullSourceLoc(L, const_cast<SourceManager&>(*SM));
    787 }
    788 
    789 PathDiagnosticRange
    790   PathDiagnosticLocation::genRange(LocationOrAnalysisDeclContext LAC) const {
    791   assert(isValid());
    792   // Note that we want a 'switch' here so that the compiler can warn us in
    793   // case we add more cases.
    794   switch (K) {
    795     case SingleLocK:
    796       return PathDiagnosticRange(SourceRange(Loc,Loc), true);
    797     case RangeK:
    798       break;
    799     case StmtK: {
    800       const Stmt *S = asStmt();
    801       switch (S->getStmtClass()) {
    802         default:
    803           break;
    804         case Stmt::DeclStmtClass: {
    805           const DeclStmt *DS = cast<DeclStmt>(S);
    806           if (DS->isSingleDecl()) {
    807             // Should always be the case, but we'll be defensive.
    808             return SourceRange(DS->getLocStart(),
    809                                DS->getSingleDecl()->getLocation());
    810           }
    811           break;
    812         }
    813           // FIXME: Provide better range information for different
    814           //  terminators.
    815         case Stmt::IfStmtClass:
    816         case Stmt::WhileStmtClass:
    817         case Stmt::DoStmtClass:
    818         case Stmt::ForStmtClass:
    819         case Stmt::ChooseExprClass:
    820         case Stmt::IndirectGotoStmtClass:
    821         case Stmt::SwitchStmtClass:
    822         case Stmt::BinaryConditionalOperatorClass:
    823         case Stmt::ConditionalOperatorClass:
    824         case Stmt::ObjCForCollectionStmtClass: {
    825           SourceLocation L = getValidSourceLocation(S, LAC);
    826           return SourceRange(L, L);
    827         }
    828       }
    829       SourceRange R = S->getSourceRange();
    830       if (R.isValid())
    831         return R;
    832       break;
    833     }
    834     case DeclK:
    835       if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
    836         return MD->getSourceRange();
    837       if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
    838         if (Stmt *Body = FD->getBody())
    839           return Body->getSourceRange();
    840       }
    841       else {
    842         SourceLocation L = D->getLocation();
    843         return PathDiagnosticRange(SourceRange(L, L), true);
    844       }
    845   }
    846 
    847   return SourceRange(Loc,Loc);
    848 }
    849 
    850 void PathDiagnosticLocation::flatten() {
    851   if (K == StmtK) {
    852     K = RangeK;
    853     S = 0;
    854     D = 0;
    855   }
    856   else if (K == DeclK) {
    857     K = SingleLocK;
    858     S = 0;
    859     D = 0;
    860   }
    861 }
    862 
    863 //===----------------------------------------------------------------------===//
    864 // Manipulation of PathDiagnosticCallPieces.
    865 //===----------------------------------------------------------------------===//
    866 
    867 PathDiagnosticCallPiece *
    868 PathDiagnosticCallPiece::construct(const ExplodedNode *N,
    869                                    const CallExitEnd &CE,
    870                                    const SourceManager &SM) {
    871   const Decl *caller = CE.getLocationContext()->getDecl();
    872   PathDiagnosticLocation pos = getLocationForCaller(CE.getCalleeContext(),
    873                                                     CE.getLocationContext(),
    874                                                     SM);
    875   return new PathDiagnosticCallPiece(caller, pos);
    876 }
    877 
    878 PathDiagnosticCallPiece *
    879 PathDiagnosticCallPiece::construct(PathPieces &path,
    880                                    const Decl *caller) {
    881   PathDiagnosticCallPiece *C = new PathDiagnosticCallPiece(path, caller);
    882   path.clear();
    883   path.push_front(C);
    884   return C;
    885 }
    886 
    887 void PathDiagnosticCallPiece::setCallee(const CallEnter &CE,
    888                                         const SourceManager &SM) {
    889   const StackFrameContext *CalleeCtx = CE.getCalleeContext();
    890   Callee = CalleeCtx->getDecl();
    891 
    892   callEnterWithin = PathDiagnosticLocation::createBegin(Callee, SM);
    893   callEnter = getLocationForCaller(CalleeCtx, CE.getLocationContext(), SM);
    894 }
    895 
    896 static inline void describeClass(raw_ostream &Out, const CXXRecordDecl *D,
    897                                  StringRef Prefix = StringRef()) {
    898   if (!D->getIdentifier())
    899     return;
    900   Out << Prefix << '\'' << *D << '\'';
    901 }
    902 
    903 static bool describeCodeDecl(raw_ostream &Out, const Decl *D,
    904                              bool ExtendedDescription,
    905                              StringRef Prefix = StringRef()) {
    906   if (!D)
    907     return false;
    908 
    909   if (isa<BlockDecl>(D)) {
    910     if (ExtendedDescription)
    911       Out << Prefix << "anonymous block";
    912     return ExtendedDescription;
    913   }
    914 
    915   if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
    916     Out << Prefix;
    917     if (ExtendedDescription && !MD->isUserProvided()) {
    918       if (MD->isExplicitlyDefaulted())
    919         Out << "defaulted ";
    920       else
    921         Out << "implicit ";
    922     }
    923 
    924     if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(MD)) {
    925       if (CD->isDefaultConstructor())
    926         Out << "default ";
    927       else if (CD->isCopyConstructor())
    928         Out << "copy ";
    929       else if (CD->isMoveConstructor())
    930         Out << "move ";
    931 
    932       Out << "constructor";
    933       describeClass(Out, MD->getParent(), " for ");
    934 
    935     } else if (isa<CXXDestructorDecl>(MD)) {
    936       if (!MD->isUserProvided()) {
    937         Out << "destructor";
    938         describeClass(Out, MD->getParent(), " for ");
    939       } else {
    940         // Use ~Foo for explicitly-written destructors.
    941         Out << "'" << *MD << "'";
    942       }
    943 
    944     } else if (MD->isCopyAssignmentOperator()) {
    945         Out << "copy assignment operator";
    946         describeClass(Out, MD->getParent(), " for ");
    947 
    948     } else if (MD->isMoveAssignmentOperator()) {
    949         Out << "move assignment operator";
    950         describeClass(Out, MD->getParent(), " for ");
    951 
    952     } else {
    953       if (MD->getParent()->getIdentifier())
    954         Out << "'" << *MD->getParent() << "::" << *MD << "'";
    955       else
    956         Out << "'" << *MD << "'";
    957     }
    958 
    959     return true;
    960   }
    961 
    962   Out << Prefix << '\'' << cast<NamedDecl>(*D) << '\'';
    963   return true;
    964 }
    965 
    966 IntrusiveRefCntPtr<PathDiagnosticEventPiece>
    967 PathDiagnosticCallPiece::getCallEnterEvent() const {
    968   if (!Callee)
    969     return 0;
    970 
    971   SmallString<256> buf;
    972   llvm::raw_svector_ostream Out(buf);
    973 
    974   Out << "Calling ";
    975   describeCodeDecl(Out, Callee, /*ExtendedDescription=*/true);
    976 
    977   assert(callEnter.asLocation().isValid());
    978   return new PathDiagnosticEventPiece(callEnter, Out.str());
    979 }
    980 
    981 IntrusiveRefCntPtr<PathDiagnosticEventPiece>
    982 PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const {
    983   if (!callEnterWithin.asLocation().isValid())
    984     return 0;
    985   if (Callee->isImplicit() || !Callee->hasBody())
    986     return 0;
    987   if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Callee))
    988     if (MD->isDefaulted())
    989       return 0;
    990 
    991   SmallString<256> buf;
    992   llvm::raw_svector_ostream Out(buf);
    993 
    994   Out << "Entered call";
    995   describeCodeDecl(Out, Caller, /*ExtendedDescription=*/false, " from ");
    996 
    997   return new PathDiagnosticEventPiece(callEnterWithin, Out.str());
    998 }
    999 
   1000 IntrusiveRefCntPtr<PathDiagnosticEventPiece>
   1001 PathDiagnosticCallPiece::getCallExitEvent() const {
   1002   if (NoExit)
   1003     return 0;
   1004 
   1005   SmallString<256> buf;
   1006   llvm::raw_svector_ostream Out(buf);
   1007 
   1008   if (!CallStackMessage.empty()) {
   1009     Out << CallStackMessage;
   1010   } else {
   1011     bool DidDescribe = describeCodeDecl(Out, Callee,
   1012                                         /*ExtendedDescription=*/false,
   1013                                         "Returning from ");
   1014     if (!DidDescribe)
   1015       Out << "Returning to caller";
   1016   }
   1017 
   1018   assert(callReturn.asLocation().isValid());
   1019   return new PathDiagnosticEventPiece(callReturn, Out.str());
   1020 }
   1021 
   1022 static void compute_path_size(const PathPieces &pieces, unsigned &size) {
   1023   for (PathPieces::const_iterator it = pieces.begin(),
   1024                                   et = pieces.end(); it != et; ++it) {
   1025     const PathDiagnosticPiece *piece = it->getPtr();
   1026     if (const PathDiagnosticCallPiece *cp =
   1027         dyn_cast<PathDiagnosticCallPiece>(piece)) {
   1028       compute_path_size(cp->path, size);
   1029     }
   1030     else
   1031       ++size;
   1032   }
   1033 }
   1034 
   1035 unsigned PathDiagnostic::full_size() {
   1036   unsigned size = 0;
   1037   compute_path_size(path, size);
   1038   return size;
   1039 }
   1040 
   1041 //===----------------------------------------------------------------------===//
   1042 // FoldingSet profiling methods.
   1043 //===----------------------------------------------------------------------===//
   1044 
   1045 void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const {
   1046   ID.AddInteger(Range.getBegin().getRawEncoding());
   1047   ID.AddInteger(Range.getEnd().getRawEncoding());
   1048   ID.AddInteger(Loc.getRawEncoding());
   1049   return;
   1050 }
   1051 
   1052 void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const {
   1053   ID.AddInteger((unsigned) getKind());
   1054   ID.AddString(str);
   1055   // FIXME: Add profiling support for code hints.
   1056   ID.AddInteger((unsigned) getDisplayHint());
   1057   ArrayRef<SourceRange> Ranges = getRanges();
   1058   for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end();
   1059                                         I != E; ++I) {
   1060     ID.AddInteger(I->getBegin().getRawEncoding());
   1061     ID.AddInteger(I->getEnd().getRawEncoding());
   1062   }
   1063 }
   1064 
   1065 void PathDiagnosticCallPiece::Profile(llvm::FoldingSetNodeID &ID) const {
   1066   PathDiagnosticPiece::Profile(ID);
   1067   for (PathPieces::const_iterator it = path.begin(),
   1068        et = path.end(); it != et; ++it) {
   1069     ID.Add(**it);
   1070   }
   1071 }
   1072 
   1073 void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const {
   1074   PathDiagnosticPiece::Profile(ID);
   1075   ID.Add(Pos);
   1076 }
   1077 
   1078 void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const {
   1079   PathDiagnosticPiece::Profile(ID);
   1080   for (const_iterator I = begin(), E = end(); I != E; ++I)
   1081     ID.Add(*I);
   1082 }
   1083 
   1084 void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const {
   1085   PathDiagnosticSpotPiece::Profile(ID);
   1086   for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end();
   1087        I != E; ++I)
   1088     ID.Add(**I);
   1089 }
   1090 
   1091 void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const {
   1092   ID.Add(getLocation());
   1093   ID.AddString(BugType);
   1094   ID.AddString(VerboseDesc);
   1095   ID.AddString(Category);
   1096 }
   1097 
   1098 void PathDiagnostic::FullProfile(llvm::FoldingSetNodeID &ID) const {
   1099   Profile(ID);
   1100   for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E; ++I)
   1101     ID.Add(**I);
   1102   for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I)
   1103     ID.AddString(*I);
   1104 }
   1105 
   1106 StackHintGenerator::~StackHintGenerator() {}
   1107 
   1108 std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){
   1109   ProgramPoint P = N->getLocation();
   1110   CallExitEnd CExit = P.castAs<CallExitEnd>();
   1111 
   1112   // FIXME: Use CallEvent to abstract this over all calls.
   1113   const Stmt *CallSite = CExit.getCalleeContext()->getCallSite();
   1114   const CallExpr *CE = dyn_cast_or_null<CallExpr>(CallSite);
   1115   if (!CE)
   1116     return "";
   1117 
   1118   if (!N)
   1119     return getMessageForSymbolNotFound();
   1120 
   1121   // Check if one of the parameters are set to the interesting symbol.
   1122   ProgramStateRef State = N->getState();
   1123   const LocationContext *LCtx = N->getLocationContext();
   1124   unsigned ArgIndex = 0;
   1125   for (CallExpr::const_arg_iterator I = CE->arg_begin(),
   1126                                     E = CE->arg_end(); I != E; ++I, ++ArgIndex){
   1127     SVal SV = State->getSVal(*I, LCtx);
   1128 
   1129     // Check if the variable corresponding to the symbol is passed by value.
   1130     SymbolRef AS = SV.getAsLocSymbol();
   1131     if (AS == Sym) {
   1132       return getMessageForArg(*I, ArgIndex);
   1133     }
   1134 
   1135     // Check if the parameter is a pointer to the symbol.
   1136     if (Optional<loc::MemRegionVal> Reg = SV.getAs<loc::MemRegionVal>()) {
   1137       SVal PSV = State->getSVal(Reg->getRegion());
   1138       SymbolRef AS = PSV.getAsLocSymbol();
   1139       if (AS == Sym) {
   1140         return getMessageForArg(*I, ArgIndex);
   1141       }
   1142     }
   1143   }
   1144 
   1145   // Check if we are returning the interesting symbol.
   1146   SVal SV = State->getSVal(CE, LCtx);
   1147   SymbolRef RetSym = SV.getAsLocSymbol();
   1148   if (RetSym == Sym) {
   1149     return getMessageForReturn(CE);
   1150   }
   1151 
   1152   return getMessageForSymbolNotFound();
   1153 }
   1154 
   1155 std::string StackHintGeneratorForSymbol::getMessageForArg(const Expr *ArgE,
   1156                                                           unsigned ArgIndex) {
   1157   // Printed parameters start at 1, not 0.
   1158   ++ArgIndex;
   1159 
   1160   SmallString<200> buf;
   1161   llvm::raw_svector_ostream os(buf);
   1162 
   1163   os << Msg << " via " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex)
   1164      << " parameter";
   1165 
   1166   return os.str();
   1167 }
   1168