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