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