]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
Copy head to stable/9 as part of 9.0-RELEASE release cycle.
[FreeBSD/stable/9.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 occurred.
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   virtual void Profile(llvm::FoldingSetNodeID& hash) const {
224     BugReport::Profile(hash);
225     for (llvm::SmallVectorImpl<SourceRange>::const_iterator I =
226           Ranges.begin(), E = Ranges.end(); I != E; ++I) {
227       const SourceRange range = *I;
228       if (!range.isValid())
229         continue;
230       hash.AddInteger(range.getBegin().getRawEncoding());
231       hash.AddInteger(range.getEnd().getRawEncoding());
232     }
233   }
234 };
235
236 class EnhancedBugReport : public RangedBugReport {
237 public:
238   typedef void (*VisitorCreator)(BugReporterContext &BRcC, const void *data,
239                                  const ExplodedNode *N);
240
241 private:
242   typedef std::vector<std::pair<VisitorCreator, const void*> > Creators;
243   Creators creators;
244
245 public:
246   EnhancedBugReport(BugType& D, llvm::StringRef description,
247                     ExplodedNode *errornode)
248    : RangedBugReport(D, description, errornode) {}
249
250   EnhancedBugReport(BugType& D, llvm::StringRef shortDescription,
251                    llvm::StringRef description, ExplodedNode *errornode)
252     : RangedBugReport(D, shortDescription, description, errornode) {}
253
254   ~EnhancedBugReport() {}
255
256   void registerInitialVisitors(BugReporterContext& BRC, const ExplodedNode* N) {
257     for (Creators::iterator I = creators.begin(), E = creators.end(); I!=E; ++I)
258       I->first(BRC, I->second, N);
259   }
260
261   void addVisitorCreator(VisitorCreator creator, const void *data) {
262     creators.push_back(std::make_pair(creator, data));
263   }
264 };
265
266 //===----------------------------------------------------------------------===//
267 // BugReporter and friends.
268 //===----------------------------------------------------------------------===//
269
270 class BugReporterData {
271 public:
272   virtual ~BugReporterData();
273   virtual Diagnostic& getDiagnostic() = 0;
274   virtual PathDiagnosticClient* getPathDiagnosticClient() = 0;
275   virtual ASTContext& getASTContext() = 0;
276   virtual SourceManager& getSourceManager() = 0;
277 };
278
279 class BugReporter {
280 public:
281   enum Kind { BaseBRKind, GRBugReporterKind };
282
283 private:
284   typedef llvm::ImmutableSet<BugType*> BugTypesTy;
285   BugTypesTy::Factory F;
286   BugTypesTy BugTypes;
287
288   const Kind kind;
289   BugReporterData& D;
290
291   void FlushReport(BugReportEquivClass& EQ);
292
293   llvm::FoldingSet<BugReportEquivClass> EQClasses;
294
295 protected:
296   BugReporter(BugReporterData& d, Kind k) : BugTypes(F.getEmptySet()), kind(k),
297                                             D(d) {}
298
299 public:
300   BugReporter(BugReporterData& d) : BugTypes(F.getEmptySet()), kind(BaseBRKind),
301                                     D(d) {}
302   virtual ~BugReporter();
303
304   void FlushReports();
305
306   Kind getKind() const { return kind; }
307
308   Diagnostic& getDiagnostic() {
309     return D.getDiagnostic();
310   }
311
312   PathDiagnosticClient* getPathDiagnosticClient() {
313     return D.getPathDiagnosticClient();
314   }
315
316   typedef BugTypesTy::iterator iterator;
317   iterator begin() { return BugTypes.begin(); }
318   iterator end() { return BugTypes.end(); }
319
320   typedef llvm::FoldingSet<BugReportEquivClass>::iterator EQClasses_iterator;
321   EQClasses_iterator EQClasses_begin() { return EQClasses.begin(); }
322   EQClasses_iterator EQClasses_end() { return EQClasses.end(); }
323
324   ASTContext& getContext() { return D.getASTContext(); }
325
326   SourceManager& getSourceManager() { return D.getSourceManager(); }
327
328   virtual void GeneratePathDiagnostic(PathDiagnostic& pathDiagnostic,
329         llvm::SmallVectorImpl<BugReport *> &bugReports) {}
330
331   void Register(BugType *BT);
332
333   void EmitReport(BugReport *R);
334
335   void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr,
336                        SourceLocation Loc,
337                        SourceRange* RangeBeg, unsigned NumRanges);
338
339   void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugCategory,
340                        llvm::StringRef BugStr, SourceLocation Loc,
341                        SourceRange* RangeBeg, unsigned NumRanges);
342
343
344   void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr,
345                        SourceLocation Loc) {
346     EmitBasicReport(BugName, BugStr, Loc, 0, 0);
347   }
348
349   void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugCategory,
350                        llvm::StringRef BugStr, SourceLocation Loc) {
351     EmitBasicReport(BugName, BugCategory, BugStr, Loc, 0, 0);
352   }
353
354   void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr,
355                        SourceLocation Loc, SourceRange R) {
356     EmitBasicReport(BugName, BugStr, Loc, &R, 1);
357   }
358
359   void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef Category,
360                        llvm::StringRef BugStr, SourceLocation Loc,
361                        SourceRange R) {
362     EmitBasicReport(BugName, Category, BugStr, Loc, &R, 1);
363   }
364
365   static bool classof(const BugReporter* R) { return true; }
366
367 private:
368   llvm::StringMap<BugType *> StrBugTypes;
369
370   /// \brief Returns a BugType that is associated with the given name and
371   /// category.
372   BugType *getBugTypeForName(llvm::StringRef name, llvm::StringRef category);
373 };
374
375 // FIXME: Get rid of GRBugReporter.  It's the wrong abstraction.
376 class GRBugReporter : public BugReporter {
377   ExprEngine& Eng;
378   llvm::SmallSet<SymbolRef, 10> NotableSymbols;
379 public:
380   GRBugReporter(BugReporterData& d, ExprEngine& eng)
381     : BugReporter(d, GRBugReporterKind), Eng(eng) {}
382
383   virtual ~GRBugReporter();
384
385   /// getEngine - Return the analysis engine used to analyze a given
386   ///  function or method.
387   ExprEngine &getEngine() { return Eng; }
388
389   /// getGraph - Get the exploded graph created by the analysis engine
390   ///  for the analyzed method or function.
391   ExplodedGraph &getGraph();
392
393   /// getStateManager - Return the state manager used by the analysis
394   ///  engine.
395   GRStateManager &getStateManager();
396
397   virtual void GeneratePathDiagnostic(PathDiagnostic &pathDiagnostic,
398                      llvm::SmallVectorImpl<BugReport*> &bugReports);
399
400   void addNotableSymbol(SymbolRef Sym) {
401     NotableSymbols.insert(Sym);
402   }
403
404   bool isNotable(SymbolRef Sym) const {
405     return (bool) NotableSymbols.count(Sym);
406   }
407
408   /// classof - Used by isa<>, cast<>, and dyn_cast<>.
409   static bool classof(const BugReporter* R) {
410     return R->getKind() == GRBugReporterKind;
411   }
412 };
413
414 class BugReporterContext {
415   GRBugReporter &BR;
416   // Not the most efficient data structure, but we use an ImmutableList for the
417   // Callbacks because it is safe to make additions to list during iteration.
418   llvm::ImmutableList<BugReporterVisitor*>::Factory F;
419   llvm::ImmutableList<BugReporterVisitor*> Callbacks;
420   llvm::FoldingSet<BugReporterVisitor> CallbacksSet;
421 public:
422   BugReporterContext(GRBugReporter& br) : BR(br), Callbacks(F.getEmptyList()) {}
423   virtual ~BugReporterContext();
424
425   void addVisitor(BugReporterVisitor* visitor);
426
427   typedef llvm::ImmutableList<BugReporterVisitor*>::iterator visitor_iterator;
428   visitor_iterator visitor_begin() { return Callbacks.begin(); }
429   visitor_iterator visitor_end() { return Callbacks.end(); }
430
431   GRBugReporter& getBugReporter() { return BR; }
432
433   ExplodedGraph &getGraph() { return BR.getGraph(); }
434
435   void addNotableSymbol(SymbolRef Sym) {
436     // FIXME: For now forward to GRBugReporter.
437     BR.addNotableSymbol(Sym);
438   }
439
440   bool isNotable(SymbolRef Sym) const {
441     // FIXME: For now forward to GRBugReporter.
442     return BR.isNotable(Sym);
443   }
444
445   GRStateManager& getStateManager() {
446     return BR.getStateManager();
447   }
448
449   SValBuilder& getSValBuilder() {
450     return getStateManager().getSValBuilder();
451   }
452
453   ASTContext& getASTContext() {
454     return BR.getContext();
455   }
456
457   SourceManager& getSourceManager() {
458     return BR.getSourceManager();
459   }
460
461   virtual BugReport::NodeResolver& getNodeResolver() = 0;
462 };
463
464 class DiagBugReport : public RangedBugReport {
465   std::list<std::string> Strs;
466   FullSourceLoc L;
467 public:
468   DiagBugReport(BugType& D, llvm::StringRef desc, FullSourceLoc l) :
469   RangedBugReport(D, desc, 0), L(l) {}
470
471   virtual ~DiagBugReport() {}
472
473   // FIXME: Move out-of-line (virtual function).
474   SourceLocation getLocation() const { return L; }
475
476   void addString(llvm::StringRef s) { Strs.push_back(s); }
477
478   typedef std::list<std::string>::const_iterator str_iterator;
479   str_iterator str_begin() const { return Strs.begin(); }
480   str_iterator str_end() const { return Strs.end(); }
481 };
482
483 //===----------------------------------------------------------------------===//
484 //===----------------------------------------------------------------------===//
485
486 namespace bugreporter {
487
488 const Stmt *GetDerefExpr(const ExplodedNode *N);
489 const Stmt *GetDenomExpr(const ExplodedNode *N);
490 const Stmt *GetCalleeExpr(const ExplodedNode *N);
491 const Stmt *GetRetValExpr(const ExplodedNode *N);
492
493 void registerTrackNullOrUndefValue(BugReporterContext& BRC, const void *stmt,
494                                    const ExplodedNode* N);
495
496 void registerFindLastStore(BugReporterContext& BRC, const void *memregion,
497                            const ExplodedNode *N);
498
499 void registerNilReceiverVisitor(BugReporterContext &BRC);
500
501 void registerVarDeclsLastStore(BugReporterContext &BRC, const void *stmt,
502                                const ExplodedNode *N);
503
504 } // end namespace clang::bugreporter
505
506 //===----------------------------------------------------------------------===//
507
508 } // end GR namespace
509
510 } // end clang namespace
511
512 #endif