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