/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 | 146k | static StringRef StripTrailingDots(StringRef s) { |
55 | 148k | for (StringRef::size_type i = s.size(); i != 0; --i1.88k ) |
56 | 146k | if (s[i - 1] != '.') |
57 | 144k | return s.substr(0, i); |
58 | 2.20k | return {}; |
59 | 146k | } |
60 | | |
61 | | PathDiagnosticPiece::PathDiagnosticPiece(StringRef s, |
62 | | Kind k, DisplayHint hint) |
63 | 31.1k | : str(StripTrailingDots(s)), kind(k), Hint(hint) {} |
64 | | |
65 | | PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint) |
66 | 19.6k | : kind(k), Hint(hint) {} |
67 | | |
68 | 50.8k | PathDiagnosticPiece::~PathDiagnosticPiece() = default; |
69 | | |
70 | 27.8k | PathDiagnosticEventPiece::~PathDiagnosticEventPiece() = default; |
71 | | |
72 | 6.98k | PathDiagnosticCallPiece::~PathDiagnosticCallPiece() = default; |
73 | | |
74 | 13.5k | PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() = default; |
75 | | |
76 | 45 | PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() = default; |
77 | | |
78 | 166 | PathDiagnosticNotePiece::~PathDiagnosticNotePiece() = default; |
79 | | |
80 | 2.27k | PathDiagnosticPopUpPiece::~PathDiagnosticPopUpPiece() = default; |
81 | | |
82 | | void PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current, |
83 | 18.0k | bool ShouldFlattenMacros) const { |
84 | 26.6k | for (auto &Piece : *this) { |
85 | 26.6k | switch (Piece->getKind()) { |
86 | 685 | case PathDiagnosticPiece::Call: { |
87 | 685 | auto &Call = cast<PathDiagnosticCallPiece>(*Piece); |
88 | 685 | if (auto CallEnter = Call.getCallEnterEvent()) |
89 | 682 | Current.push_back(std::move(CallEnter)); |
90 | 685 | Call.path.flattenTo(Primary, Primary, ShouldFlattenMacros); |
91 | 685 | if (auto callExit = Call.getCallExitEvent()) |
92 | 431 | Current.push_back(std::move(callExit)); |
93 | 685 | break; |
94 | 0 | } |
95 | 45 | case PathDiagnosticPiece::Macro: { |
96 | 45 | auto &Macro = cast<PathDiagnosticMacroPiece>(*Piece); |
97 | 45 | if (ShouldFlattenMacros) { |
98 | 45 | Macro.subPieces.flattenTo(Primary, Primary, ShouldFlattenMacros); |
99 | 0 | } 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 | 45 | break; |
107 | 0 | } |
108 | 21.6k | case PathDiagnosticPiece::Event: |
109 | 25.4k | case PathDiagnosticPiece::ControlFlow: |
110 | 25.6k | case PathDiagnosticPiece::Note: |
111 | 25.9k | case PathDiagnosticPiece::PopUp: |
112 | 25.9k | Current.push_back(Piece); |
113 | 25.9k | break; |
114 | 26.6k | } |
115 | 26.6k | } |
116 | 18.0k | } |
117 | | |
118 | 28.9k | 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 | 28.9k | path(pathImpl) {} |
132 | | |
133 | 0 | void PathDiagnosticConsumer::anchor() {} |
134 | | |
135 | 1.47k | PathDiagnosticConsumer::~PathDiagnosticConsumer() { |
136 | | // Delete the contents of the FoldingSet if it isn't empty already. |
137 | 1.47k | for (auto &Diag : Diags) |
138 | 0 | delete &Diag; |
139 | 1.47k | } |
140 | | |
141 | | void PathDiagnosticConsumer::HandlePathDiagnostic( |
142 | 16.0k | std::unique_ptr<PathDiagnostic> D) { |
143 | 16.0k | 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 | 16.0k | D->flattenLocations(); |
150 | | |
151 | | // If the PathDiagnosticConsumer does not support diagnostics that |
152 | | // cross file boundaries, prune out such diagnostics now. |
153 | 16.0k | if (!supportsCrossFileDiagnostics()) { |
154 | | // Verify that the entire path is from the same FileID. |
155 | 511 | FileID FID; |
156 | 511 | const SourceManager &SMgr = D->path.front()->getLocation().getManager(); |
157 | 511 | SmallVector<const PathPieces *, 5> WorkList; |
158 | 511 | WorkList.push_back(&D->path); |
159 | 511 | SmallString<128> buf; |
160 | 511 | llvm::raw_svector_ostream warning(buf); |
161 | 511 | warning << "warning: Path diagnostic report is not generated. Current " |
162 | 511 | << "output format does not support diagnostics that cross file " |
163 | 511 | << "boundaries. Refer to --analyzer-output for valid output " |
164 | 511 | << "formats\n"; |
165 | | |
166 | 1.13k | while (!WorkList.empty()) { |
167 | 624 | const PathPieces &path = *WorkList.pop_back_val(); |
168 | | |
169 | 3.23k | for (const auto &I : path) { |
170 | 3.23k | const PathDiagnosticPiece *piece = I.get(); |
171 | 3.23k | FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc(); |
172 | | |
173 | 3.23k | if (FID.isInvalid()) { |
174 | 511 | FID = SMgr.getFileID(L); |
175 | 2.72k | } 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.23k | ArrayRef<SourceRange> Ranges = piece->getRanges(); |
182 | 1.35k | for (const auto &I : Ranges) { |
183 | 1.35k | SourceLocation L = SMgr.getExpansionLoc(I.getBegin()); |
184 | 1.35k | if (!L.isFileID() || SMgr.getFileID(L) != FID) { |
185 | 0 | llvm::errs() << warning.str(); |
186 | 0 | return; |
187 | 0 | } |
188 | 1.35k | L = SMgr.getExpansionLoc(I.getEnd()); |
189 | 1.35k | if (!L.isFileID() || SMgr.getFileID(L) != FID) { |
190 | 0 | llvm::errs() << warning.str(); |
191 | 0 | return; |
192 | 0 | } |
193 | 1.35k | } |
194 | | |
195 | 3.23k | if (const auto *call = dyn_cast<PathDiagnosticCallPiece>(piece)) |
196 | 76 | WorkList.push_back(&call->path); |
197 | 3.15k | else if (const auto *macro = dyn_cast<PathDiagnosticMacroPiece>(piece)) |
198 | 37 | WorkList.push_back(¯o->subPieces); |
199 | 3.23k | } |
200 | 624 | } |
201 | | |
202 | 510 | if (FID.isInvalid()) |
203 | 0 | return; // FIXME: Emit a warning? |
204 | 16.0k | } |
205 | | |
206 | | // Profile the node to see if we already have something matching it |
207 | 16.0k | llvm::FoldingSetNodeID profile; |
208 | 16.0k | D->Profile(profile); |
209 | 16.0k | void *InsertPos = nullptr; |
210 | | |
211 | 16.0k | 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 | 65 | const unsigned orig_size = orig->full_size(); |
217 | 65 | const unsigned new_size = D->full_size(); |
218 | 65 | if (orig_size <= new_size) |
219 | 65 | return; |
220 | | |
221 | 0 | assert(orig != D.get()); |
222 | 0 | Diags.RemoveNode(orig); |
223 | 0 | delete orig; |
224 | 0 | } |
225 | | |
226 | 15.9k | Diags.InsertNode(D.release()); |
227 | 15.9k | } |
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 | 9 | const PathDiagnosticPiece &Y) { |
269 | 9 | if (X.getKind() != Y.getKind()) |
270 | 0 | return X.getKind() < Y.getKind(); |
271 | | |
272 | 9 | FullSourceLoc XL = X.getLocation().asLocation(); |
273 | 9 | FullSourceLoc YL = Y.getLocation().asLocation(); |
274 | 9 | if (XL != YL) |
275 | 0 | return XL.isBeforeInTranslationUnitThan(YL); |
276 | | |
277 | 9 | if (X.getString() != Y.getString()) |
278 | 0 | return X.getString() < Y.getString(); |
279 | | |
280 | 9 | if (X.getRanges().size() != Y.getRanges().size()) |
281 | 2 | return X.getRanges().size() < Y.getRanges().size(); |
282 | | |
283 | 7 | const SourceManager &SM = XL.getManager(); |
284 | | |
285 | 7 | for (unsigned i = 0, n = X.getRanges().size(); i < n; ++i0 ) { |
286 | 7 | SourceRange XR = X.getRanges()[i]; |
287 | 7 | SourceRange YR = Y.getRanges()[i]; |
288 | 7 | if (XR != YR) { |
289 | 7 | if (XR.getBegin() != YR.getBegin()) |
290 | 0 | return SM.isBeforeInTranslationUnit(XR.getBegin(), YR.getBegin()); |
291 | 7 | return SM.isBeforeInTranslationUnit(XR.getEnd(), YR.getEnd()); |
292 | 7 | } |
293 | 7 | } |
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 | 11 | static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y) { |
314 | 11 | if (X.size() != Y.size()) |
315 | 2 | return X.size() < Y.size(); |
316 | | |
317 | 9 | PathPieces::const_iterator X_I = X.begin(), X_end = X.end(); |
318 | 9 | PathPieces::const_iterator Y_I = Y.begin(), Y_end = Y.end(); |
319 | | |
320 | 9 | for ( ; X_I != X_end && Y_I != Y_end; ++X_I, ++Y_I0 ) { |
321 | 9 | Optional<bool> b = comparePiece(**X_I, **Y_I); |
322 | 9 | if (b.hasValue()) |
323 | 9 | return b.getValue(); |
324 | 9 | } |
325 | | |
326 | 0 | return None; |
327 | 9 | } |
328 | | |
329 | 135k | static bool compareCrossTUSourceLocs(FullSourceLoc XL, FullSourceLoc YL) { |
330 | 135k | if (XL.isInvalid() && YL.isValid()31 ) |
331 | 31 | return true; |
332 | 135k | if (XL.isValid() && YL.isInvalid()) |
333 | 13 | return false; |
334 | 135k | std::pair<FileID, unsigned> XOffs = XL.getDecomposedLoc(); |
335 | 135k | std::pair<FileID, unsigned> YOffs = YL.getDecomposedLoc(); |
336 | 135k | const SourceManager &SM = XL.getManager(); |
337 | 135k | std::pair<bool, bool> InSameTU = SM.isInTheSameTranslationUnit(XOffs, YOffs); |
338 | 135k | if (InSameTU.first) |
339 | 135k | 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 | 135k | static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) { |
352 | 135k | FullSourceLoc XL = X.getLocation().asLocation(); |
353 | 135k | FullSourceLoc YL = Y.getLocation().asLocation(); |
354 | 135k | if (XL != YL) |
355 | 135k | return compareCrossTUSourceLocs(XL, YL); |
356 | 433 | FullSourceLoc XUL = X.getUniqueingLoc().asLocation(); |
357 | 433 | FullSourceLoc YUL = Y.getUniqueingLoc().asLocation(); |
358 | 433 | if (XUL != YUL) |
359 | 62 | return compareCrossTUSourceLocs(XUL, YUL); |
360 | 371 | if (X.getBugType() != Y.getBugType()) |
361 | 0 | return X.getBugType() < Y.getBugType(); |
362 | 371 | if (X.getCategory() != Y.getCategory()) |
363 | 0 | return X.getCategory() < Y.getCategory(); |
364 | 371 | if (X.getVerboseDescription() != Y.getVerboseDescription()) |
365 | 360 | return X.getVerboseDescription() < Y.getVerboseDescription(); |
366 | 11 | if (X.getShortDescription() != Y.getShortDescription()) |
367 | 0 | return X.getShortDescription() < Y.getShortDescription(); |
368 | 11 | auto CompareDecls = [&XL](const Decl *D1, const Decl *D2) -> Optional<bool> { |
369 | 11 | if (D1 == D2) |
370 | 11 | 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 | 11 | if (auto Result = CompareDecls(X.getDeclWithIssue(), Y.getDeclWithIssue())) |
385 | 0 | return *Result; |
386 | 11 | if (XUL.isValid()) { |
387 | 0 | if (auto Result = CompareDecls(X.getUniqueingDecl(), Y.getUniqueingDecl())) |
388 | 0 | return *Result; |
389 | 11 | } |
390 | 11 | PathDiagnostic::meta_iterator XI = X.meta_begin(), XE = X.meta_end(); |
391 | 11 | PathDiagnostic::meta_iterator YI = Y.meta_begin(), YE = Y.meta_end(); |
392 | 11 | if (XE - XI != YE - YI) |
393 | 0 | return (XE - XI) < (YE - YI); |
394 | 11 | for ( ; XI != XE ; ++XI, ++YI0 ) { |
395 | 0 | if (*XI != *YI) |
396 | 0 | return (*XI) < (*YI); |
397 | 0 | } |
398 | 11 | Optional<bool> b = comparePath(X.path, Y.path); |
399 | 11 | assert(b.hasValue()); |
400 | 11 | return b.getValue(); |
401 | 11 | } |
402 | | |
403 | | void PathDiagnosticConsumer::FlushDiagnostics( |
404 | 1.52k | PathDiagnosticConsumer::FilesMade *Files) { |
405 | 1.52k | if (flushed) |
406 | 45 | return; |
407 | | |
408 | 1.47k | flushed = true; |
409 | | |
410 | 1.47k | std::vector<const PathDiagnostic *> BatchDiags; |
411 | 1.47k | for (const auto &D : Diags) |
412 | 15.9k | BatchDiags.push_back(&D); |
413 | | |
414 | | // Sort the diagnostics so that they are always emitted in a deterministic |
415 | | // order. |
416 | 1.47k | int (*Comp)(const PathDiagnostic *const *, const PathDiagnostic *const *) = |
417 | 87.8k | [](const PathDiagnostic *const *X, const PathDiagnostic *const *Y) { |
418 | 87.8k | assert(*X != *Y && "PathDiagnostics not uniqued!"); |
419 | 87.8k | if (compare(**X, **Y)) |
420 | 40.0k | return -1; |
421 | 47.7k | assert(compare(**Y, **X) && "Not a total order!"); |
422 | 47.7k | return 1; |
423 | 47.7k | }; |
424 | 1.47k | array_pod_sort(BatchDiags.begin(), BatchDiags.end(), Comp); |
425 | | |
426 | 1.47k | FlushDiagnosticsImpl(BatchDiags, Files); |
427 | | |
428 | | // Delete the flushed diagnostics. |
429 | 1.47k | for (const auto D : BatchDiags) |
430 | 15.9k | delete D; |
431 | | |
432 | | // Clear out the FoldingSet. |
433 | 1.47k | Diags.clear(); |
434 | 1.47k | } |
435 | | |
436 | 1.35k | PathDiagnosticConsumer::FilesMade::~FilesMade() { |
437 | 1.35k | for (PDFileEntry &Entry : Set) |
438 | 94 | Entry.~PDFileEntry(); |
439 | 1.35k | } |
440 | | |
441 | | void PathDiagnosticConsumer::FilesMade::addDiagnostic(const PathDiagnostic &PD, |
442 | | StringRef ConsumerName, |
443 | 94 | StringRef FileName) { |
444 | 94 | llvm::FoldingSetNodeID NodeID; |
445 | 94 | NodeID.Add(PD); |
446 | 94 | void *InsertPos; |
447 | 94 | PDFileEntry *Entry = Set.FindNodeOrInsertPos(NodeID, InsertPos); |
448 | 94 | if (!Entry) { |
449 | 94 | Entry = Alloc.Allocate<PDFileEntry>(); |
450 | 94 | Entry = new (Entry) PDFileEntry(NodeID); |
451 | 94 | Set.InsertNode(Entry, InsertPos); |
452 | 94 | } |
453 | | |
454 | | // Allocate persistent storage for the file name. |
455 | 94 | char *FileName_cstr = (char*) Alloc.Allocate(FileName.size(), 1); |
456 | 94 | memcpy(FileName_cstr, FileName.data(), FileName.size()); |
457 | | |
458 | 94 | Entry->files.push_back(std::make_pair(ConsumerName, |
459 | 94 | StringRef(FileName_cstr, |
460 | 94 | FileName.size()))); |
461 | 94 | } |
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 | 97.7k | const Stmt *S, LocationOrAnalysisDeclContext LAC, bool UseEndOfStatement) { |
480 | 97.7k | SourceLocation L = UseEndOfStatement ? S->getEndLoc()5 : S->getBeginLoc(); |
481 | 97.7k | assert(!LAC.isNull() && |
482 | 97.7k | "A valid LocationContext or AnalysisDeclContext should be passed to " |
483 | 97.7k | "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 | 97.7k | 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 | 97.7k | return L; |
520 | 97.7k | } |
521 | | |
522 | | static PathDiagnosticLocation |
523 | | getLocationForCaller(const StackFrameContext *SFC, |
524 | | const LocationContext *CallerCtx, |
525 | 13.8k | const SourceManager &SM) { |
526 | 13.8k | const CFGBlock &Block = *SFC->getCallSiteBlock(); |
527 | 13.8k | CFGElement Source = Block[SFC->getIndex()]; |
528 | | |
529 | 13.8k | switch (Source.getKind()) { |
530 | 10.0k | case CFGElement::Statement: |
531 | 13.5k | case CFGElement::Constructor: |
532 | 13.6k | case CFGElement::CXXRecordTypedCall: |
533 | 13.6k | return PathDiagnosticLocation(Source.castAs<CFGStmt>().getStmt(), |
534 | 13.6k | 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 | 13.5k | } |
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 | 13.5k | } |
545 | 24 | case CFGElement::DeleteDtor: { |
546 | 24 | const CFGDeleteDtor &Dtor = Source.castAs<CFGDeleteDtor>(); |
547 | 24 | return PathDiagnosticLocation(Dtor.getDeleteExpr(), SM, CallerCtx); |
548 | 13.5k | } |
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 | 0 | } |
556 | 72 | case CFGElement::NewAllocator: { |
557 | 72 | const CFGNewAllocator &Alloc = Source.castAs<CFGNewAllocator>(); |
558 | 72 | return PathDiagnosticLocation(Alloc.getAllocatorExpr(), SM, CallerCtx); |
559 | 0 | } |
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 | 0 | } |
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 | 0 | } |
575 | | |
576 | 0 | llvm_unreachable("Unknown CFGElement kind"); |
577 | 0 | } |
578 | | |
579 | | PathDiagnosticLocation |
580 | | PathDiagnosticLocation::createBegin(const Decl *D, |
581 | 8.54k | const SourceManager &SM) { |
582 | 8.54k | return PathDiagnosticLocation(D->getBeginLoc(), SM, SingleLocK); |
583 | 8.54k | } |
584 | | |
585 | | PathDiagnosticLocation |
586 | | PathDiagnosticLocation::createBegin(const Stmt *S, |
587 | | const SourceManager &SM, |
588 | 3.08k | LocationOrAnalysisDeclContext LAC) { |
589 | 3.08k | return PathDiagnosticLocation(getValidSourceLocation(S, LAC), |
590 | 3.08k | SM, SingleLocK); |
591 | 3.08k | } |
592 | | |
593 | | PathDiagnosticLocation |
594 | | PathDiagnosticLocation::createEnd(const Stmt *S, |
595 | | const SourceManager &SM, |
596 | 721 | LocationOrAnalysisDeclContext LAC) { |
597 | 721 | if (const auto *CS = dyn_cast<CompoundStmt>(S)) |
598 | 716 | return createEndBrace(CS, SM); |
599 | 5 | return PathDiagnosticLocation(getValidSourceLocation(S, LAC, /*End=*/true), |
600 | 5 | SM, SingleLocK); |
601 | 5 | } |
602 | | |
603 | | PathDiagnosticLocation |
604 | | PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO, |
605 | 3.43k | const SourceManager &SM) { |
606 | 3.43k | return PathDiagnosticLocation(BO->getOperatorLoc(), SM, SingleLocK); |
607 | 3.43k | } |
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 | 4 | } |
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 | 741 | const SourceManager &SM) { |
640 | 741 | SourceLocation L = CS->getRBracLoc(); |
641 | 741 | return PathDiagnosticLocation(L, SM, SingleLocK); |
642 | 741 | } |
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 | 156 | const SourceManager &SM) { |
660 | 156 | SourceLocation L = LC->getDecl()->getBodyRBrace(); |
661 | 156 | return PathDiagnosticLocation(L, SM, SingleLocK); |
662 | 156 | } |
663 | | |
664 | | PathDiagnosticLocation |
665 | | PathDiagnosticLocation::create(const ProgramPoint& P, |
666 | 2.35k | const SourceManager &SMng) { |
667 | 2.35k | const Stmt* S = nullptr; |
668 | 2.35k | if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) { |
669 | 317 | const CFGBlock *BSrc = BE->getSrc(); |
670 | 317 | 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 | 207 | } else { |
677 | 207 | S = BSrc->getTerminatorCondition(); |
678 | 207 | 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 | 10 | return PathDiagnosticLocation::createBegin( |
685 | 10 | P.getLocationContext()->getDecl(), SMng); |
686 | 10 | } |
687 | 2.03k | } |
688 | 2.03k | } else if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) { |
689 | 1.94k | S = SP->getStmt(); |
690 | 1.94k | if (P.getAs<PostStmtPurgeDeadSymbols>()) |
691 | 0 | return PathDiagnosticLocation::createEnd(S, SMng, P.getLocationContext()); |
692 | 93 | } else if (Optional<PostInitializer> PIP = P.getAs<PostInitializer>()) { |
693 | 6 | return PathDiagnosticLocation(PIP->getInitializer()->getSourceLocation(), |
694 | 6 | SMng); |
695 | 87 | } else if (Optional<PreImplicitCall> PIC = P.getAs<PreImplicitCall>()) { |
696 | 0 | return PathDiagnosticLocation(PIC->getLocation(), SMng); |
697 | 87 | } else if (Optional<PostImplicitCall> PIE = P.getAs<PostImplicitCall>()) { |
698 | 0 | return PathDiagnosticLocation(PIE->getLocation(), SMng); |
699 | 87 | } else if (Optional<CallEnter> CE = P.getAs<CallEnter>()) { |
700 | 3 | return getLocationForCaller(CE->getCalleeContext(), |
701 | 3 | CE->getLocationContext(), |
702 | 3 | SMng); |
703 | 84 | } else if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) { |
704 | 0 | return getLocationForCaller(CEE->getCalleeContext(), |
705 | 0 | CEE->getLocationContext(), |
706 | 0 | SMng); |
707 | 84 | } else if (auto CEB = P.getAs<CallExitBegin>()) { |
708 | 78 | if (const ReturnStmt *RS = CEB->getReturnStmt()) |
709 | 30 | return PathDiagnosticLocation::createBegin(RS, SMng, |
710 | 30 | CEB->getLocationContext()); |
711 | 48 | return PathDiagnosticLocation( |
712 | 48 | CEB->getLocationContext()->getDecl()->getSourceRange().getEnd(), SMng); |
713 | 6 | } else if (Optional<BlockEntrance> BE = 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 | 1 | } else if (auto NewAllocElt = 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 | 1 | } else if (Optional<FunctionExitPoint> FE = P.getAs<FunctionExitPoint>()) { |
727 | 1 | return PathDiagnosticLocation(FE->getStmt(), SMng, |
728 | 1 | FE->getLocationContext()); |
729 | 0 | } else { |
730 | 0 | llvm_unreachable("Unexpected ProgramPoint"); |
731 | 0 | } |
732 | | |
733 | 2.14k | return PathDiagnosticLocation(S, SMng, P.getLocationContext()); |
734 | 2.14k | } |
735 | | |
736 | | PathDiagnosticLocation PathDiagnosticLocation::createSingleLocation( |
737 | 45 | const PathDiagnosticLocation &PDL) { |
738 | 45 | FullSourceLoc L = PDL.asLocation(); |
739 | 45 | return PathDiagnosticLocation(L, L.getManager(), SingleLocK); |
740 | 45 | } |
741 | | |
742 | | FullSourceLoc |
743 | | PathDiagnosticLocation::genLocation(SourceLocation L, |
744 | 109k | LocationOrAnalysisDeclContext LAC) const { |
745 | 109k | 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 | 109k | switch (K) { |
749 | 16.4k | case SingleLocK: |
750 | 16.4k | case RangeK: |
751 | 16.4k | break; |
752 | 92.5k | case StmtK: |
753 | | // Defensive checking. |
754 | 92.5k | if (!S) |
755 | 0 | break; |
756 | 92.5k | return FullSourceLoc(getValidSourceLocation(S, LAC), |
757 | 92.5k | const_cast<SourceManager&>(*SM)); |
758 | 300 | case DeclK: |
759 | | // Defensive checking. |
760 | 300 | if (!D) |
761 | 0 | break; |
762 | 300 | return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM)); |
763 | 16.4k | } |
764 | | |
765 | 16.4k | return FullSourceLoc(L, const_cast<SourceManager&>(*SM)); |
766 | 16.4k | } |
767 | | |
768 | | PathDiagnosticRange |
769 | 109k | PathDiagnosticLocation::genRange(LocationOrAnalysisDeclContext LAC) const { |
770 | 109k | 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 | 109k | switch (K) { |
774 | 16.7k | case SingleLocK: |
775 | 16.7k | return PathDiagnosticRange(SourceRange(Loc,Loc), true); |
776 | 0 | case RangeK: |
777 | 0 | break; |
778 | 92.5k | case StmtK: { |
779 | 92.5k | const Stmt *S = asStmt(); |
780 | 92.5k | switch (S->getStmtClass()) { |
781 | 84.6k | default: |
782 | 84.6k | break; |
783 | 5.70k | case Stmt::DeclStmtClass: { |
784 | 5.70k | const auto *DS = cast<DeclStmt>(S); |
785 | 5.70k | if (DS->isSingleDecl()) { |
786 | | // Should always be the case, but we'll be defensive. |
787 | 5.69k | return SourceRange(DS->getBeginLoc(), |
788 | 5.69k | DS->getSingleDecl()->getLocation()); |
789 | 5.69k | } |
790 | 12 | break; |
791 | 12 | } |
792 | | // FIXME: Provide better range information for different |
793 | | // terminators. |
794 | 1.65k | case Stmt::IfStmtClass: |
795 | 1.73k | case Stmt::WhileStmtClass: |
796 | 1.74k | case Stmt::DoStmtClass: |
797 | 1.98k | case Stmt::ForStmtClass: |
798 | 1.98k | case Stmt::ChooseExprClass: |
799 | 1.98k | case Stmt::IndirectGotoStmtClass: |
800 | 2.03k | case Stmt::SwitchStmtClass: |
801 | 2.04k | case Stmt::BinaryConditionalOperatorClass: |
802 | 2.10k | case Stmt::ConditionalOperatorClass: |
803 | 2.15k | case Stmt::ObjCForCollectionStmtClass: { |
804 | 2.15k | SourceLocation L = getValidSourceLocation(S, LAC); |
805 | 2.15k | return SourceRange(L, L); |
806 | 84.6k | } |
807 | 84.6k | } |
808 | 84.6k | SourceRange R = S->getSourceRange(); |
809 | 84.6k | if (R.isValid()) |
810 | 84.6k | return R; |
811 | 0 | break; |
812 | 0 | } |
813 | 300 | case DeclK: |
814 | 300 | if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) |
815 | 2 | return MD->getSourceRange(); |
816 | 298 | if (const auto *FD = dyn_cast<FunctionDecl>(D)) { |
817 | 9 | if (Stmt *Body = FD->getBody()) |
818 | 9 | return Body->getSourceRange(); |
819 | 289 | } |
820 | 289 | else { |
821 | 289 | SourceLocation L = D->getLocation(); |
822 | 289 | return PathDiagnosticRange(SourceRange(L, L), true); |
823 | 289 | } |
824 | 0 | } |
825 | | |
826 | 0 | return SourceRange(Loc, Loc); |
827 | 0 | } |
828 | | |
829 | 42.0k | void PathDiagnosticLocation::flatten() { |
830 | 42.0k | if (K == StmtK) { |
831 | 34.0k | K = RangeK; |
832 | 34.0k | S = nullptr; |
833 | 34.0k | D = nullptr; |
834 | 34.0k | } |
835 | 7.93k | else if (K == DeclK) { |
836 | 442 | K = SingleLocK; |
837 | 442 | S = nullptr; |
838 | 442 | D = nullptr; |
839 | 442 | } |
840 | 42.0k | } |
841 | | |
842 | | //===----------------------------------------------------------------------===// |
843 | | // Manipulation of PathDiagnosticCallPieces. |
844 | | //===----------------------------------------------------------------------===// |
845 | | |
846 | | std::shared_ptr<PathDiagnosticCallPiece> |
847 | | PathDiagnosticCallPiece::construct(const CallExitEnd &CE, |
848 | 6.81k | const SourceManager &SM) { |
849 | 6.81k | const Decl *caller = CE.getLocationContext()->getDecl(); |
850 | 6.81k | PathDiagnosticLocation pos = getLocationForCaller(CE.getCalleeContext(), |
851 | 6.81k | CE.getLocationContext(), |
852 | 6.81k | SM); |
853 | 6.81k | return std::shared_ptr<PathDiagnosticCallPiece>( |
854 | 6.81k | new PathDiagnosticCallPiece(caller, pos)); |
855 | 6.81k | } |
856 | | |
857 | | PathDiagnosticCallPiece * |
858 | | PathDiagnosticCallPiece::construct(PathPieces &path, |
859 | 166 | const Decl *caller) { |
860 | 166 | std::shared_ptr<PathDiagnosticCallPiece> C( |
861 | 166 | new PathDiagnosticCallPiece(path, caller)); |
862 | 166 | path.clear(); |
863 | 166 | auto *R = C.get(); |
864 | 166 | path.push_front(std::move(C)); |
865 | 166 | return R; |
866 | 166 | } |
867 | | |
868 | | void PathDiagnosticCallPiece::setCallee(const CallEnter &CE, |
869 | 6.98k | const SourceManager &SM) { |
870 | 6.98k | const StackFrameContext *CalleeCtx = CE.getCalleeContext(); |
871 | 6.98k | Callee = CalleeCtx->getDecl(); |
872 | | |
873 | 6.98k | callEnterWithin = PathDiagnosticLocation::createBegin(Callee, SM); |
874 | 6.98k | 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 | 6.98k | if (const auto *MD = dyn_cast<ObjCMethodDecl>(Callee)) |
883 | 28 | IsCalleeAnAutosynthesizedPropertyAccessor = ( |
884 | 28 | MD->isPropertyAccessor() && |
885 | 3 | CalleeCtx->getAnalysisDeclContext()->isBodyAutosynthesized()); |
886 | 6.98k | } |
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); |
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 | 188 | StringRef Prefix = StringRef()) { |
923 | 188 | if (!D->getIdentifier()) |
924 | 0 | return; |
925 | 188 | Out << Prefix << '\'' << *D; |
926 | 188 | if (const auto T = dyn_cast<ClassTemplateSpecializationDecl>(D)) |
927 | 17 | describeTemplateParameters(Out, T->getTemplateArgs().asArray(), |
928 | 17 | D->getLangOpts(), "<", ">"); |
929 | | |
930 | 188 | Out << '\''; |
931 | 188 | } |
932 | | |
933 | | static bool describeCodeDecl(raw_ostream &Out, const Decl *D, |
934 | | bool ExtendedDescription, |
935 | 1.72k | StringRef Prefix = StringRef()) { |
936 | 1.72k | if (!D) |
937 | 0 | return false; |
938 | | |
939 | 1.72k | if (isa<BlockDecl>(D)) { |
940 | 113 | if (ExtendedDescription) |
941 | 75 | Out << Prefix << "anonymous block"; |
942 | 113 | return ExtendedDescription; |
943 | 113 | } |
944 | | |
945 | 1.60k | if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) { |
946 | 362 | Out << Prefix; |
947 | 362 | if (ExtendedDescription && !MD->isUserProvided()248 ) { |
948 | 38 | if (MD->isExplicitlyDefaulted()) |
949 | 10 | Out << "defaulted "; |
950 | 28 | else |
951 | 28 | Out << "implicit "; |
952 | 38 | } |
953 | | |
954 | 362 | if (const auto *CD = dyn_cast<CXXConstructorDecl>(MD)) { |
955 | 153 | if (CD->isDefaultConstructor()) |
956 | 28 | Out << "default "; |
957 | 125 | else if (CD->isCopyConstructor()) |
958 | 20 | Out << "copy "; |
959 | 105 | else if (CD->isMoveConstructor()) |
960 | 28 | Out << "move "; |
961 | | |
962 | 153 | Out << "constructor"; |
963 | 153 | describeClass(Out, MD->getParent(), " for "); |
964 | 209 | } 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 | 150 | } else if (MD->isCopyAssignmentOperator()) { |
973 | 14 | Out << "copy assignment operator"; |
974 | 14 | describeClass(Out, MD->getParent(), " for "); |
975 | 136 | } else if (MD->isMoveAssignmentOperator()) { |
976 | 14 | Out << "move assignment operator"; |
977 | 14 | 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 | 362 | return true; |
986 | 362 | } |
987 | | |
988 | 1.24k | Out << Prefix << '\'' << cast<NamedDecl>(*D); |
989 | | |
990 | | // Adding template parameters. |
991 | 1.24k | if (const auto FD = dyn_cast<FunctionDecl>(D)) |
992 | 1.13k | if (const TemplateArgumentList *TAList = |
993 | 44 | FD->getTemplateSpecializationArgs()) |
994 | 44 | describeTemplateParameters(Out, TAList->asArray(), FD->getLangOpts(), "<", |
995 | 44 | ">"); |
996 | | |
997 | 1.24k | Out << '\''; |
998 | 1.24k | return true; |
999 | 1.24k | } |
1000 | | |
1001 | | std::shared_ptr<PathDiagnosticEventPiece> |
1002 | 981 | 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 | 981 | if (!Callee || IsCalleeAnAutosynthesizedPropertyAccessor) |
1008 | 5 | return nullptr; |
1009 | | |
1010 | 976 | SmallString<256> buf; |
1011 | 976 | llvm::raw_svector_ostream Out(buf); |
1012 | | |
1013 | 976 | Out << "Calling "; |
1014 | 976 | describeCodeDecl(Out, Callee, /*ExtendedDescription=*/true); |
1015 | | |
1016 | 976 | assert(callEnter.asLocation().isValid()); |
1017 | 976 | return std::make_shared<PathDiagnosticEventPiece>(callEnter, Out.str()); |
1018 | 976 | } |
1019 | | |
1020 | | std::shared_ptr<PathDiagnosticEventPiece> |
1021 | 296 | PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const { |
1022 | 296 | if (!callEnterWithin.asLocation().isValid()) |
1023 | 0 | return nullptr; |
1024 | 296 | if (Callee->isImplicit() || !Callee->hasBody()286 ) |
1025 | 20 | return nullptr; |
1026 | 276 | if (const auto *MD = dyn_cast<CXXMethodDecl>(Callee)) |
1027 | 48 | if (MD->isDefaulted()) |
1028 | 4 | return nullptr; |
1029 | | |
1030 | 272 | SmallString<256> buf; |
1031 | 272 | llvm::raw_svector_ostream Out(buf); |
1032 | | |
1033 | 272 | Out << "Entered call"; |
1034 | 272 | describeCodeDecl(Out, Caller, /*ExtendedDescription=*/false, " from "); |
1035 | | |
1036 | 272 | return std::make_shared<PathDiagnosticEventPiece>(callEnterWithin, Out.str()); |
1037 | 272 | } |
1038 | | |
1039 | | std::shared_ptr<PathDiagnosticEventPiece> |
1040 | 833 | 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 | 833 | if (NoExit || IsCalleeAnAutosynthesizedPropertyAccessor510 ) |
1046 | 327 | return nullptr; |
1047 | | |
1048 | 506 | SmallString<256> buf; |
1049 | 506 | llvm::raw_svector_ostream Out(buf); |
1050 | | |
1051 | 506 | if (!CallStackMessage.empty()) { |
1052 | 34 | Out << CallStackMessage; |
1053 | 472 | } else { |
1054 | 472 | bool DidDescribe = describeCodeDecl(Out, Callee, |
1055 | 472 | /*ExtendedDescription=*/false, |
1056 | 472 | "Returning from "); |
1057 | 472 | if (!DidDescribe) |
1058 | 34 | Out << "Returning to caller"; |
1059 | 472 | } |
1060 | | |
1061 | 506 | assert(callReturn.asLocation().isValid()); |
1062 | 506 | return std::make_shared<PathDiagnosticEventPiece>(callReturn, Out.str()); |
1063 | 506 | } |
1064 | | |
1065 | 142 | static void compute_path_size(const PathPieces &pieces, unsigned &size) { |
1066 | 192 | for (const auto &I : pieces) { |
1067 | 192 | const PathDiagnosticPiece *piece = I.get(); |
1068 | 192 | if (const auto *cp = dyn_cast<PathDiagnosticCallPiece>(piece)) |
1069 | 12 | compute_path_size(cp->path, size); |
1070 | 180 | else |
1071 | 180 | ++size; |
1072 | 192 | } |
1073 | 142 | } |
1074 | | |
1075 | 130 | unsigned PathDiagnostic::full_size() { |
1076 | 130 | unsigned size = 0; |
1077 | 130 | compute_path_size(path, size); |
1078 | 130 | return size; |
1079 | 130 | } |
1080 | | |
1081 | | //===----------------------------------------------------------------------===// |
1082 | | // FoldingSet profiling methods. |
1083 | | //===----------------------------------------------------------------------===// |
1084 | | |
1085 | 117k | void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const { |
1086 | 117k | ID.Add(Range.getBegin()); |
1087 | 117k | ID.Add(Range.getEnd()); |
1088 | 117k | ID.Add(static_cast<const SourceLocation &>(Loc)); |
1089 | 117k | } |
1090 | | |
1091 | 2.93k | void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const { |
1092 | 2.93k | ID.AddInteger((unsigned) getKind()); |
1093 | 2.93k | ID.AddString(str); |
1094 | | // FIXME: Add profiling support for code hints. |
1095 | 2.93k | ID.AddInteger((unsigned) getDisplayHint()); |
1096 | 2.93k | ArrayRef<SourceRange> Ranges = getRanges(); |
1097 | 2.93k | for (const auto &I : Ranges) { |
1098 | 2.93k | ID.Add(I.getBegin()); |
1099 | 2.93k | ID.Add(I.getEnd()); |
1100 | 2.93k | } |
1101 | 2.93k | } |
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 | 2.93k | void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const { |
1110 | 2.93k | PathDiagnosticPiece::Profile(ID); |
1111 | 2.93k | ID.Add(Pos); |
1112 | 2.93k | } |
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 | 165 | void PathDiagnosticPopUpPiece::Profile(llvm::FoldingSetNodeID &ID) const { |
1131 | 165 | PathDiagnosticSpotPiece::Profile(ID); |
1132 | 165 | } |
1133 | | |
1134 | 56.2k | void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const { |
1135 | 56.2k | ID.Add(getLocation()); |
1136 | 56.2k | ID.Add(getUniqueingLoc()); |
1137 | 56.2k | ID.AddString(BugType); |
1138 | 56.2k | ID.AddString(VerboseDesc); |
1139 | 56.2k | ID.AddString(Category); |
1140 | 56.2k | } |
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 | } |