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