1 //===- PathDiagnostic.cpp - Path-Specific Diagnostic Handling -------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 //  This file defines the PathDiagnostic-related interfaces.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "clang/Analysis/PathDiagnostic.h"
14 #include "clang/AST/Decl.h"
15 #include "clang/AST/DeclBase.h"
16 #include "clang/AST/DeclCXX.h"
17 #include "clang/AST/DeclObjC.h"
18 #include "clang/AST/DeclTemplate.h"
19 #include "clang/AST/Expr.h"
20 #include "clang/AST/ExprCXX.h"
21 #include "clang/AST/OperationKinds.h"
22 #include "clang/AST/ParentMap.h"
23 #include "clang/AST/PrettyPrinter.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 "llvm/ADT/ArrayRef.h"
34 #include "llvm/ADT/FoldingSet.h"
35 #include "llvm/ADT/STLExtras.h"
36 #include "llvm/ADT/SmallString.h"
37 #include "llvm/ADT/SmallVector.h"
38 #include "llvm/ADT/StringExtras.h"
39 #include "llvm/ADT/StringRef.h"
40 #include "llvm/Support/Casting.h"
41 #include "llvm/Support/ErrorHandling.h"
42 #include "llvm/Support/raw_ostream.h"
43 #include <cassert>
44 #include <cstring>
45 #include <memory>
46 #include <optional>
47 #include <utility>
48 #include <vector>
49 
50 using namespace clang;
51 using namespace ento;
52 
StripTrailingDots(StringRef s)53 static StringRef StripTrailingDots(StringRef s) { return s.rtrim('.'); }
54 
PathDiagnosticPiece(StringRef s,Kind k,DisplayHint hint)55 PathDiagnosticPiece::PathDiagnosticPiece(StringRef s,
56                                          Kind k, DisplayHint hint)
57     : str(StripTrailingDots(s)), kind(k), Hint(hint) {}
58 
PathDiagnosticPiece(Kind k,DisplayHint hint)59 PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint)
60     : kind(k), Hint(hint) {}
61 
62 PathDiagnosticPiece::~PathDiagnosticPiece() = default;
63 
64 PathDiagnosticEventPiece::~PathDiagnosticEventPiece() = default;
65 
66 PathDiagnosticCallPiece::~PathDiagnosticCallPiece() = default;
67 
68 PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() = default;
69 
70 PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() = default;
71 
72 PathDiagnosticNotePiece::~PathDiagnosticNotePiece() = default;
73 
74 PathDiagnosticPopUpPiece::~PathDiagnosticPopUpPiece() = default;
75 
flattenTo(PathPieces & Primary,PathPieces & Current,bool ShouldFlattenMacros) const76 void PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current,
77                            bool ShouldFlattenMacros) const {
78   for (auto &Piece : *this) {
79     switch (Piece->getKind()) {
80     case PathDiagnosticPiece::Call: {
81       auto &Call = cast<PathDiagnosticCallPiece>(*Piece);
82       if (auto CallEnter = Call.getCallEnterEvent())
83         Current.push_back(std::move(CallEnter));
84       Call.path.flattenTo(Primary, Primary, ShouldFlattenMacros);
85       if (auto callExit = Call.getCallExitEvent())
86         Current.push_back(std::move(callExit));
87       break;
88     }
89     case PathDiagnosticPiece::Macro: {
90       auto &Macro = cast<PathDiagnosticMacroPiece>(*Piece);
91       if (ShouldFlattenMacros) {
92         Macro.subPieces.flattenTo(Primary, Primary, ShouldFlattenMacros);
93       } else {
94         Current.push_back(Piece);
95         PathPieces NewPath;
96         Macro.subPieces.flattenTo(Primary, NewPath, ShouldFlattenMacros);
97         // FIXME: This probably shouldn't mutate the original path piece.
98         Macro.subPieces = NewPath;
99       }
100       break;
101     }
102     case PathDiagnosticPiece::Event:
103     case PathDiagnosticPiece::ControlFlow:
104     case PathDiagnosticPiece::Note:
105     case PathDiagnosticPiece::PopUp:
106       Current.push_back(Piece);
107       break;
108     }
109   }
110 }
111 
112 PathDiagnostic::~PathDiagnostic() = default;
113 
PathDiagnostic(StringRef CheckerName,const Decl * declWithIssue,StringRef bugtype,StringRef verboseDesc,StringRef shortDesc,StringRef category,PathDiagnosticLocation LocationToUnique,const Decl * DeclToUnique,std::unique_ptr<FilesToLineNumsMap> ExecutedLines)114 PathDiagnostic::PathDiagnostic(
115     StringRef CheckerName, const Decl *declWithIssue, StringRef bugtype,
116     StringRef verboseDesc, StringRef shortDesc, StringRef category,
117     PathDiagnosticLocation LocationToUnique, const Decl *DeclToUnique,
118     std::unique_ptr<FilesToLineNumsMap> ExecutedLines)
119     : CheckerName(CheckerName), DeclWithIssue(declWithIssue),
120       BugType(StripTrailingDots(bugtype)),
121       VerboseDesc(StripTrailingDots(verboseDesc)),
122       ShortDesc(StripTrailingDots(shortDesc)),
123       Category(StripTrailingDots(category)), UniqueingLoc(LocationToUnique),
124       UniqueingDecl(DeclToUnique), ExecutedLines(std::move(ExecutedLines)),
125       path(pathImpl) {}
126 
anchor()127 void PathDiagnosticConsumer::anchor() {}
128 
~PathDiagnosticConsumer()129 PathDiagnosticConsumer::~PathDiagnosticConsumer() {
130   // Delete the contents of the FoldingSet if it isn't empty already.
131   for (auto &Diag : Diags)
132     delete &Diag;
133 }
134 
HandlePathDiagnostic(std::unique_ptr<PathDiagnostic> D)135 void PathDiagnosticConsumer::HandlePathDiagnostic(
136     std::unique_ptr<PathDiagnostic> D) {
137   if (!D || D->path.empty())
138     return;
139 
140   // We need to flatten the locations (convert Stmt* to locations) because
141   // the referenced statements may be freed by the time the diagnostics
142   // are emitted.
143   D->flattenLocations();
144 
145   // If the PathDiagnosticConsumer does not support diagnostics that
146   // cross file boundaries, prune out such diagnostics now.
147   if (!supportsCrossFileDiagnostics()) {
148     // Verify that the entire path is from the same FileID.
149     FileID FID;
150     const SourceManager &SMgr = D->path.front()->getLocation().getManager();
151     SmallVector<const PathPieces *, 5> WorkList;
152     WorkList.push_back(&D->path);
153     SmallString<128> buf;
154     llvm::raw_svector_ostream warning(buf);
155     warning << "warning: Path diagnostic report is not generated. Current "
156             << "output format does not support diagnostics that cross file "
157             << "boundaries. Refer to --analyzer-output for valid output "
158             << "formats\n";
159 
160     while (!WorkList.empty()) {
161       const PathPieces &path = *WorkList.pop_back_val();
162 
163       for (const auto &I : path) {
164         const PathDiagnosticPiece *piece = I.get();
165         FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc();
166 
167         if (FID.isInvalid()) {
168           FID = SMgr.getFileID(L);
169         } else if (SMgr.getFileID(L) != FID) {
170           llvm::errs() << warning.str();
171           return;
172         }
173 
174         // Check the source ranges.
175         ArrayRef<SourceRange> Ranges = piece->getRanges();
176         for (const auto &I : Ranges) {
177           SourceLocation L = SMgr.getExpansionLoc(I.getBegin());
178           if (!L.isFileID() || SMgr.getFileID(L) != FID) {
179             llvm::errs() << warning.str();
180             return;
181           }
182           L = SMgr.getExpansionLoc(I.getEnd());
183           if (!L.isFileID() || SMgr.getFileID(L) != FID) {
184             llvm::errs() << warning.str();
185             return;
186           }
187         }
188 
189         if (const auto *call = dyn_cast<PathDiagnosticCallPiece>(piece))
190           WorkList.push_back(&call->path);
191         else if (const auto *macro = dyn_cast<PathDiagnosticMacroPiece>(piece))
192           WorkList.push_back(&macro->subPieces);
193       }
194     }
195 
196     if (FID.isInvalid())
197       return; // FIXME: Emit a warning?
198   }
199 
200   // Profile the node to see if we already have something matching it
201   llvm::FoldingSetNodeID profile;
202   D->Profile(profile);
203   void *InsertPos = nullptr;
204 
205   if (PathDiagnostic *orig = Diags.FindNodeOrInsertPos(profile, InsertPos)) {
206     // Keep the PathDiagnostic with the shorter path.
207     // Note, the enclosing routine is called in deterministic order, so the
208     // results will be consistent between runs (no reason to break ties if the
209     // size is the same).
210     const unsigned orig_size = orig->full_size();
211     const unsigned new_size = D->full_size();
212     if (orig_size <= new_size)
213       return;
214 
215     assert(orig != D.get());
216     Diags.RemoveNode(orig);
217     delete orig;
218   }
219 
220   Diags.InsertNode(D.release());
221 }
222 
223 static std::optional<bool> comparePath(const PathPieces &X,
224                                        const PathPieces &Y);
225 
226 static std::optional<bool>
compareControlFlow(const PathDiagnosticControlFlowPiece & X,const PathDiagnosticControlFlowPiece & Y)227 compareControlFlow(const PathDiagnosticControlFlowPiece &X,
228                    const PathDiagnosticControlFlowPiece &Y) {
229   FullSourceLoc XSL = X.getStartLocation().asLocation();
230   FullSourceLoc YSL = Y.getStartLocation().asLocation();
231   if (XSL != YSL)
232     return XSL.isBeforeInTranslationUnitThan(YSL);
233   FullSourceLoc XEL = X.getEndLocation().asLocation();
234   FullSourceLoc YEL = Y.getEndLocation().asLocation();
235   if (XEL != YEL)
236     return XEL.isBeforeInTranslationUnitThan(YEL);
237   return std::nullopt;
238 }
239 
compareMacro(const PathDiagnosticMacroPiece & X,const PathDiagnosticMacroPiece & Y)240 static std::optional<bool> compareMacro(const PathDiagnosticMacroPiece &X,
241                                         const PathDiagnosticMacroPiece &Y) {
242   return comparePath(X.subPieces, Y.subPieces);
243 }
244 
compareCall(const PathDiagnosticCallPiece & X,const PathDiagnosticCallPiece & Y)245 static std::optional<bool> compareCall(const PathDiagnosticCallPiece &X,
246                                        const PathDiagnosticCallPiece &Y) {
247   FullSourceLoc X_CEL = X.callEnter.asLocation();
248   FullSourceLoc Y_CEL = Y.callEnter.asLocation();
249   if (X_CEL != Y_CEL)
250     return X_CEL.isBeforeInTranslationUnitThan(Y_CEL);
251   FullSourceLoc X_CEWL = X.callEnterWithin.asLocation();
252   FullSourceLoc Y_CEWL = Y.callEnterWithin.asLocation();
253   if (X_CEWL != Y_CEWL)
254     return X_CEWL.isBeforeInTranslationUnitThan(Y_CEWL);
255   FullSourceLoc X_CRL = X.callReturn.asLocation();
256   FullSourceLoc Y_CRL = Y.callReturn.asLocation();
257   if (X_CRL != Y_CRL)
258     return X_CRL.isBeforeInTranslationUnitThan(Y_CRL);
259   return comparePath(X.path, Y.path);
260 }
261 
comparePiece(const PathDiagnosticPiece & X,const PathDiagnosticPiece & Y)262 static std::optional<bool> comparePiece(const PathDiagnosticPiece &X,
263                                         const PathDiagnosticPiece &Y) {
264   if (X.getKind() != Y.getKind())
265     return X.getKind() < Y.getKind();
266 
267   FullSourceLoc XL = X.getLocation().asLocation();
268   FullSourceLoc YL = Y.getLocation().asLocation();
269   if (XL != YL)
270     return XL.isBeforeInTranslationUnitThan(YL);
271 
272   if (X.getString() != Y.getString())
273     return X.getString() < Y.getString();
274 
275   if (X.getRanges().size() != Y.getRanges().size())
276     return X.getRanges().size() < Y.getRanges().size();
277 
278   const SourceManager &SM = XL.getManager();
279 
280   for (unsigned i = 0, n = X.getRanges().size(); i < n; ++i) {
281     SourceRange XR = X.getRanges()[i];
282     SourceRange YR = Y.getRanges()[i];
283     if (XR != YR) {
284       if (XR.getBegin() != YR.getBegin())
285         return SM.isBeforeInTranslationUnit(XR.getBegin(), YR.getBegin());
286       return SM.isBeforeInTranslationUnit(XR.getEnd(), YR.getEnd());
287     }
288   }
289 
290   switch (X.getKind()) {
291     case PathDiagnosticPiece::ControlFlow:
292       return compareControlFlow(cast<PathDiagnosticControlFlowPiece>(X),
293                                 cast<PathDiagnosticControlFlowPiece>(Y));
294     case PathDiagnosticPiece::Macro:
295       return compareMacro(cast<PathDiagnosticMacroPiece>(X),
296                           cast<PathDiagnosticMacroPiece>(Y));
297     case PathDiagnosticPiece::Call:
298       return compareCall(cast<PathDiagnosticCallPiece>(X),
299                          cast<PathDiagnosticCallPiece>(Y));
300     case PathDiagnosticPiece::Event:
301     case PathDiagnosticPiece::Note:
302     case PathDiagnosticPiece::PopUp:
303       return std::nullopt;
304   }
305   llvm_unreachable("all cases handled");
306 }
307 
comparePath(const PathPieces & X,const PathPieces & Y)308 static std::optional<bool> comparePath(const PathPieces &X,
309                                        const PathPieces &Y) {
310   if (X.size() != Y.size())
311     return X.size() < Y.size();
312 
313   PathPieces::const_iterator X_I = X.begin(), X_end = X.end();
314   PathPieces::const_iterator Y_I = Y.begin(), Y_end = Y.end();
315 
316   for (; X_I != X_end && Y_I != Y_end; ++X_I, ++Y_I)
317     if (std::optional<bool> b = comparePiece(**X_I, **Y_I))
318       return *b;
319 
320   return std::nullopt;
321 }
322 
compareCrossTUSourceLocs(FullSourceLoc XL,FullSourceLoc YL)323 static bool compareCrossTUSourceLocs(FullSourceLoc XL, FullSourceLoc YL) {
324   if (XL.isInvalid() && YL.isValid())
325     return true;
326   if (XL.isValid() && YL.isInvalid())
327     return false;
328   std::pair<FileID, unsigned> XOffs = XL.getDecomposedLoc();
329   std::pair<FileID, unsigned> YOffs = YL.getDecomposedLoc();
330   const SourceManager &SM = XL.getManager();
331   std::pair<bool, bool> InSameTU = SM.isInTheSameTranslationUnit(XOffs, YOffs);
332   if (InSameTU.first)
333     return XL.isBeforeInTranslationUnitThan(YL);
334   OptionalFileEntryRef XFE =
335       SM.getFileEntryRefForID(XL.getSpellingLoc().getFileID());
336   OptionalFileEntryRef YFE =
337       SM.getFileEntryRefForID(YL.getSpellingLoc().getFileID());
338   if (!XFE || !YFE)
339     return XFE && !YFE;
340   int NameCmp = XFE->getName().compare(YFE->getName());
341   if (NameCmp != 0)
342     return NameCmp < 0;
343   // Last resort: Compare raw file IDs that are possibly expansions.
344   return XL.getFileID() < YL.getFileID();
345 }
346 
compare(const PathDiagnostic & X,const PathDiagnostic & Y)347 static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) {
348   FullSourceLoc XL = X.getLocation().asLocation();
349   FullSourceLoc YL = Y.getLocation().asLocation();
350   if (XL != YL)
351     return compareCrossTUSourceLocs(XL, YL);
352   FullSourceLoc XUL = X.getUniqueingLoc().asLocation();
353   FullSourceLoc YUL = Y.getUniqueingLoc().asLocation();
354   if (XUL != YUL)
355     return compareCrossTUSourceLocs(XUL, YUL);
356   if (X.getBugType() != Y.getBugType())
357     return X.getBugType() < Y.getBugType();
358   if (X.getCategory() != Y.getCategory())
359     return X.getCategory() < Y.getCategory();
360   if (X.getVerboseDescription() != Y.getVerboseDescription())
361     return X.getVerboseDescription() < Y.getVerboseDescription();
362   if (X.getShortDescription() != Y.getShortDescription())
363     return X.getShortDescription() < Y.getShortDescription();
364   auto CompareDecls = [&XL](const Decl *D1,
365                             const Decl *D2) -> std::optional<bool> {
366     if (D1 == D2)
367       return std::nullopt;
368     if (!D1)
369       return true;
370     if (!D2)
371       return false;
372     SourceLocation D1L = D1->getLocation();
373     SourceLocation D2L = D2->getLocation();
374     if (D1L != D2L) {
375       const SourceManager &SM = XL.getManager();
376       return compareCrossTUSourceLocs(FullSourceLoc(D1L, SM),
377                                       FullSourceLoc(D2L, SM));
378     }
379     return std::nullopt;
380   };
381   if (auto Result = CompareDecls(X.getDeclWithIssue(), Y.getDeclWithIssue()))
382     return *Result;
383   if (XUL.isValid()) {
384     if (auto Result = CompareDecls(X.getUniqueingDecl(), Y.getUniqueingDecl()))
385       return *Result;
386   }
387   PathDiagnostic::meta_iterator XI = X.meta_begin(), XE = X.meta_end();
388   PathDiagnostic::meta_iterator YI = Y.meta_begin(), YE = Y.meta_end();
389   if (XE - XI != YE - YI)
390     return (XE - XI) < (YE - YI);
391   for ( ; XI != XE ; ++XI, ++YI) {
392     if (*XI != *YI)
393       return (*XI) < (*YI);
394   }
395   return *comparePath(X.path, Y.path);
396 }
397 
FlushDiagnostics(PathDiagnosticConsumer::FilesMade * Files)398 void PathDiagnosticConsumer::FlushDiagnostics(
399                                      PathDiagnosticConsumer::FilesMade *Files) {
400   if (flushed)
401     return;
402 
403   flushed = true;
404 
405   std::vector<const PathDiagnostic *> BatchDiags;
406   for (const auto &D : Diags)
407     BatchDiags.push_back(&D);
408 
409   // Sort the diagnostics so that they are always emitted in a deterministic
410   // order.
411   int (*Comp)(const PathDiagnostic *const *, const PathDiagnostic *const *) =
412       [](const PathDiagnostic *const *X, const PathDiagnostic *const *Y) {
413         assert(*X != *Y && "PathDiagnostics not uniqued!");
414         if (compare(**X, **Y))
415           return -1;
416         assert(compare(**Y, **X) && "Not a total order!");
417         return 1;
418       };
419   array_pod_sort(BatchDiags.begin(), BatchDiags.end(), Comp);
420 
421   FlushDiagnosticsImpl(BatchDiags, Files);
422 
423   // Delete the flushed diagnostics.
424   for (const auto D : BatchDiags)
425     delete D;
426 
427   // Clear out the FoldingSet.
428   Diags.clear();
429 }
430 
~FilesMade()431 PathDiagnosticConsumer::FilesMade::~FilesMade() {
432   for (auto It = Set.begin(); It != Set.end();)
433     (It++)->~PDFileEntry();
434 }
435 
addDiagnostic(const PathDiagnostic & PD,StringRef ConsumerName,StringRef FileName)436 void PathDiagnosticConsumer::FilesMade::addDiagnostic(const PathDiagnostic &PD,
437                                                       StringRef ConsumerName,
438                                                       StringRef FileName) {
439   llvm::FoldingSetNodeID NodeID;
440   NodeID.Add(PD);
441   void *InsertPos;
442   PDFileEntry *Entry = Set.FindNodeOrInsertPos(NodeID, InsertPos);
443   if (!Entry) {
444     Entry = Alloc.Allocate<PDFileEntry>();
445     Entry = new (Entry) PDFileEntry(NodeID);
446     Set.InsertNode(Entry, InsertPos);
447   }
448 
449   // Allocate persistent storage for the file name.
450   char *FileName_cstr = (char*) Alloc.Allocate(FileName.size(), 1);
451   memcpy(FileName_cstr, FileName.data(), FileName.size());
452 
453   Entry->files.push_back(std::make_pair(ConsumerName,
454                                         StringRef(FileName_cstr,
455                                                   FileName.size())));
456 }
457 
458 PathDiagnosticConsumer::PDFileEntry::ConsumerFiles *
getFiles(const PathDiagnostic & PD)459 PathDiagnosticConsumer::FilesMade::getFiles(const PathDiagnostic &PD) {
460   llvm::FoldingSetNodeID NodeID;
461   NodeID.Add(PD);
462   void *InsertPos;
463   PDFileEntry *Entry = Set.FindNodeOrInsertPos(NodeID, InsertPos);
464   if (!Entry)
465     return nullptr;
466   return &Entry->files;
467 }
468 
469 //===----------------------------------------------------------------------===//
470 // PathDiagnosticLocation methods.
471 //===----------------------------------------------------------------------===//
472 
getValidSourceLocation(const Stmt * S,LocationOrAnalysisDeclContext LAC,bool UseEndOfStatement)473 SourceLocation PathDiagnosticLocation::getValidSourceLocation(
474     const Stmt *S, LocationOrAnalysisDeclContext LAC, bool UseEndOfStatement) {
475   SourceLocation L = UseEndOfStatement ? S->getEndLoc() : S->getBeginLoc();
476   assert(!LAC.isNull() &&
477          "A valid LocationContext or AnalysisDeclContext should be passed to "
478          "PathDiagnosticLocation upon creation.");
479 
480   // S might be a temporary statement that does not have a location in the
481   // source code, so find an enclosing statement and use its location.
482   if (!L.isValid()) {
483     AnalysisDeclContext *ADC;
484     if (LAC.is<const LocationContext*>())
485       ADC = LAC.get<const LocationContext*>()->getAnalysisDeclContext();
486     else
487       ADC = LAC.get<AnalysisDeclContext*>();
488 
489     ParentMap &PM = ADC->getParentMap();
490 
491     const Stmt *Parent = S;
492     do {
493       Parent = PM.getParent(Parent);
494 
495       // In rare cases, we have implicit top-level expressions,
496       // such as arguments for implicit member initializers.
497       // In this case, fall back to the start of the body (even if we were
498       // asked for the statement end location).
499       if (!Parent) {
500         const Stmt *Body = ADC->getBody();
501         if (Body)
502           L = Body->getBeginLoc();
503         else
504           L = ADC->getDecl()->getEndLoc();
505         break;
506       }
507 
508       L = UseEndOfStatement ? Parent->getEndLoc() : Parent->getBeginLoc();
509     } while (!L.isValid());
510   }
511 
512   // FIXME: Ironically, this assert actually fails in some cases.
513   //assert(L.isValid());
514   return L;
515 }
516 
517 static PathDiagnosticLocation
getLocationForCaller(const StackFrameContext * SFC,const LocationContext * CallerCtx,const SourceManager & SM)518 getLocationForCaller(const StackFrameContext *SFC,
519                      const LocationContext *CallerCtx,
520                      const SourceManager &SM) {
521   const CFGBlock &Block = *SFC->getCallSiteBlock();
522   CFGElement Source = Block[SFC->getIndex()];
523 
524   switch (Source.getKind()) {
525   case CFGElement::Statement:
526   case CFGElement::Constructor:
527   case CFGElement::CXXRecordTypedCall:
528     return PathDiagnosticLocation(Source.castAs<CFGStmt>().getStmt(),
529                                   SM, CallerCtx);
530   case CFGElement::Initializer: {
531     const CFGInitializer &Init = Source.castAs<CFGInitializer>();
532     return PathDiagnosticLocation(Init.getInitializer()->getInit(),
533                                   SM, CallerCtx);
534   }
535   case CFGElement::AutomaticObjectDtor: {
536     const CFGAutomaticObjDtor &Dtor = Source.castAs<CFGAutomaticObjDtor>();
537     return PathDiagnosticLocation::createEnd(Dtor.getTriggerStmt(),
538                                              SM, CallerCtx);
539   }
540   case CFGElement::DeleteDtor: {
541     const CFGDeleteDtor &Dtor = Source.castAs<CFGDeleteDtor>();
542     return PathDiagnosticLocation(Dtor.getDeleteExpr(), SM, CallerCtx);
543   }
544   case CFGElement::BaseDtor:
545   case CFGElement::MemberDtor: {
546     const AnalysisDeclContext *CallerInfo = CallerCtx->getAnalysisDeclContext();
547     if (const Stmt *CallerBody = CallerInfo->getBody())
548       return PathDiagnosticLocation::createEnd(CallerBody, SM, CallerCtx);
549     return PathDiagnosticLocation::create(CallerInfo->getDecl(), SM);
550   }
551   case CFGElement::NewAllocator: {
552     const CFGNewAllocator &Alloc = Source.castAs<CFGNewAllocator>();
553     return PathDiagnosticLocation(Alloc.getAllocatorExpr(), SM, CallerCtx);
554   }
555   case CFGElement::TemporaryDtor: {
556     // Temporary destructors are for temporaries. They die immediately at around
557     // the location of CXXBindTemporaryExpr. If they are lifetime-extended,
558     // they'd be dealt with via an AutomaticObjectDtor instead.
559     const auto &Dtor = Source.castAs<CFGTemporaryDtor>();
560     return PathDiagnosticLocation::createEnd(Dtor.getBindTemporaryExpr(), SM,
561                                              CallerCtx);
562   }
563   case CFGElement::ScopeBegin:
564   case CFGElement::ScopeEnd:
565   case CFGElement::CleanupFunction:
566     llvm_unreachable("not yet implemented!");
567   case CFGElement::LifetimeEnds:
568   case CFGElement::LoopExit:
569     llvm_unreachable("CFGElement kind should not be on callsite!");
570   }
571 
572   llvm_unreachable("Unknown CFGElement kind");
573 }
574 
575 PathDiagnosticLocation
createBegin(const Decl * D,const SourceManager & SM)576 PathDiagnosticLocation::createBegin(const Decl *D,
577                                     const SourceManager &SM) {
578   return PathDiagnosticLocation(D->getBeginLoc(), SM, SingleLocK);
579 }
580 
581 PathDiagnosticLocation
createBegin(const Stmt * S,const SourceManager & SM,LocationOrAnalysisDeclContext LAC)582 PathDiagnosticLocation::createBegin(const Stmt *S,
583                                     const SourceManager &SM,
584                                     LocationOrAnalysisDeclContext LAC) {
585   assert(S && "Statement cannot be null");
586   return PathDiagnosticLocation(getValidSourceLocation(S, LAC),
587                                 SM, SingleLocK);
588 }
589 
590 PathDiagnosticLocation
createEnd(const Stmt * S,const SourceManager & SM,LocationOrAnalysisDeclContext LAC)591 PathDiagnosticLocation::createEnd(const Stmt *S,
592                                   const SourceManager &SM,
593                                   LocationOrAnalysisDeclContext LAC) {
594   if (const auto *CS = dyn_cast<CompoundStmt>(S))
595     return createEndBrace(CS, SM);
596   return PathDiagnosticLocation(getValidSourceLocation(S, LAC, /*End=*/true),
597                                 SM, SingleLocK);
598 }
599 
600 PathDiagnosticLocation
createOperatorLoc(const BinaryOperator * BO,const SourceManager & SM)601 PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO,
602                                           const SourceManager &SM) {
603   return PathDiagnosticLocation(BO->getOperatorLoc(), SM, SingleLocK);
604 }
605 
606 PathDiagnosticLocation
createConditionalColonLoc(const ConditionalOperator * CO,const SourceManager & SM)607 PathDiagnosticLocation::createConditionalColonLoc(
608                                             const ConditionalOperator *CO,
609                                             const SourceManager &SM) {
610   return PathDiagnosticLocation(CO->getColonLoc(), SM, SingleLocK);
611 }
612 
613 PathDiagnosticLocation
createMemberLoc(const MemberExpr * ME,const SourceManager & SM)614 PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME,
615                                         const SourceManager &SM) {
616 
617   assert(ME->getMemberLoc().isValid() || ME->getBeginLoc().isValid());
618 
619   // In some cases, getMemberLoc isn't valid -- in this case we'll return with
620   // some other related valid SourceLocation.
621   if (ME->getMemberLoc().isValid())
622     return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK);
623 
624   return PathDiagnosticLocation(ME->getBeginLoc(), SM, SingleLocK);
625 }
626 
627 PathDiagnosticLocation
createBeginBrace(const CompoundStmt * CS,const SourceManager & SM)628 PathDiagnosticLocation::createBeginBrace(const CompoundStmt *CS,
629                                          const SourceManager &SM) {
630   SourceLocation L = CS->getLBracLoc();
631   return PathDiagnosticLocation(L, SM, SingleLocK);
632 }
633 
634 PathDiagnosticLocation
createEndBrace(const CompoundStmt * CS,const SourceManager & SM)635 PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS,
636                                        const SourceManager &SM) {
637   SourceLocation L = CS->getRBracLoc();
638   return PathDiagnosticLocation(L, SM, SingleLocK);
639 }
640 
641 PathDiagnosticLocation
createDeclBegin(const LocationContext * LC,const SourceManager & SM)642 PathDiagnosticLocation::createDeclBegin(const LocationContext *LC,
643                                         const SourceManager &SM) {
644   // FIXME: Should handle CXXTryStmt if analyser starts supporting C++.
645   if (const auto *CS = dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody()))
646     if (!CS->body_empty()) {
647       SourceLocation Loc = (*CS->body_begin())->getBeginLoc();
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   const Stmt* S = nullptr;
665   if (std::optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
666     const CFGBlock *BSrc = BE->getSrc();
667     if (BSrc->getTerminator().isVirtualBaseBranch()) {
668       // TODO: VirtualBaseBranches should also appear for destructors.
669       // In this case we should put the diagnostic at the end of decl.
670       return PathDiagnosticLocation::createBegin(
671           P.getLocationContext()->getDecl(), SMng);
672 
673     } else {
674       S = BSrc->getTerminatorCondition();
675       if (!S) {
676         // If the BlockEdge has no terminator condition statement but its
677         // source is the entry of the CFG (e.g. a checker crated the branch at
678         // the beginning of a function), use the function's declaration instead.
679         assert(BSrc == &BSrc->getParent()->getEntry() && "CFGBlock has no "
680                "TerminatorCondition and is not the enrty block of the CFG");
681         return PathDiagnosticLocation::createBegin(
682             P.getLocationContext()->getDecl(), SMng);
683       }
684     }
685   } else if (std::optional<StmtPoint> SP = P.getAs<StmtPoint>()) {
686     S = SP->getStmt();
687     if (P.getAs<PostStmtPurgeDeadSymbols>())
688       return PathDiagnosticLocation::createEnd(S, SMng, P.getLocationContext());
689   } else if (std::optional<PostInitializer> PIP = P.getAs<PostInitializer>()) {
690     return PathDiagnosticLocation(PIP->getInitializer()->getSourceLocation(),
691                                   SMng);
692   } else if (std::optional<PreImplicitCall> PIC = P.getAs<PreImplicitCall>()) {
693     return PathDiagnosticLocation(PIC->getLocation(), SMng);
694   } else if (std::optional<PostImplicitCall> PIE =
695                  P.getAs<PostImplicitCall>()) {
696     return PathDiagnosticLocation(PIE->getLocation(), SMng);
697   } else if (std::optional<CallEnter> CE = P.getAs<CallEnter>()) {
698     return getLocationForCaller(CE->getCalleeContext(),
699                                 CE->getLocationContext(),
700                                 SMng);
701   } else if (std::optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) {
702     return getLocationForCaller(CEE->getCalleeContext(),
703                                 CEE->getLocationContext(),
704                                 SMng);
705   } else if (auto CEB = P.getAs<CallExitBegin>()) {
706     if (const ReturnStmt *RS = CEB->getReturnStmt())
707       return PathDiagnosticLocation::createBegin(RS, SMng,
708                                                  CEB->getLocationContext());
709     return PathDiagnosticLocation(
710         CEB->getLocationContext()->getDecl()->getSourceRange().getEnd(), SMng);
711   } else if (std::optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) {
712     if (std::optional<CFGElement> BlockFront = BE->getFirstElement()) {
713       if (auto StmtElt = BlockFront->getAs<CFGStmt>()) {
714         return PathDiagnosticLocation(StmtElt->getStmt()->getBeginLoc(), SMng);
715       } else if (auto NewAllocElt = BlockFront->getAs<CFGNewAllocator>()) {
716         return PathDiagnosticLocation(
717             NewAllocElt->getAllocatorExpr()->getBeginLoc(), SMng);
718       }
719       llvm_unreachable("Unexpected CFG element at front of block");
720     }
721 
722     return PathDiagnosticLocation(
723         BE->getBlock()->getTerminatorStmt()->getBeginLoc(), SMng);
724   } else if (std::optional<FunctionExitPoint> FE =
725                  P.getAs<FunctionExitPoint>()) {
726     return PathDiagnosticLocation(FE->getStmt(), SMng,
727                                   FE->getLocationContext());
728   } else {
729     llvm_unreachable("Unexpected ProgramPoint");
730   }
731 
732   return PathDiagnosticLocation(S, SMng, P.getLocationContext());
733 }
734 
createSingleLocation(const PathDiagnosticLocation & PDL)735 PathDiagnosticLocation PathDiagnosticLocation::createSingleLocation(
736                                            const PathDiagnosticLocation &PDL) {
737   FullSourceLoc L = PDL.asLocation();
738   return PathDiagnosticLocation(L, L.getManager(), SingleLocK);
739 }
740 
741 FullSourceLoc
genLocation(SourceLocation L,LocationOrAnalysisDeclContext LAC) const742   PathDiagnosticLocation::genLocation(SourceLocation L,
743                                       LocationOrAnalysisDeclContext LAC) const {
744   assert(isValid());
745   // Note that we want a 'switch' here so that the compiler can warn us in
746   // case we add more cases.
747   switch (K) {
748     case SingleLocK:
749     case RangeK:
750       break;
751     case StmtK:
752       // Defensive checking.
753       if (!S)
754         break;
755       return FullSourceLoc(getValidSourceLocation(S, LAC),
756                            const_cast<SourceManager&>(*SM));
757     case DeclK:
758       // Defensive checking.
759       if (!D)
760         break;
761       return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM));
762   }
763 
764   return FullSourceLoc(L, const_cast<SourceManager&>(*SM));
765 }
766 
767 PathDiagnosticRange
genRange(LocationOrAnalysisDeclContext LAC) const768   PathDiagnosticLocation::genRange(LocationOrAnalysisDeclContext LAC) const {
769   assert(isValid());
770   // Note that we want a 'switch' here so that the compiler can warn us in
771   // case we add more cases.
772   switch (K) {
773     case SingleLocK:
774       return PathDiagnosticRange(SourceRange(Loc,Loc), true);
775     case RangeK:
776       break;
777     case StmtK: {
778       const Stmt *S = asStmt();
779       switch (S->getStmtClass()) {
780         default:
781           break;
782         case Stmt::DeclStmtClass: {
783           const auto *DS = cast<DeclStmt>(S);
784           if (DS->isSingleDecl()) {
785             // Should always be the case, but we'll be defensive.
786             return SourceRange(DS->getBeginLoc(),
787                                DS->getSingleDecl()->getLocation());
788           }
789           break;
790         }
791           // FIXME: Provide better range information for different
792           //  terminators.
793         case Stmt::IfStmtClass:
794         case Stmt::WhileStmtClass:
795         case Stmt::DoStmtClass:
796         case Stmt::ForStmtClass:
797         case Stmt::ChooseExprClass:
798         case Stmt::IndirectGotoStmtClass:
799         case Stmt::SwitchStmtClass:
800         case Stmt::BinaryConditionalOperatorClass:
801         case Stmt::ConditionalOperatorClass:
802         case Stmt::ObjCForCollectionStmtClass: {
803           SourceLocation L = getValidSourceLocation(S, LAC);
804           return SourceRange(L, L);
805         }
806       }
807       SourceRange R = S->getSourceRange();
808       if (R.isValid())
809         return R;
810       break;
811     }
812     case DeclK:
813       if (const auto *MD = dyn_cast<ObjCMethodDecl>(D))
814         return MD->getSourceRange();
815       if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
816         if (Stmt *Body = FD->getBody())
817           return Body->getSourceRange();
818       }
819       else {
820         SourceLocation L = D->getLocation();
821         return PathDiagnosticRange(SourceRange(L, L), true);
822       }
823   }
824 
825   return SourceRange(Loc, Loc);
826 }
827 
flatten()828 void PathDiagnosticLocation::flatten() {
829   if (K == StmtK) {
830     K = RangeK;
831     S = nullptr;
832     D = nullptr;
833   }
834   else if (K == DeclK) {
835     K = SingleLocK;
836     S = nullptr;
837     D = nullptr;
838   }
839 }
840 
841 //===----------------------------------------------------------------------===//
842 // Manipulation of PathDiagnosticCallPieces.
843 //===----------------------------------------------------------------------===//
844 
845 std::shared_ptr<PathDiagnosticCallPiece>
construct(const CallExitEnd & CE,const SourceManager & SM)846 PathDiagnosticCallPiece::construct(const CallExitEnd &CE,
847                                    const SourceManager &SM) {
848   const Decl *caller = CE.getLocationContext()->getDecl();
849   PathDiagnosticLocation pos = getLocationForCaller(CE.getCalleeContext(),
850                                                     CE.getLocationContext(),
851                                                     SM);
852   return std::shared_ptr<PathDiagnosticCallPiece>(
853       new PathDiagnosticCallPiece(caller, pos));
854 }
855 
856 PathDiagnosticCallPiece *
construct(PathPieces & path,const Decl * caller)857 PathDiagnosticCallPiece::construct(PathPieces &path,
858                                    const Decl *caller) {
859   std::shared_ptr<PathDiagnosticCallPiece> C(
860       new PathDiagnosticCallPiece(path, caller));
861   path.clear();
862   auto *R = C.get();
863   path.push_front(std::move(C));
864   return R;
865 }
866 
setCallee(const CallEnter & CE,const SourceManager & SM)867 void PathDiagnosticCallPiece::setCallee(const CallEnter &CE,
868                                         const SourceManager &SM) {
869   const StackFrameContext *CalleeCtx = CE.getCalleeContext();
870   Callee = CalleeCtx->getDecl();
871 
872   callEnterWithin = PathDiagnosticLocation::createBegin(Callee, SM);
873   callEnter = getLocationForCaller(CalleeCtx, CE.getLocationContext(), SM);
874 
875   // Autosynthesized property accessors are special because we'd never
876   // pop back up to non-autosynthesized code until we leave them.
877   // This is not generally true for autosynthesized callees, which may call
878   // non-autosynthesized callbacks.
879   // Unless set here, the IsCalleeAnAutosynthesizedPropertyAccessor flag
880   // defaults to false.
881   if (const auto *MD = dyn_cast<ObjCMethodDecl>(Callee))
882     IsCalleeAnAutosynthesizedPropertyAccessor = (
883         MD->isPropertyAccessor() &&
884         CalleeCtx->getAnalysisDeclContext()->isBodyAutosynthesized());
885 }
886 
887 static void describeTemplateParameters(raw_ostream &Out,
888                                        const ArrayRef<TemplateArgument> TAList,
889                                        const LangOptions &LO,
890                                        StringRef Prefix = StringRef(),
891                                        StringRef Postfix = StringRef());
892 
describeTemplateParameter(raw_ostream & Out,const TemplateArgument & TArg,const LangOptions & LO)893 static void describeTemplateParameter(raw_ostream &Out,
894                                       const TemplateArgument &TArg,
895                                       const LangOptions &LO) {
896 
897   if (TArg.getKind() == TemplateArgument::ArgKind::Pack) {
898     describeTemplateParameters(Out, TArg.getPackAsArray(), LO);
899   } else {
900     TArg.print(PrintingPolicy(LO), Out, /*IncludeType*/ true);
901   }
902 }
903 
describeTemplateParameters(raw_ostream & Out,const ArrayRef<TemplateArgument> TAList,const LangOptions & LO,StringRef Prefix,StringRef Postfix)904 static void describeTemplateParameters(raw_ostream &Out,
905                                        const ArrayRef<TemplateArgument> TAList,
906                                        const LangOptions &LO,
907                                        StringRef Prefix, StringRef Postfix) {
908   if (TAList.empty())
909     return;
910 
911   Out << Prefix;
912   for (int I = 0, Last = TAList.size() - 1; I != Last; ++I) {
913     describeTemplateParameter(Out, TAList[I], LO);
914     Out << ", ";
915   }
916   describeTemplateParameter(Out, TAList[TAList.size() - 1], LO);
917   Out << Postfix;
918 }
919 
describeClass(raw_ostream & Out,const CXXRecordDecl * D,StringRef Prefix=StringRef ())920 static void describeClass(raw_ostream &Out, const CXXRecordDecl *D,
921                           StringRef Prefix = StringRef()) {
922   if (!D->getIdentifier())
923     return;
924   Out << Prefix << '\'' << *D;
925   if (const auto T = dyn_cast<ClassTemplateSpecializationDecl>(D))
926     describeTemplateParameters(Out, T->getTemplateArgs().asArray(),
927                                D->getLangOpts(), "<", ">");
928 
929   Out << '\'';
930 }
931 
describeCodeDecl(raw_ostream & Out,const Decl * D,bool ExtendedDescription,StringRef Prefix=StringRef ())932 static bool describeCodeDecl(raw_ostream &Out, const Decl *D,
933                              bool ExtendedDescription,
934                              StringRef Prefix = StringRef()) {
935   if (!D)
936     return false;
937 
938   if (isa<BlockDecl>(D)) {
939     if (ExtendedDescription)
940       Out << Prefix << "anonymous block";
941     return ExtendedDescription;
942   }
943 
944   if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
945     Out << Prefix;
946     if (ExtendedDescription && !MD->isUserProvided()) {
947       if (MD->isExplicitlyDefaulted())
948         Out << "defaulted ";
949       else
950         Out << "implicit ";
951     }
952 
953     if (const auto *CD = dyn_cast<CXXConstructorDecl>(MD)) {
954       if (CD->isDefaultConstructor())
955         Out << "default ";
956       else if (CD->isCopyConstructor())
957         Out << "copy ";
958       else if (CD->isMoveConstructor())
959         Out << "move ";
960 
961       Out << "constructor";
962       describeClass(Out, MD->getParent(), " for ");
963     } else if (isa<CXXDestructorDecl>(MD)) {
964       if (!MD->isUserProvided()) {
965         Out << "destructor";
966         describeClass(Out, MD->getParent(), " for ");
967       } else {
968         // Use ~Foo for explicitly-written destructors.
969         Out << "'" << *MD << "'";
970       }
971     } else if (MD->isCopyAssignmentOperator()) {
972         Out << "copy assignment operator";
973         describeClass(Out, MD->getParent(), " for ");
974     } else if (MD->isMoveAssignmentOperator()) {
975         Out << "move assignment operator";
976         describeClass(Out, MD->getParent(), " for ");
977     } else {
978       if (MD->getParent()->getIdentifier())
979         Out << "'" << *MD->getParent() << "::" << *MD << "'";
980       else
981         Out << "'" << *MD << "'";
982     }
983 
984     return true;
985   }
986 
987   Out << Prefix << '\'' << cast<NamedDecl>(*D);
988 
989   // Adding template parameters.
990   if (const auto FD = dyn_cast<FunctionDecl>(D))
991     if (const TemplateArgumentList *TAList =
992                                     FD->getTemplateSpecializationArgs())
993       describeTemplateParameters(Out, TAList->asArray(), FD->getLangOpts(), "<",
994                                  ">");
995 
996   Out << '\'';
997   return true;
998 }
999 
1000 std::shared_ptr<PathDiagnosticEventPiece>
getCallEnterEvent() const1001 PathDiagnosticCallPiece::getCallEnterEvent() const {
1002   // We do not produce call enters and call exits for autosynthesized property
1003   // accessors. We do generally produce them for other functions coming from
1004   // the body farm because they may call callbacks that bring us back into
1005   // visible code.
1006   if (!Callee || IsCalleeAnAutosynthesizedPropertyAccessor)
1007     return nullptr;
1008 
1009   SmallString<256> buf;
1010   llvm::raw_svector_ostream Out(buf);
1011 
1012   Out << "Calling ";
1013   describeCodeDecl(Out, Callee, /*ExtendedDescription=*/true);
1014 
1015   assert(callEnter.asLocation().isValid());
1016   return std::make_shared<PathDiagnosticEventPiece>(callEnter, Out.str());
1017 }
1018 
1019 std::shared_ptr<PathDiagnosticEventPiece>
getCallEnterWithinCallerEvent() const1020 PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const {
1021   if (!callEnterWithin.asLocation().isValid())
1022     return nullptr;
1023   if (Callee->isImplicit() || !Callee->hasBody())
1024     return nullptr;
1025   if (const auto *MD = dyn_cast<CXXMethodDecl>(Callee))
1026     if (MD->isDefaulted())
1027       return nullptr;
1028 
1029   SmallString<256> buf;
1030   llvm::raw_svector_ostream Out(buf);
1031 
1032   Out << "Entered call";
1033   describeCodeDecl(Out, Caller, /*ExtendedDescription=*/false, " from ");
1034 
1035   return std::make_shared<PathDiagnosticEventPiece>(callEnterWithin, Out.str());
1036 }
1037 
1038 std::shared_ptr<PathDiagnosticEventPiece>
getCallExitEvent() const1039 PathDiagnosticCallPiece::getCallExitEvent() const {
1040   // We do not produce call enters and call exits for autosynthesized property
1041   // accessors. We do generally produce them for other functions coming from
1042   // the body farm because they may call callbacks that bring us back into
1043   // visible code.
1044   if (NoExit || IsCalleeAnAutosynthesizedPropertyAccessor)
1045     return nullptr;
1046 
1047   SmallString<256> buf;
1048   llvm::raw_svector_ostream Out(buf);
1049 
1050   if (!CallStackMessage.empty()) {
1051     Out << CallStackMessage;
1052   } else {
1053     bool DidDescribe = describeCodeDecl(Out, Callee,
1054                                         /*ExtendedDescription=*/false,
1055                                         "Returning from ");
1056     if (!DidDescribe)
1057       Out << "Returning to caller";
1058   }
1059 
1060   assert(callReturn.asLocation().isValid());
1061   return std::make_shared<PathDiagnosticEventPiece>(callReturn, Out.str());
1062 }
1063 
compute_path_size(const PathPieces & pieces,unsigned & size)1064 static void compute_path_size(const PathPieces &pieces, unsigned &size) {
1065   for (const auto &I : pieces) {
1066     const PathDiagnosticPiece *piece = I.get();
1067     if (const auto *cp = dyn_cast<PathDiagnosticCallPiece>(piece))
1068       compute_path_size(cp->path, size);
1069     else
1070       ++size;
1071   }
1072 }
1073 
full_size()1074 unsigned PathDiagnostic::full_size() {
1075   unsigned size = 0;
1076   compute_path_size(path, size);
1077   return size;
1078 }
1079 
1080 //===----------------------------------------------------------------------===//
1081 // FoldingSet profiling methods.
1082 //===----------------------------------------------------------------------===//
1083 
Profile(llvm::FoldingSetNodeID & ID) const1084 void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const {
1085   ID.Add(Range.getBegin());
1086   ID.Add(Range.getEnd());
1087   ID.Add(static_cast<const SourceLocation &>(Loc));
1088 }
1089 
Profile(llvm::FoldingSetNodeID & ID) const1090 void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1091   ID.AddInteger((unsigned) getKind());
1092   ID.AddString(str);
1093   // FIXME: Add profiling support for code hints.
1094   ID.AddInteger((unsigned) getDisplayHint());
1095   ArrayRef<SourceRange> Ranges = getRanges();
1096   for (const auto &I : Ranges) {
1097     ID.Add(I.getBegin());
1098     ID.Add(I.getEnd());
1099   }
1100 }
1101 
Profile(llvm::FoldingSetNodeID & ID) const1102 void PathDiagnosticCallPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1103   PathDiagnosticPiece::Profile(ID);
1104   for (const auto &I : path)
1105     ID.Add(*I);
1106 }
1107 
Profile(llvm::FoldingSetNodeID & ID) const1108 void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1109   PathDiagnosticPiece::Profile(ID);
1110   ID.Add(Pos);
1111 }
1112 
Profile(llvm::FoldingSetNodeID & ID) const1113 void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1114   PathDiagnosticPiece::Profile(ID);
1115   for (const auto &I : *this)
1116     ID.Add(I);
1117 }
1118 
Profile(llvm::FoldingSetNodeID & ID) const1119 void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1120   PathDiagnosticSpotPiece::Profile(ID);
1121   for (const auto &I : subPieces)
1122     ID.Add(*I);
1123 }
1124 
Profile(llvm::FoldingSetNodeID & ID) const1125 void PathDiagnosticNotePiece::Profile(llvm::FoldingSetNodeID &ID) const {
1126   PathDiagnosticSpotPiece::Profile(ID);
1127 }
1128 
Profile(llvm::FoldingSetNodeID & ID) const1129 void PathDiagnosticPopUpPiece::Profile(llvm::FoldingSetNodeID &ID) const {
1130   PathDiagnosticSpotPiece::Profile(ID);
1131 }
1132 
Profile(llvm::FoldingSetNodeID & ID) const1133 void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const {
1134   ID.Add(getLocation());
1135   ID.Add(getUniqueingLoc());
1136   ID.AddString(BugType);
1137   ID.AddString(VerboseDesc);
1138   ID.AddString(Category);
1139 }
1140 
FullProfile(llvm::FoldingSetNodeID & ID) const1141 void PathDiagnostic::FullProfile(llvm::FoldingSetNodeID &ID) const {
1142   Profile(ID);
1143   for (const auto &I : path)
1144     ID.Add(*I);
1145   for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I)
1146     ID.AddString(*I);
1147 }
1148 
dump() const1149 LLVM_DUMP_METHOD void PathPieces::dump() const {
1150   unsigned index = 0;
1151   for (PathPieces::const_iterator I = begin(), E = end(); I != E; ++I) {
1152     llvm::errs() << "[" << index++ << "]  ";
1153     (*I)->dump();
1154     llvm::errs() << "\n";
1155   }
1156 }
1157 
dump() const1158 LLVM_DUMP_METHOD void PathDiagnosticCallPiece::dump() const {
1159   llvm::errs() << "CALL\n--------------\n";
1160 
1161   if (const Stmt *SLoc = getLocation().getStmtOrNull())
1162     SLoc->dump();
1163   else if (const auto *ND = dyn_cast_or_null<NamedDecl>(getCallee()))
1164     llvm::errs() << *ND << "\n";
1165   else
1166     getLocation().dump();
1167 }
1168 
dump() const1169 LLVM_DUMP_METHOD void PathDiagnosticEventPiece::dump() const {
1170   llvm::errs() << "EVENT\n--------------\n";
1171   llvm::errs() << getString() << "\n";
1172   llvm::errs() << " ---- at ----\n";
1173   getLocation().dump();
1174 }
1175 
dump() const1176 LLVM_DUMP_METHOD void PathDiagnosticControlFlowPiece::dump() const {
1177   llvm::errs() << "CONTROL\n--------------\n";
1178   getStartLocation().dump();
1179   llvm::errs() << " ---- to ----\n";
1180   getEndLocation().dump();
1181 }
1182 
dump() const1183 LLVM_DUMP_METHOD void PathDiagnosticMacroPiece::dump() const {
1184   llvm::errs() << "MACRO\n--------------\n";
1185   // FIXME: Print which macro is being invoked.
1186 }
1187 
dump() const1188 LLVM_DUMP_METHOD void PathDiagnosticNotePiece::dump() const {
1189   llvm::errs() << "NOTE\n--------------\n";
1190   llvm::errs() << getString() << "\n";
1191   llvm::errs() << " ---- at ----\n";
1192   getLocation().dump();
1193 }
1194 
dump() const1195 LLVM_DUMP_METHOD void PathDiagnosticPopUpPiece::dump() const {
1196   llvm::errs() << "POP-UP\n--------------\n";
1197   llvm::errs() << getString() << "\n";
1198   llvm::errs() << " ---- at ----\n";
1199   getLocation().dump();
1200 }
1201 
dump() const1202 LLVM_DUMP_METHOD void PathDiagnosticLocation::dump() const {
1203   if (!isValid()) {
1204     llvm::errs() << "<INVALID>\n";
1205     return;
1206   }
1207 
1208   switch (K) {
1209   case RangeK:
1210     // FIXME: actually print the range.
1211     llvm::errs() << "<range>\n";
1212     break;
1213   case SingleLocK:
1214     asLocation().dump();
1215     llvm::errs() << "\n";
1216     break;
1217   case StmtK:
1218     if (S)
1219       S->dump();
1220     else
1221       llvm::errs() << "<NULL STMT>\n";
1222     break;
1223   case DeclK:
1224     if (const auto *ND = dyn_cast_or_null<NamedDecl>(D))
1225       llvm::errs() << *ND << "\n";
1226     else if (isa<BlockDecl>(D))
1227       // FIXME: Make this nicer.
1228       llvm::errs() << "<block>\n";
1229     else if (D)
1230       llvm::errs() << "<unknown decl>\n";
1231     else
1232       llvm::errs() << "<NULL DECL>\n";
1233     break;
1234   }
1235 }
1236