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