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