1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | #include "clang/StaticAnalyzer/Core/BugReporter/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/Stmt.h" |
24 | #include "clang/AST/Type.h" |
25 | #include "clang/Analysis/AnalysisDeclContext.h" |
26 | #include "clang/Analysis/CFG.h" |
27 | #include "clang/Analysis/ProgramPoint.h" |
28 | #include "clang/Basic/FileManager.h" |
29 | #include "clang/Basic/LLVM.h" |
30 | #include "clang/Basic/SourceLocation.h" |
31 | #include "clang/Basic/SourceManager.h" |
32 | #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" |
33 | #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" |
34 | #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" |
35 | #include "llvm/ADT/ArrayRef.h" |
36 | #include "llvm/ADT/FoldingSet.h" |
37 | #include "llvm/ADT/None.h" |
38 | #include "llvm/ADT/Optional.h" |
39 | #include "llvm/ADT/STLExtras.h" |
40 | #include "llvm/ADT/SmallString.h" |
41 | #include "llvm/ADT/SmallVector.h" |
42 | #include "llvm/ADT/StringExtras.h" |
43 | #include "llvm/ADT/StringRef.h" |
44 | #include "llvm/Support/Casting.h" |
45 | #include "llvm/Support/ErrorHandling.h" |
46 | #include "llvm/Support/raw_ostream.h" |
47 | #include <cassert> |
48 | #include <cstring> |
49 | #include <memory> |
50 | #include <utility> |
51 | #include <vector> |
52 | |
53 | using namespace clang; |
54 | using namespace ento; |
55 | |
56 | bool PathDiagnosticMacroPiece::containsEvent() const { |
57 | for (const auto &P : subPieces) { |
58 | if (isa<PathDiagnosticEventPiece>(*P)) |
59 | return true; |
60 | if (const auto *MP = dyn_cast<PathDiagnosticMacroPiece>(P.get())) |
61 | if (MP->containsEvent()) |
62 | return true; |
63 | } |
64 | return false; |
65 | } |
66 | |
67 | static StringRef StripTrailingDots(StringRef s) { |
68 | for (StringRef::size_type i = s.size(); i != 0; --i) |
69 | if (s[i - 1] != '.') |
70 | return s.substr(0, i); |
71 | return {}; |
72 | } |
73 | |
74 | PathDiagnosticPiece::PathDiagnosticPiece(StringRef s, |
75 | Kind k, DisplayHint hint) |
76 | : str(StripTrailingDots(s)), kind(k), Hint(hint) {} |
77 | |
78 | PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint) |
79 | : kind(k), Hint(hint) {} |
80 | |
81 | PathDiagnosticPiece::~PathDiagnosticPiece() = default; |
82 | |
83 | PathDiagnosticEventPiece::~PathDiagnosticEventPiece() = default; |
84 | |
85 | PathDiagnosticCallPiece::~PathDiagnosticCallPiece() = default; |
86 | |
87 | PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() = default; |
88 | |
89 | PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() = default; |
90 | |
91 | PathDiagnosticNotePiece::~PathDiagnosticNotePiece() = default; |
92 | |
93 | void PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current, |
94 | bool ShouldFlattenMacros) const { |
95 | for (auto &Piece : *this) { |
96 | switch (Piece->getKind()) { |
97 | case PathDiagnosticPiece::Call: { |
98 | auto &Call = cast<PathDiagnosticCallPiece>(*Piece); |
99 | if (auto CallEnter = Call.getCallEnterEvent()) |
100 | Current.push_back(std::move(CallEnter)); |
101 | Call.path.flattenTo(Primary, Primary, ShouldFlattenMacros); |
102 | if (auto callExit = Call.getCallExitEvent()) |
103 | Current.push_back(std::move(callExit)); |
104 | break; |
105 | } |
106 | case PathDiagnosticPiece::Macro: { |
107 | auto &Macro = cast<PathDiagnosticMacroPiece>(*Piece); |
108 | if (ShouldFlattenMacros) { |
109 | Macro.subPieces.flattenTo(Primary, Primary, ShouldFlattenMacros); |
110 | } else { |
111 | Current.push_back(Piece); |
112 | PathPieces NewPath; |
113 | Macro.subPieces.flattenTo(Primary, NewPath, ShouldFlattenMacros); |
114 | |
115 | Macro.subPieces = NewPath; |
116 | } |
117 | break; |
118 | } |
119 | case PathDiagnosticPiece::Event: |
120 | case PathDiagnosticPiece::ControlFlow: |
121 | case PathDiagnosticPiece::Note: |
122 | Current.push_back(Piece); |
123 | break; |
124 | } |
125 | } |
126 | } |
127 | |
128 | PathDiagnostic::~PathDiagnostic() = default; |
129 | |
130 | PathDiagnostic::PathDiagnostic( |
131 | StringRef CheckName, const Decl *declWithIssue, StringRef bugtype, |
132 | StringRef verboseDesc, StringRef shortDesc, StringRef category, |
133 | PathDiagnosticLocation LocationToUnique, const Decl *DeclToUnique, |
134 | std::unique_ptr<FilesToLineNumsMap> ExecutedLines) |
135 | : CheckName(CheckName), DeclWithIssue(declWithIssue), |
136 | BugType(StripTrailingDots(bugtype)), |
137 | VerboseDesc(StripTrailingDots(verboseDesc)), |
138 | ShortDesc(StripTrailingDots(shortDesc)), |
139 | Category(StripTrailingDots(category)), UniqueingLoc(LocationToUnique), |
140 | UniqueingDecl(DeclToUnique), ExecutedLines(std::move(ExecutedLines)), |
141 | path(pathImpl) {} |
142 | |
143 | static PathDiagnosticCallPiece * |
144 | (PathDiagnosticCallPiece *CP, |
145 | const SourceManager &SMgr) { |
146 | SourceLocation CallLoc = CP->callEnter.asLocation(); |
147 | |
148 | |
149 | if (CallLoc.isMacroID()) |
150 | return nullptr; |
151 | |
152 | (0) . __assert_fail ("AnalysisManager..isInCodeFile(CallLoc, SMgr) && \"The call piece should not be in a header file.\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp", 153, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(AnalysisManager::isInCodeFile(CallLoc, SMgr) && |
153 | (0) . __assert_fail ("AnalysisManager..isInCodeFile(CallLoc, SMgr) && \"The call piece should not be in a header file.\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp", 153, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true"> "The call piece should not be in a header file."); |
154 | |
155 | |
156 | if (!AnalysisManager::isInCodeFile(CP->callEnterWithin.asLocation(), SMgr)) |
157 | return CP; |
158 | |
159 | const PathPieces &Path = CP->path; |
160 | if (Path.empty()) |
161 | return nullptr; |
162 | |
163 | |
164 | |
165 | if (auto *CPInner = dyn_cast<PathDiagnosticCallPiece>(Path.back().get())) |
166 | return getFirstStackedCallToHeaderFile(CPInner, SMgr); |
167 | |
168 | |
169 | return nullptr; |
170 | } |
171 | |
172 | void PathDiagnostic::resetDiagnosticLocationToMainFile() { |
173 | if (path.empty()) |
174 | return; |
175 | |
176 | PathDiagnosticPiece *LastP = path.back().get(); |
177 | assert(LastP); |
178 | const SourceManager &SMgr = LastP->getLocation().getManager(); |
179 | |
180 | |
181 | |
182 | if (auto *CP = dyn_cast<PathDiagnosticCallPiece>(LastP)) { |
183 | CP = getFirstStackedCallToHeaderFile(CP, SMgr); |
184 | if (CP) { |
185 | |
186 | CP->setAsLastInMainSourceFile(); |
187 | |
188 | |
189 | const auto *ND = dyn_cast<NamedDecl>(CP->getCallee()); |
190 | if (ND) { |
191 | SmallString<200> buf; |
192 | llvm::raw_svector_ostream os(buf); |
193 | os << " (within a call to '" << ND->getDeclName() << "')"; |
194 | appendToDesc(os.str()); |
195 | } |
196 | |
197 | |
198 | DeclWithIssue = CP->getCaller(); |
199 | Loc = CP->getLocation(); |
200 | |
201 | return; |
202 | } |
203 | } |
204 | } |
205 | |
206 | void PathDiagnosticConsumer::anchor() {} |
207 | |
208 | PathDiagnosticConsumer::~PathDiagnosticConsumer() { |
209 | |
210 | for (auto &Diag : Diags) |
211 | delete &Diag; |
212 | } |
213 | |
214 | void PathDiagnosticConsumer::HandlePathDiagnostic( |
215 | std::unique_ptr<PathDiagnostic> D) { |
216 | if (!D || D->path.empty()) |
217 | return; |
218 | |
219 | |
220 | |
221 | |
222 | D->flattenLocations(); |
223 | |
224 | |
225 | |
226 | if (!supportsCrossFileDiagnostics()) { |
227 | |
228 | FileID FID; |
229 | const SourceManager &SMgr = D->path.front()->getLocation().getManager(); |
230 | SmallVector<const PathPieces *, 5> WorkList; |
231 | WorkList.push_back(&D->path); |
232 | SmallString<128> buf; |
233 | llvm::raw_svector_ostream warning(buf); |
234 | warning << "warning: Path diagnostic report is not generated. Current " |
235 | << "output format does not support diagnostics that cross file " |
236 | << "boundaries. Refer to --analyzer-output for valid output " |
237 | << "formats\n"; |
238 | |
239 | while (!WorkList.empty()) { |
240 | const PathPieces &path = *WorkList.pop_back_val(); |
241 | |
242 | for (const auto &I : path) { |
243 | const PathDiagnosticPiece *piece = I.get(); |
244 | FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc(); |
245 | |
246 | if (FID.isInvalid()) { |
247 | FID = SMgr.getFileID(L); |
248 | } else if (SMgr.getFileID(L) != FID) { |
249 | llvm::errs() << warning.str(); |
250 | return; |
251 | } |
252 | |
253 | |
254 | ArrayRef<SourceRange> Ranges = piece->getRanges(); |
255 | for (const auto &I : Ranges) { |
256 | SourceLocation L = SMgr.getExpansionLoc(I.getBegin()); |
257 | if (!L.isFileID() || SMgr.getFileID(L) != FID) { |
258 | llvm::errs() << warning.str(); |
259 | return; |
260 | } |
261 | L = SMgr.getExpansionLoc(I.getEnd()); |
262 | if (!L.isFileID() || SMgr.getFileID(L) != FID) { |
263 | llvm::errs() << warning.str(); |
264 | return; |
265 | } |
266 | } |
267 | |
268 | if (const auto *call = dyn_cast<PathDiagnosticCallPiece>(piece)) |
269 | WorkList.push_back(&call->path); |
270 | else if (const auto *macro = dyn_cast<PathDiagnosticMacroPiece>(piece)) |
271 | WorkList.push_back(¯o->subPieces); |
272 | } |
273 | } |
274 | |
275 | if (FID.isInvalid()) |
276 | return; |
277 | } |
278 | |
279 | |
280 | llvm::FoldingSetNodeID profile; |
281 | D->Profile(profile); |
282 | void *InsertPos = nullptr; |
283 | |
284 | if (PathDiagnostic *orig = Diags.FindNodeOrInsertPos(profile, InsertPos)) { |
285 | |
286 | |
287 | |
288 | |
289 | const unsigned orig_size = orig->full_size(); |
290 | const unsigned new_size = D->full_size(); |
291 | if (orig_size <= new_size) |
292 | return; |
293 | |
294 | assert(orig != D.get()); |
295 | Diags.RemoveNode(orig); |
296 | delete orig; |
297 | } |
298 | |
299 | Diags.InsertNode(D.release()); |
300 | } |
301 | |
302 | static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y); |
303 | |
304 | static Optional<bool> |
305 | compareControlFlow(const PathDiagnosticControlFlowPiece &X, |
306 | const PathDiagnosticControlFlowPiece &Y) { |
307 | FullSourceLoc XSL = X.getStartLocation().asLocation(); |
308 | FullSourceLoc YSL = Y.getStartLocation().asLocation(); |
309 | if (XSL != YSL) |
310 | return XSL.isBeforeInTranslationUnitThan(YSL); |
311 | FullSourceLoc XEL = X.getEndLocation().asLocation(); |
312 | FullSourceLoc YEL = Y.getEndLocation().asLocation(); |
313 | if (XEL != YEL) |
314 | return XEL.isBeforeInTranslationUnitThan(YEL); |
315 | return None; |
316 | } |
317 | |
318 | static Optional<bool> compareMacro(const PathDiagnosticMacroPiece &X, |
319 | const PathDiagnosticMacroPiece &Y) { |
320 | return comparePath(X.subPieces, Y.subPieces); |
321 | } |
322 | |
323 | static Optional<bool> compareCall(const PathDiagnosticCallPiece &X, |
324 | const PathDiagnosticCallPiece &Y) { |
325 | FullSourceLoc X_CEL = X.callEnter.asLocation(); |
326 | FullSourceLoc Y_CEL = Y.callEnter.asLocation(); |
327 | if (X_CEL != Y_CEL) |
328 | return X_CEL.isBeforeInTranslationUnitThan(Y_CEL); |
329 | FullSourceLoc X_CEWL = X.callEnterWithin.asLocation(); |
330 | FullSourceLoc Y_CEWL = Y.callEnterWithin.asLocation(); |
331 | if (X_CEWL != Y_CEWL) |
332 | return X_CEWL.isBeforeInTranslationUnitThan(Y_CEWL); |
333 | FullSourceLoc X_CRL = X.callReturn.asLocation(); |
334 | FullSourceLoc Y_CRL = Y.callReturn.asLocation(); |
335 | if (X_CRL != Y_CRL) |
336 | return X_CRL.isBeforeInTranslationUnitThan(Y_CRL); |
337 | return comparePath(X.path, Y.path); |
338 | } |
339 | |
340 | static Optional<bool> comparePiece(const PathDiagnosticPiece &X, |
341 | const PathDiagnosticPiece &Y) { |
342 | if (X.getKind() != Y.getKind()) |
343 | return X.getKind() < Y.getKind(); |
344 | |
345 | FullSourceLoc XL = X.getLocation().asLocation(); |
346 | FullSourceLoc YL = Y.getLocation().asLocation(); |
347 | if (XL != YL) |
348 | return XL.isBeforeInTranslationUnitThan(YL); |
349 | |
350 | if (X.getString() != Y.getString()) |
351 | return X.getString() < Y.getString(); |
352 | |
353 | if (X.getRanges().size() != Y.getRanges().size()) |
354 | return X.getRanges().size() < Y.getRanges().size(); |
355 | |
356 | const SourceManager &SM = XL.getManager(); |
357 | |
358 | for (unsigned i = 0, n = X.getRanges().size(); i < n; ++i) { |
359 | SourceRange XR = X.getRanges()[i]; |
360 | SourceRange YR = Y.getRanges()[i]; |
361 | if (XR != YR) { |
362 | if (XR.getBegin() != YR.getBegin()) |
363 | return SM.isBeforeInTranslationUnit(XR.getBegin(), YR.getBegin()); |
364 | return SM.isBeforeInTranslationUnit(XR.getEnd(), YR.getEnd()); |
365 | } |
366 | } |
367 | |
368 | switch (X.getKind()) { |
369 | case PathDiagnosticPiece::ControlFlow: |
370 | return compareControlFlow(cast<PathDiagnosticControlFlowPiece>(X), |
371 | cast<PathDiagnosticControlFlowPiece>(Y)); |
372 | case PathDiagnosticPiece::Event: |
373 | case PathDiagnosticPiece::Note: |
374 | return None; |
375 | case PathDiagnosticPiece::Macro: |
376 | return compareMacro(cast<PathDiagnosticMacroPiece>(X), |
377 | cast<PathDiagnosticMacroPiece>(Y)); |
378 | case PathDiagnosticPiece::Call: |
379 | return compareCall(cast<PathDiagnosticCallPiece>(X), |
380 | cast<PathDiagnosticCallPiece>(Y)); |
381 | } |
382 | llvm_unreachable("all cases handled"); |
383 | } |
384 | |
385 | static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y) { |
386 | if (X.size() != Y.size()) |
387 | return X.size() < Y.size(); |
388 | |
389 | PathPieces::const_iterator X_I = X.begin(), X_end = X.end(); |
390 | PathPieces::const_iterator Y_I = Y.begin(), Y_end = Y.end(); |
391 | |
392 | for ( ; X_I != X_end && Y_I != Y_end; ++X_I, ++Y_I) { |
393 | Optional<bool> b = comparePiece(**X_I, **Y_I); |
394 | if (b.hasValue()) |
395 | return b.getValue(); |
396 | } |
397 | |
398 | return None; |
399 | } |
400 | |
401 | static bool compareCrossTUSourceLocs(FullSourceLoc XL, FullSourceLoc YL) { |
402 | std::pair<FileID, unsigned> XOffs = XL.getDecomposedLoc(); |
403 | std::pair<FileID, unsigned> YOffs = YL.getDecomposedLoc(); |
404 | const SourceManager &SM = XL.getManager(); |
405 | std::pair<bool, bool> InSameTU = SM.isInTheSameTranslationUnit(XOffs, YOffs); |
406 | if (InSameTU.first) |
407 | return XL.isBeforeInTranslationUnitThan(YL); |
408 | const FileEntry *XFE = SM.getFileEntryForID(XL.getSpellingLoc().getFileID()); |
409 | const FileEntry *YFE = SM.getFileEntryForID(YL.getSpellingLoc().getFileID()); |
410 | if (!XFE || !YFE) |
411 | return XFE && !YFE; |
412 | int NameCmp = XFE->getName().compare(YFE->getName()); |
413 | if (NameCmp != 0) |
414 | return NameCmp == -1; |
415 | |
416 | return XL.getFileID() < YL.getFileID(); |
417 | } |
418 | |
419 | static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) { |
420 | FullSourceLoc XL = X.getLocation().asLocation(); |
421 | FullSourceLoc YL = Y.getLocation().asLocation(); |
422 | if (XL != YL) |
423 | return compareCrossTUSourceLocs(XL, YL); |
424 | if (X.getBugType() != Y.getBugType()) |
425 | return X.getBugType() < Y.getBugType(); |
426 | if (X.getCategory() != Y.getCategory()) |
427 | return X.getCategory() < Y.getCategory(); |
428 | if (X.getVerboseDescription() != Y.getVerboseDescription()) |
429 | return X.getVerboseDescription() < Y.getVerboseDescription(); |
430 | if (X.getShortDescription() != Y.getShortDescription()) |
431 | return X.getShortDescription() < Y.getShortDescription(); |
432 | if (X.getDeclWithIssue() != Y.getDeclWithIssue()) { |
433 | const Decl *XD = X.getDeclWithIssue(); |
434 | if (!XD) |
435 | return true; |
436 | const Decl *YD = Y.getDeclWithIssue(); |
437 | if (!YD) |
438 | return false; |
439 | SourceLocation XDL = XD->getLocation(); |
440 | SourceLocation YDL = YD->getLocation(); |
441 | if (XDL != YDL) { |
442 | const SourceManager &SM = XL.getManager(); |
443 | return compareCrossTUSourceLocs(FullSourceLoc(XDL, SM), |
444 | FullSourceLoc(YDL, SM)); |
445 | } |
446 | } |
447 | PathDiagnostic::meta_iterator XI = X.meta_begin(), XE = X.meta_end(); |
448 | PathDiagnostic::meta_iterator YI = Y.meta_begin(), YE = Y.meta_end(); |
449 | if (XE - XI != YE - YI) |
450 | return (XE - XI) < (YE - YI); |
451 | for ( ; XI != XE ; ++XI, ++YI) { |
452 | if (*XI != *YI) |
453 | return (*XI) < (*YI); |
454 | } |
455 | Optional<bool> b = comparePath(X.path, Y.path); |
456 | assert(b.hasValue()); |
457 | return b.getValue(); |
458 | } |
459 | |
460 | void PathDiagnosticConsumer::FlushDiagnostics( |
461 | PathDiagnosticConsumer::FilesMade *Files) { |
462 | if (flushed) |
463 | return; |
464 | |
465 | flushed = true; |
466 | |
467 | std::vector<const PathDiagnostic *> BatchDiags; |
468 | for (const auto &D : Diags) |
469 | BatchDiags.push_back(&D); |
470 | |
471 | |
472 | |
473 | int (*Comp)(const PathDiagnostic *const *, const PathDiagnostic *const *) = |
474 | [](const PathDiagnostic *const *X, const PathDiagnostic *const *Y) { |
475 | (0) . __assert_fail ("*X != *Y && \"PathDiagnostics not uniqued!\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp", 475, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(*X != *Y && "PathDiagnostics not uniqued!"); |
476 | if (compare(**X, **Y)) |
477 | return -1; |
478 | (0) . __assert_fail ("compare(**Y, **X) && \"Not a total order!\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp", 478, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(compare(**Y, **X) && "Not a total order!"); |
479 | return 1; |
480 | }; |
481 | array_pod_sort(BatchDiags.begin(), BatchDiags.end(), Comp); |
482 | |
483 | FlushDiagnosticsImpl(BatchDiags, Files); |
484 | |
485 | |
486 | for (const auto D : BatchDiags) |
487 | delete D; |
488 | |
489 | |
490 | Diags.clear(); |
491 | } |
492 | |
493 | PathDiagnosticConsumer::FilesMade::~FilesMade() { |
494 | for (PDFileEntry &Entry : Set) |
495 | Entry.~PDFileEntry(); |
496 | } |
497 | |
498 | void PathDiagnosticConsumer::FilesMade::addDiagnostic(const PathDiagnostic &PD, |
499 | StringRef ConsumerName, |
500 | StringRef FileName) { |
501 | llvm::FoldingSetNodeID NodeID; |
502 | NodeID.Add(PD); |
503 | void *InsertPos; |
504 | PDFileEntry *Entry = Set.FindNodeOrInsertPos(NodeID, InsertPos); |
505 | if (!Entry) { |
506 | Entry = Alloc.Allocate<PDFileEntry>(); |
507 | Entry = new (Entry) PDFileEntry(NodeID); |
508 | Set.InsertNode(Entry, InsertPos); |
509 | } |
510 | |
511 | |
512 | char *FileName_cstr = (char*) Alloc.Allocate(FileName.size(), 1); |
513 | memcpy(FileName_cstr, FileName.data(), FileName.size()); |
514 | |
515 | Entry->files.push_back(std::make_pair(ConsumerName, |
516 | StringRef(FileName_cstr, |
517 | FileName.size()))); |
518 | } |
519 | |
520 | PathDiagnosticConsumer::PDFileEntry::ConsumerFiles * |
521 | PathDiagnosticConsumer::FilesMade::getFiles(const PathDiagnostic &PD) { |
522 | llvm::FoldingSetNodeID NodeID; |
523 | NodeID.Add(PD); |
524 | void *InsertPos; |
525 | PDFileEntry *Entry = Set.FindNodeOrInsertPos(NodeID, InsertPos); |
526 | if (!Entry) |
527 | return nullptr; |
528 | return &Entry->files; |
529 | } |
530 | |
531 | |
532 | |
533 | |
534 | |
535 | static SourceLocation getValidSourceLocation(const Stmt* S, |
536 | LocationOrAnalysisDeclContext LAC, |
537 | bool UseEnd = false) { |
538 | SourceLocation L = UseEnd ? S->getEndLoc() : S->getBeginLoc(); |
539 | (0) . __assert_fail ("!LAC.isNull() && \"A valid LocationContext or AnalysisDeclContext should \" \"be passed to PathDiagnosticLocation upon creation.\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp", 540, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(!LAC.isNull() && "A valid LocationContext or AnalysisDeclContext should " |
540 | (0) . __assert_fail ("!LAC.isNull() && \"A valid LocationContext or AnalysisDeclContext should \" \"be passed to PathDiagnosticLocation upon creation.\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp", 540, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true"> "be passed to PathDiagnosticLocation upon creation."); |
541 | |
542 | |
543 | |
544 | if (!L.isValid()) { |
545 | AnalysisDeclContext *ADC; |
546 | if (LAC.is<const LocationContext*>()) |
547 | ADC = LAC.get<const LocationContext*>()->getAnalysisDeclContext(); |
548 | else |
549 | ADC = LAC.get<AnalysisDeclContext*>(); |
550 | |
551 | ParentMap &PM = ADC->getParentMap(); |
552 | |
553 | const Stmt *Parent = S; |
554 | do { |
555 | Parent = PM.getParent(Parent); |
556 | |
557 | |
558 | |
559 | |
560 | |
561 | if (!Parent) { |
562 | const Stmt *Body = ADC->getBody(); |
563 | if (Body) |
564 | L = Body->getBeginLoc(); |
565 | else |
566 | L = ADC->getDecl()->getEndLoc(); |
567 | break; |
568 | } |
569 | |
570 | L = UseEnd ? Parent->getEndLoc() : Parent->getBeginLoc(); |
571 | } while (!L.isValid()); |
572 | } |
573 | |
574 | |
575 | |
576 | return L; |
577 | } |
578 | |
579 | static PathDiagnosticLocation |
580 | getLocationForCaller(const StackFrameContext *SFC, |
581 | const LocationContext *CallerCtx, |
582 | const SourceManager &SM) { |
583 | const CFGBlock &Block = *SFC->getCallSiteBlock(); |
584 | CFGElement Source = Block[SFC->getIndex()]; |
585 | |
586 | switch (Source.getKind()) { |
587 | case CFGElement::Statement: |
588 | case CFGElement::Constructor: |
589 | case CFGElement::CXXRecordTypedCall: |
590 | return PathDiagnosticLocation(Source.castAs<CFGStmt>().getStmt(), |
591 | SM, CallerCtx); |
592 | case CFGElement::Initializer: { |
593 | const CFGInitializer &Init = Source.castAs<CFGInitializer>(); |
594 | return PathDiagnosticLocation(Init.getInitializer()->getInit(), |
595 | SM, CallerCtx); |
596 | } |
597 | case CFGElement::AutomaticObjectDtor: { |
598 | const CFGAutomaticObjDtor &Dtor = Source.castAs<CFGAutomaticObjDtor>(); |
599 | return PathDiagnosticLocation::createEnd(Dtor.getTriggerStmt(), |
600 | SM, CallerCtx); |
601 | } |
602 | case CFGElement::DeleteDtor: { |
603 | const CFGDeleteDtor &Dtor = Source.castAs<CFGDeleteDtor>(); |
604 | return PathDiagnosticLocation(Dtor.getDeleteExpr(), SM, CallerCtx); |
605 | } |
606 | case CFGElement::BaseDtor: |
607 | case CFGElement::MemberDtor: { |
608 | const AnalysisDeclContext *CallerInfo = CallerCtx->getAnalysisDeclContext(); |
609 | if (const Stmt *CallerBody = CallerInfo->getBody()) |
610 | return PathDiagnosticLocation::createEnd(CallerBody, SM, CallerCtx); |
611 | return PathDiagnosticLocation::create(CallerInfo->getDecl(), SM); |
612 | } |
613 | case CFGElement::NewAllocator: { |
614 | const CFGNewAllocator &Alloc = Source.castAs<CFGNewAllocator>(); |
615 | return PathDiagnosticLocation(Alloc.getAllocatorExpr(), SM, CallerCtx); |
616 | } |
617 | case CFGElement::TemporaryDtor: { |
618 | |
619 | |
620 | |
621 | const auto &Dtor = Source.castAs<CFGTemporaryDtor>(); |
622 | return PathDiagnosticLocation::createEnd(Dtor.getBindTemporaryExpr(), SM, |
623 | CallerCtx); |
624 | } |
625 | case CFGElement::ScopeBegin: |
626 | case CFGElement::ScopeEnd: |
627 | llvm_unreachable("not yet implemented!"); |
628 | case CFGElement::LifetimeEnds: |
629 | case CFGElement::LoopExit: |
630 | llvm_unreachable("CFGElement kind should not be on callsite!"); |
631 | } |
632 | |
633 | llvm_unreachable("Unknown CFGElement kind"); |
634 | } |
635 | |
636 | PathDiagnosticLocation |
637 | PathDiagnosticLocation::createBegin(const Decl *D, |
638 | const SourceManager &SM) { |
639 | return PathDiagnosticLocation(D->getBeginLoc(), SM, SingleLocK); |
640 | } |
641 | |
642 | PathDiagnosticLocation |
643 | PathDiagnosticLocation::createBegin(const Stmt *S, |
644 | const SourceManager &SM, |
645 | LocationOrAnalysisDeclContext LAC) { |
646 | return PathDiagnosticLocation(getValidSourceLocation(S, LAC), |
647 | SM, SingleLocK); |
648 | } |
649 | |
650 | PathDiagnosticLocation |
651 | PathDiagnosticLocation::createEnd(const Stmt *S, |
652 | const SourceManager &SM, |
653 | LocationOrAnalysisDeclContext LAC) { |
654 | if (const auto *CS = dyn_cast<CompoundStmt>(S)) |
655 | return createEndBrace(CS, SM); |
656 | return PathDiagnosticLocation(getValidSourceLocation(S, LAC, ), |
657 | SM, SingleLocK); |
658 | } |
659 | |
660 | PathDiagnosticLocation |
661 | PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO, |
662 | const SourceManager &SM) { |
663 | return PathDiagnosticLocation(BO->getOperatorLoc(), SM, SingleLocK); |
664 | } |
665 | |
666 | PathDiagnosticLocation |
667 | PathDiagnosticLocation::createConditionalColonLoc( |
668 | const ConditionalOperator *CO, |
669 | const SourceManager &SM) { |
670 | return PathDiagnosticLocation(CO->getColonLoc(), SM, SingleLocK); |
671 | } |
672 | |
673 | PathDiagnosticLocation |
674 | PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME, |
675 | const SourceManager &SM) { |
676 | |
677 | getMemberLoc().isValid() || ME->getBeginLoc().isValid()", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp", 677, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(ME->getMemberLoc().isValid() || ME->getBeginLoc().isValid()); |
678 | |
679 | |
680 | |
681 | if (ME->getMemberLoc().isValid()) |
682 | return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK); |
683 | |
684 | return PathDiagnosticLocation(ME->getBeginLoc(), SM, SingleLocK); |
685 | } |
686 | |
687 | PathDiagnosticLocation |
688 | PathDiagnosticLocation::createBeginBrace(const CompoundStmt *CS, |
689 | const SourceManager &SM) { |
690 | SourceLocation L = CS->getLBracLoc(); |
691 | return PathDiagnosticLocation(L, SM, SingleLocK); |
692 | } |
693 | |
694 | PathDiagnosticLocation |
695 | PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS, |
696 | const SourceManager &SM) { |
697 | SourceLocation L = CS->getRBracLoc(); |
698 | return PathDiagnosticLocation(L, SM, SingleLocK); |
699 | } |
700 | |
701 | PathDiagnosticLocation |
702 | PathDiagnosticLocation::createDeclBegin(const LocationContext *LC, |
703 | const SourceManager &SM) { |
704 | |
705 | if (const auto *CS = dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody())) |
706 | if (!CS->body_empty()) { |
707 | SourceLocation Loc = (*CS->body_begin())->getBeginLoc(); |
708 | return PathDiagnosticLocation(Loc, SM, SingleLocK); |
709 | } |
710 | |
711 | return PathDiagnosticLocation(); |
712 | } |
713 | |
714 | PathDiagnosticLocation |
715 | PathDiagnosticLocation::createDeclEnd(const LocationContext *LC, |
716 | const SourceManager &SM) { |
717 | SourceLocation L = LC->getDecl()->getBodyRBrace(); |
718 | return PathDiagnosticLocation(L, SM, SingleLocK); |
719 | } |
720 | |
721 | PathDiagnosticLocation |
722 | PathDiagnosticLocation::create(const ProgramPoint& P, |
723 | const SourceManager &SMng) { |
724 | const Stmt* S = nullptr; |
725 | if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) { |
726 | const CFGBlock *BSrc = BE->getSrc(); |
727 | S = BSrc->getTerminatorCondition(); |
728 | } else if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) { |
729 | S = SP->getStmt(); |
730 | if (P.getAs<PostStmtPurgeDeadSymbols>()) |
731 | return PathDiagnosticLocation::createEnd(S, SMng, P.getLocationContext()); |
732 | } else if (Optional<PostInitializer> PIP = P.getAs<PostInitializer>()) { |
733 | return PathDiagnosticLocation(PIP->getInitializer()->getSourceLocation(), |
734 | SMng); |
735 | } else if (Optional<PreImplicitCall> PIC = P.getAs<PreImplicitCall>()) { |
736 | return PathDiagnosticLocation(PIC->getLocation(), SMng); |
737 | } else if (Optional<PostImplicitCall> PIE = P.getAs<PostImplicitCall>()) { |
738 | return PathDiagnosticLocation(PIE->getLocation(), SMng); |
739 | } else if (Optional<CallEnter> CE = P.getAs<CallEnter>()) { |
740 | return getLocationForCaller(CE->getCalleeContext(), |
741 | CE->getLocationContext(), |
742 | SMng); |
743 | } else if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) { |
744 | return getLocationForCaller(CEE->getCalleeContext(), |
745 | CEE->getLocationContext(), |
746 | SMng); |
747 | } else if (auto CEB = P.getAs<CallExitBegin>()) { |
748 | if (const ReturnStmt *RS = CEB->getReturnStmt()) |
749 | return PathDiagnosticLocation::createBegin(RS, SMng, |
750 | CEB->getLocationContext()); |
751 | return PathDiagnosticLocation( |
752 | CEB->getLocationContext()->getDecl()->getSourceRange().getEnd(), SMng); |
753 | } else if (Optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) { |
754 | CFGElement BlockFront = BE->getBlock()->front(); |
755 | if (auto StmtElt = BlockFront.getAs<CFGStmt>()) { |
756 | return PathDiagnosticLocation(StmtElt->getStmt()->getBeginLoc(), SMng); |
757 | } else if (auto NewAllocElt = BlockFront.getAs<CFGNewAllocator>()) { |
758 | return PathDiagnosticLocation( |
759 | NewAllocElt->getAllocatorExpr()->getBeginLoc(), SMng); |
760 | } |
761 | llvm_unreachable("Unexpected CFG element at front of block"); |
762 | } else { |
763 | llvm_unreachable("Unexpected ProgramPoint"); |
764 | } |
765 | |
766 | return PathDiagnosticLocation(S, SMng, P.getLocationContext()); |
767 | } |
768 | |
769 | static const LocationContext * |
770 | findTopAutosynthesizedParentContext(const LocationContext *LC) { |
771 | getAnalysisDeclContext()->isBodyAutosynthesized()", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp", 771, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(LC->getAnalysisDeclContext()->isBodyAutosynthesized()); |
772 | const LocationContext *ParentLC = LC->getParent(); |
773 | (0) . __assert_fail ("ParentLC && \"We don't start analysis from autosynthesized code\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp", 773, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(ParentLC && "We don't start analysis from autosynthesized code"); |
774 | while (ParentLC->getAnalysisDeclContext()->isBodyAutosynthesized()) { |
775 | LC = ParentLC; |
776 | ParentLC = LC->getParent(); |
777 | (0) . __assert_fail ("ParentLC && \"We don't start analysis from autosynthesized code\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp", 777, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(ParentLC && "We don't start analysis from autosynthesized code"); |
778 | } |
779 | return LC; |
780 | } |
781 | |
782 | const Stmt *PathDiagnosticLocation::getStmt(const ExplodedNode *N) { |
783 | |
784 | |
785 | |
786 | const LocationContext *LC = N->getLocationContext(); |
787 | if (LC->getAnalysisDeclContext()->isBodyAutosynthesized()) { |
788 | |
789 | return cast<StackFrameContext>(findTopAutosynthesizedParentContext(LC)) |
790 | ->getCallSite(); |
791 | } |
792 | |
793 | ProgramPoint P = N->getLocation(); |
794 | if (auto SP = P.getAs<StmtPoint>()) |
795 | return SP->getStmt(); |
796 | if (auto BE = P.getAs<BlockEdge>()) |
797 | return BE->getSrc()->getTerminator(); |
798 | if (auto CE = P.getAs<CallEnter>()) |
799 | return CE->getCallExpr(); |
800 | if (auto CEE = P.getAs<CallExitEnd>()) |
801 | return CEE->getCalleeContext()->getCallSite(); |
802 | if (auto PIPP = P.getAs<PostInitializer>()) |
803 | return PIPP->getInitializer()->getInit(); |
804 | if (auto CEB = P.getAs<CallExitBegin>()) |
805 | return CEB->getReturnStmt(); |
806 | if (auto FEP = P.getAs<FunctionExitPoint>()) |
807 | return FEP->getStmt(); |
808 | |
809 | return nullptr; |
810 | } |
811 | |
812 | const Stmt *PathDiagnosticLocation::getNextStmt(const ExplodedNode *N) { |
813 | for (N = N->getFirstSucc(); N; N = N->getFirstSucc()) { |
814 | if (const Stmt *S = getStmt(N)) { |
815 | |
816 | |
817 | switch (S->getStmtClass()) { |
818 | case Stmt::ChooseExprClass: |
819 | case Stmt::BinaryConditionalOperatorClass: |
820 | case Stmt::ConditionalOperatorClass: |
821 | continue; |
822 | case Stmt::BinaryOperatorClass: { |
823 | BinaryOperatorKind Op = cast<BinaryOperator>(S)->getOpcode(); |
824 | if (Op == BO_LAnd || Op == BO_LOr) |
825 | continue; |
826 | break; |
827 | } |
828 | default: |
829 | break; |
830 | } |
831 | |
832 | return S; |
833 | } |
834 | } |
835 | |
836 | return nullptr; |
837 | } |
838 | |
839 | PathDiagnosticLocation |
840 | PathDiagnosticLocation::createEndOfPath(const ExplodedNode *N, |
841 | const SourceManager &SM) { |
842 | (0) . __assert_fail ("N && \"Cannot create a location with a null node.\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp", 842, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(N && "Cannot create a location with a null node."); |
843 | const Stmt *S = getStmt(N); |
844 | const LocationContext *LC = N->getLocationContext(); |
845 | |
846 | if (!S) { |
847 | |
848 | if (Optional<PreImplicitCall> PIE = N->getLocationAs<PreImplicitCall>()) |
849 | return PathDiagnosticLocation(PIE->getLocation(), SM); |
850 | if (auto FE = N->getLocationAs<FunctionExitPoint>()) { |
851 | if (const ReturnStmt *RS = FE->getStmt()) |
852 | return PathDiagnosticLocation::createBegin(RS, SM, LC); |
853 | } |
854 | S = getNextStmt(N); |
855 | } |
856 | |
857 | if (S) { |
858 | ProgramPoint P = N->getLocation(); |
859 | |
860 | |
861 | if (const auto *ME = dyn_cast<MemberExpr>(S)) |
862 | return PathDiagnosticLocation::createMemberLoc(ME, SM); |
863 | |
864 | |
865 | if (const auto *B = dyn_cast<BinaryOperator>(S)) |
866 | return PathDiagnosticLocation::createOperatorLoc(B, SM); |
867 | |
868 | if (P.getAs<PostStmtPurgeDeadSymbols>()) |
869 | return PathDiagnosticLocation::createEnd(S, SM, LC); |
870 | |
871 | if (S->getBeginLoc().isValid()) |
872 | return PathDiagnosticLocation(S, SM, LC); |
873 | return PathDiagnosticLocation(getValidSourceLocation(S, LC), SM); |
874 | } |
875 | |
876 | return createDeclEnd(N->getLocationContext(), SM); |
877 | } |
878 | |
879 | PathDiagnosticLocation PathDiagnosticLocation::createSingleLocation( |
880 | const PathDiagnosticLocation &PDL) { |
881 | FullSourceLoc L = PDL.asLocation(); |
882 | return PathDiagnosticLocation(L, L.getManager(), SingleLocK); |
883 | } |
884 | |
885 | FullSourceLoc |
886 | PathDiagnosticLocation::genLocation(SourceLocation L, |
887 | LocationOrAnalysisDeclContext LAC) const { |
888 | assert(isValid()); |
889 | |
890 | |
891 | switch (K) { |
892 | case SingleLocK: |
893 | case RangeK: |
894 | break; |
895 | case StmtK: |
896 | |
897 | if (!S) |
898 | break; |
899 | return FullSourceLoc(getValidSourceLocation(S, LAC), |
900 | const_cast<SourceManager&>(*SM)); |
901 | case DeclK: |
902 | |
903 | if (!D) |
904 | break; |
905 | return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM)); |
906 | } |
907 | |
908 | return FullSourceLoc(L, const_cast<SourceManager&>(*SM)); |
909 | } |
910 | |
911 | PathDiagnosticRange |
912 | PathDiagnosticLocation::genRange(LocationOrAnalysisDeclContext LAC) const { |
913 | assert(isValid()); |
914 | |
915 | |
916 | switch (K) { |
917 | case SingleLocK: |
918 | return PathDiagnosticRange(SourceRange(Loc,Loc), true); |
919 | case RangeK: |
920 | break; |
921 | case StmtK: { |
922 | const Stmt *S = asStmt(); |
923 | switch (S->getStmtClass()) { |
924 | default: |
925 | break; |
926 | case Stmt::DeclStmtClass: { |
927 | const auto *DS = cast<DeclStmt>(S); |
928 | if (DS->isSingleDecl()) { |
929 | |
930 | return SourceRange(DS->getBeginLoc(), |
931 | DS->getSingleDecl()->getLocation()); |
932 | } |
933 | break; |
934 | } |
935 | |
936 | |
937 | case Stmt::IfStmtClass: |
938 | case Stmt::WhileStmtClass: |
939 | case Stmt::DoStmtClass: |
940 | case Stmt::ForStmtClass: |
941 | case Stmt::ChooseExprClass: |
942 | case Stmt::IndirectGotoStmtClass: |
943 | case Stmt::SwitchStmtClass: |
944 | case Stmt::BinaryConditionalOperatorClass: |
945 | case Stmt::ConditionalOperatorClass: |
946 | case Stmt::ObjCForCollectionStmtClass: { |
947 | SourceLocation L = getValidSourceLocation(S, LAC); |
948 | return SourceRange(L, L); |
949 | } |
950 | } |
951 | SourceRange R = S->getSourceRange(); |
952 | if (R.isValid()) |
953 | return R; |
954 | break; |
955 | } |
956 | case DeclK: |
957 | if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) |
958 | return MD->getSourceRange(); |
959 | if (const auto *FD = dyn_cast<FunctionDecl>(D)) { |
960 | if (Stmt *Body = FD->getBody()) |
961 | return Body->getSourceRange(); |
962 | } |
963 | else { |
964 | SourceLocation L = D->getLocation(); |
965 | return PathDiagnosticRange(SourceRange(L, L), true); |
966 | } |
967 | } |
968 | |
969 | return SourceRange(Loc, Loc); |
970 | } |
971 | |
972 | void PathDiagnosticLocation::flatten() { |
973 | if (K == StmtK) { |
974 | K = RangeK; |
975 | S = nullptr; |
976 | D = nullptr; |
977 | } |
978 | else if (K == DeclK) { |
979 | K = SingleLocK; |
980 | S = nullptr; |
981 | D = nullptr; |
982 | } |
983 | } |
984 | |
985 | |
986 | |
987 | |
988 | |
989 | std::shared_ptr<PathDiagnosticCallPiece> |
990 | PathDiagnosticCallPiece::construct(const CallExitEnd &CE, |
991 | const SourceManager &SM) { |
992 | const Decl *caller = CE.getLocationContext()->getDecl(); |
993 | PathDiagnosticLocation pos = getLocationForCaller(CE.getCalleeContext(), |
994 | CE.getLocationContext(), |
995 | SM); |
996 | return std::shared_ptr<PathDiagnosticCallPiece>( |
997 | new PathDiagnosticCallPiece(caller, pos)); |
998 | } |
999 | |
1000 | PathDiagnosticCallPiece * |
1001 | PathDiagnosticCallPiece::construct(PathPieces &path, |
1002 | const Decl *caller) { |
1003 | std::shared_ptr<PathDiagnosticCallPiece> C( |
1004 | new PathDiagnosticCallPiece(path, caller)); |
1005 | path.clear(); |
1006 | auto *R = C.get(); |
1007 | path.push_front(std::move(C)); |
1008 | return R; |
1009 | } |
1010 | |
1011 | void PathDiagnosticCallPiece::setCallee(const CallEnter &CE, |
1012 | const SourceManager &SM) { |
1013 | const StackFrameContext *CalleeCtx = CE.getCalleeContext(); |
1014 | Callee = CalleeCtx->getDecl(); |
1015 | |
1016 | callEnterWithin = PathDiagnosticLocation::createBegin(Callee, SM); |
1017 | callEnter = getLocationForCaller(CalleeCtx, CE.getLocationContext(), SM); |
1018 | |
1019 | |
1020 | |
1021 | |
1022 | |
1023 | |
1024 | |
1025 | if (const auto *MD = dyn_cast<ObjCMethodDecl>(Callee)) |
1026 | IsCalleeAnAutosynthesizedPropertyAccessor = ( |
1027 | MD->isPropertyAccessor() && |
1028 | CalleeCtx->getAnalysisDeclContext()->isBodyAutosynthesized()); |
1029 | } |
1030 | |
1031 | static void describeTemplateParameters(raw_ostream &Out, |
1032 | const ArrayRef<TemplateArgument> TAList, |
1033 | const LangOptions &LO, |
1034 | StringRef Prefix = StringRef(), |
1035 | StringRef Postfix = StringRef()); |
1036 | |
1037 | static void describeTemplateParameter(raw_ostream &Out, |
1038 | const TemplateArgument &TArg, |
1039 | const LangOptions &LO) { |
1040 | |
1041 | if (TArg.getKind() == TemplateArgument::ArgKind::Pack) { |
1042 | describeTemplateParameters(Out, TArg.getPackAsArray(), LO); |
1043 | } else { |
1044 | TArg.print(PrintingPolicy(LO), Out); |
1045 | } |
1046 | } |
1047 | |
1048 | static void describeTemplateParameters(raw_ostream &Out, |
1049 | const ArrayRef<TemplateArgument> TAList, |
1050 | const LangOptions &LO, |
1051 | StringRef Prefix, StringRef Postfix) { |
1052 | if (TAList.empty()) |
1053 | return; |
1054 | |
1055 | Out << Prefix; |
1056 | for (int I = 0, Last = TAList.size() - 1; I != Last; ++I) { |
1057 | describeTemplateParameter(Out, TAList[I], LO); |
1058 | Out << ", "; |
1059 | } |
1060 | describeTemplateParameter(Out, TAList[TAList.size() - 1], LO); |
1061 | Out << Postfix; |
1062 | } |
1063 | |
1064 | static void describeClass(raw_ostream &Out, const CXXRecordDecl *D, |
1065 | StringRef Prefix = StringRef()) { |
1066 | if (!D->getIdentifier()) |
1067 | return; |
1068 | Out << Prefix << '\'' << *D; |
1069 | if (const auto T = dyn_cast<ClassTemplateSpecializationDecl>(D)) |
1070 | describeTemplateParameters(Out, T->getTemplateArgs().asArray(), |
1071 | D->getASTContext().getLangOpts(), "<", ">"); |
1072 | |
1073 | Out << '\''; |
1074 | } |
1075 | |
1076 | static bool describeCodeDecl(raw_ostream &Out, const Decl *D, |
1077 | bool ExtendedDescription, |
1078 | StringRef Prefix = StringRef()) { |
1079 | if (!D) |
1080 | return false; |
1081 | |
1082 | if (isa<BlockDecl>(D)) { |
1083 | if (ExtendedDescription) |
1084 | Out << Prefix << "anonymous block"; |
1085 | return ExtendedDescription; |
1086 | } |
1087 | |
1088 | if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) { |
1089 | Out << Prefix; |
1090 | if (ExtendedDescription && !MD->isUserProvided()) { |
1091 | if (MD->isExplicitlyDefaulted()) |
1092 | Out << "defaulted "; |
1093 | else |
1094 | Out << "implicit "; |
1095 | } |
1096 | |
1097 | if (const auto *CD = dyn_cast<CXXConstructorDecl>(MD)) { |
1098 | if (CD->isDefaultConstructor()) |
1099 | Out << "default "; |
1100 | else if (CD->isCopyConstructor()) |
1101 | Out << "copy "; |
1102 | else if (CD->isMoveConstructor()) |
1103 | Out << "move "; |
1104 | |
1105 | Out << "constructor"; |
1106 | describeClass(Out, MD->getParent(), " for "); |
1107 | } else if (isa<CXXDestructorDecl>(MD)) { |
1108 | if (!MD->isUserProvided()) { |
1109 | Out << "destructor"; |
1110 | describeClass(Out, MD->getParent(), " for "); |
1111 | } else { |
1112 | |
1113 | Out << "'" << *MD << "'"; |
1114 | } |
1115 | } else if (MD->isCopyAssignmentOperator()) { |
1116 | Out << "copy assignment operator"; |
1117 | describeClass(Out, MD->getParent(), " for "); |
1118 | } else if (MD->isMoveAssignmentOperator()) { |
1119 | Out << "move assignment operator"; |
1120 | describeClass(Out, MD->getParent(), " for "); |
1121 | } else { |
1122 | if (MD->getParent()->getIdentifier()) |
1123 | Out << "'" << *MD->getParent() << "::" << *MD << "'"; |
1124 | else |
1125 | Out << "'" << *MD << "'"; |
1126 | } |
1127 | |
1128 | return true; |
1129 | } |
1130 | |
1131 | Out << Prefix << '\'' << cast<NamedDecl>(*D); |
1132 | |
1133 | |
1134 | if (const auto FD = dyn_cast<FunctionDecl>(D)) |
1135 | if (const TemplateArgumentList *TAList = |
1136 | FD->getTemplateSpecializationArgs()) |
1137 | describeTemplateParameters(Out, TAList->asArray(), |
1138 | FD->getASTContext().getLangOpts(), "<", ">"); |
1139 | |
1140 | Out << '\''; |
1141 | return true; |
1142 | } |
1143 | |
1144 | std::shared_ptr<PathDiagnosticEventPiece> |
1145 | PathDiagnosticCallPiece::getCallEnterEvent() const { |
1146 | |
1147 | |
1148 | |
1149 | |
1150 | if (!Callee || IsCalleeAnAutosynthesizedPropertyAccessor) |
1151 | return nullptr; |
1152 | |
1153 | SmallString<256> buf; |
1154 | llvm::raw_svector_ostream Out(buf); |
1155 | |
1156 | Out << "Calling "; |
1157 | describeCodeDecl(Out, Callee, ); |
1158 | |
1159 | assert(callEnter.asLocation().isValid()); |
1160 | return std::make_shared<PathDiagnosticEventPiece>(callEnter, Out.str()); |
1161 | } |
1162 | |
1163 | std::shared_ptr<PathDiagnosticEventPiece> |
1164 | PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const { |
1165 | if (!callEnterWithin.asLocation().isValid()) |
1166 | return nullptr; |
1167 | if (Callee->isImplicit() || !Callee->hasBody()) |
1168 | return nullptr; |
1169 | if (const auto *MD = dyn_cast<CXXMethodDecl>(Callee)) |
1170 | if (MD->isDefaulted()) |
1171 | return nullptr; |
1172 | |
1173 | SmallString<256> buf; |
1174 | llvm::raw_svector_ostream Out(buf); |
1175 | |
1176 | Out << "Entered call"; |
1177 | describeCodeDecl(Out, Caller, , " from "); |
1178 | |
1179 | return std::make_shared<PathDiagnosticEventPiece>(callEnterWithin, Out.str()); |
1180 | } |
1181 | |
1182 | std::shared_ptr<PathDiagnosticEventPiece> |
1183 | PathDiagnosticCallPiece::getCallExitEvent() const { |
1184 | |
1185 | |
1186 | |
1187 | |
1188 | if (NoExit || IsCalleeAnAutosynthesizedPropertyAccessor) |
1189 | return nullptr; |
1190 | |
1191 | SmallString<256> buf; |
1192 | llvm::raw_svector_ostream Out(buf); |
1193 | |
1194 | if (!CallStackMessage.empty()) { |
1195 | Out << CallStackMessage; |
1196 | } else { |
1197 | bool DidDescribe = describeCodeDecl(Out, Callee, |
1198 | , |
1199 | "Returning from "); |
1200 | if (!DidDescribe) |
1201 | Out << "Returning to caller"; |
1202 | } |
1203 | |
1204 | assert(callReturn.asLocation().isValid()); |
1205 | return std::make_shared<PathDiagnosticEventPiece>(callReturn, Out.str()); |
1206 | } |
1207 | |
1208 | static void compute_path_size(const PathPieces &pieces, unsigned &size) { |
1209 | for (const auto &I : pieces) { |
1210 | const PathDiagnosticPiece *piece = I.get(); |
1211 | if (const auto *cp = dyn_cast<PathDiagnosticCallPiece>(piece)) |
1212 | compute_path_size(cp->path, size); |
1213 | else |
1214 | ++size; |
1215 | } |
1216 | } |
1217 | |
1218 | unsigned PathDiagnostic::full_size() { |
1219 | unsigned size = 0; |
1220 | compute_path_size(path, size); |
1221 | return size; |
1222 | } |
1223 | |
1224 | |
1225 | |
1226 | |
1227 | |
1228 | void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const { |
1229 | ID.AddInteger(Range.getBegin().getRawEncoding()); |
1230 | ID.AddInteger(Range.getEnd().getRawEncoding()); |
1231 | ID.AddInteger(Loc.getRawEncoding()); |
1232 | } |
1233 | |
1234 | void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const { |
1235 | ID.AddInteger((unsigned) getKind()); |
1236 | ID.AddString(str); |
1237 | |
1238 | ID.AddInteger((unsigned) getDisplayHint()); |
1239 | ArrayRef<SourceRange> Ranges = getRanges(); |
1240 | for (const auto &I : Ranges) { |
1241 | ID.AddInteger(I.getBegin().getRawEncoding()); |
1242 | ID.AddInteger(I.getEnd().getRawEncoding()); |
1243 | } |
1244 | } |
1245 | |
1246 | void PathDiagnosticCallPiece::Profile(llvm::FoldingSetNodeID &ID) const { |
1247 | PathDiagnosticPiece::Profile(ID); |
1248 | for (const auto &I : path) |
1249 | ID.Add(*I); |
1250 | } |
1251 | |
1252 | void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const { |
1253 | PathDiagnosticPiece::Profile(ID); |
1254 | ID.Add(Pos); |
1255 | } |
1256 | |
1257 | void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const { |
1258 | PathDiagnosticPiece::Profile(ID); |
1259 | for (const auto &I : *this) |
1260 | ID.Add(I); |
1261 | } |
1262 | |
1263 | void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const { |
1264 | PathDiagnosticSpotPiece::Profile(ID); |
1265 | for (const auto &I : subPieces) |
1266 | ID.Add(*I); |
1267 | } |
1268 | |
1269 | void PathDiagnosticNotePiece::Profile(llvm::FoldingSetNodeID &ID) const { |
1270 | PathDiagnosticSpotPiece::Profile(ID); |
1271 | } |
1272 | |
1273 | void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const { |
1274 | ID.Add(getLocation()); |
1275 | ID.AddString(BugType); |
1276 | ID.AddString(VerboseDesc); |
1277 | ID.AddString(Category); |
1278 | } |
1279 | |
1280 | void PathDiagnostic::FullProfile(llvm::FoldingSetNodeID &ID) const { |
1281 | Profile(ID); |
1282 | for (const auto &I : path) |
1283 | ID.Add(*I); |
1284 | for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I) |
1285 | ID.AddString(*I); |
1286 | } |
1287 | |
1288 | StackHintGenerator::~StackHintGenerator() = default; |
1289 | |
1290 | std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){ |
1291 | if (!N) |
1292 | return getMessageForSymbolNotFound(); |
1293 | |
1294 | ProgramPoint P = N->getLocation(); |
1295 | CallExitEnd CExit = P.castAs<CallExitEnd>(); |
1296 | |
1297 | |
1298 | const Stmt *CallSite = CExit.getCalleeContext()->getCallSite(); |
1299 | const auto *CE = dyn_cast_or_null<CallExpr>(CallSite); |
1300 | if (!CE) |
1301 | return {}; |
1302 | |
1303 | |
1304 | unsigned ArgIndex = 0; |
1305 | for (CallExpr::const_arg_iterator I = CE->arg_begin(), |
1306 | E = CE->arg_end(); I != E; ++I, ++ArgIndex){ |
1307 | SVal SV = N->getSVal(*I); |
1308 | |
1309 | |
1310 | SymbolRef AS = SV.getAsLocSymbol(); |
1311 | if (AS == Sym) { |
1312 | return getMessageForArg(*I, ArgIndex); |
1313 | } |
1314 | |
1315 | |
1316 | if (Optional<loc::MemRegionVal> Reg = SV.getAs<loc::MemRegionVal>()) { |
1317 | |
1318 | if ((*I)->getType()->isVoidPointerType()) |
1319 | continue; |
1320 | SVal PSV = N->getState()->getSVal(Reg->getRegion()); |
1321 | SymbolRef AS = PSV.getAsLocSymbol(); |
1322 | if (AS == Sym) { |
1323 | return getMessageForArg(*I, ArgIndex); |
1324 | } |
1325 | } |
1326 | } |
1327 | |
1328 | |
1329 | SVal SV = N->getSVal(CE); |
1330 | SymbolRef RetSym = SV.getAsLocSymbol(); |
1331 | if (RetSym == Sym) { |
1332 | return getMessageForReturn(CE); |
1333 | } |
1334 | |
1335 | return getMessageForSymbolNotFound(); |
1336 | } |
1337 | |
1338 | std::string StackHintGeneratorForSymbol::getMessageForArg(const Expr *ArgE, |
1339 | unsigned ArgIndex) { |
1340 | |
1341 | ++ArgIndex; |
1342 | |
1343 | SmallString<200> buf; |
1344 | llvm::raw_svector_ostream os(buf); |
1345 | |
1346 | os << Msg << " via " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex) |
1347 | << " parameter"; |
1348 | |
1349 | return os.str(); |
1350 | } |
1351 | |
1352 | LLVM_DUMP_METHOD void PathPieces::dump() const { |
1353 | unsigned index = 0; |
1354 | for (PathPieces::const_iterator I = begin(), E = end(); I != E; ++I) { |
1355 | llvm::errs() << "[" << index++ << "] "; |
1356 | (*I)->dump(); |
1357 | llvm::errs() << "\n"; |
1358 | } |
1359 | } |
1360 | |
1361 | LLVM_DUMP_METHOD void PathDiagnosticCallPiece::dump() const { |
1362 | llvm::errs() << "CALL\n--------------\n"; |
1363 | |
1364 | if (const Stmt *SLoc = getLocation().getStmtOrNull()) |
1365 | SLoc->dump(); |
1366 | else if (const auto *ND = dyn_cast_or_null<NamedDecl>(getCallee())) |
1367 | llvm::errs() << *ND << "\n"; |
1368 | else |
1369 | getLocation().dump(); |
1370 | } |
1371 | |
1372 | LLVM_DUMP_METHOD void PathDiagnosticEventPiece::dump() const { |
1373 | llvm::errs() << "EVENT\n--------------\n"; |
1374 | llvm::errs() << getString() << "\n"; |
1375 | llvm::errs() << " ---- at ----\n"; |
1376 | getLocation().dump(); |
1377 | } |
1378 | |
1379 | LLVM_DUMP_METHOD void PathDiagnosticControlFlowPiece::dump() const { |
1380 | llvm::errs() << "CONTROL\n--------------\n"; |
1381 | getStartLocation().dump(); |
1382 | llvm::errs() << " ---- to ----\n"; |
1383 | getEndLocation().dump(); |
1384 | } |
1385 | |
1386 | LLVM_DUMP_METHOD void PathDiagnosticMacroPiece::dump() const { |
1387 | llvm::errs() << "MACRO\n--------------\n"; |
1388 | |
1389 | } |
1390 | |
1391 | LLVM_DUMP_METHOD void PathDiagnosticNotePiece::dump() const { |
1392 | llvm::errs() << "NOTE\n--------------\n"; |
1393 | llvm::errs() << getString() << "\n"; |
1394 | llvm::errs() << " ---- at ----\n"; |
1395 | getLocation().dump(); |
1396 | } |
1397 | |
1398 | LLVM_DUMP_METHOD void PathDiagnosticLocation::dump() const { |
1399 | if (!isValid()) { |
1400 | llvm::errs() << "<INVALID>\n"; |
1401 | return; |
1402 | } |
1403 | |
1404 | switch (K) { |
1405 | case RangeK: |
1406 | |
1407 | llvm::errs() << "<range>\n"; |
1408 | break; |
1409 | case SingleLocK: |
1410 | asLocation().dump(); |
1411 | llvm::errs() << "\n"; |
1412 | break; |
1413 | case StmtK: |
1414 | if (S) |
1415 | S->dump(); |
1416 | else |
1417 | llvm::errs() << "<NULL STMT>\n"; |
1418 | break; |
1419 | case DeclK: |
1420 | if (const auto *ND = dyn_cast_or_null<NamedDecl>(D)) |
1421 | llvm::errs() << *ND << "\n"; |
1422 | else if (isa<BlockDecl>(D)) |
1423 | |
1424 | llvm::errs() << "<block>\n"; |
1425 | else if (D) |
1426 | llvm::errs() << "<unknown decl>\n"; |
1427 | else |
1428 | llvm::errs() << "<NULL DECL>\n"; |
1429 | break; |
1430 | } |
1431 | } |
1432 | |