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