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