1 //===- PathDiagnostic.cpp - Path-Specific Diagnostic Handling -------------===//
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/DeclBase.h"
17 #include "clang/AST/DeclCXX.h"
18 #include "clang/AST/DeclObjC.h"
19 #include "clang/AST/DeclTemplate.h"
20 #include "clang/AST/Expr.h"
21 #include "clang/AST/ExprCXX.h"
22 #include "clang/AST/OperationKinds.h"
23 #include "clang/AST/ParentMap.h"
24 #include "clang/AST/Stmt.h"
25 #include "clang/AST/Type.h"
26 #include "clang/Analysis/AnalysisDeclContext.h"
27 #include "clang/Analysis/CFG.h"
28 #include "clang/Analysis/ProgramPoint.h"
29 #include "clang/Basic/FileManager.h"
30 #include "clang/Basic/LLVM.h"
31 #include "clang/Basic/SourceLocation.h"
32 #include "clang/Basic/SourceManager.h"
33 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
34 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
35 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
36 #include "llvm/ADT/ArrayRef.h"
37 #include "llvm/ADT/FoldingSet.h"
38 #include "llvm/ADT/None.h"
39 #include "llvm/ADT/Optional.h"
40 #include "llvm/ADT/STLExtras.h"
41 #include "llvm/ADT/SmallString.h"
42 #include "llvm/ADT/SmallVector.h"
43 #include "llvm/ADT/StringExtras.h"
44 #include "llvm/ADT/StringRef.h"
45 #include "llvm/Support/Casting.h"
46 #include "llvm/Support/ErrorHandling.h"
47 #include "llvm/Support/raw_ostream.h"
48 #include <cassert>
49 #include <cstring>
50 #include <memory>
51 #include <utility>
52 #include <vector>
53 
54 using namespace clang;
55 using namespace ento;
56 
containsEvent() const57 bool PathDiagnosticMacroPiece::containsEvent() const {
58   for (const auto &P : subPieces) {
59     if (isa<PathDiagnosticEventPiece>(*P))
60       return true;
61     if (const auto *MP = dyn_cast<PathDiagnosticMacroPiece>(P.get()))
62       if (MP->containsEvent())
63         return true;
64   }
65   return false;
66 }
67 
StripTrailingDots(StringRef s)68 static StringRef StripTrailingDots(StringRef s) {
69   for (StringRef::size_type i = s.size(); i != 0; --i)
70     if (s[i - 1] != '.')
71       return s.substr(0, i);
72   return {};
73 }
74 
PathDiagnosticPiece(StringRef s,Kind k,DisplayHint hint)75 PathDiagnosticPiece::PathDiagnosticPiece(StringRef s,
76                                          Kind k, DisplayHint hint)
77     : str(StripTrailingDots(s)), kind(k), Hint(hint) {}
78 
PathDiagnosticPiece(Kind k,DisplayHint hint)79 PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint)
80     : kind(k), Hint(hint) {}
81 
82 PathDiagnosticPiece::~PathDiagnosticPiece() = default;
83 
84 PathDiagnosticEventPiece::~PathDiagnosticEventPiece() = default;
85 
86 PathDiagnosticCallPiece::~PathDiagnosticCallPiece() = default;
87 
88 PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() = default;
89 
90 PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() = default;
91 
92 PathDiagnosticNotePiece::~PathDiagnosticNotePiece() = default;
93 
flattenTo(PathPieces & Primary,PathPieces & Current,bool ShouldFlattenMacros) const94 void PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current,
95                            bool ShouldFlattenMacros) const {
96   for (auto &Piece : *this) {
97     switch (Piece->getKind()) {
98     case PathDiagnosticPiece::Call: {
99       auto &Call = cast<PathDiagnosticCallPiece>(*Piece);
100       if (auto CallEnter = Call.getCallEnterEvent())
101         Current.push_back(std::move(CallEnter));
102       Call.path.flattenTo(Primary, Primary, ShouldFlattenMacros);
103       if (auto callExit = Call.getCallExitEvent())
104         Current.push_back(std::move(callExit));
105       break;
106     }
107     case PathDiagnosticPiece::Macro: {
108       auto &Macro = cast<PathDiagnosticMacroPiece>(*Piece);
109       if (ShouldFlattenMacros) {
110         Macro.subPieces.flattenTo(Primary, Primary, ShouldFlattenMacros);
111       } else {
112         Current.push_back(Piece);
113         PathPieces NewPath;
114         Macro.subPieces.flattenTo(Primary, NewPath, ShouldFlattenMacros);
115         // FIXME: This probably shouldn't mutate the original path piece.
116         Macro.subPieces = NewPath;
117       }
118       break;
119     }
120     case PathDiagnosticPiece::Event:
121     case PathDiagnosticPiece::ControlFlow:
122     case PathDiagnosticPiece::Note:
123       Current.push_back(Piece);
124       break;
125     }
126   }
127 }
128 
129 PathDiagnostic::~PathDiagnostic() = default;
130 
PathDiagnostic(StringRef CheckName,const Decl * declWithIssue,StringRef bugtype,StringRef verboseDesc,StringRef shortDesc,StringRef category,PathDiagnosticLocation LocationToUnique,const Decl * DeclToUnique,std::unique_ptr<FilesToLineNumsMap> ExecutedLines)131 PathDiagnostic::PathDiagnostic(
132     StringRef CheckName, const Decl *declWithIssue, StringRef bugtype,
133     StringRef verboseDesc, StringRef shortDesc, StringRef category,
134     PathDiagnosticLocation LocationToUnique, const Decl *DeclToUnique,
135     std::unique_ptr<FilesToLineNumsMap> ExecutedLines)
136     : CheckName(CheckName), DeclWithIssue(declWithIssue),
137       BugType(StripTrailingDots(bugtype)),
138       VerboseDesc(StripTrailingDots(verboseDesc)),
139       ShortDesc(StripTrailingDots(shortDesc)),
140       Category(StripTrailingDots(category)), UniqueingLoc(LocationToUnique),
141       UniqueingDecl(DeclToUnique), ExecutedLines(std::move(ExecutedLines)),
142       path(pathImpl) {}
143 
144 static PathDiagnosticCallPiece *
getFirstStackedCallToHeaderFile(PathDiagnosticCallPiece * CP,const SourceManager & SMgr)145 getFirstStackedCallToHeaderFile(PathDiagnosticCallPiece *CP,
146                                 const SourceManager &SMgr) {
147   SourceLocation CallLoc = CP->callEnter.asLocation();
148 
149   // If the call is within a macro, don't do anything (for now).
150   if (CallLoc.isMacroID())
151     return nullptr;
152 
153   assert(AnalysisManager::isInCodeFile(CallLoc, SMgr) &&
154          "The call piece should not be in a header file.");
155 
156   // Check if CP represents a path through a function outside of the main file.
157   if (!AnalysisManager::isInCodeFile(CP->callEnterWithin.asLocation(), SMgr))
158     return CP;
159 
160   const PathPieces &Path = CP->path;
161   if (Path.empty())
162     return nullptr;
163 
164   // Check if the last piece in the callee path is a call to a function outside
165   // of the main file.
166   if (auto *CPInner = dyn_cast<PathDiagnosticCallPiece>(Path.back().get()))
167     return getFirstStackedCallToHeaderFile(CPInner, SMgr);
168 
169   // Otherwise, the last piece is in the main file.
170   return nullptr;
171 }
172 
resetDiagnosticLocationToMainFile()173 void PathDiagnostic::resetDiagnosticLocationToMainFile() {
174   if (path.empty())
175     return;
176 
177   PathDiagnosticPiece *LastP = path.back().get();
178   assert(LastP);
179   const SourceManager &SMgr = LastP->getLocation().getManager();
180 
181   // We only need to check if the report ends inside headers, if the last piece
182   // is a call piece.
183   if (auto *CP = dyn_cast<PathDiagnosticCallPiece>(LastP)) {
184     CP = getFirstStackedCallToHeaderFile(CP, SMgr);
185     if (CP) {
186       // Mark the piece.
187        CP->setAsLastInMainSourceFile();
188 
189       // Update the path diagnostic message.
190       const auto *ND = dyn_cast<NamedDecl>(CP->getCallee());
191       if (ND) {
192         SmallString<200> buf;
193         llvm::raw_svector_ostream os(buf);
194         os << " (within a call to '" << ND->getDeclName() << "')";
195         appendToDesc(os.str());
196       }
197 
198       // Reset the report containing declaration and location.
199       DeclWithIssue = CP->getCaller();
200       Loc = CP->getLocation();
201 
202       return;
203     }
204   }
205 }
206 
anchor()207 void PathDiagnosticConsumer::anchor() {}
208 
~PathDiagnosticConsumer()209 PathDiagnosticConsumer::~PathDiagnosticConsumer() {
210   // Delete the contents of the FoldingSet if it isn't empty already.
211   for (auto &Diag : Diags)
212     delete &Diag;
213 }
214 
HandlePathDiagnostic(std::unique_ptr<PathDiagnostic> D)215 void PathDiagnosticConsumer::HandlePathDiagnostic(
216     std::unique_ptr<PathDiagnostic> D) {
217   if (!D || D->path.empty())
218     return;
219 
220   // We need to flatten the locations (convert Stmt* to locations) because
221   // the referenced statements may be freed by the time the diagnostics
222   // are emitted.
223   D->flattenLocations();
224 
225   // If the PathDiagnosticConsumer does not support diagnostics that
226   // cross file boundaries, prune out such diagnostics now.
227   if (!supportsCrossFileDiagnostics()) {
228     // Verify that the entire path is from the same FileID.
229     FileID FID;
230     const SourceManager &SMgr = D->path.front()->getLocation().getManager();
231     SmallVector<const PathPieces *, 5> WorkList;
232     WorkList.push_back(&D->path);
233     SmallString<128> buf;
234     llvm::raw_svector_ostream warning(buf);
235     warning << "warning: Path diagnostic report is not generated. Current "
236             << "output format does not support diagnostics that cross file "
237             << "boundaries. Refer to --analyzer-output for valid output "
238             << "formats\n";
239 
240     while (!WorkList.empty()) {
241       const PathPieces &path = *WorkList.pop_back_val();
242 
243       for (const auto &I : path) {
244         const PathDiagnosticPiece *piece = I.get();
245         FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc();
246 
247         if (FID.isInvalid()) {
248           FID = SMgr.getFileID(L);
249         } else if (SMgr.getFileID(L) != FID) {
250           llvm::errs() << warning.str();
251           return;
252         }
253 
254         // Check the source ranges.
255         ArrayRef<SourceRange> Ranges = piece->getRanges();
256         for (const auto &I : Ranges) {
257           SourceLocation L = SMgr.getExpansionLoc(I.getBegin());
258           if (!L.isFileID() || SMgr.getFileID(L) != FID) {
259             llvm::errs() << warning.str();
260             return;
261           }
262           L = SMgr.getExpansionLoc(I.getEnd());
263           if (!L.isFileID() || SMgr.getFileID(L) != FID) {
264             llvm::errs() << warning.str();
265             return;
266           }
267         }
268 
269         if (const auto *call = dyn_cast<PathDiagnosticCallPiece>(piece))
270           WorkList.push_back(&call->path);
271         else if (const auto *macro = dyn_cast<PathDiagnosticMacroPiece>(piece))
272           WorkList.push_back(&macro->subPieces);
273       }
274     }
275 
276     if (FID.isInvalid())
277       return; // FIXME: Emit a warning?
278   }
279 
280   // Profile the node to see if we already have something matching it
281   llvm::FoldingSetNodeID profile;
282   D->Profile(profile);
283   void *InsertPos = nullptr;
284 
285   if (PathDiagnostic *orig = Diags.FindNodeOrInsertPos(profile, InsertPos)) {
286     // Keep the PathDiagnostic with the shorter path.
287     // Note, the enclosing routine is called in deterministic order, so the
288     // results will be consistent between runs (no reason to break ties if the
289     // size is the same).
290     const unsigned orig_size = orig->full_size();
291     const unsigned new_size = D->full_size();
292     if (orig_size <= new_size)
293       return;
294 
295     assert(orig != D.get());
296     Diags.RemoveNode(orig);
297     delete orig;
298   }
299 
300   Diags.InsertNode(D.release());
301 }
302 
303 static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y);
304 
305 static Optional<bool>
compareControlFlow(const PathDiagnosticControlFlowPiece & X,const PathDiagnosticControlFlowPiece & Y)306 compareControlFlow(const PathDiagnosticControlFlowPiece &X,
307                    const PathDiagnosticControlFlowPiece &Y) {
308   FullSourceLoc XSL = X.getStartLocation().asLocation();
309   FullSourceLoc YSL = Y.getStartLocation().asLocation();
310   if (XSL != YSL)
311     return XSL.isBeforeInTranslationUnitThan(YSL);
312   FullSourceLoc XEL = X.getEndLocation().asLocation();
313   FullSourceLoc YEL = Y.getEndLocation().asLocation();
314   if (XEL != YEL)
315     return XEL.isBeforeInTranslationUnitThan(YEL);
316   return None;
317 }
318 
compareMacro(const PathDiagnosticMacroPiece & X,const PathDiagnosticMacroPiece & Y)319 static Optional<bool> compareMacro(const PathDiagnosticMacroPiece &X,
320                                    const PathDiagnosticMacroPiece &Y) {
321   return comparePath(X.subPieces, Y.subPieces);
322 }
323 
compareCall(const PathDiagnosticCallPiece & X,const PathDiagnosticCallPiece & Y)324 static Optional<bool> compareCall(const PathDiagnosticCallPiece &X,
325                                   const PathDiagnosticCallPiece &Y) {
326   FullSourceLoc X_CEL = X.callEnter.asLocation();
327   FullSourceLoc Y_CEL = Y.callEnter.asLocation();
328   if (X_CEL != Y_CEL)
329     return X_CEL.isBeforeInTranslationUnitThan(Y_CEL);
330   FullSourceLoc X_CEWL = X.callEnterWithin.asLocation();
331   FullSourceLoc Y_CEWL = Y.callEnterWithin.asLocation();
332   if (X_CEWL != Y_CEWL)
333     return X_CEWL.isBeforeInTranslationUnitThan(Y_CEWL);
334   FullSourceLoc X_CRL = X.callReturn.asLocation();
335   FullSourceLoc Y_CRL = Y.callReturn.asLocation();
336   if (X_CRL != Y_CRL)
337     return X_CRL.isBeforeInTranslationUnitThan(Y_CRL);
338   return comparePath(X.path, Y.path);
339 }
340 
comparePiece(const PathDiagnosticPiece & X,const PathDiagnosticPiece & Y)341 static Optional<bool> comparePiece(const PathDiagnosticPiece &X,
342                                    const PathDiagnosticPiece &Y) {
343   if (X.getKind() != Y.getKind())
344     return X.getKind() < Y.getKind();
345 
346   FullSourceLoc XL = X.getLocation().asLocation();
347   FullSourceLoc YL = Y.getLocation().asLocation();
348   if (XL != YL)
349     return XL.isBeforeInTranslationUnitThan(YL);
350 
351   if (X.getString() != Y.getString())
352     return X.getString() < Y.getString();
353 
354   if (X.getRanges().size() != Y.getRanges().size())
355     return X.getRanges().size() < Y.getRanges().size();
356 
357   const SourceManager &SM = XL.getManager();
358 
359   for (unsigned i = 0, n = X.getRanges().size(); i < n; ++i) {
360     SourceRange XR = X.getRanges()[i];
361     SourceRange YR = Y.getRanges()[i];
362     if (XR != YR) {
363       if (XR.getBegin() != YR.getBegin())
364         return SM.isBeforeInTranslationUnit(XR.getBegin(), YR.getBegin());
365       return SM.isBeforeInTranslationUnit(XR.getEnd(), YR.getEnd());
366     }
367   }
368 
369   switch (X.getKind()) {
370     case PathDiagnosticPiece::ControlFlow:
371       return compareControlFlow(cast<PathDiagnosticControlFlowPiece>(X),
372                                 cast<PathDiagnosticControlFlowPiece>(Y));
373     case PathDiagnosticPiece::Event:
374     case PathDiagnosticPiece::Note:
375       return None;
376     case PathDiagnosticPiece::Macro:
377       return compareMacro(cast<PathDiagnosticMacroPiece>(X),
378                           cast<PathDiagnosticMacroPiece>(Y));
379     case PathDiagnosticPiece::Call:
380       return compareCall(cast<PathDiagnosticCallPiece>(X),
381                          cast<PathDiagnosticCallPiece>(Y));
382   }
383   llvm_unreachable("all cases handled");
384 }
385 
comparePath(const PathPieces & X,const PathPieces & Y)386 static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y) {
387   if (X.size() != Y.size())
388     return X.size() < Y.size();
389 
390   PathPieces::const_iterator X_I = X.begin(), X_end = X.end();
391   PathPieces::const_iterator Y_I = Y.begin(), Y_end = Y.end();
392 
393   for ( ; X_I != X_end && Y_I != Y_end; ++X_I, ++Y_I) {
394     Optional<bool> b = comparePiece(**X_I, **Y_I);
395     if (b.hasValue())
396       return b.getValue();
397   }
398 
399   return None;
400 }
401 
compareCrossTUSourceLocs(FullSourceLoc XL,FullSourceLoc YL)402 static bool compareCrossTUSourceLocs(FullSourceLoc XL, FullSourceLoc YL) {
403   std::pair<FileID, unsigned> XOffs = XL.getDecomposedLoc();
404   std::pair<FileID, unsigned> YOffs = YL.getDecomposedLoc();
405   const SourceManager &SM = XL.getManager();
406   std::pair<bool, bool> InSameTU = SM.isInTheSameTranslationUnit(XOffs, YOffs);
407   if (InSameTU.first)
408     return XL.isBeforeInTranslationUnitThan(YL);
409   const FileEntry *XFE = SM.getFileEntryForID(XL.getSpellingLoc().getFileID());
410   const FileEntry *YFE = SM.getFileEntryForID(YL.getSpellingLoc().getFileID());
411   if (!XFE || !YFE)
412     return XFE && !YFE;
413   int NameCmp = XFE->getName().compare(YFE->getName());
414   if (NameCmp != 0)
415     return NameCmp == -1;
416   // Last resort: Compare raw file IDs that are possibly expansions.
417   return XL.getFileID() < YL.getFileID();
418 }
419 
compare(const PathDiagnostic & X,const PathDiagnostic & Y)420 static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) {
421   FullSourceLoc XL = X.getLocation().asLocation();
422   FullSourceLoc YL = Y.getLocation().asLocation();
423   if (XL != YL)
424     return compareCrossTUSourceLocs(XL, YL);
425   if (X.getBugType() != Y.getBugType())
426     return X.getBugType() < Y.getBugType();
427   if (X.getCategory() != Y.getCategory())
428     return X.getCategory() < Y.getCategory();
429   if (X.getVerboseDescription() != Y.getVerboseDescription())
430     return X.getVerboseDescription() < Y.getVerboseDescription();
431   if (X.getShortDescription() != Y.getShortDescription())
432     return X.getShortDescription() < Y.getShortDescription();
433   if (X.getDeclWithIssue() != Y.getDeclWithIssue()) {
434     const Decl *XD = X.getDeclWithIssue();
435     if (!XD)
436       return true;
437     const Decl *YD = Y.getDeclWithIssue();
438     if (!YD)
439       return false;
440     SourceLocation XDL = XD->getLocation();
441     SourceLocation YDL = YD->getLocation();
442     if (XDL != YDL) {
443       const SourceManager &SM = XL.getManager();
444       return compareCrossTUSourceLocs(FullSourceLoc(XDL, SM),
445                                       FullSourceLoc(YDL, SM));
446     }
447   }
448   PathDiagnostic::meta_iterator XI = X.meta_begin(), XE = X.meta_end();
449   PathDiagnostic::meta_iterator YI = Y.meta_begin(), YE = Y.meta_end();
450   if (XE - XI != YE - YI)
451     return (XE - XI) < (YE - YI);
452   for ( ; XI != XE ; ++XI, ++YI) {
453     if (*XI != *YI)
454       return (*XI) < (*YI);
455   }
456   Optional<bool> b = comparePath(X.path, Y.path);
457   assert(b.hasValue());
458   return b.getValue();
459 }
460 
FlushDiagnostics(PathDiagnosticConsumer::FilesMade * Files)461 void PathDiagnosticConsumer::FlushDiagnostics(
462                                      PathDiagnosticConsumer::FilesMade *Files) {
463   if (flushed)
464     return;
465 
466   flushed = true;
467 
468   std::vector<const PathDiagnostic *> BatchDiags;
469   for (const auto &D : Diags)
470     BatchDiags.push_back(&D);
471 
472   // Sort the diagnostics so that they are always emitted in a deterministic
473   // order.
474   int (*Comp)(const PathDiagnostic *const *, const PathDiagnostic *const *) =
475       [](const PathDiagnostic *const *X, const PathDiagnostic *const *Y) {
476         assert(*X != *Y && "PathDiagnostics not uniqued!");
477         if (compare(**X, **Y))
478           return -1;
479         assert(compare(**Y, **X) && "Not a total order!");
480         return 1;
481       };
482   array_pod_sort(BatchDiags.begin(), BatchDiags.end(), Comp);
483 
484   FlushDiagnosticsImpl(BatchDiags, Files);
485 
486   // Delete the flushed diagnostics.
487   for (const auto D : BatchDiags)
488     delete D;
489 
490   // Clear out the FoldingSet.
491   Diags.clear();
492 }
493 
~FilesMade()494 PathDiagnosticConsumer::FilesMade::~FilesMade() {
495   for (PDFileEntry &Entry : Set)
496     Entry.~PDFileEntry();
497 }
498 
addDiagnostic(const PathDiagnostic & PD,StringRef ConsumerName,StringRef FileName)499 void PathDiagnosticConsumer::FilesMade::addDiagnostic(const PathDiagnostic &PD,
500                                                       StringRef ConsumerName,
501                                                       StringRef FileName) {
502   llvm::FoldingSetNodeID NodeID;
503   NodeID.Add(PD);
504   void *InsertPos;
505   PDFileEntry *Entry = Set.FindNodeOrInsertPos(NodeID, InsertPos);
506   if (!Entry) {
507     Entry = Alloc.Allocate<PDFileEntry>();
508     Entry = new (Entry) PDFileEntry(NodeID);
509     Set.InsertNode(Entry, InsertPos);
510   }
511 
512   // Allocate persistent storage for the file name.
513   char *FileName_cstr = (char*) Alloc.Allocate(FileName.size(), 1);
514   memcpy(FileName_cstr, FileName.data(), FileName.size());
515 
516   Entry->files.push_back(std::make_pair(ConsumerName,
517                                         StringRef(FileName_cstr,
518                                                   FileName.size())));
519 }
520 
521 PathDiagnosticConsumer::PDFileEntry::ConsumerFiles *
getFiles(const PathDiagnostic & PD)522 PathDiagnosticConsumer::FilesMade::getFiles(const PathDiagnostic &PD) {
523   llvm::FoldingSetNodeID NodeID;
524   NodeID.Add(PD);
525   void *InsertPos;
526   PDFileEntry *Entry = Set.FindNodeOrInsertPos(NodeID, InsertPos);
527   if (!Entry)
528     return nullptr;
529   return &Entry->files;
530 }
531 
532 //===----------------------------------------------------------------------===//
533 // PathDiagnosticLocation methods.
534 //===----------------------------------------------------------------------===//
535 
getValidSourceLocation(const Stmt * S,LocationOrAnalysisDeclContext LAC,bool UseEnd=false)536 static SourceLocation getValidSourceLocation(const Stmt* S,
537                                              LocationOrAnalysisDeclContext LAC,
538                                              bool UseEnd = false) {
539   SourceLocation L = UseEnd ? S->getEndLoc() : S->getBeginLoc();
540   assert(!LAC.isNull() && "A valid LocationContext or AnalysisDeclContext should "
541                           "be passed to PathDiagnosticLocation upon creation.");
542 
543   // S might be a temporary statement that does not have a location in the
544   // source code, so find an enclosing statement and use its location.
545   if (!L.isValid()) {
546     AnalysisDeclContext *ADC;
547     if (LAC.is<const LocationContext*>())
548       ADC = LAC.get<const LocationContext*>()->getAnalysisDeclContext();
549     else
550       ADC = LAC.get<AnalysisDeclContext*>();
551 
552     ParentMap &PM = ADC->getParentMap();
553 
554     const Stmt *Parent = S;
555     do {
556       Parent = PM.getParent(Parent);
557 
558       // In rare cases, we have implicit top-level expressions,
559       // such as arguments for implicit member initializers.
560       // In this case, fall back to the start of the body (even if we were
561       // asked for the statement end location).
562       if (!Parent) {
563         const Stmt *Body = ADC->getBody();
564         if (Body)
565           L = Body->getBeginLoc();
566         else
567           L = ADC->getDecl()->getEndLoc();
568         break;
569       }
570 
571       L = UseEnd ? Parent->getEndLoc() : Parent->getBeginLoc();
572     } while (!L.isValid());
573   }
574 
575   return L;
576 }
577 
578 static PathDiagnosticLocation
getLocationForCaller(const StackFrameContext * SFC,const LocationContext * CallerCtx,const SourceManager & SM)579 getLocationForCaller(const StackFrameContext *SFC,
580                      const LocationContext *CallerCtx,
581                      const SourceManager &SM) {
582   const CFGBlock &Block = *SFC->getCallSiteBlock();
583   CFGElement Source = Block[SFC->getIndex()];
584 
585   switch (Source.getKind()) {
586   case CFGElement::Statement:
587   case CFGElement::Constructor:
588   case CFGElement::CXXRecordTypedCall:
589     return PathDiagnosticLocation(Source.castAs<CFGStmt>().getStmt(),
590                                   SM, CallerCtx);
591   case CFGElement::Initializer: {
592     const CFGInitializer &Init = Source.castAs<CFGInitializer>();
593     return PathDiagnosticLocation(Init.getInitializer()->getInit(),
594                                   SM, CallerCtx);
595   }
596   case CFGElement::AutomaticObjectDtor: {
597     const CFGAutomaticObjDtor &Dtor = Source.castAs<CFGAutomaticObjDtor>();
598     return PathDiagnosticLocation::createEnd(Dtor.getTriggerStmt(),
599                                              SM, CallerCtx);
600   }
601   case CFGElement::DeleteDtor: {
602     const CFGDeleteDtor &Dtor = Source.castAs<CFGDeleteDtor>();
603     return PathDiagnosticLocation(Dtor.getDeleteExpr(), SM, CallerCtx);
604   }
605   case CFGElement::BaseDtor:
606   case CFGElement::MemberDtor: {
607     const AnalysisDeclContext *CallerInfo = CallerCtx->getAnalysisDeclContext();
608     if (const Stmt *CallerBody = CallerInfo->getBody())
609       return PathDiagnosticLocation::createEnd(CallerBody, SM, CallerCtx);
610     return PathDiagnosticLocation::create(CallerInfo->getDecl(), SM);
611   }
612   case CFGElement::NewAllocator: {
613     const CFGNewAllocator &Alloc = Source.castAs<CFGNewAllocator>();
614     return PathDiagnosticLocation(Alloc.getAllocatorExpr(), SM, CallerCtx);
615   }
616   case CFGElement::TemporaryDtor: {
617     // Temporary destructors are for temporaries. They die immediately at around
618     // the location of CXXBindTemporaryExpr. If they are lifetime-extended,
619     // they'd be dealt with via an AutomaticObjectDtor instead.
620     const auto &Dtor = Source.castAs<CFGTemporaryDtor>();
621     return PathDiagnosticLocation::createEnd(Dtor.getBindTemporaryExpr(), SM,
622                                              CallerCtx);
623   }
624   case CFGElement::ScopeBegin:
625   case CFGElement::ScopeEnd:
626     llvm_unreachable("not yet implemented!");
627   case CFGElement::LifetimeEnds:
628   case CFGElement::LoopExit:
629     llvm_unreachable("CFGElement kind should not be on callsite!");
630   }
631 
632   llvm_unreachable("Unknown CFGElement kind");
633 }
634 
635 PathDiagnosticLocation
createBegin(const Decl * D,const SourceManager & SM)636 PathDiagnosticLocation::createBegin(const Decl *D,
637                                     const SourceManager &SM) {
638   return PathDiagnosticLocation(D->getBeginLoc(), SM, SingleLocK);
639 }
640 
641 PathDiagnosticLocation
createBegin(const Stmt * S,const SourceManager & SM,LocationOrAnalysisDeclContext LAC)642 PathDiagnosticLocation::createBegin(const Stmt *S,
643                                     const SourceManager &SM,
644                                     LocationOrAnalysisDeclContext LAC) {
645   return PathDiagnosticLocation(getValidSourceLocation(S, LAC),
646                                 SM, SingleLocK);
647 }
648 
649 PathDiagnosticLocation
createEnd(const Stmt * S,const SourceManager & SM,LocationOrAnalysisDeclContext LAC)650 PathDiagnosticLocation::createEnd(const Stmt *S,
651                                   const SourceManager &SM,
652                                   LocationOrAnalysisDeclContext LAC) {
653   if (const auto *CS = dyn_cast<CompoundStmt>(S))
654     return createEndBrace(CS, SM);
655   return PathDiagnosticLocation(getValidSourceLocation(S, LAC, /*End=*/true),
656                                 SM, SingleLocK);
657 }
658 
659 PathDiagnosticLocation
createOperatorLoc(const BinaryOperator * BO,const SourceManager & SM)660 PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO,
661                                           const SourceManager &SM) {
662   return PathDiagnosticLocation(BO->getOperatorLoc(), SM, SingleLocK);
663 }
664 
665 PathDiagnosticLocation
createConditionalColonLoc(const ConditionalOperator * CO,const SourceManager & SM)666 PathDiagnosticLocation::createConditionalColonLoc(
667                                             const ConditionalOperator *CO,
668                                             const SourceManager &SM) {
669   return PathDiagnosticLocation(CO->getColonLoc(), SM, SingleLocK);
670 }
671 
672 PathDiagnosticLocation
createMemberLoc(const MemberExpr * ME,const SourceManager & SM)673 PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME,
674                                         const SourceManager &SM) {
675   return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK);
676 }
677 
678 PathDiagnosticLocation
createBeginBrace(const CompoundStmt * CS,const SourceManager & SM)679 PathDiagnosticLocation::createBeginBrace(const CompoundStmt *CS,
680                                          const SourceManager &SM) {
681   SourceLocation L = CS->getLBracLoc();
682   return PathDiagnosticLocation(L, SM, SingleLocK);
683 }
684 
685 PathDiagnosticLocation
createEndBrace(const CompoundStmt * CS,const SourceManager & SM)686 PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS,
687                                        const SourceManager &SM) {
688   SourceLocation L = CS->getRBracLoc();
689   return PathDiagnosticLocation(L, SM, SingleLocK);
690 }
691 
692 PathDiagnosticLocation
createDeclBegin(const LocationContext * LC,const SourceManager & SM)693 PathDiagnosticLocation::createDeclBegin(const LocationContext *LC,
694                                         const SourceManager &SM) {
695   // FIXME: Should handle CXXTryStmt if analyser starts supporting C++.
696   if (const auto *CS = dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody()))
697     if (!CS->body_empty()) {
698       SourceLocation Loc = (*CS->body_begin())->getBeginLoc();
699       return PathDiagnosticLocation(Loc, SM, SingleLocK);
700     }
701 
702   return PathDiagnosticLocation();
703 }
704 
705 PathDiagnosticLocation
createDeclEnd(const LocationContext * LC,const SourceManager & SM)706 PathDiagnosticLocation::createDeclEnd(const LocationContext *LC,
707                                       const SourceManager &SM) {
708   SourceLocation L = LC->getDecl()->getBodyRBrace();
709   return PathDiagnosticLocation(L, SM, SingleLocK);
710 }
711 
712 PathDiagnosticLocation
create(const ProgramPoint & P,const SourceManager & SMng)713 PathDiagnosticLocation::create(const ProgramPoint& P,
714                                const SourceManager &SMng) {
715   const Stmt* S = nullptr;
716   if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
717     const CFGBlock *BSrc = BE->getSrc();
718     S = BSrc->getTerminatorCondition();
719   } else if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) {
720     S = SP->getStmt();
721     if (P.getAs<PostStmtPurgeDeadSymbols>())
722       return PathDiagnosticLocation::createEnd(S, SMng, P.getLocationContext());
723   } else if (Optional<PostInitializer> PIP = P.getAs<PostInitializer>()) {
724     return PathDiagnosticLocation(PIP->getInitializer()->getSourceLocation(),
725                                   SMng);
726   } else if (Optional<PreImplicitCall> PIC = P.getAs<PreImplicitCall>()) {
727     return PathDiagnosticLocation(PIC->getLocation(), SMng);
728   } else if (Optional<PostImplicitCall> PIE = P.getAs<PostImplicitCall>()) {
729     return PathDiagnosticLocation(PIE->getLocation(), SMng);
730   } else if (Optional<CallEnter> CE = P.getAs<CallEnter>()) {
731     return getLocationForCaller(CE->getCalleeContext(),
732                                 CE->getLocationContext(),
733                                 SMng);
734   } else if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) {
735     return getLocationForCaller(CEE->getCalleeContext(),
736                                 CEE->getLocationContext(),
737                                 SMng);
738   } else if (Optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) {
739     CFGElement BlockFront = BE->getBlock()->front();
740     if (auto StmtElt = BlockFront.getAs<CFGStmt>()) {
741       return PathDiagnosticLocation(StmtElt->getStmt()->getBeginLoc(), SMng);
742     } else if (auto NewAllocElt = BlockFront.getAs<CFGNewAllocator>()) {
743       return PathDiagnosticLocation(
744           NewAllocElt->getAllocatorExpr()->getBeginLoc(), SMng);
745     }
746     llvm_unreachable("Unexpected CFG element at front of block");
747   } else {
748     llvm_unreachable("Unexpected ProgramPoint");
749   }
750 
751   return PathDiagnosticLocation(S, SMng, P.getLocationContext());
752 }
753 
754 static const LocationContext *
findTopAutosynthesizedParentContext(const LocationContext * LC)755 findTopAutosynthesizedParentContext(const LocationContext *LC) {
756   assert(LC->getAnalysisDeclContext()->isBodyAutosynthesized());
757   const LocationContext *ParentLC = LC->getParent();
758   assert(ParentLC && "We don't start analysis from autosynthesized code");
759   while (ParentLC->getAnalysisDeclContext()->isBodyAutosynthesized()) {
760     LC = ParentLC;
761     ParentLC = LC->getParent();
762     assert(ParentLC && "We don't start analysis from autosynthesized code");
763   }
764   return LC;
765 }
766 
getStmt(const ExplodedNode * N)767 const Stmt *PathDiagnosticLocation::getStmt(const ExplodedNode *N) {
768   // We cannot place diagnostics on autosynthesized code.
769   // Put them onto the call site through which we jumped into autosynthesized
770   // code for the first time.
771   const LocationContext *LC = N->getLocationContext();
772   if (LC->getAnalysisDeclContext()->isBodyAutosynthesized()) {
773     // It must be a stack frame because we only autosynthesize functions.
774     return cast<StackFrameContext>(findTopAutosynthesizedParentContext(LC))
775         ->getCallSite();
776   }
777   // Otherwise, see if the node's program point directly points to a statement.
778   ProgramPoint P = N->getLocation();
779   if (auto SP = P.getAs<StmtPoint>())
780     return SP->getStmt();
781   if (auto BE = P.getAs<BlockEdge>())
782     return BE->getSrc()->getTerminator();
783   if (auto CE = P.getAs<CallEnter>())
784     return CE->getCallExpr();
785   if (auto CEE = P.getAs<CallExitEnd>())
786     return CEE->getCalleeContext()->getCallSite();
787   if (auto PIPP = P.getAs<PostInitializer>())
788     return PIPP->getInitializer()->getInit();
789   if (auto CEB = P.getAs<CallExitBegin>())
790     return CEB->getReturnStmt();
791   if (auto FEP = P.getAs<FunctionExitPoint>())
792     return FEP->getStmt();
793 
794   return nullptr;
795 }
796 
getNextStmt(const ExplodedNode * N)797 const Stmt *PathDiagnosticLocation::getNextStmt(const ExplodedNode *N) {
798   for (N = N->getFirstSucc(); N; N = N->getFirstSucc()) {
799     if (const Stmt *S = getStmt(N)) {
800       // Check if the statement is '?' or '&&'/'||'.  These are "merges",
801       // not actual statement points.
802       switch (S->getStmtClass()) {
803         case Stmt::ChooseExprClass:
804         case Stmt::BinaryConditionalOperatorClass:
805         case Stmt::ConditionalOperatorClass:
806           continue;
807         case Stmt::BinaryOperatorClass: {
808           BinaryOperatorKind Op = cast<BinaryOperator>(S)->getOpcode();
809           if (Op == BO_LAnd || Op == BO_LOr)
810             continue;
811           break;
812         }
813         default:
814           break;
815       }
816       // We found the statement, so return it.
817       return S;
818     }
819   }
820 
821   return nullptr;
822 }
823 
824 PathDiagnosticLocation
createEndOfPath(const ExplodedNode * N,const SourceManager & SM)825   PathDiagnosticLocation::createEndOfPath(const ExplodedNode *N,
826                                           const SourceManager &SM) {
827   assert(N && "Cannot create a location with a null node.");
828   const Stmt *S = getStmt(N);
829   const LocationContext *LC = N->getLocationContext();
830 
831   if (!S) {
832     // If this is an implicit call, return the implicit call point location.
833     if (Optional<PreImplicitCall> PIE = N->getLocationAs<PreImplicitCall>())
834       return PathDiagnosticLocation(PIE->getLocation(), SM);
835     if (auto FE = N->getLocationAs<FunctionExitPoint>()) {
836       if (const ReturnStmt *RS = FE->getStmt())
837         return PathDiagnosticLocation::createBegin(RS, SM, LC);
838     }
839     S = getNextStmt(N);
840   }
841 
842   if (S) {
843     ProgramPoint P = N->getLocation();
844 
845     // For member expressions, return the location of the '.' or '->'.
846     if (const auto *ME = dyn_cast<MemberExpr>(S))
847       return PathDiagnosticLocation::createMemberLoc(ME, SM);
848 
849     // For binary operators, return the location of the operator.
850     if (const auto *B = dyn_cast<BinaryOperator>(S))
851       return PathDiagnosticLocation::createOperatorLoc(B, SM);
852 
853     if (P.getAs<PostStmtPurgeDeadSymbols>())
854       return PathDiagnosticLocation::createEnd(S, SM, LC);
855 
856     if (S->getBeginLoc().isValid())
857       return PathDiagnosticLocation(S, SM, LC);
858     return PathDiagnosticLocation(getValidSourceLocation(S, LC), SM);
859   }
860 
861   return createDeclEnd(N->getLocationContext(), SM);
862 }
863 
createSingleLocation(const PathDiagnosticLocation & PDL)864 PathDiagnosticLocation PathDiagnosticLocation::createSingleLocation(
865                                            const PathDiagnosticLocation &PDL) {
866   FullSourceLoc L = PDL.asLocation();
867   return PathDiagnosticLocation(L, L.getManager(), SingleLocK);
868 }
869 
870 FullSourceLoc
genLocation(SourceLocation L,LocationOrAnalysisDeclContext LAC) const871   PathDiagnosticLocation::genLocation(SourceLocation L,
872                                       LocationOrAnalysisDeclContext LAC) const {
873   assert(isValid());
874   // Note that we want a 'switch' here so that the compiler can warn us in
875   // case we add more cases.
876   switch (K) {
877     case SingleLocK:
878     case RangeK:
879       break;
880     case StmtK:
881       // Defensive checking.
882       if (!S)
883         break;
884       return FullSourceLoc(getValidSourceLocation(S, LAC),
885                            const_cast<SourceManager&>(*SM));
886     case DeclK:
887       // Defensive checking.
888       if (!D)
889         break;
890       return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM));
891   }
892 
893   return FullSourceLoc(L, const_cast<SourceManager&>(*SM));
894 }
895 
896 PathDiagnosticRange
genRange(LocationOrAnalysisDeclContext LAC) const897   PathDiagnosticLocation::genRange(LocationOrAnalysisDeclContext LAC) const {
898   assert(isValid());
899   // Note that we want a 'switch' here so that the compiler can warn us in
900   // case we add more cases.
901   switch (K) {
902     case SingleLocK:
903       return PathDiagnosticRange(SourceRange(Loc,Loc), true);
904     case RangeK:
905       break;
906     case StmtK: {
907       const Stmt *S = asStmt();
908       switch (S->getStmtClass()) {
909         default:
910           break;
911         case Stmt::DeclStmtClass: {
912           const auto *DS = cast<DeclStmt>(S);
913           if (DS->isSingleDecl()) {
914             // Should always be the case, but we'll be defensive.
915             return SourceRange(DS->getBeginLoc(),
916                                DS->getSingleDecl()->getLocation());
917           }
918           break;
919         }
920           // FIXME: Provide better range information for different
921           //  terminators.
922         case Stmt::IfStmtClass:
923         case Stmt::WhileStmtClass:
924         case Stmt::DoStmtClass:
925         case Stmt::ForStmtClass:
926         case Stmt::ChooseExprClass:
927         case Stmt::IndirectGotoStmtClass:
928         case Stmt::SwitchStmtClass:
929         case Stmt::BinaryConditionalOperatorClass:
930         case Stmt::ConditionalOperatorClass:
931         case Stmt::ObjCForCollectionStmtClass: {
932           SourceLocation L = getValidSourceLocation(S, LAC);
933           return SourceRange(L, L);
934         }
935       }
936       SourceRange R = S->getSourceRange();
937       if (R.isValid())
938         return R;
939       break;
940     }
941     case DeclK:
942       if (const auto *MD = dyn_cast<ObjCMethodDecl>(D))
943         return MD->getSourceRange();
944       if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
945         if (Stmt *Body = FD->getBody())
946           return Body->getSourceRange();
947       }
948       else {
949         SourceLocation L = D->getLocation();
950         return PathDiagnosticRange(SourceRange(L, L), true);
951       }
952   }
953 
954   return SourceRange(Loc, Loc);
955 }
956 
flatten()957 void PathDiagnosticLocation::flatten() {
958   if (K == StmtK) {
959     K = RangeK;
960     S = nullptr;
961     D = nullptr;
962   }
963   else if (K == DeclK) {
964     K = SingleLocK;
965     S = nullptr;
966     D = nullptr;
967   }
968 }
969 
970 //===----------------------------------------------------------------------===//
971 // Manipulation of PathDiagnosticCallPieces.
972 //===----------------------------------------------------------------------===//
973 
974 std::shared_ptr<PathDiagnosticCallPiece>
construct(const CallExitEnd & CE,const SourceManager & SM)975 PathDiagnosticCallPiece::construct(const CallExitEnd &CE,
976                                    const SourceManager &SM) {
977   const Decl *caller = CE.getLocationContext()->getDecl();
978   PathDiagnosticLocation pos = getLocationForCaller(CE.getCalleeContext(),
979                                                     CE.getLocationContext(),
980                                                     SM);
981   return std::shared_ptr<PathDiagnosticCallPiece>(
982       new PathDiagnosticCallPiece(caller, pos));
983 }
984 
985 PathDiagnosticCallPiece *
construct(PathPieces & path,const Decl * caller)986 PathDiagnosticCallPiece::construct(PathPieces &path,
987                                    const Decl *caller) {
988   std::shared_ptr<PathDiagnosticCallPiece> C(
989       new PathDiagnosticCallPiece(path, caller));
990   path.clear();
991   auto *R = C.get();
992   path.push_front(std::move(C));
993   return R;
994 }
995 
setCallee(const CallEnter & CE,const SourceManager & SM)996 void PathDiagnosticCallPiece::setCallee(const CallEnter &CE,
997                                         const SourceManager &SM) {
998   const StackFrameContext *CalleeCtx = CE.getCalleeContext();
999   Callee = CalleeCtx->getDecl();
1000 
1001   callEnterWithin = PathDiagnosticLocation::createBegin(Callee, SM);
1002   callEnter = getLocationForCaller(CalleeCtx, CE.getLocationContext(), SM);
1003 
1004   // Autosynthesized property accessors are special because we'd never
1005   // pop back up to non-autosynthesized code until we leave them.
1006   // This is not generally true for autosynthesized callees, which may call
1007   // non-autosynthesized callbacks.
1008   // Unless set here, the IsCalleeAnAutosynthesizedPropertyAccessor flag
1009   // defaults to false.
1010   if (const auto *MD = dyn_cast<ObjCMethodDecl>(Callee))
1011     IsCalleeAnAutosynthesizedPropertyAccessor = (
1012         MD->isPropertyAccessor() &&
1013         CalleeCtx->getAnalysisDeclContext()->isBodyAutosynthesized());
1014 }
1015 
1016 static void describeTemplateParameters(raw_ostream &Out,
1017                                        const ArrayRef<TemplateArgument> TAList,
1018                                        const LangOptions &LO,
1019                                        StringRef Prefix = StringRef(),
1020                                        StringRef Postfix = StringRef());
1021 
describeTemplateParameter(raw_ostream & Out,const TemplateArgument & TArg,const LangOptions & LO)1022 static void describeTemplateParameter(raw_ostream &Out,
1023                                       const TemplateArgument &TArg,
1024                                       const LangOptions &LO) {
1025 
1026   if (TArg.getKind() == TemplateArgument::ArgKind::Pack) {
1027     describeTemplateParameters(Out, TArg.getPackAsArray(), LO);
1028   } else {
1029     TArg.print(PrintingPolicy(LO), Out);
1030   }
1031 }
1032 
describeTemplateParameters(raw_ostream & Out,const ArrayRef<TemplateArgument> TAList,const LangOptions & LO,StringRef Prefix,StringRef Postfix)1033 static void describeTemplateParameters(raw_ostream &Out,
1034                                        const ArrayRef<TemplateArgument> TAList,
1035                                        const LangOptions &LO,
1036                                        StringRef Prefix, StringRef Postfix) {
1037   if (TAList.empty())
1038     return;
1039 
1040   Out << Prefix;
1041   for (int I = 0, Last = TAList.size() - 1; I != Last; ++I) {
1042     describeTemplateParameter(Out, TAList[I], LO);
1043     Out << ", ";
1044   }
1045   describeTemplateParameter(Out, TAList[TAList.size() - 1], LO);
1046   Out << Postfix;
1047 }
1048 
describeClass(raw_ostream & Out,const CXXRecordDecl * D,StringRef Prefix=StringRef ())1049 static void describeClass(raw_ostream &Out, const CXXRecordDecl *D,
1050                           StringRef Prefix = StringRef()) {
1051   if (!D->getIdentifier())
1052     return;
1053   Out << Prefix << '\'' << *D;
1054   if (const auto T = dyn_cast<ClassTemplateSpecializationDecl>(D))
1055     describeTemplateParameters(Out, T->getTemplateArgs().asArray(),
1056                                D->getASTContext().getLangOpts(), "<", ">");
1057 
1058   Out << '\'';
1059 }
1060 
describeCodeDecl(raw_ostream & Out,const Decl * D,bool ExtendedDescription,StringRef Prefix=StringRef ())1061 static bool describeCodeDecl(raw_ostream &Out, const Decl *D,
1062                              bool ExtendedDescription,
1063                              StringRef Prefix = StringRef()) {
1064   if (!D)
1065     return false;
1066 
1067   if (isa<BlockDecl>(D)) {
1068     if (ExtendedDescription)
1069       Out << Prefix << "anonymous block";
1070     return ExtendedDescription;
1071   }
1072 
1073   if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
1074     Out << Prefix;
1075     if (ExtendedDescription && !MD->isUserProvided()) {
1076       if (MD->isExplicitlyDefaulted())
1077         Out << "defaulted ";
1078       else
1079         Out << "implicit ";
1080     }
1081 
1082     if (const auto *CD = dyn_cast<CXXConstructorDecl>(MD)) {
1083       if (CD->isDefaultConstructor())
1084         Out << "default ";
1085       else if (CD->isCopyConstructor())
1086         Out << "copy ";
1087       else if (CD->isMoveConstructor())
1088         Out << "move ";
1089 
1090       Out << "constructor";
1091       describeClass(Out, MD->getParent(), " for ");
1092     } else if (isa<CXXDestructorDecl>(MD)) {
1093       if (!MD->isUserProvided()) {
1094         Out << "destructor";
1095         describeClass(Out, MD->getParent(), " for ");
1096       } else {
1097         // Use ~Foo for explicitly-written destructors.
1098         Out << "'" << *MD << "'";
1099       }
1100     } else if (MD->isCopyAssignmentOperator()) {
1101         Out << "copy assignment operator";
1102         describeClass(Out, MD->getParent(), " for ");
1103     } else if (MD->isMoveAssignmentOperator()) {
1104         Out << "move assignment operator";
1105         describeClass(Out, MD->getParent(), " for ");
1106     } else {
1107       if (MD->getParent()->getIdentifier())
1108         Out << "'" << *MD->getParent() << "::" << *MD << "'";
1109       else
1110         Out << "'" << *MD << "'";
1111     }
1112 
1113     return true;
1114   }
1115 
1116   Out << Prefix << '\'' << cast<NamedDecl>(*D);
1117 
1118   // Adding template parameters.
1119   if (const auto FD = dyn_cast<FunctionDecl>(D))
1120     if (const TemplateArgumentList *TAList =
1121                                     FD->getTemplateSpecializationArgs())
1122       describeTemplateParameters(Out, TAList->asArray(),
1123                                  FD->getASTContext().getLangOpts(), "<", ">");
1124 
1125   Out << '\'';
1126   return true;
1127 }
1128 
1129 std::shared_ptr<PathDiagnosticEventPiece>
getCallEnterEvent() const1130 PathDiagnosticCallPiece::getCallEnterEvent() const {
1131   // We do not produce call enters and call exits for autosynthesized property
1132   // accessors. We do generally produce them for other functions coming from
1133   // the body farm because they may call callbacks that bring us back into
1134   // visible code.
1135   if (!Callee || IsCalleeAnAutosynthesizedPropertyAccessor)
1136     return nullptr;
1137 
1138   SmallString<256> buf;
1139   llvm::raw_svector_ostream Out(buf);
1140 
1141   Out << "Calling ";
1142   describeCodeDecl(Out, Callee, /*ExtendedDescription=*/true);
1143 
1144   assert(callEnter.asLocation().isValid());
1145   return std::make_shared<PathDiagnosticEventPiece>(callEnter, Out.str());
1146 }
1147 
1148 std::shared_ptr<PathDiagnosticEventPiece>
getCallEnterWithinCallerEvent() const1149 PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const {
1150   if (!callEnterWithin.asLocation().isValid())
1151     return nullptr;
1152   if (Callee->isImplicit() || !Callee->hasBody())
1153     return nullptr;
1154   if (const auto *MD = dyn_cast<CXXMethodDecl>(Callee))
1155     if (MD->isDefaulted())
1156       return nullptr;
1157 
1158   SmallString<256> buf;
1159   llvm::raw_svector_ostream Out(buf);
1160 
1161   Out << "Entered call";
1162   describeCodeDecl(Out, Caller, /*ExtendedDescription=*/false, " from ");
1163 
1164   return std::make_shared<PathDiagnosticEventPiece>(callEnterWithin, Out.str());
1165 }
1166 
1167 std::shared_ptr<PathDiagnosticEventPiece>
getCallExitEvent() const1168 PathDiagnosticCallPiece::getCallExitEvent() const {
1169   // We do not produce call enters and call exits for autosynthesized property
1170   // accessors. We do generally produce them for other functions coming from
1171   // the body farm because they may call callbacks that bring us back into
1172   // visible code.
1173   if (NoExit || IsCalleeAnAutosynthesizedPropertyAccessor)
1174     return nullptr;
1175 
1176   SmallString<256> buf;
1177   llvm::raw_svector_ostream Out(buf);
1178 
1179   if (!CallStackMessage.empty()) {
1180     Out << CallStackMessage;
1181   } else {
1182     bool DidDescribe = describeCodeDecl(Out, Callee,
1183                                         /*ExtendedDescription=*/false,
1184                                         "Returning from ");
1185     if (!DidDescribe)
1186       Out << "Returning to caller";
1187   }
1188 
1189   assert(callReturn.asLocation().isValid());
1190   return std::make_shared<PathDiagnosticEventPiece>(callReturn, Out.str());
1191 }
1192 
compute_path_size(const PathPieces & pieces,unsigned & size)1193 static void compute_path_size(const PathPieces &pieces, unsigned &size) {
1194   for (const auto &I : pieces) {
1195     const PathDiagnosticPiece *piece = I.get();
1196     if (const auto *cp = dyn_cast<PathDiagnosticCallPiece>(piece))
1197       compute_path_size(cp->path, size);
1198     else
1199       ++size;
1200   }
1201 }
1202 
full_size()1203 unsigned PathDiagnostic::full_size() {
1204   unsigned size = 0;
1205   compute_path_size(path, size);
1206   return size;
1207 }
1208 
1209 //===----------------------------------------------------------------------===//
1210 // FoldingSet profiling methods.
1211 //===----------------------------------------------------------------------===//
1212 
Profile(llvm::FoldingSetNodeID & ID) const1213 void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const {
1214   ID.AddInteger(Range.getBegin().getRawEncoding());
1215   ID.AddInteger(Range.getEnd().getRawEncoding());
1216   ID.AddInteger(Loc.getRawEncoding());
1217 }
1218 
Profile(llvm::FoldingSetNodeID & ID) const1219 void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1220   ID.AddInteger((unsigned) getKind());
1221   ID.AddString(str);
1222   // FIXME: Add profiling support for code hints.
1223   ID.AddInteger((unsigned) getDisplayHint());
1224   ArrayRef<SourceRange> Ranges = getRanges();
1225   for (const auto &I : Ranges) {
1226     ID.AddInteger(I.getBegin().getRawEncoding());
1227     ID.AddInteger(I.getEnd().getRawEncoding());
1228   }
1229 }
1230 
Profile(llvm::FoldingSetNodeID & ID) const1231 void PathDiagnosticCallPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1232   PathDiagnosticPiece::Profile(ID);
1233   for (const auto &I : path)
1234     ID.Add(*I);
1235 }
1236 
Profile(llvm::FoldingSetNodeID & ID) const1237 void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1238   PathDiagnosticPiece::Profile(ID);
1239   ID.Add(Pos);
1240 }
1241 
Profile(llvm::FoldingSetNodeID & ID) const1242 void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1243   PathDiagnosticPiece::Profile(ID);
1244   for (const auto &I : *this)
1245     ID.Add(I);
1246 }
1247 
Profile(llvm::FoldingSetNodeID & ID) const1248 void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1249   PathDiagnosticSpotPiece::Profile(ID);
1250   for (const auto &I : subPieces)
1251     ID.Add(*I);
1252 }
1253 
Profile(llvm::FoldingSetNodeID & ID) const1254 void PathDiagnosticNotePiece::Profile(llvm::FoldingSetNodeID &ID) const {
1255   PathDiagnosticSpotPiece::Profile(ID);
1256 }
1257 
Profile(llvm::FoldingSetNodeID & ID) const1258 void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const {
1259   ID.Add(getLocation());
1260   ID.AddString(BugType);
1261   ID.AddString(VerboseDesc);
1262   ID.AddString(Category);
1263 }
1264 
FullProfile(llvm::FoldingSetNodeID & ID) const1265 void PathDiagnostic::FullProfile(llvm::FoldingSetNodeID &ID) const {
1266   Profile(ID);
1267   for (const auto &I : path)
1268     ID.Add(*I);
1269   for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I)
1270     ID.AddString(*I);
1271 }
1272 
1273 StackHintGenerator::~StackHintGenerator() = default;
1274 
getMessage(const ExplodedNode * N)1275 std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){
1276   if (!N)
1277     return getMessageForSymbolNotFound();
1278 
1279   ProgramPoint P = N->getLocation();
1280   CallExitEnd CExit = P.castAs<CallExitEnd>();
1281 
1282   // FIXME: Use CallEvent to abstract this over all calls.
1283   const Stmt *CallSite = CExit.getCalleeContext()->getCallSite();
1284   const auto *CE = dyn_cast_or_null<CallExpr>(CallSite);
1285   if (!CE)
1286     return {};
1287 
1288   // Check if one of the parameters are set to the interesting symbol.
1289   unsigned ArgIndex = 0;
1290   for (CallExpr::const_arg_iterator I = CE->arg_begin(),
1291                                     E = CE->arg_end(); I != E; ++I, ++ArgIndex){
1292     SVal SV = N->getSVal(*I);
1293 
1294     // Check if the variable corresponding to the symbol is passed by value.
1295     SymbolRef AS = SV.getAsLocSymbol();
1296     if (AS == Sym) {
1297       return getMessageForArg(*I, ArgIndex);
1298     }
1299 
1300     // Check if the parameter is a pointer to the symbol.
1301     if (Optional<loc::MemRegionVal> Reg = SV.getAs<loc::MemRegionVal>()) {
1302       // Do not attempt to dereference void*.
1303       if ((*I)->getType()->isVoidPointerType())
1304         continue;
1305       SVal PSV = N->getState()->getSVal(Reg->getRegion());
1306       SymbolRef AS = PSV.getAsLocSymbol();
1307       if (AS == Sym) {
1308         return getMessageForArg(*I, ArgIndex);
1309       }
1310     }
1311   }
1312 
1313   // Check if we are returning the interesting symbol.
1314   SVal SV = N->getSVal(CE);
1315   SymbolRef RetSym = SV.getAsLocSymbol();
1316   if (RetSym == Sym) {
1317     return getMessageForReturn(CE);
1318   }
1319 
1320   return getMessageForSymbolNotFound();
1321 }
1322 
getMessageForArg(const Expr * ArgE,unsigned ArgIndex)1323 std::string StackHintGeneratorForSymbol::getMessageForArg(const Expr *ArgE,
1324                                                           unsigned ArgIndex) {
1325   // Printed parameters start at 1, not 0.
1326   ++ArgIndex;
1327 
1328   SmallString<200> buf;
1329   llvm::raw_svector_ostream os(buf);
1330 
1331   os << Msg << " via " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex)
1332      << " parameter";
1333 
1334   return os.str();
1335 }
1336 
dump() const1337 LLVM_DUMP_METHOD void PathPieces::dump() const {
1338   unsigned index = 0;
1339   for (PathPieces::const_iterator I = begin(), E = end(); I != E; ++I) {
1340     llvm::errs() << "[" << index++ << "]  ";
1341     (*I)->dump();
1342     llvm::errs() << "\n";
1343   }
1344 }
1345 
dump() const1346 LLVM_DUMP_METHOD void PathDiagnosticCallPiece::dump() const {
1347   llvm::errs() << "CALL\n--------------\n";
1348 
1349   if (const Stmt *SLoc = getLocation().getStmtOrNull())
1350     SLoc->dump();
1351   else if (const auto *ND = dyn_cast_or_null<NamedDecl>(getCallee()))
1352     llvm::errs() << *ND << "\n";
1353   else
1354     getLocation().dump();
1355 }
1356 
dump() const1357 LLVM_DUMP_METHOD void PathDiagnosticEventPiece::dump() const {
1358   llvm::errs() << "EVENT\n--------------\n";
1359   llvm::errs() << getString() << "\n";
1360   llvm::errs() << " ---- at ----\n";
1361   getLocation().dump();
1362 }
1363 
dump() const1364 LLVM_DUMP_METHOD void PathDiagnosticControlFlowPiece::dump() const {
1365   llvm::errs() << "CONTROL\n--------------\n";
1366   getStartLocation().dump();
1367   llvm::errs() << " ---- to ----\n";
1368   getEndLocation().dump();
1369 }
1370 
dump() const1371 LLVM_DUMP_METHOD void PathDiagnosticMacroPiece::dump() const {
1372   llvm::errs() << "MACRO\n--------------\n";
1373   // FIXME: Print which macro is being invoked.
1374 }
1375 
dump() const1376 LLVM_DUMP_METHOD void PathDiagnosticNotePiece::dump() const {
1377   llvm::errs() << "NOTE\n--------------\n";
1378   llvm::errs() << getString() << "\n";
1379   llvm::errs() << " ---- at ----\n";
1380   getLocation().dump();
1381 }
1382 
dump() const1383 LLVM_DUMP_METHOD void PathDiagnosticLocation::dump() const {
1384   if (!isValid()) {
1385     llvm::errs() << "<INVALID>\n";
1386     return;
1387   }
1388 
1389   switch (K) {
1390   case RangeK:
1391     // FIXME: actually print the range.
1392     llvm::errs() << "<range>\n";
1393     break;
1394   case SingleLocK:
1395     asLocation().dump();
1396     llvm::errs() << "\n";
1397     break;
1398   case StmtK:
1399     if (S)
1400       S->dump();
1401     else
1402       llvm::errs() << "<NULL STMT>\n";
1403     break;
1404   case DeclK:
1405     if (const auto *ND = dyn_cast_or_null<NamedDecl>(D))
1406       llvm::errs() << *ND << "\n";
1407     else if (isa<BlockDecl>(D))
1408       // FIXME: Make this nicer.
1409       llvm::errs() << "<block>\n";
1410     else if (D)
1411       llvm::errs() << "<unknown decl>\n";
1412     else
1413       llvm::errs() << "<NULL DECL>\n";
1414     break;
1415   }
1416 }
1417