1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | #ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTER_H |
15 | #define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTER_H |
16 | |
17 | #include "clang/Basic/LLVM.h" |
18 | #include "clang/Basic/SourceLocation.h" |
19 | #include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h" |
20 | #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" |
21 | #include "clang/StaticAnalyzer/Core/CheckerManager.h" |
22 | #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" |
23 | #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" |
24 | #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h" |
25 | #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" |
26 | #include "llvm/ADT/ArrayRef.h" |
27 | #include "llvm/ADT/DenseSet.h" |
28 | #include "llvm/ADT/FoldingSet.h" |
29 | #include "llvm/ADT/ImmutableSet.h" |
30 | #include "llvm/ADT/None.h" |
31 | #include "llvm/ADT/SmallSet.h" |
32 | #include "llvm/ADT/SmallVector.h" |
33 | #include "llvm/ADT/StringMap.h" |
34 | #include "llvm/ADT/StringRef.h" |
35 | #include "llvm/ADT/ilist.h" |
36 | #include "llvm/ADT/ilist_node.h" |
37 | #include "llvm/ADT/iterator_range.h" |
38 | #include <cassert> |
39 | #include <memory> |
40 | #include <string> |
41 | #include <utility> |
42 | #include <vector> |
43 | |
44 | namespace clang { |
45 | |
46 | class AnalyzerOptions; |
47 | class ASTContext; |
48 | class Decl; |
49 | class DiagnosticsEngine; |
50 | class LocationContext; |
51 | class SourceManager; |
52 | class Stmt; |
53 | |
54 | namespace ento { |
55 | |
56 | class BugType; |
57 | class CheckerBase; |
58 | class ExplodedGraph; |
59 | class ExplodedNode; |
60 | class ExprEngine; |
61 | class MemRegion; |
62 | class SValBuilder; |
63 | |
64 | |
65 | |
66 | |
67 | |
68 | |
69 | |
70 | using DiagnosticForConsumerMapTy = |
71 | llvm::DenseMap<PathDiagnosticConsumer *, std::unique_ptr<PathDiagnostic>>; |
72 | |
73 | |
74 | |
75 | class BugReport : public llvm::ilist_node<BugReport> { |
76 | public: |
77 | class NodeResolver { |
78 | virtual void anchor(); |
79 | |
80 | public: |
81 | virtual ~NodeResolver() = default; |
82 | |
83 | virtual const ExplodedNode* |
84 | getOriginalNode(const ExplodedNode *N) = 0; |
85 | }; |
86 | |
87 | using ranges_iterator = const SourceRange *; |
88 | using VisitorList = SmallVector<std::unique_ptr<BugReporterVisitor>, 8>; |
89 | using visitor_iterator = VisitorList::iterator; |
90 | using = SmallVector<StringRef, 2>; |
91 | using NoteList = SmallVector<std::shared_ptr<PathDiagnosticNotePiece>, 4>; |
92 | |
93 | protected: |
94 | friend class BugReportEquivClass; |
95 | friend class BugReporter; |
96 | |
97 | const BugType& BT; |
98 | const Decl *DeclWithIssue = nullptr; |
99 | std::string ShortDescription; |
100 | std::string Description; |
101 | PathDiagnosticLocation Location; |
102 | PathDiagnosticLocation UniqueingLocation; |
103 | const Decl *UniqueingDecl; |
104 | |
105 | const ExplodedNode *ErrorNode = nullptr; |
106 | SmallVector<SourceRange, 4> Ranges; |
107 | ExtraTextList ; |
108 | NoteList Notes; |
109 | |
110 | using Symbols = llvm::DenseSet<SymbolRef>; |
111 | using Regions = llvm::DenseSet<const MemRegion *>; |
112 | |
113 | |
114 | |
115 | |
116 | |
117 | |
118 | SmallVector<Symbols *, 2> interestingSymbols; |
119 | |
120 | |
121 | |
122 | |
123 | |
124 | |
125 | SmallVector<Regions *, 2> interestingRegions; |
126 | |
127 | |
128 | |
129 | llvm::SmallSet<const LocationContext *, 2> InterestingLocationContexts; |
130 | |
131 | |
132 | |
133 | VisitorList Callbacks; |
134 | |
135 | |
136 | llvm::FoldingSet<BugReporterVisitor> CallbacksSet; |
137 | |
138 | |
139 | |
140 | |
141 | bool DoNotPrunePath = false; |
142 | |
143 | |
144 | |
145 | |
146 | |
147 | using InvalidationRecord = std::pair<const void *, const void *>; |
148 | |
149 | |
150 | |
151 | |
152 | |
153 | |
154 | llvm::SmallSet<InvalidationRecord, 4> Invalidations; |
155 | |
156 | private: |
157 | |
158 | Symbols &getInterestingSymbols(); |
159 | Regions &getInterestingRegions(); |
160 | |
161 | void lazyInitializeInterestingSets(); |
162 | void pushInterestingSymbolsAndRegions(); |
163 | void popInterestingSymbolsAndRegions(); |
164 | |
165 | public: |
166 | BugReport(const BugType& bt, StringRef desc, const ExplodedNode *errornode) |
167 | : BT(bt), Description(desc), ErrorNode(errornode) {} |
168 | |
169 | BugReport(const BugType& bt, StringRef shortDesc, StringRef desc, |
170 | const ExplodedNode *errornode) |
171 | : BT(bt), ShortDescription(shortDesc), Description(desc), |
172 | ErrorNode(errornode) {} |
173 | |
174 | BugReport(const BugType &bt, StringRef desc, PathDiagnosticLocation l) |
175 | : BT(bt), Description(desc), Location(l) {} |
176 | |
177 | |
178 | |
179 | |
180 | |
181 | |
182 | |
183 | |
184 | BugReport(BugType& bt, StringRef desc, const ExplodedNode *errornode, |
185 | PathDiagnosticLocation LocationToUnique, const Decl *DeclToUnique) |
186 | : BT(bt), Description(desc), UniqueingLocation(LocationToUnique), |
187 | UniqueingDecl(DeclToUnique), ErrorNode(errornode) {} |
188 | |
189 | virtual ~BugReport(); |
190 | |
191 | const BugType& getBugType() const { return BT; } |
192 | |
193 | |
194 | |
195 | |
196 | |
197 | |
198 | |
199 | |
200 | |
201 | |
202 | |
203 | |
204 | bool isPathSensitive() const { return ErrorNode != nullptr; } |
205 | |
206 | const ExplodedNode *getErrorNode() const { return ErrorNode; } |
207 | |
208 | StringRef getDescription() const { return Description; } |
209 | |
210 | StringRef getShortDescription(bool UseFallback = true) const { |
211 | if (ShortDescription.empty() && UseFallback) |
212 | return Description; |
213 | return ShortDescription; |
214 | } |
215 | |
216 | |
217 | |
218 | bool shouldPrunePath() const { return !DoNotPrunePath; } |
219 | |
220 | |
221 | void disablePathPruning() { DoNotPrunePath = true; } |
222 | |
223 | void markInteresting(SymbolRef sym); |
224 | void markInteresting(const MemRegion *R); |
225 | void markInteresting(SVal V); |
226 | void markInteresting(const LocationContext *LC); |
227 | |
228 | bool isInteresting(SymbolRef sym); |
229 | bool isInteresting(const MemRegion *R); |
230 | bool isInteresting(SVal V); |
231 | bool isInteresting(const LocationContext *LC); |
232 | |
233 | |
234 | |
235 | |
236 | |
237 | bool isValid() const { |
238 | return Invalidations.empty(); |
239 | } |
240 | |
241 | |
242 | |
243 | |
244 | |
245 | |
246 | |
247 | |
248 | |
249 | |
250 | void markInvalid(const void *Tag, const void *Data) { |
251 | Invalidations.insert(std::make_pair(Tag, Data)); |
252 | } |
253 | |
254 | |
255 | |
256 | const Decl *getDeclWithIssue() const; |
257 | |
258 | |
259 | |
260 | void setDeclWithIssue(const Decl *declWithIssue) { |
261 | DeclWithIssue = declWithIssue; |
262 | } |
263 | |
264 | |
265 | |
266 | |
267 | |
268 | |
269 | void addNote(StringRef Msg, const PathDiagnosticLocation &Pos, |
270 | ArrayRef<SourceRange> Ranges) { |
271 | auto P = std::make_shared<PathDiagnosticNotePiece>(Pos, Msg); |
272 | |
273 | for (const auto &R : Ranges) |
274 | P->addRange(R); |
275 | |
276 | Notes.push_back(std::move(P)); |
277 | } |
278 | |
279 | |
280 | |
281 | void addNote(StringRef Msg, const PathDiagnosticLocation &Pos) { |
282 | std::vector<SourceRange> Ranges; |
283 | addNote(Msg, Pos, Ranges); |
284 | } |
285 | |
286 | virtual const NoteList &getNotes() { |
287 | return Notes; |
288 | } |
289 | |
290 | |
291 | |
292 | |
293 | void (StringRef S) { |
294 | ExtraText.push_back(S); |
295 | } |
296 | |
297 | virtual const ExtraTextList &() { |
298 | return ExtraText; |
299 | } |
300 | |
301 | |
302 | |
303 | |
304 | |
305 | |
306 | virtual PathDiagnosticLocation getLocation(const SourceManager &SM) const; |
307 | |
308 | |
309 | PathDiagnosticLocation getUniqueingLocation() const { |
310 | return UniqueingLocation; |
311 | } |
312 | |
313 | |
314 | const Decl *getUniqueingDecl() const { |
315 | return UniqueingDecl; |
316 | } |
317 | |
318 | const Stmt *getStmt() const; |
319 | |
320 | |
321 | |
322 | |
323 | |
324 | |
325 | |
326 | |
327 | void addRange(SourceRange R) { |
328 | (0) . __assert_fail ("(R.isValid() || Ranges.empty()) && \"Invalid range can only be used \" \"to specify that the report does not have a range.\"", "/home/seafit/code_projects/clang_source/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h", 329, __PRETTY_FUNCTION__))" file_link="../../../../../../include/assert.h.html#88" macro="true">assert((R.isValid() || Ranges.empty()) && "Invalid range can only be used " |
329 | (0) . __assert_fail ("(R.isValid() || Ranges.empty()) && \"Invalid range can only be used \" \"to specify that the report does not have a range.\"", "/home/seafit/code_projects/clang_source/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h", 329, __PRETTY_FUNCTION__))" file_link="../../../../../../include/assert.h.html#88" macro="true"> "to specify that the report does not have a range."); |
330 | Ranges.push_back(R); |
331 | } |
332 | |
333 | |
334 | virtual llvm::iterator_range<ranges_iterator> getRanges(); |
335 | |
336 | |
337 | |
338 | |
339 | |
340 | |
341 | |
342 | |
343 | void addVisitor(std::unique_ptr<BugReporterVisitor> visitor); |
344 | |
345 | |
346 | void clearVisitors(); |
347 | |
348 | |
349 | visitor_iterator visitor_begin() { return Callbacks.begin(); } |
350 | visitor_iterator visitor_end() { return Callbacks.end(); } |
351 | |
352 | |
353 | |
354 | |
355 | virtual void Profile(llvm::FoldingSetNodeID& hash) const; |
356 | }; |
357 | |
358 | |
359 | |
360 | |
361 | |
362 | class BugReportEquivClass : public llvm::FoldingSetNode { |
363 | friend class BugReporter; |
364 | |
365 | |
366 | llvm::ilist<BugReport> Reports; |
367 | |
368 | void AddReport(std::unique_ptr<BugReport> R) { |
369 | Reports.push_back(R.release()); |
370 | } |
371 | |
372 | public: |
373 | BugReportEquivClass(std::unique_ptr<BugReport> R) { AddReport(std::move(R)); } |
374 | ~BugReportEquivClass(); |
375 | |
376 | void Profile(llvm::FoldingSetNodeID& ID) const { |
377 | assert(!Reports.empty()); |
378 | Reports.front().Profile(ID); |
379 | } |
380 | |
381 | using iterator = llvm::ilist<BugReport>::iterator; |
382 | using const_iterator = llvm::ilist<BugReport>::const_iterator; |
383 | |
384 | iterator begin() { return Reports.begin(); } |
385 | iterator end() { return Reports.end(); } |
386 | |
387 | const_iterator begin() const { return Reports.begin(); } |
388 | const_iterator end() const { return Reports.end(); } |
389 | }; |
390 | |
391 | |
392 | |
393 | |
394 | |
395 | class BugReporterData { |
396 | public: |
397 | virtual ~BugReporterData(); |
398 | |
399 | virtual DiagnosticsEngine& getDiagnostic() = 0; |
400 | virtual ArrayRef<PathDiagnosticConsumer*> getPathDiagnosticConsumers() = 0; |
401 | virtual ASTContext &getASTContext() = 0; |
402 | virtual SourceManager &getSourceManager() = 0; |
403 | virtual AnalyzerOptions &getAnalyzerOptions() = 0; |
404 | }; |
405 | |
406 | |
407 | |
408 | |
409 | |
410 | |
411 | class BugReporter { |
412 | public: |
413 | enum Kind { BaseBRKind, GRBugReporterKind }; |
414 | |
415 | private: |
416 | using BugTypesTy = llvm::ImmutableSet<BugType *>; |
417 | |
418 | BugTypesTy::Factory F; |
419 | BugTypesTy BugTypes; |
420 | |
421 | const Kind kind; |
422 | BugReporterData& D; |
423 | |
424 | |
425 | void FlushReport(BugReportEquivClass& EQ); |
426 | |
427 | |
428 | std::unique_ptr<DiagnosticForConsumerMapTy> |
429 | generateDiagnosticForConsumerMap(BugReport *exampleReport, |
430 | ArrayRef<PathDiagnosticConsumer *> consumers, |
431 | ArrayRef<BugReport *> bugReports); |
432 | |
433 | |
434 | llvm::FoldingSet<BugReportEquivClass> EQClasses; |
435 | |
436 | |
437 | std::vector<BugReportEquivClass *> EQClassesVector; |
438 | |
439 | protected: |
440 | BugReporter(BugReporterData& d, Kind k) |
441 | : BugTypes(F.getEmptySet()), kind(k), D(d) {} |
442 | |
443 | public: |
444 | BugReporter(BugReporterData& d) |
445 | : BugTypes(F.getEmptySet()), kind(BaseBRKind), D(d) {} |
446 | virtual ~BugReporter(); |
447 | |
448 | |
449 | void FlushReports(); |
450 | |
451 | Kind getKind() const { return kind; } |
452 | |
453 | DiagnosticsEngine& getDiagnostic() { |
454 | return D.getDiagnostic(); |
455 | } |
456 | |
457 | ArrayRef<PathDiagnosticConsumer*> getPathDiagnosticConsumers() { |
458 | return D.getPathDiagnosticConsumers(); |
459 | } |
460 | |
461 | |
462 | using iterator = BugTypesTy::iterator; |
463 | iterator begin() { return BugTypes.begin(); } |
464 | iterator end() { return BugTypes.end(); } |
465 | |
466 | |
467 | using EQClasses_iterator = llvm::FoldingSet<BugReportEquivClass>::iterator; |
468 | EQClasses_iterator EQClasses_begin() { return EQClasses.begin(); } |
469 | EQClasses_iterator EQClasses_end() { return EQClasses.end(); } |
470 | |
471 | ASTContext &getContext() { return D.getASTContext(); } |
472 | |
473 | SourceManager &getSourceManager() { return D.getSourceManager(); } |
474 | |
475 | AnalyzerOptions &getAnalyzerOptions() { return D.getAnalyzerOptions(); } |
476 | |
477 | virtual std::unique_ptr<DiagnosticForConsumerMapTy> |
478 | generatePathDiagnostics(ArrayRef<PathDiagnosticConsumer *> consumers, |
479 | ArrayRef<BugReport *> &bugReports) { |
480 | return {}; |
481 | } |
482 | |
483 | void Register(const BugType *BT); |
484 | |
485 | |
486 | |
487 | |
488 | |
489 | |
490 | void emitReport(std::unique_ptr<BugReport> R); |
491 | |
492 | void EmitBasicReport(const Decl *DeclWithIssue, const CheckerBase *Checker, |
493 | StringRef BugName, StringRef BugCategory, |
494 | StringRef BugStr, PathDiagnosticLocation Loc, |
495 | ArrayRef<SourceRange> Ranges = None); |
496 | |
497 | void EmitBasicReport(const Decl *DeclWithIssue, CheckName CheckName, |
498 | StringRef BugName, StringRef BugCategory, |
499 | StringRef BugStr, PathDiagnosticLocation Loc, |
500 | ArrayRef<SourceRange> Ranges = None); |
501 | |
502 | private: |
503 | llvm::StringMap<BugType *> StrBugTypes; |
504 | |
505 | |
506 | |
507 | BugType *getBugTypeForName(CheckName CheckName, StringRef name, |
508 | StringRef category); |
509 | }; |
510 | |
511 | |
512 | class GRBugReporter : public BugReporter { |
513 | ExprEngine& Eng; |
514 | |
515 | public: |
516 | GRBugReporter(BugReporterData& d, ExprEngine& eng) |
517 | : BugReporter(d, GRBugReporterKind), Eng(eng) {} |
518 | |
519 | ~GRBugReporter() override; |
520 | |
521 | |
522 | |
523 | ExplodedGraph &getGraph(); |
524 | |
525 | |
526 | |
527 | ProgramStateManager &getStateManager(); |
528 | |
529 | |
530 | |
531 | |
532 | |
533 | |
534 | std::unique_ptr<DiagnosticForConsumerMapTy> |
535 | generatePathDiagnostics(ArrayRef<PathDiagnosticConsumer *> consumers, |
536 | ArrayRef<BugReport *> &bugReports) override; |
537 | |
538 | |
539 | static bool classof(const BugReporter* R) { |
540 | return R->getKind() == GRBugReporterKind; |
541 | } |
542 | }; |
543 | |
544 | |
545 | class NodeMapClosure : public BugReport::NodeResolver { |
546 | InterExplodedGraphMap &M; |
547 | |
548 | public: |
549 | NodeMapClosure(InterExplodedGraphMap &m) : M(m) {} |
550 | |
551 | const ExplodedNode *getOriginalNode(const ExplodedNode *N) override { |
552 | return M.lookup(N); |
553 | } |
554 | }; |
555 | |
556 | class BugReporterContext { |
557 | GRBugReporter &BR; |
558 | NodeMapClosure NMC; |
559 | |
560 | virtual void anchor(); |
561 | |
562 | public: |
563 | BugReporterContext(GRBugReporter &br, InterExplodedGraphMap &Backmap) |
564 | : BR(br), NMC(Backmap) {} |
565 | |
566 | virtual ~BugReporterContext() = default; |
567 | |
568 | GRBugReporter& getBugReporter() { return BR; } |
569 | |
570 | ExplodedGraph &getGraph() { return BR.getGraph(); } |
571 | |
572 | ProgramStateManager& getStateManager() { |
573 | return BR.getStateManager(); |
574 | } |
575 | |
576 | SValBuilder &getSValBuilder() { |
577 | return getStateManager().getSValBuilder(); |
578 | } |
579 | |
580 | ASTContext &getASTContext() { |
581 | return BR.getContext(); |
582 | } |
583 | |
584 | SourceManager& getSourceManager() { |
585 | return BR.getSourceManager(); |
586 | } |
587 | |
588 | AnalyzerOptions &getAnalyzerOptions() { |
589 | return BR.getAnalyzerOptions(); |
590 | } |
591 | |
592 | NodeMapClosure& getNodeResolver() { return NMC; } |
593 | }; |
594 | |
595 | } |
596 | |
597 | } |
598 | |
599 | #endif |
600 | |