]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
* Add the readline(3) API to libedit. The libedit versions of
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / clang / include / clang / StaticAnalyzer / Core / BugReporter / BugReporter.h
1 //===---  BugReporter.h - Generate PathDiagnostics --------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 //  This file defines BugReporter, a utility class for generating
11 //  PathDiagnostics for analyses based on GRState.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #ifndef LLVM_CLANG_GR_BUGREPORTER
16 #define LLVM_CLANG_GR_BUGREPORTER
17
18 #include "clang/Basic/SourceLocation.h"
19 #include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
20 #include "llvm/ADT/FoldingSet.h"
21 #include "llvm/ADT/ImmutableList.h"
22 #include "llvm/ADT/ImmutableSet.h"
23 #include "llvm/ADT/SmallSet.h"
24 #include <list>
25
26 namespace clang {
27
28 class ASTContext;
29 class Diagnostic;
30 class Stmt;
31 class ParentMap;
32
33 namespace ento {
34
35 class PathDiagnostic;
36 class PathDiagnosticPiece;
37 class PathDiagnosticClient;
38 class ExplodedNode;
39 class ExplodedGraph;
40 class BugReporter;
41 class BugReporterContext;
42 class ExprEngine;
43 class GRState;
44 class BugType;
45
46 //===----------------------------------------------------------------------===//
47 // Interface for individual bug reports.
48 //===----------------------------------------------------------------------===//
49
50 class BugReporterVisitor : public llvm::FoldingSetNode {
51 public:
52   virtual ~BugReporterVisitor();
53   virtual PathDiagnosticPiece* VisitNode(const ExplodedNode* N,
54                                          const ExplodedNode* PrevN,
55                                          BugReporterContext& BRC) = 0;
56
57   virtual bool isOwnedByReporterContext() { return true; }
58   virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0;
59 };
60
61 // FIXME: Combine this with RangedBugReport and remove RangedBugReport.
62 class BugReport : public BugReporterVisitor {
63 protected:
64   BugType& BT;
65   std::string ShortDescription;
66   std::string Description;
67   const ExplodedNode *ErrorNode;
68   mutable SourceRange R;
69
70 protected:
71   friend class BugReporter;
72   friend class BugReportEquivClass;
73
74   virtual void Profile(llvm::FoldingSetNodeID& hash) const {
75     hash.AddPointer(&BT);
76     hash.AddInteger(getLocation().getRawEncoding());
77     hash.AddString(Description);
78   }
79
80 public:
81   class NodeResolver {
82   public:
83     virtual ~NodeResolver() {}
84     virtual const ExplodedNode*
85             getOriginalNode(const ExplodedNode* N) = 0;
86   };
87
88   BugReport(BugType& bt, llvm::StringRef desc, const ExplodedNode *errornode)
89     : BT(bt), Description(desc), ErrorNode(errornode) {}
90
91   BugReport(BugType& bt, llvm::StringRef shortDesc, llvm::StringRef desc,
92             const ExplodedNode *errornode)
93   : BT(bt), ShortDescription(shortDesc), Description(desc),
94     ErrorNode(errornode) {}
95
96   virtual ~BugReport();
97
98   virtual bool isOwnedByReporterContext() { return false; }
99
100   const BugType& getBugType() const { return BT; }
101   BugType& getBugType() { return BT; }
102
103   // FIXME: Perhaps this should be moved into a subclass?
104   const ExplodedNode* getErrorNode() const { return ErrorNode; }
105
106   // FIXME: Do we need this?  Maybe getLocation() should return a ProgramPoint
107   // object.
108   // FIXME: If we do need it, we can probably just make it private to
109   // BugReporter.
110   const Stmt* getStmt() const;
111
112   const llvm::StringRef getDescription() const { return Description; }
113
114   const llvm::StringRef getShortDescription() const {
115     return ShortDescription.empty() ? Description : ShortDescription;
116   }
117
118   // FIXME: Is this needed?
119   virtual std::pair<const char**,const char**> getExtraDescriptiveText() {
120     return std::make_pair((const char**)0,(const char**)0);
121   }
122
123   // FIXME: Perhaps move this into a subclass.
124   virtual PathDiagnosticPiece* getEndPath(BugReporterContext& BRC,
125                                           const ExplodedNode* N);
126
127   /// getLocation - Return the "definitive" location of the reported bug.
128   ///  While a bug can span an entire path, usually there is a specific
129   ///  location that can be used to identify where the key issue occured.
130   ///  This location is used by clients rendering diagnostics.
131   virtual SourceLocation getLocation() const;
132
133   typedef const SourceRange *ranges_iterator;
134
135   /// getRanges - Returns the source ranges associated with this bug.
136   virtual std::pair<ranges_iterator, ranges_iterator> getRanges() const;
137
138   virtual PathDiagnosticPiece* VisitNode(const ExplodedNode* N,
139                                          const ExplodedNode* PrevN,
140                                          BugReporterContext& BR);
141
142   virtual void registerInitialVisitors(BugReporterContext& BRC,
143                                        const ExplodedNode* N) {}
144 };
145
146 //===----------------------------------------------------------------------===//
147 // BugTypes (collections of related reports).
148 //===----------------------------------------------------------------------===//
149
150 class BugReportEquivClass : public llvm::FoldingSetNode {
151   // List of *owned* BugReport objects.
152   std::list<BugReport*> Reports;
153
154   friend class BugReporter;
155   void AddReport(BugReport* R) { Reports.push_back(R); }
156 public:
157   BugReportEquivClass(BugReport* R) { Reports.push_back(R); }
158   ~BugReportEquivClass();
159
160   void Profile(llvm::FoldingSetNodeID& ID) const {
161     assert(!Reports.empty());
162     (*Reports.begin())->Profile(ID);
163   }
164
165   class iterator {
166     std::list<BugReport*>::iterator impl;
167   public:
168     iterator(std::list<BugReport*>::iterator i) : impl(i) {}
169     iterator& operator++() { ++impl; return *this; }
170     bool operator==(const iterator& I) const { return I.impl == impl; }
171     bool operator!=(const iterator& I) const { return I.impl != impl; }
172     BugReport* operator*() const { return *impl; }
173     BugReport* operator->() const { return *impl; }
174   };
175
176   class const_iterator {
177     std::list<BugReport*>::const_iterator impl;
178   public:
179     const_iterator(std::list<BugReport*>::const_iterator i) : impl(i) {}
180     const_iterator& operator++() { ++impl; return *this; }
181     bool operator==(const const_iterator& I) const { return I.impl == impl; }
182     bool operator!=(const const_iterator& I) const { return I.impl != impl; }
183     const BugReport* operator*() const { return *impl; }
184     const BugReport* operator->() const { return *impl; }
185   };
186
187   iterator begin() { return iterator(Reports.begin()); }
188   iterator end() { return iterator(Reports.end()); }
189
190   const_iterator begin() const { return const_iterator(Reports.begin()); }
191   const_iterator end() const { return const_iterator(Reports.end()); }
192 };
193
194
195 //===----------------------------------------------------------------------===//
196 // Specialized subclasses of BugReport.
197 //===----------------------------------------------------------------------===//
198
199 // FIXME: Collapse this with the default BugReport class.
200 class RangedBugReport : public BugReport {
201   llvm::SmallVector<SourceRange, 4> Ranges;
202 public:
203   RangedBugReport(BugType& D, llvm::StringRef description,
204                   ExplodedNode *errornode)
205     : BugReport(D, description, errornode) {}
206
207   RangedBugReport(BugType& D, llvm::StringRef shortDescription,
208                   llvm::StringRef description, ExplodedNode *errornode)
209   : BugReport(D, shortDescription, description, errornode) {}
210
211   ~RangedBugReport();
212
213   // FIXME: Move this out of line.
214   void addRange(SourceRange R) {
215     assert(R.isValid());
216     Ranges.push_back(R);
217   }
218
219   virtual std::pair<ranges_iterator, ranges_iterator> getRanges() const {
220     return std::make_pair(Ranges.begin(), Ranges.end());
221   }
222 };
223
224 class EnhancedBugReport : public RangedBugReport {
225 public:
226   typedef void (*VisitorCreator)(BugReporterContext &BRcC, const void *data,
227                                  const ExplodedNode *N);
228
229 private:
230   typedef std::vector<std::pair<VisitorCreator, const void*> > Creators;
231   Creators creators;
232
233 public:
234   EnhancedBugReport(BugType& D, llvm::StringRef description,
235                     ExplodedNode *errornode)
236    : RangedBugReport(D, description, errornode) {}
237
238   EnhancedBugReport(BugType& D, llvm::StringRef shortDescription,
239                    llvm::StringRef description, ExplodedNode *errornode)
240     : RangedBugReport(D, shortDescription, description, errornode) {}
241
242   ~EnhancedBugReport() {}
243
244   void registerInitialVisitors(BugReporterContext& BRC, const ExplodedNode* N) {
245     for (Creators::iterator I = creators.begin(), E = creators.end(); I!=E; ++I)
246       I->first(BRC, I->second, N);
247   }
248
249   void addVisitorCreator(VisitorCreator creator, const void *data) {
250     creators.push_back(std::make_pair(creator, data));
251   }
252 };
253
254 //===----------------------------------------------------------------------===//
255 // BugReporter and friends.
256 //===----------------------------------------------------------------------===//
257
258 class BugReporterData {
259 public:
260   virtual ~BugReporterData();
261   virtual Diagnostic& getDiagnostic() = 0;
262   virtual PathDiagnosticClient* getPathDiagnosticClient() = 0;
263   virtual ASTContext& getASTContext() = 0;
264   virtual SourceManager& getSourceManager() = 0;
265 };
266
267 class BugReporter {
268 public:
269   enum Kind { BaseBRKind, GRBugReporterKind };
270
271 private:
272   typedef llvm::ImmutableSet<BugType*> BugTypesTy;
273   BugTypesTy::Factory F;
274   BugTypesTy BugTypes;
275
276   const Kind kind;
277   BugReporterData& D;
278
279   void FlushReport(BugReportEquivClass& EQ);
280
281   llvm::FoldingSet<BugReportEquivClass> EQClasses;
282
283 protected:
284   BugReporter(BugReporterData& d, Kind k) : BugTypes(F.getEmptySet()), kind(k),
285                                             D(d) {}
286
287 public:
288   BugReporter(BugReporterData& d) : BugTypes(F.getEmptySet()), kind(BaseBRKind),
289                                     D(d) {}
290   virtual ~BugReporter();
291
292   void FlushReports();
293
294   Kind getKind() const { return kind; }
295
296   Diagnostic& getDiagnostic() {
297     return D.getDiagnostic();
298   }
299
300   PathDiagnosticClient* getPathDiagnosticClient() {
301     return D.getPathDiagnosticClient();
302   }
303
304   typedef BugTypesTy::iterator iterator;
305   iterator begin() { return BugTypes.begin(); }
306   iterator end() { return BugTypes.end(); }
307
308   typedef llvm::FoldingSet<BugReportEquivClass>::iterator EQClasses_iterator;
309   EQClasses_iterator EQClasses_begin() { return EQClasses.begin(); }
310   EQClasses_iterator EQClasses_end() { return EQClasses.end(); }
311
312   ASTContext& getContext() { return D.getASTContext(); }
313
314   SourceManager& getSourceManager() { return D.getSourceManager(); }
315
316   virtual void GeneratePathDiagnostic(PathDiagnostic& pathDiagnostic,
317         llvm::SmallVectorImpl<BugReport *> &bugReports) {}
318
319   void Register(BugType *BT);
320
321   void EmitReport(BugReport *R);
322
323   void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr,
324                        SourceLocation Loc,
325                        SourceRange* RangeBeg, unsigned NumRanges);
326
327   void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugCategory,
328                        llvm::StringRef BugStr, SourceLocation Loc,
329                        SourceRange* RangeBeg, unsigned NumRanges);
330
331
332   void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr,
333                        SourceLocation Loc) {
334     EmitBasicReport(BugName, BugStr, Loc, 0, 0);
335   }
336
337   void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugCategory,
338                        llvm::StringRef BugStr, SourceLocation Loc) {
339     EmitBasicReport(BugName, BugCategory, BugStr, Loc, 0, 0);
340   }
341
342   void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr,
343                        SourceLocation Loc, SourceRange R) {
344     EmitBasicReport(BugName, BugStr, Loc, &R, 1);
345   }
346
347   void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef Category,
348                        llvm::StringRef BugStr, SourceLocation Loc,
349                        SourceRange R) {
350     EmitBasicReport(BugName, Category, BugStr, Loc, &R, 1);
351   }
352
353   static bool classof(const BugReporter* R) { return true; }
354
355 private:
356   llvm::StringMap<BugType *> StrBugTypes;
357
358   /// \brief Returns a BugType that is associated with the given name and
359   /// category.
360   BugType *getBugTypeForName(llvm::StringRef name, llvm::StringRef category);
361 };
362
363 // FIXME: Get rid of GRBugReporter.  It's the wrong abstraction.
364 class GRBugReporter : public BugReporter {
365   ExprEngine& Eng;
366   llvm::SmallSet<SymbolRef, 10> NotableSymbols;
367 public:
368   GRBugReporter(BugReporterData& d, ExprEngine& eng)
369     : BugReporter(d, GRBugReporterKind), Eng(eng) {}
370
371   virtual ~GRBugReporter();
372
373   /// getEngine - Return the analysis engine used to analyze a given
374   ///  function or method.
375   ExprEngine &getEngine() { return Eng; }
376
377   /// getGraph - Get the exploded graph created by the analysis engine
378   ///  for the analyzed method or function.
379   ExplodedGraph &getGraph();
380
381   /// getStateManager - Return the state manager used by the analysis
382   ///  engine.
383   GRStateManager &getStateManager();
384
385   virtual void GeneratePathDiagnostic(PathDiagnostic &pathDiagnostic,
386                      llvm::SmallVectorImpl<BugReport*> &bugReports);
387
388   void addNotableSymbol(SymbolRef Sym) {
389     NotableSymbols.insert(Sym);
390   }
391
392   bool isNotable(SymbolRef Sym) const {
393     return (bool) NotableSymbols.count(Sym);
394   }
395
396   /// classof - Used by isa<>, cast<>, and dyn_cast<>.
397   static bool classof(const BugReporter* R) {
398     return R->getKind() == GRBugReporterKind;
399   }
400 };
401
402 class BugReporterContext {
403   GRBugReporter &BR;
404   // Not the most efficient data structure, but we use an ImmutableList for the
405   // Callbacks because it is safe to make additions to list during iteration.
406   llvm::ImmutableList<BugReporterVisitor*>::Factory F;
407   llvm::ImmutableList<BugReporterVisitor*> Callbacks;
408   llvm::FoldingSet<BugReporterVisitor> CallbacksSet;
409 public:
410   BugReporterContext(GRBugReporter& br) : BR(br), Callbacks(F.getEmptyList()) {}
411   virtual ~BugReporterContext();
412
413   void addVisitor(BugReporterVisitor* visitor);
414
415   typedef llvm::ImmutableList<BugReporterVisitor*>::iterator visitor_iterator;
416   visitor_iterator visitor_begin() { return Callbacks.begin(); }
417   visitor_iterator visitor_end() { return Callbacks.end(); }
418
419   GRBugReporter& getBugReporter() { return BR; }
420
421   ExplodedGraph &getGraph() { return BR.getGraph(); }
422
423   void addNotableSymbol(SymbolRef Sym) {
424     // FIXME: For now forward to GRBugReporter.
425     BR.addNotableSymbol(Sym);
426   }
427
428   bool isNotable(SymbolRef Sym) const {
429     // FIXME: For now forward to GRBugReporter.
430     return BR.isNotable(Sym);
431   }
432
433   GRStateManager& getStateManager() {
434     return BR.getStateManager();
435   }
436
437   SValBuilder& getSValBuilder() {
438     return getStateManager().getSValBuilder();
439   }
440
441   ASTContext& getASTContext() {
442     return BR.getContext();
443   }
444
445   SourceManager& getSourceManager() {
446     return BR.getSourceManager();
447   }
448
449   virtual BugReport::NodeResolver& getNodeResolver() = 0;
450 };
451
452 class DiagBugReport : public RangedBugReport {
453   std::list<std::string> Strs;
454   FullSourceLoc L;
455 public:
456   DiagBugReport(BugType& D, llvm::StringRef desc, FullSourceLoc l) :
457   RangedBugReport(D, desc, 0), L(l) {}
458
459   virtual ~DiagBugReport() {}
460
461   // FIXME: Move out-of-line (virtual function).
462   SourceLocation getLocation() const { return L; }
463
464   void addString(llvm::StringRef s) { Strs.push_back(s); }
465
466   typedef std::list<std::string>::const_iterator str_iterator;
467   str_iterator str_begin() const { return Strs.begin(); }
468   str_iterator str_end() const { return Strs.end(); }
469 };
470
471 //===----------------------------------------------------------------------===//
472 //===----------------------------------------------------------------------===//
473
474 namespace bugreporter {
475
476 const Stmt *GetDerefExpr(const ExplodedNode *N);
477 const Stmt *GetDenomExpr(const ExplodedNode *N);
478 const Stmt *GetCalleeExpr(const ExplodedNode *N);
479 const Stmt *GetRetValExpr(const ExplodedNode *N);
480
481 void registerTrackNullOrUndefValue(BugReporterContext& BRC, const void *stmt,
482                                    const ExplodedNode* N);
483
484 void registerFindLastStore(BugReporterContext& BRC, const void *memregion,
485                            const ExplodedNode *N);
486
487 void registerNilReceiverVisitor(BugReporterContext &BRC);
488
489 void registerVarDeclsLastStore(BugReporterContext &BRC, const void *stmt,
490                                const ExplodedNode *N);
491
492 } // end namespace clang::bugreporter
493
494 //===----------------------------------------------------------------------===//
495
496 } // end GR namespace
497
498 } // end clang namespace
499
500 #endif