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