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/AST/Decl.h"
00016 #include "clang/AST/DeclCXX.h"
00017 #include "clang/AST/DeclObjC.h"
00018 #include "clang/AST/Expr.h"
00019 #include "clang/AST/ExprCXX.h"
00020 #include "clang/AST/ParentMap.h"
00021 #include "clang/AST/StmtCXX.h"
00022 #include "clang/Basic/SourceManager.h"
00023 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
00024 #include "llvm/ADT/SmallString.h"
00025 #include "llvm/ADT/StringExtras.h"
00026 #include "llvm/Support/raw_ostream.h"
00027 
00028 using namespace clang;
00029 using namespace ento;
00030 
00031 bool PathDiagnosticMacroPiece::containsEvent() const {
00032   for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end();
00033        I!=E; ++I) {
00034     if (isa<PathDiagnosticEventPiece>(*I))
00035       return true;
00036     if (PathDiagnosticMacroPiece *MP = dyn_cast<PathDiagnosticMacroPiece>(*I))
00037       if (MP->containsEvent())
00038         return true;
00039   }
00040   return false;
00041 }
00042 
00043 static StringRef StripTrailingDots(StringRef s) {
00044   for (StringRef::size_type i = s.size(); i != 0; --i)
00045     if (s[i - 1] != '.')
00046       return s.substr(0, i);
00047   return "";
00048 }
00049 
00050 PathDiagnosticPiece::PathDiagnosticPiece(StringRef s,
00051                                          Kind k, DisplayHint hint)
00052   : str(StripTrailingDots(s)), kind(k), Hint(hint),
00053     LastInMainSourceFile(false) {}
00054 
00055 PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint)
00056   : kind(k), Hint(hint), LastInMainSourceFile(false) {}
00057 
00058 PathDiagnosticPiece::~PathDiagnosticPiece() {}
00059 PathDiagnosticEventPiece::~PathDiagnosticEventPiece() {}
00060 PathDiagnosticCallPiece::~PathDiagnosticCallPiece() {}
00061 PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() {}
00062 PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() {}
00063 
00064 
00065 PathPieces::~PathPieces() {}
00066 
00067 void PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current,
00068                            bool ShouldFlattenMacros) const {
00069   for (PathPieces::const_iterator I = begin(), E = end(); I != E; ++I) {
00070     PathDiagnosticPiece *Piece = I->get();
00071 
00072     switch (Piece->getKind()) {
00073     case PathDiagnosticPiece::Call: {
00074       PathDiagnosticCallPiece *Call = cast<PathDiagnosticCallPiece>(Piece);
00075       IntrusiveRefCntPtr<PathDiagnosticEventPiece> CallEnter =
00076         Call->getCallEnterEvent();
00077       if (CallEnter)
00078         Current.push_back(CallEnter);
00079       Call->path.flattenTo(Primary, Primary, ShouldFlattenMacros);
00080       IntrusiveRefCntPtr<PathDiagnosticEventPiece> callExit =
00081         Call->getCallExitEvent();
00082       if (callExit)
00083         Current.push_back(callExit);
00084       break;
00085     }
00086     case PathDiagnosticPiece::Macro: {
00087       PathDiagnosticMacroPiece *Macro = cast<PathDiagnosticMacroPiece>(Piece);
00088       if (ShouldFlattenMacros) {
00089         Macro->subPieces.flattenTo(Primary, Primary, ShouldFlattenMacros);
00090       } else {
00091         Current.push_back(Piece);
00092         PathPieces NewPath;
00093         Macro->subPieces.flattenTo(Primary, NewPath, ShouldFlattenMacros);
00094         // FIXME: This probably shouldn't mutate the original path piece.
00095         Macro->subPieces = NewPath;
00096       }
00097       break;
00098     }
00099     case PathDiagnosticPiece::Event:
00100     case PathDiagnosticPiece::ControlFlow:
00101       Current.push_back(Piece);
00102       break;
00103     }
00104   }
00105 }
00106 
00107 
00108 PathDiagnostic::~PathDiagnostic() {}
00109 
00110 PathDiagnostic::PathDiagnostic(StringRef CheckName, const Decl *declWithIssue,
00111                                StringRef bugtype, StringRef verboseDesc,
00112                                StringRef shortDesc, StringRef category,
00113                                PathDiagnosticLocation LocationToUnique,
00114                                const Decl *DeclToUnique)
00115   : CheckName(CheckName),
00116     DeclWithIssue(declWithIssue),
00117     BugType(StripTrailingDots(bugtype)),
00118     VerboseDesc(StripTrailingDots(verboseDesc)),
00119     ShortDesc(StripTrailingDots(shortDesc)),
00120     Category(StripTrailingDots(category)),
00121     UniqueingLoc(LocationToUnique),
00122     UniqueingDecl(DeclToUnique),
00123     path(pathImpl) {}
00124 
00125 static PathDiagnosticCallPiece *
00126 getFirstStackedCallToHeaderFile(PathDiagnosticCallPiece *CP,
00127                                 const SourceManager &SMgr) {
00128   SourceLocation CallLoc = CP->callEnter.asLocation();
00129 
00130   // If the call is within a macro, don't do anything (for now).
00131   if (CallLoc.isMacroID())
00132     return nullptr;
00133 
00134   assert(SMgr.isInMainFile(CallLoc) &&
00135          "The call piece should be in the main file.");
00136 
00137   // Check if CP represents a path through a function outside of the main file.
00138   if (!SMgr.isInMainFile(CP->callEnterWithin.asLocation()))
00139     return CP;
00140 
00141   const PathPieces &Path = CP->path;
00142   if (Path.empty())
00143     return nullptr;
00144 
00145   // Check if the last piece in the callee path is a call to a function outside
00146   // of the main file.
00147   if (PathDiagnosticCallPiece *CPInner =
00148       dyn_cast<PathDiagnosticCallPiece>(Path.back())) {
00149     return getFirstStackedCallToHeaderFile(CPInner, SMgr);
00150   }
00151 
00152   // Otherwise, the last piece is in the main file.
00153   return nullptr;
00154 }
00155 
00156 void PathDiagnostic::resetDiagnosticLocationToMainFile() {
00157   if (path.empty())
00158     return;
00159 
00160   PathDiagnosticPiece *LastP = path.back().get();
00161   assert(LastP);
00162   const SourceManager &SMgr = LastP->getLocation().getManager();
00163 
00164   // We only need to check if the report ends inside headers, if the last piece
00165   // is a call piece.
00166   if (PathDiagnosticCallPiece *CP = dyn_cast<PathDiagnosticCallPiece>(LastP)) {
00167     CP = getFirstStackedCallToHeaderFile(CP, SMgr);
00168     if (CP) {
00169       // Mark the piece.
00170        CP->setAsLastInMainSourceFile();
00171 
00172       // Update the path diagnostic message.
00173       const NamedDecl *ND = dyn_cast<NamedDecl>(CP->getCallee());
00174       if (ND) {
00175         SmallString<200> buf;
00176         llvm::raw_svector_ostream os(buf);
00177         os << " (within a call to '" << ND->getDeclName() << "')";
00178         appendToDesc(os.str());
00179       }
00180 
00181       // Reset the report containing declaration and location.
00182       DeclWithIssue = CP->getCaller();
00183       Loc = CP->getLocation();
00184       
00185       return;
00186     }
00187   }
00188 }
00189 
00190 void PathDiagnosticConsumer::anchor() { }
00191 
00192 PathDiagnosticConsumer::~PathDiagnosticConsumer() {
00193   // Delete the contents of the FoldingSet if it isn't empty already.
00194   for (llvm::FoldingSet<PathDiagnostic>::iterator it =
00195        Diags.begin(), et = Diags.end() ; it != et ; ++it) {
00196     delete &*it;
00197   }
00198 }
00199 
00200 void PathDiagnosticConsumer::HandlePathDiagnostic(
00201     std::unique_ptr<PathDiagnostic> D) {
00202   if (!D || D->path.empty())
00203     return;
00204   
00205   // We need to flatten the locations (convert Stmt* to locations) because
00206   // the referenced statements may be freed by the time the diagnostics
00207   // are emitted.
00208   D->flattenLocations();
00209 
00210   // If the PathDiagnosticConsumer does not support diagnostics that
00211   // cross file boundaries, prune out such diagnostics now.
00212   if (!supportsCrossFileDiagnostics()) {
00213     // Verify that the entire path is from the same FileID.
00214     FileID FID;
00215     const SourceManager &SMgr = D->path.front()->getLocation().getManager();
00216     SmallVector<const PathPieces *, 5> WorkList;
00217     WorkList.push_back(&D->path);
00218 
00219     while (!WorkList.empty()) {
00220       const PathPieces &path = *WorkList.pop_back_val();
00221 
00222       for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E;
00223            ++I) {
00224         const PathDiagnosticPiece *piece = I->get();
00225         FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc();
00226       
00227         if (FID.isInvalid()) {
00228           FID = SMgr.getFileID(L);
00229         } else if (SMgr.getFileID(L) != FID)
00230           return; // FIXME: Emit a warning?
00231       
00232         // Check the source ranges.
00233         ArrayRef<SourceRange> Ranges = piece->getRanges();
00234         for (ArrayRef<SourceRange>::iterator I = Ranges.begin(),
00235                                              E = Ranges.end(); I != E; ++I) {
00236           SourceLocation L = SMgr.getExpansionLoc(I->getBegin());
00237           if (!L.isFileID() || SMgr.getFileID(L) != FID)
00238             return; // FIXME: Emit a warning?
00239           L = SMgr.getExpansionLoc(I->getEnd());
00240           if (!L.isFileID() || SMgr.getFileID(L) != FID)
00241             return; // FIXME: Emit a warning?
00242         }
00243         
00244         if (const PathDiagnosticCallPiece *call =
00245             dyn_cast<PathDiagnosticCallPiece>(piece)) {
00246           WorkList.push_back(&call->path);
00247         }
00248         else if (const PathDiagnosticMacroPiece *macro =
00249                  dyn_cast<PathDiagnosticMacroPiece>(piece)) {
00250           WorkList.push_back(&macro->subPieces);
00251         }
00252       }
00253     }
00254     
00255     if (FID.isInvalid())
00256       return; // FIXME: Emit a warning?
00257   }  
00258 
00259   // Profile the node to see if we already have something matching it
00260   llvm::FoldingSetNodeID profile;
00261   D->Profile(profile);
00262   void *InsertPos = nullptr;
00263 
00264   if (PathDiagnostic *orig = Diags.FindNodeOrInsertPos(profile, InsertPos)) {
00265     // Keep the PathDiagnostic with the shorter path.
00266     // Note, the enclosing routine is called in deterministic order, so the
00267     // results will be consistent between runs (no reason to break ties if the
00268     // size is the same).
00269     const unsigned orig_size = orig->full_size();
00270     const unsigned new_size = D->full_size();
00271     if (orig_size <= new_size)
00272       return;
00273 
00274     assert(orig != D.get());
00275     Diags.RemoveNode(orig);
00276     delete orig;
00277   }
00278 
00279   Diags.InsertNode(D.release());
00280 }
00281 
00282 static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y);
00283 static Optional<bool>
00284 compareControlFlow(const PathDiagnosticControlFlowPiece &X,
00285                    const PathDiagnosticControlFlowPiece &Y) {
00286   FullSourceLoc XSL = X.getStartLocation().asLocation();
00287   FullSourceLoc YSL = Y.getStartLocation().asLocation();
00288   if (XSL != YSL)
00289     return XSL.isBeforeInTranslationUnitThan(YSL);
00290   FullSourceLoc XEL = X.getEndLocation().asLocation();
00291   FullSourceLoc YEL = Y.getEndLocation().asLocation();
00292   if (XEL != YEL)
00293     return XEL.isBeforeInTranslationUnitThan(YEL);
00294   return None;
00295 }
00296 
00297 static Optional<bool> compareMacro(const PathDiagnosticMacroPiece &X,
00298                                    const PathDiagnosticMacroPiece &Y) {
00299   return comparePath(X.subPieces, Y.subPieces);
00300 }
00301 
00302 static Optional<bool> compareCall(const PathDiagnosticCallPiece &X,
00303                                   const PathDiagnosticCallPiece &Y) {
00304   FullSourceLoc X_CEL = X.callEnter.asLocation();
00305   FullSourceLoc Y_CEL = Y.callEnter.asLocation();
00306   if (X_CEL != Y_CEL)
00307     return X_CEL.isBeforeInTranslationUnitThan(Y_CEL);
00308   FullSourceLoc X_CEWL = X.callEnterWithin.asLocation();
00309   FullSourceLoc Y_CEWL = Y.callEnterWithin.asLocation();
00310   if (X_CEWL != Y_CEWL)
00311     return X_CEWL.isBeforeInTranslationUnitThan(Y_CEWL);
00312   FullSourceLoc X_CRL = X.callReturn.asLocation();
00313   FullSourceLoc Y_CRL = Y.callReturn.asLocation();
00314   if (X_CRL != Y_CRL)
00315     return X_CRL.isBeforeInTranslationUnitThan(Y_CRL);
00316   return comparePath(X.path, Y.path);
00317 }
00318 
00319 static Optional<bool> comparePiece(const PathDiagnosticPiece &X,
00320                                    const PathDiagnosticPiece &Y) {
00321   if (X.getKind() != Y.getKind())
00322     return X.getKind() < Y.getKind();
00323   
00324   FullSourceLoc XL = X.getLocation().asLocation();
00325   FullSourceLoc YL = Y.getLocation().asLocation();
00326   if (XL != YL)
00327     return XL.isBeforeInTranslationUnitThan(YL);
00328 
00329   if (X.getString() != Y.getString())
00330     return X.getString() < Y.getString();
00331 
00332   if (X.getRanges().size() != Y.getRanges().size())
00333     return X.getRanges().size() < Y.getRanges().size();
00334 
00335   const SourceManager &SM = XL.getManager();
00336   
00337   for (unsigned i = 0, n = X.getRanges().size(); i < n; ++i) {
00338     SourceRange XR = X.getRanges()[i];
00339     SourceRange YR = Y.getRanges()[i];
00340     if (XR != YR) {
00341       if (XR.getBegin() != YR.getBegin())
00342         return SM.isBeforeInTranslationUnit(XR.getBegin(), YR.getBegin());
00343       return SM.isBeforeInTranslationUnit(XR.getEnd(), YR.getEnd());
00344     }
00345   }
00346   
00347   switch (X.getKind()) {
00348     case clang::ento::PathDiagnosticPiece::ControlFlow:
00349       return compareControlFlow(cast<PathDiagnosticControlFlowPiece>(X),
00350                                 cast<PathDiagnosticControlFlowPiece>(Y));
00351     case clang::ento::PathDiagnosticPiece::Event:
00352       return None;
00353     case clang::ento::PathDiagnosticPiece::Macro:
00354       return compareMacro(cast<PathDiagnosticMacroPiece>(X),
00355                           cast<PathDiagnosticMacroPiece>(Y));
00356     case clang::ento::PathDiagnosticPiece::Call:
00357       return compareCall(cast<PathDiagnosticCallPiece>(X),
00358                          cast<PathDiagnosticCallPiece>(Y));
00359   }
00360   llvm_unreachable("all cases handled");
00361 }
00362 
00363 static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y) {
00364   if (X.size() != Y.size())
00365     return X.size() < Y.size();
00366 
00367   PathPieces::const_iterator X_I = X.begin(), X_end = X.end();
00368   PathPieces::const_iterator Y_I = Y.begin(), Y_end = Y.end();
00369 
00370   for ( ; X_I != X_end && Y_I != Y_end; ++X_I, ++Y_I) {
00371     Optional<bool> b = comparePiece(**X_I, **Y_I);
00372     if (b.hasValue())
00373       return b.getValue();
00374   }
00375 
00376   return None;
00377 }
00378 
00379 static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) {
00380   FullSourceLoc XL = X.getLocation().asLocation();
00381   FullSourceLoc YL = Y.getLocation().asLocation();
00382   if (XL != YL)
00383     return XL.isBeforeInTranslationUnitThan(YL);
00384   if (X.getBugType() != Y.getBugType())
00385     return X.getBugType() < Y.getBugType();
00386   if (X.getCategory() != Y.getCategory())
00387     return X.getCategory() < Y.getCategory();
00388   if (X.getVerboseDescription() != Y.getVerboseDescription())
00389     return X.getVerboseDescription() < Y.getVerboseDescription();
00390   if (X.getShortDescription() != Y.getShortDescription())
00391     return X.getShortDescription() < Y.getShortDescription();
00392   if (X.getDeclWithIssue() != Y.getDeclWithIssue()) {
00393     const Decl *XD = X.getDeclWithIssue();
00394     if (!XD)
00395       return true;
00396     const Decl *YD = Y.getDeclWithIssue();
00397     if (!YD)
00398       return false;
00399     SourceLocation XDL = XD->getLocation();
00400     SourceLocation YDL = YD->getLocation();
00401     if (XDL != YDL) {
00402       const SourceManager &SM = XL.getManager();
00403       return SM.isBeforeInTranslationUnit(XDL, YDL);
00404     }
00405   }
00406   PathDiagnostic::meta_iterator XI = X.meta_begin(), XE = X.meta_end();
00407   PathDiagnostic::meta_iterator YI = Y.meta_begin(), YE = Y.meta_end();
00408   if (XE - XI != YE - YI)
00409     return (XE - XI) < (YE - YI);
00410   for ( ; XI != XE ; ++XI, ++YI) {
00411     if (*XI != *YI)
00412       return (*XI) < (*YI);
00413   }
00414   Optional<bool> b = comparePath(X.path, Y.path);
00415   assert(b.hasValue());
00416   return b.getValue();
00417 }
00418 
00419 void PathDiagnosticConsumer::FlushDiagnostics(
00420                                      PathDiagnosticConsumer::FilesMade *Files) {
00421   if (flushed)
00422     return;
00423   
00424   flushed = true;
00425   
00426   std::vector<const PathDiagnostic *> BatchDiags;
00427   for (llvm::FoldingSet<PathDiagnostic>::iterator it = Diags.begin(),
00428        et = Diags.end(); it != et; ++it) {
00429     const PathDiagnostic *D = &*it;
00430     BatchDiags.push_back(D);
00431   }
00432 
00433   // Sort the diagnostics so that they are always emitted in a deterministic
00434   // order.
00435   if (!BatchDiags.empty())
00436     std::sort(BatchDiags.begin(), BatchDiags.end(),
00437               [](const PathDiagnostic *X, const PathDiagnostic *Y) {
00438       return X != Y && compare(*X, *Y);
00439     });
00440 
00441   FlushDiagnosticsImpl(BatchDiags, Files);
00442 
00443   // Delete the flushed diagnostics.
00444   for (std::vector<const PathDiagnostic *>::iterator it = BatchDiags.begin(),
00445        et = BatchDiags.end(); it != et; ++it) {
00446     const PathDiagnostic *D = *it;
00447     delete D;
00448   }
00449   
00450   // Clear out the FoldingSet.
00451   Diags.clear();
00452 }
00453 
00454 PathDiagnosticConsumer::FilesMade::~FilesMade() {
00455   for (PDFileEntry &Entry : *this)
00456     Entry.~PDFileEntry();
00457 }
00458 
00459 void PathDiagnosticConsumer::FilesMade::addDiagnostic(const PathDiagnostic &PD,
00460                                                       StringRef ConsumerName,
00461                                                       StringRef FileName) {
00462   llvm::FoldingSetNodeID NodeID;
00463   NodeID.Add(PD);
00464   void *InsertPos;
00465   PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos);
00466   if (!Entry) {
00467     Entry = Alloc.Allocate<PDFileEntry>();
00468     Entry = new (Entry) PDFileEntry(NodeID);
00469     InsertNode(Entry, InsertPos);
00470   }
00471   
00472   // Allocate persistent storage for the file name.
00473   char *FileName_cstr = (char*) Alloc.Allocate(FileName.size(), 1);
00474   memcpy(FileName_cstr, FileName.data(), FileName.size());
00475 
00476   Entry->files.push_back(std::make_pair(ConsumerName,
00477                                         StringRef(FileName_cstr,
00478                                                   FileName.size())));
00479 }
00480 
00481 PathDiagnosticConsumer::PDFileEntry::ConsumerFiles *
00482 PathDiagnosticConsumer::FilesMade::getFiles(const PathDiagnostic &PD) {
00483   llvm::FoldingSetNodeID NodeID;
00484   NodeID.Add(PD);
00485   void *InsertPos;
00486   PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos);
00487   if (!Entry)
00488     return nullptr;
00489   return &Entry->files;
00490 }
00491 
00492 //===----------------------------------------------------------------------===//
00493 // PathDiagnosticLocation methods.
00494 //===----------------------------------------------------------------------===//
00495 
00496 static SourceLocation getValidSourceLocation(const Stmt* S,
00497                                              LocationOrAnalysisDeclContext LAC,
00498                                              bool UseEnd = false) {
00499   SourceLocation L = UseEnd ? S->getLocEnd() : S->getLocStart();
00500   assert(!LAC.isNull() && "A valid LocationContext or AnalysisDeclContext should "
00501                           "be passed to PathDiagnosticLocation upon creation.");
00502 
00503   // S might be a temporary statement that does not have a location in the
00504   // source code, so find an enclosing statement and use its location.
00505   if (!L.isValid()) {
00506 
00507     AnalysisDeclContext *ADC;
00508     if (LAC.is<const LocationContext*>())
00509       ADC = LAC.get<const LocationContext*>()->getAnalysisDeclContext();
00510     else
00511       ADC = LAC.get<AnalysisDeclContext*>();
00512 
00513     ParentMap &PM = ADC->getParentMap();
00514 
00515     const Stmt *Parent = S;
00516     do {
00517       Parent = PM.getParent(Parent);
00518 
00519       // In rare cases, we have implicit top-level expressions,
00520       // such as arguments for implicit member initializers.
00521       // In this case, fall back to the start of the body (even if we were
00522       // asked for the statement end location).
00523       if (!Parent) {
00524         const Stmt *Body = ADC->getBody();
00525         if (Body)
00526           L = Body->getLocStart();
00527         else
00528           L = ADC->getDecl()->getLocEnd();
00529         break;
00530       }
00531 
00532       L = UseEnd ? Parent->getLocEnd() : Parent->getLocStart();
00533     } while (!L.isValid());
00534   }
00535 
00536   return L;
00537 }
00538 
00539 static PathDiagnosticLocation
00540 getLocationForCaller(const StackFrameContext *SFC,
00541                      const LocationContext *CallerCtx,
00542                      const SourceManager &SM) {
00543   const CFGBlock &Block = *SFC->getCallSiteBlock();
00544   CFGElement Source = Block[SFC->getIndex()];
00545 
00546   switch (Source.getKind()) {
00547   case CFGElement::Statement:
00548     return PathDiagnosticLocation(Source.castAs<CFGStmt>().getStmt(),
00549                                   SM, CallerCtx);
00550   case CFGElement::Initializer: {
00551     const CFGInitializer &Init = Source.castAs<CFGInitializer>();
00552     return PathDiagnosticLocation(Init.getInitializer()->getInit(),
00553                                   SM, CallerCtx);
00554   }
00555   case CFGElement::AutomaticObjectDtor: {
00556     const CFGAutomaticObjDtor &Dtor = Source.castAs<CFGAutomaticObjDtor>();
00557     return PathDiagnosticLocation::createEnd(Dtor.getTriggerStmt(),
00558                                              SM, CallerCtx);
00559   }
00560   case CFGElement::DeleteDtor: {
00561     const CFGDeleteDtor &Dtor = Source.castAs<CFGDeleteDtor>();
00562     return PathDiagnosticLocation(Dtor.getDeleteExpr(), SM, CallerCtx);
00563   }
00564   case CFGElement::BaseDtor:
00565   case CFGElement::MemberDtor: {
00566     const AnalysisDeclContext *CallerInfo = CallerCtx->getAnalysisDeclContext();
00567     if (const Stmt *CallerBody = CallerInfo->getBody())
00568       return PathDiagnosticLocation::createEnd(CallerBody, SM, CallerCtx);
00569     return PathDiagnosticLocation::create(CallerInfo->getDecl(), SM);
00570   }
00571   case CFGElement::TemporaryDtor:
00572   case CFGElement::NewAllocator:
00573     llvm_unreachable("not yet implemented!");
00574   }
00575 
00576   llvm_unreachable("Unknown CFGElement kind");
00577 }
00578 
00579 
00580 PathDiagnosticLocation
00581   PathDiagnosticLocation::createBegin(const Decl *D,
00582                                       const SourceManager &SM) {
00583   return PathDiagnosticLocation(D->getLocStart(), SM, SingleLocK);
00584 }
00585 
00586 PathDiagnosticLocation
00587   PathDiagnosticLocation::createBegin(const Stmt *S,
00588                                       const SourceManager &SM,
00589                                       LocationOrAnalysisDeclContext LAC) {
00590   return PathDiagnosticLocation(getValidSourceLocation(S, LAC),
00591                                 SM, SingleLocK);
00592 }
00593 
00594 
00595 PathDiagnosticLocation
00596 PathDiagnosticLocation::createEnd(const Stmt *S,
00597                                   const SourceManager &SM,
00598                                   LocationOrAnalysisDeclContext LAC) {
00599   if (const CompoundStmt *CS = dyn_cast<CompoundStmt>(S))
00600     return createEndBrace(CS, SM);
00601   return PathDiagnosticLocation(getValidSourceLocation(S, LAC, /*End=*/true),
00602                                 SM, SingleLocK);
00603 }
00604 
00605 PathDiagnosticLocation
00606   PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO,
00607                                             const SourceManager &SM) {
00608   return PathDiagnosticLocation(BO->getOperatorLoc(), SM, SingleLocK);
00609 }
00610 
00611 PathDiagnosticLocation
00612   PathDiagnosticLocation::createConditionalColonLoc(
00613                                             const ConditionalOperator *CO,
00614                                             const SourceManager &SM) {
00615   return PathDiagnosticLocation(CO->getColonLoc(), SM, SingleLocK);
00616 }
00617 
00618 
00619 PathDiagnosticLocation
00620   PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME,
00621                                           const SourceManager &SM) {
00622   return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK);
00623 }
00624 
00625 PathDiagnosticLocation
00626   PathDiagnosticLocation::createBeginBrace(const CompoundStmt *CS,
00627                                            const SourceManager &SM) {
00628   SourceLocation L = CS->getLBracLoc();
00629   return PathDiagnosticLocation(L, SM, SingleLocK);
00630 }
00631 
00632 PathDiagnosticLocation
00633   PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS,
00634                                          const SourceManager &SM) {
00635   SourceLocation L = CS->getRBracLoc();
00636   return PathDiagnosticLocation(L, SM, SingleLocK);
00637 }
00638 
00639 PathDiagnosticLocation
00640   PathDiagnosticLocation::createDeclBegin(const LocationContext *LC,
00641                                           const SourceManager &SM) {
00642   // FIXME: Should handle CXXTryStmt if analyser starts supporting C++.
00643   if (const CompoundStmt *CS =
00644         dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody()))
00645     if (!CS->body_empty()) {
00646       SourceLocation Loc = (*CS->body_begin())->getLocStart();
00647       return PathDiagnosticLocation(Loc, SM, SingleLocK);
00648     }
00649 
00650   return PathDiagnosticLocation();
00651 }
00652 
00653 PathDiagnosticLocation
00654   PathDiagnosticLocation::createDeclEnd(const LocationContext *LC,
00655                                         const SourceManager &SM) {
00656   SourceLocation L = LC->getDecl()->getBodyRBrace();
00657   return PathDiagnosticLocation(L, SM, SingleLocK);
00658 }
00659 
00660 PathDiagnosticLocation
00661   PathDiagnosticLocation::create(const ProgramPoint& P,
00662                                  const SourceManager &SMng) {
00663 
00664   const Stmt* S = nullptr;
00665   if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
00666     const CFGBlock *BSrc = BE->getSrc();
00667     S = BSrc->getTerminatorCondition();
00668   } else if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) {
00669     S = SP->getStmt();
00670     if (P.getAs<PostStmtPurgeDeadSymbols>())
00671       return PathDiagnosticLocation::createEnd(S, SMng, P.getLocationContext());
00672   } else if (Optional<PostInitializer> PIP = P.getAs<PostInitializer>()) {
00673     return PathDiagnosticLocation(PIP->getInitializer()->getSourceLocation(),
00674                                   SMng);
00675   } else if (Optional<PostImplicitCall> PIE = P.getAs<PostImplicitCall>()) {
00676     return PathDiagnosticLocation(PIE->getLocation(), SMng);
00677   } else if (Optional<CallEnter> CE = P.getAs<CallEnter>()) {
00678     return getLocationForCaller(CE->getCalleeContext(),
00679                                 CE->getLocationContext(),
00680                                 SMng);
00681   } else if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) {
00682     return getLocationForCaller(CEE->getCalleeContext(),
00683                                 CEE->getLocationContext(),
00684                                 SMng);
00685   } else {
00686     llvm_unreachable("Unexpected ProgramPoint");
00687   }
00688 
00689   return PathDiagnosticLocation(S, SMng, P.getLocationContext());
00690 }
00691 
00692 const Stmt *PathDiagnosticLocation::getStmt(const ExplodedNode *N) {
00693   ProgramPoint P = N->getLocation();
00694   if (Optional<StmtPoint> SP = P.getAs<StmtPoint>())
00695     return SP->getStmt();
00696   if (Optional<BlockEdge> BE = P.getAs<BlockEdge>())
00697     return BE->getSrc()->getTerminator();
00698   if (Optional<CallEnter> CE = P.getAs<CallEnter>())
00699     return CE->getCallExpr();
00700   if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>())
00701     return CEE->getCalleeContext()->getCallSite();
00702   if (Optional<PostInitializer> PIPP = P.getAs<PostInitializer>())
00703     return PIPP->getInitializer()->getInit();
00704 
00705   return nullptr;
00706 }
00707 
00708 const Stmt *PathDiagnosticLocation::getNextStmt(const ExplodedNode *N) {
00709   for (N = N->getFirstSucc(); N; N = N->getFirstSucc()) {
00710     if (const Stmt *S = getStmt(N)) {
00711       // Check if the statement is '?' or '&&'/'||'.  These are "merges",
00712       // not actual statement points.
00713       switch (S->getStmtClass()) {
00714         case Stmt::ChooseExprClass:
00715         case Stmt::BinaryConditionalOperatorClass:
00716         case Stmt::ConditionalOperatorClass:
00717           continue;
00718         case Stmt::BinaryOperatorClass: {
00719           BinaryOperatorKind Op = cast<BinaryOperator>(S)->getOpcode();
00720           if (Op == BO_LAnd || Op == BO_LOr)
00721             continue;
00722           break;
00723         }
00724         default:
00725           break;
00726       }
00727       // We found the statement, so return it.
00728       return S;
00729     }
00730   }
00731 
00732   return nullptr;
00733 }
00734 
00735 PathDiagnosticLocation
00736   PathDiagnosticLocation::createEndOfPath(const ExplodedNode *N,
00737                                           const SourceManager &SM) {
00738   assert(N && "Cannot create a location with a null node.");
00739   const Stmt *S = getStmt(N);
00740 
00741   if (!S) {
00742     // If this is an implicit call, return the implicit call point location.
00743     if (Optional<PreImplicitCall> PIE = N->getLocationAs<PreImplicitCall>())
00744       return PathDiagnosticLocation(PIE->getLocation(), SM);
00745     S = getNextStmt(N);
00746   }
00747 
00748   if (S) {
00749     ProgramPoint P = N->getLocation();
00750     const LocationContext *LC = N->getLocationContext();
00751 
00752     // For member expressions, return the location of the '.' or '->'.
00753     if (const MemberExpr *ME = dyn_cast<MemberExpr>(S))
00754       return PathDiagnosticLocation::createMemberLoc(ME, SM);
00755 
00756     // For binary operators, return the location of the operator.
00757     if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S))
00758       return PathDiagnosticLocation::createOperatorLoc(B, SM);
00759 
00760     if (P.getAs<PostStmtPurgeDeadSymbols>())
00761       return PathDiagnosticLocation::createEnd(S, SM, LC);
00762 
00763     if (S->getLocStart().isValid())
00764       return PathDiagnosticLocation(S, SM, LC);
00765     return PathDiagnosticLocation(getValidSourceLocation(S, LC), SM);
00766   }
00767 
00768   return createDeclEnd(N->getLocationContext(), SM);
00769 }
00770 
00771 PathDiagnosticLocation PathDiagnosticLocation::createSingleLocation(
00772                                            const PathDiagnosticLocation &PDL) {
00773   FullSourceLoc L = PDL.asLocation();
00774   return PathDiagnosticLocation(L, L.getManager(), SingleLocK);
00775 }
00776 
00777 FullSourceLoc
00778   PathDiagnosticLocation::genLocation(SourceLocation L,
00779                                       LocationOrAnalysisDeclContext LAC) const {
00780   assert(isValid());
00781   // Note that we want a 'switch' here so that the compiler can warn us in
00782   // case we add more cases.
00783   switch (K) {
00784     case SingleLocK:
00785     case RangeK:
00786       break;
00787     case StmtK:
00788       // Defensive checking.
00789       if (!S)
00790         break;
00791       return FullSourceLoc(getValidSourceLocation(S, LAC),
00792                            const_cast<SourceManager&>(*SM));
00793     case DeclK:
00794       // Defensive checking.
00795       if (!D)
00796         break;
00797       return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM));
00798   }
00799 
00800   return FullSourceLoc(L, const_cast<SourceManager&>(*SM));
00801 }
00802 
00803 PathDiagnosticRange
00804   PathDiagnosticLocation::genRange(LocationOrAnalysisDeclContext LAC) const {
00805   assert(isValid());
00806   // Note that we want a 'switch' here so that the compiler can warn us in
00807   // case we add more cases.
00808   switch (K) {
00809     case SingleLocK:
00810       return PathDiagnosticRange(SourceRange(Loc,Loc), true);
00811     case RangeK:
00812       break;
00813     case StmtK: {
00814       const Stmt *S = asStmt();
00815       switch (S->getStmtClass()) {
00816         default:
00817           break;
00818         case Stmt::DeclStmtClass: {
00819           const DeclStmt *DS = cast<DeclStmt>(S);
00820           if (DS->isSingleDecl()) {
00821             // Should always be the case, but we'll be defensive.
00822             return SourceRange(DS->getLocStart(),
00823                                DS->getSingleDecl()->getLocation());
00824           }
00825           break;
00826         }
00827           // FIXME: Provide better range information for different
00828           //  terminators.
00829         case Stmt::IfStmtClass:
00830         case Stmt::WhileStmtClass:
00831         case Stmt::DoStmtClass:
00832         case Stmt::ForStmtClass:
00833         case Stmt::ChooseExprClass:
00834         case Stmt::IndirectGotoStmtClass:
00835         case Stmt::SwitchStmtClass:
00836         case Stmt::BinaryConditionalOperatorClass:
00837         case Stmt::ConditionalOperatorClass:
00838         case Stmt::ObjCForCollectionStmtClass: {
00839           SourceLocation L = getValidSourceLocation(S, LAC);
00840           return SourceRange(L, L);
00841         }
00842       }
00843       SourceRange R = S->getSourceRange();
00844       if (R.isValid())
00845         return R;
00846       break;  
00847     }
00848     case DeclK:
00849       if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
00850         return MD->getSourceRange();
00851       if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
00852         if (Stmt *Body = FD->getBody())
00853           return Body->getSourceRange();
00854       }
00855       else {
00856         SourceLocation L = D->getLocation();
00857         return PathDiagnosticRange(SourceRange(L, L), true);
00858       }
00859   }
00860 
00861   return SourceRange(Loc,Loc);
00862 }
00863 
00864 void PathDiagnosticLocation::flatten() {
00865   if (K == StmtK) {
00866     K = RangeK;
00867     S = nullptr;
00868     D = nullptr;
00869   }
00870   else if (K == DeclK) {
00871     K = SingleLocK;
00872     S = nullptr;
00873     D = nullptr;
00874   }
00875 }
00876 
00877 //===----------------------------------------------------------------------===//
00878 // Manipulation of PathDiagnosticCallPieces.
00879 //===----------------------------------------------------------------------===//
00880 
00881 PathDiagnosticCallPiece *
00882 PathDiagnosticCallPiece::construct(const ExplodedNode *N,
00883                                    const CallExitEnd &CE,
00884                                    const SourceManager &SM) {
00885   const Decl *caller = CE.getLocationContext()->getDecl();
00886   PathDiagnosticLocation pos = getLocationForCaller(CE.getCalleeContext(),
00887                                                     CE.getLocationContext(),
00888                                                     SM);
00889   return new PathDiagnosticCallPiece(caller, pos);
00890 }
00891 
00892 PathDiagnosticCallPiece *
00893 PathDiagnosticCallPiece::construct(PathPieces &path,
00894                                    const Decl *caller) {
00895   PathDiagnosticCallPiece *C = new PathDiagnosticCallPiece(path, caller);
00896   path.clear();
00897   path.push_front(C);
00898   return C;
00899 }
00900 
00901 void PathDiagnosticCallPiece::setCallee(const CallEnter &CE,
00902                                         const SourceManager &SM) {
00903   const StackFrameContext *CalleeCtx = CE.getCalleeContext();
00904   Callee = CalleeCtx->getDecl();
00905 
00906   callEnterWithin = PathDiagnosticLocation::createBegin(Callee, SM);
00907   callEnter = getLocationForCaller(CalleeCtx, CE.getLocationContext(), SM);
00908 }
00909 
00910 static inline void describeClass(raw_ostream &Out, const CXXRecordDecl *D,
00911                                  StringRef Prefix = StringRef()) {
00912   if (!D->getIdentifier())
00913     return;
00914   Out << Prefix << '\'' << *D << '\'';
00915 }
00916 
00917 static bool describeCodeDecl(raw_ostream &Out, const Decl *D,
00918                              bool ExtendedDescription,
00919                              StringRef Prefix = StringRef()) {
00920   if (!D)
00921     return false;
00922 
00923   if (isa<BlockDecl>(D)) {
00924     if (ExtendedDescription)
00925       Out << Prefix << "anonymous block";
00926     return ExtendedDescription;
00927   }
00928 
00929   if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
00930     Out << Prefix;
00931     if (ExtendedDescription && !MD->isUserProvided()) {
00932       if (MD->isExplicitlyDefaulted())
00933         Out << "defaulted ";
00934       else
00935         Out << "implicit ";
00936     }
00937 
00938     if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(MD)) {
00939       if (CD->isDefaultConstructor())
00940         Out << "default ";
00941       else if (CD->isCopyConstructor())
00942         Out << "copy ";
00943       else if (CD->isMoveConstructor())
00944         Out << "move ";
00945 
00946       Out << "constructor";
00947       describeClass(Out, MD->getParent(), " for ");
00948       
00949     } else if (isa<CXXDestructorDecl>(MD)) {
00950       if (!MD->isUserProvided()) {
00951         Out << "destructor";
00952         describeClass(Out, MD->getParent(), " for ");
00953       } else {
00954         // Use ~Foo for explicitly-written destructors.
00955         Out << "'" << *MD << "'";
00956       }
00957 
00958     } else if (MD->isCopyAssignmentOperator()) {
00959         Out << "copy assignment operator";
00960         describeClass(Out, MD->getParent(), " for ");
00961 
00962     } else if (MD->isMoveAssignmentOperator()) {
00963         Out << "move assignment operator";
00964         describeClass(Out, MD->getParent(), " for ");
00965 
00966     } else {
00967       if (MD->getParent()->getIdentifier())
00968         Out << "'" << *MD->getParent() << "::" << *MD << "'";
00969       else
00970         Out << "'" << *MD << "'";
00971     }
00972 
00973     return true;
00974   }
00975 
00976   Out << Prefix << '\'' << cast<NamedDecl>(*D) << '\'';
00977   return true;
00978 }
00979 
00980 IntrusiveRefCntPtr<PathDiagnosticEventPiece>
00981 PathDiagnosticCallPiece::getCallEnterEvent() const {
00982   if (!Callee)
00983     return nullptr;
00984 
00985   SmallString<256> buf;
00986   llvm::raw_svector_ostream Out(buf);
00987 
00988   Out << "Calling ";
00989   describeCodeDecl(Out, Callee, /*ExtendedDescription=*/true);
00990 
00991   assert(callEnter.asLocation().isValid());
00992   return new PathDiagnosticEventPiece(callEnter, Out.str());
00993 }
00994 
00995 IntrusiveRefCntPtr<PathDiagnosticEventPiece>
00996 PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const {
00997   if (!callEnterWithin.asLocation().isValid())
00998     return nullptr;
00999   if (Callee->isImplicit() || !Callee->hasBody())
01000     return nullptr;
01001   if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Callee))
01002     if (MD->isDefaulted())
01003       return nullptr;
01004 
01005   SmallString<256> buf;
01006   llvm::raw_svector_ostream Out(buf);
01007 
01008   Out << "Entered call";
01009   describeCodeDecl(Out, Caller, /*ExtendedDescription=*/false, " from ");
01010 
01011   return new PathDiagnosticEventPiece(callEnterWithin, Out.str());
01012 }
01013 
01014 IntrusiveRefCntPtr<PathDiagnosticEventPiece>
01015 PathDiagnosticCallPiece::getCallExitEvent() const {
01016   if (NoExit)
01017     return nullptr;
01018 
01019   SmallString<256> buf;
01020   llvm::raw_svector_ostream Out(buf);
01021 
01022   if (!CallStackMessage.empty()) {
01023     Out << CallStackMessage;
01024   } else {
01025     bool DidDescribe = describeCodeDecl(Out, Callee,
01026                                         /*ExtendedDescription=*/false,
01027                                         "Returning from ");
01028     if (!DidDescribe)
01029       Out << "Returning to caller";
01030   }
01031 
01032   assert(callReturn.asLocation().isValid());
01033   return new PathDiagnosticEventPiece(callReturn, Out.str());
01034 }
01035 
01036 static void compute_path_size(const PathPieces &pieces, unsigned &size) {
01037   for (PathPieces::const_iterator it = pieces.begin(),
01038                                   et = pieces.end(); it != et; ++it) {
01039     const PathDiagnosticPiece *piece = it->get();
01040     if (const PathDiagnosticCallPiece *cp = 
01041         dyn_cast<PathDiagnosticCallPiece>(piece)) {
01042       compute_path_size(cp->path, size);
01043     }
01044     else
01045       ++size;
01046   }
01047 }
01048 
01049 unsigned PathDiagnostic::full_size() {
01050   unsigned size = 0;
01051   compute_path_size(path, size);
01052   return size;
01053 }
01054 
01055 //===----------------------------------------------------------------------===//
01056 // FoldingSet profiling methods.
01057 //===----------------------------------------------------------------------===//
01058 
01059 void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const {
01060   ID.AddInteger(Range.getBegin().getRawEncoding());
01061   ID.AddInteger(Range.getEnd().getRawEncoding());
01062   ID.AddInteger(Loc.getRawEncoding());
01063   return;
01064 }
01065 
01066 void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const {
01067   ID.AddInteger((unsigned) getKind());
01068   ID.AddString(str);
01069   // FIXME: Add profiling support for code hints.
01070   ID.AddInteger((unsigned) getDisplayHint());
01071   ArrayRef<SourceRange> Ranges = getRanges();
01072   for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end();
01073                                         I != E; ++I) {
01074     ID.AddInteger(I->getBegin().getRawEncoding());
01075     ID.AddInteger(I->getEnd().getRawEncoding());
01076   }  
01077 }
01078 
01079 void PathDiagnosticCallPiece::Profile(llvm::FoldingSetNodeID &ID) const {
01080   PathDiagnosticPiece::Profile(ID);
01081   for (PathPieces::const_iterator it = path.begin(), 
01082        et = path.end(); it != et; ++it) {
01083     ID.Add(**it);
01084   }
01085 }
01086 
01087 void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const {
01088   PathDiagnosticPiece::Profile(ID);
01089   ID.Add(Pos);
01090 }
01091 
01092 void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const {
01093   PathDiagnosticPiece::Profile(ID);
01094   for (const_iterator I = begin(), E = end(); I != E; ++I)
01095     ID.Add(*I);
01096 }
01097 
01098 void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const {
01099   PathDiagnosticSpotPiece::Profile(ID);
01100   for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end();
01101        I != E; ++I)
01102     ID.Add(**I);
01103 }
01104 
01105 void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const {
01106   ID.Add(getLocation());
01107   ID.AddString(BugType);
01108   ID.AddString(VerboseDesc);
01109   ID.AddString(Category);
01110 }
01111 
01112 void PathDiagnostic::FullProfile(llvm::FoldingSetNodeID &ID) const {
01113   Profile(ID);
01114   for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E; ++I)
01115     ID.Add(**I);
01116   for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I)
01117     ID.AddString(*I);
01118 }
01119 
01120 StackHintGenerator::~StackHintGenerator() {}
01121 
01122 std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){
01123   ProgramPoint P = N->getLocation();
01124   CallExitEnd CExit = P.castAs<CallExitEnd>();
01125 
01126   // FIXME: Use CallEvent to abstract this over all calls.
01127   const Stmt *CallSite = CExit.getCalleeContext()->getCallSite();
01128   const CallExpr *CE = dyn_cast_or_null<CallExpr>(CallSite);
01129   if (!CE)
01130     return "";
01131 
01132   if (!N)
01133     return getMessageForSymbolNotFound();
01134 
01135   // Check if one of the parameters are set to the interesting symbol.
01136   ProgramStateRef State = N->getState();
01137   const LocationContext *LCtx = N->getLocationContext();
01138   unsigned ArgIndex = 0;
01139   for (CallExpr::const_arg_iterator I = CE->arg_begin(),
01140                                     E = CE->arg_end(); I != E; ++I, ++ArgIndex){
01141     SVal SV = State->getSVal(*I, LCtx);
01142 
01143     // Check if the variable corresponding to the symbol is passed by value.
01144     SymbolRef AS = SV.getAsLocSymbol();
01145     if (AS == Sym) {
01146       return getMessageForArg(*I, ArgIndex);
01147     }
01148 
01149     // Check if the parameter is a pointer to the symbol.
01150     if (Optional<loc::MemRegionVal> Reg = SV.getAs<loc::MemRegionVal>()) {
01151       SVal PSV = State->getSVal(Reg->getRegion());
01152       SymbolRef AS = PSV.getAsLocSymbol();
01153       if (AS == Sym) {
01154         return getMessageForArg(*I, ArgIndex);
01155       }
01156     }
01157   }
01158 
01159   // Check if we are returning the interesting symbol.
01160   SVal SV = State->getSVal(CE, LCtx);
01161   SymbolRef RetSym = SV.getAsLocSymbol();
01162   if (RetSym == Sym) {
01163     return getMessageForReturn(CE);
01164   }
01165 
01166   return getMessageForSymbolNotFound();
01167 }
01168 
01169 std::string StackHintGeneratorForSymbol::getMessageForArg(const Expr *ArgE,
01170                                                           unsigned ArgIndex) {
01171   // Printed parameters start at 1, not 0.
01172   ++ArgIndex;
01173 
01174   SmallString<200> buf;
01175   llvm::raw_svector_ostream os(buf);
01176 
01177   os << Msg << " via " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex)
01178      << " parameter";
01179 
01180   return os.str();
01181 }