BugReporter.h revision 3aa1ab27c14d16c853ccb61f17a4a75d8e366806
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_ANALYSIS_BUGREPORTER
16#define LLVM_CLANG_ANALYSIS_BUGREPORTER
17
18#include "clang/Basic/Diagnostic.h"
19#include "clang/Basic/SourceLocation.h"
20#include "clang/Analysis/PathSensitive/GRState.h"
21#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
22#include "llvm/ADT/SmallPtrSet.h"
23#include "llvm/ADT/SmallSet.h"
24#include "llvm/ADT/SmallString.h"
25#include "llvm/ADT/StringExtras.h"
26#include "llvm/ADT/ImmutableSet.h"
27#include <list>
28
29namespace clang {
30
31class PathDiagnostic;
32class PathDiagnosticPiece;
33class PathDiagnosticClient;
34class ASTContext;
35class Diagnostic;
36class BugReporter;
37class GRExprEngine;
38class GRState;
39class Stmt;
40class BugType;
41class ParentMap;
42
43//===----------------------------------------------------------------------===//
44// Interface for individual bug reports.
45//===----------------------------------------------------------------------===//
46
47// FIXME: Combine this with RangedBugReport and remove RangedBugReport.
48class BugReport {
49protected:
50  BugType& BT;
51  std::string Description;
52  const ExplodedNode<GRState> *EndNode;
53  SourceRange R;
54
55protected:
56  friend class BugReporter;
57  friend class BugReportEquivClass;
58
59  virtual void Profile(llvm::FoldingSetNodeID& hash) const {
60    hash.AddInteger(getLocation().getRawEncoding());
61  }
62
63public:
64  class NodeResolver {
65  public:
66    virtual ~NodeResolver() {}
67    virtual const ExplodedNode<GRState>*
68            getOriginalNode(const ExplodedNode<GRState>* N) = 0;
69  };
70
71  BugReport(BugType& bt, const char* desc, const ExplodedNode<GRState> *n)
72    : BT(bt), Description(desc), EndNode(n) {}
73
74  virtual ~BugReport();
75
76  const BugType& getBugType() const { return BT; }
77  BugType& getBugType() { return BT; }
78
79  // FIXME: Perhaps this should be moved into a subclass?
80  const ExplodedNode<GRState>* getEndNode() const { return EndNode; }
81
82  // FIXME: Do we need this?  Maybe getLocation() should return a ProgramPoint
83  // object.
84  Stmt* getStmt(BugReporter& BR) const;
85
86  const std::string& getDescription() const { return Description; }
87
88  // FIXME: Is this needed?
89  virtual std::pair<const char**,const char**> getExtraDescriptiveText() {
90    return std::make_pair((const char**)0,(const char**)0);
91  }
92
93  // FIXME: Perhaps move this into a subclass.
94  virtual PathDiagnosticPiece* getEndPath(BugReporter& BR,
95                                          const ExplodedNode<GRState>* N);
96
97  /// getLocation - Return the "definitive" location of the reported bug.
98  ///  While a bug can span an entire path, usually there is a specific
99  ///  location that can be used to identify where the key issue occured.
100  ///  This location is used by clients rendering diagnostics.
101  virtual SourceLocation getLocation() const;
102
103  /// getRanges - Returns the source ranges associated with this bug.
104  virtual void getRanges(BugReporter& BR,const SourceRange*& beg,
105                         const SourceRange*& end);
106
107  // FIXME: Perhaps this should be moved into a subclass?
108  virtual PathDiagnosticPiece* VisitNode(const ExplodedNode<GRState>* N,
109                                         const ExplodedNode<GRState>* PrevN,
110                                         const ExplodedGraph<GRState>& G,
111                                         BugReporter& BR,
112                                         NodeResolver& NR);
113};
114
115//===----------------------------------------------------------------------===//
116// BugTypes (collections of related reports).
117//===----------------------------------------------------------------------===//
118
119class BugReportEquivClass : public llvm::FoldingSetNode {
120  // List of *owned* BugReport objects.
121  std::list<BugReport*> Reports;
122
123  friend class BugReporter;
124  void AddReport(BugReport* R) { Reports.push_back(R); }
125public:
126  BugReportEquivClass(BugReport* R) { Reports.push_back(R); }
127  ~BugReportEquivClass();
128
129  void Profile(llvm::FoldingSetNodeID& ID) const {
130    assert(!Reports.empty());
131    (*Reports.begin())->Profile(ID);
132  }
133
134  class iterator {
135    std::list<BugReport*>::iterator impl;
136  public:
137    iterator(std::list<BugReport*>::iterator i) : impl(i) {}
138    iterator& operator++() { ++impl; return *this; }
139    bool operator==(const iterator& I) const { return I.impl == impl; }
140    bool operator!=(const iterator& I) const { return I.impl != impl; }
141    BugReport* operator*() const { return *impl; }
142    BugReport* operator->() const { return *impl; }
143  };
144
145  class const_iterator {
146    std::list<BugReport*>::const_iterator impl;
147  public:
148    const_iterator(std::list<BugReport*>::const_iterator i) : impl(i) {}
149    const_iterator& operator++() { ++impl; return *this; }
150    bool operator==(const const_iterator& I) const { return I.impl == impl; }
151    bool operator!=(const const_iterator& I) const { return I.impl != impl; }
152    const BugReport* operator*() const { return *impl; }
153    const BugReport* operator->() const { return *impl; }
154  };
155
156  iterator begin() { return iterator(Reports.begin()); }
157  iterator end() { return iterator(Reports.end()); }
158
159  const_iterator begin() const { return const_iterator(Reports.begin()); }
160  const_iterator end() const { return const_iterator(Reports.end()); }
161};
162
163class BugType {
164private:
165  const std::string Name;
166  const std::string Category;
167  llvm::FoldingSet<BugReportEquivClass> EQClasses;
168  friend class BugReporter;
169public:
170  BugType(const char *name, const char* cat) : Name(name), Category(cat) {}
171  virtual ~BugType();
172
173  // FIXME: Should these be made strings as well?
174  const std::string& getName() const { return Name; }
175  const std::string& getCategory() const { return Category; }
176
177  virtual void FlushReports(BugReporter& BR);
178  void AddReport(BugReport* BR);
179
180  typedef llvm::FoldingSet<BugReportEquivClass>::iterator iterator;
181  iterator begin() { return EQClasses.begin(); }
182  iterator end() { return EQClasses.end(); }
183
184  typedef llvm::FoldingSet<BugReportEquivClass>::const_iterator const_iterator;
185  const_iterator begin() const { return EQClasses.begin(); }
186  const_iterator end() const { return EQClasses.end(); }
187};
188
189//===----------------------------------------------------------------------===//
190// Specialized subclasses of BugReport.
191//===----------------------------------------------------------------------===//
192
193// FIXME: Collapse this with the default BugReport class.
194class RangedBugReport : public BugReport {
195  std::vector<SourceRange> Ranges;
196public:
197  RangedBugReport(BugType& D, const char* description, ExplodedNode<GRState> *n)
198    : BugReport(D, description, n) {}
199
200  ~RangedBugReport();
201
202  // FIXME: Move this out of line.
203  void addRange(SourceRange R) { Ranges.push_back(R); }
204
205  // FIXME: Move this out of line.
206  void getRanges(BugReporter& BR,const SourceRange*& beg,
207                 const SourceRange*& end) {
208
209    if (Ranges.empty()) {
210      beg = NULL;
211      end = NULL;
212    }
213    else {
214      beg = &Ranges[0];
215      end = beg + Ranges.size();
216    }
217  }
218};
219
220//===----------------------------------------------------------------------===//
221// BugReporter and friends.
222//===----------------------------------------------------------------------===//
223
224class BugReporterData {
225public:
226  virtual ~BugReporterData();
227  virtual Diagnostic& getDiagnostic() = 0;
228  virtual PathDiagnosticClient* getPathDiagnosticClient() = 0;
229  virtual ASTContext& getContext() = 0;
230  virtual SourceManager& getSourceManager() = 0;
231  virtual CFG* getCFG() = 0;
232  virtual ParentMap& getParentMap() = 0;
233  virtual LiveVariables* getLiveVariables() = 0;
234};
235
236class BugReporter {
237public:
238  enum Kind { BaseBRKind, GRBugReporterKind };
239
240private:
241  typedef llvm::ImmutableSet<BugType*> BugTypesTy;
242  BugTypesTy::Factory F;
243  BugTypesTy BugTypes;
244
245  const Kind kind;
246  BugReporterData& D;
247
248  void FlushReport(BugReportEquivClass& EQ);
249
250protected:
251  BugReporter(BugReporterData& d, Kind k) : BugTypes(F.GetEmptySet()), kind(k), D(d) {}
252
253public:
254  BugReporter(BugReporterData& d) : BugTypes(F.GetEmptySet()), kind(BaseBRKind), D(d) {}
255  virtual ~BugReporter();
256
257  void FlushReports();
258
259  Kind getKind() const { return kind; }
260
261  Diagnostic& getDiagnostic() {
262    return D.getDiagnostic();
263  }
264
265  PathDiagnosticClient* getPathDiagnosticClient() {
266    return D.getPathDiagnosticClient();
267  }
268
269  typedef BugTypesTy::iterator iterator;
270  iterator begin() { return BugTypes.begin(); }
271  iterator end() { return BugTypes.end(); }
272
273  ASTContext& getContext() { return D.getContext(); }
274
275  SourceManager& getSourceManager() { return D.getSourceManager(); }
276
277  CFG* getCFG() { return D.getCFG(); }
278
279  ParentMap& getParentMap() { return D.getParentMap(); }
280
281  LiveVariables* getLiveVariables() { return D.getLiveVariables(); }
282
283  virtual void GeneratePathDiagnostic(PathDiagnostic& PD,
284                                      BugReportEquivClass& EQ) {}
285
286  void Register(BugType *BT);
287
288  void EmitReport(BugReport *R);
289
290  void EmitBasicReport(const char* BugName, const char* BugStr,
291                       SourceLocation Loc,
292                       SourceRange* RangeBeg, unsigned NumRanges);
293
294  void EmitBasicReport(const char* BugName, const char* BugCategory,
295                       const char* BugStr, SourceLocation Loc,
296                       SourceRange* RangeBeg, unsigned NumRanges);
297
298
299  void EmitBasicReport(const char* BugName, const char* BugStr,
300                       SourceLocation Loc) {
301    EmitBasicReport(BugName, BugStr, Loc, 0, 0);
302  }
303
304  void EmitBasicReport(const char* BugName, const char* BugCategory,
305                       const char* BugStr, SourceLocation Loc) {
306    EmitBasicReport(BugName, BugCategory, BugStr, Loc, 0, 0);
307  }
308
309  void EmitBasicReport(const char* BugName, const char* BugStr,
310                       SourceLocation Loc, SourceRange R) {
311    EmitBasicReport(BugName, BugStr, Loc, &R, 1);
312  }
313
314  void EmitBasicReport(const char* BugName, const char* Category,
315                       const char* BugStr, SourceLocation Loc, SourceRange R) {
316    EmitBasicReport(BugName, Category, BugStr, Loc, &R, 1);
317  }
318
319  static bool classof(const BugReporter* R) { return true; }
320};
321
322// FIXME: Get rid of GRBugReporter.  It's the wrong abstraction.
323class GRBugReporter : public BugReporter {
324  GRExprEngine& Eng;
325  llvm::SmallSet<SymbolRef, 10> NotableSymbols;
326public:
327  GRBugReporter(BugReporterData& d, GRExprEngine& eng)
328    : BugReporter(d, GRBugReporterKind), Eng(eng) {}
329
330  virtual ~GRBugReporter();
331
332  /// getEngine - Return the analysis engine used to analyze a given
333  ///  function or method.
334  GRExprEngine& getEngine() { return Eng; }
335
336  /// getGraph - Get the exploded graph created by the analysis engine
337  ///  for the analyzed method or function.
338  ExplodedGraph<GRState>& getGraph();
339
340  /// getStateManager - Return the state manager used by the analysis
341  ///  engine.
342  GRStateManager& getStateManager();
343
344  virtual void GeneratePathDiagnostic(PathDiagnostic& PD,
345                                      BugReportEquivClass& R);
346
347  void addNotableSymbol(SymbolRef Sym) {
348    NotableSymbols.insert(Sym);
349  }
350
351  bool isNotable(SymbolRef Sym) const {
352    return (bool) NotableSymbols.count(Sym);
353  }
354
355  /// classof - Used by isa<>, cast<>, and dyn_cast<>.
356  static bool classof(const BugReporter* R) {
357    return R->getKind() == GRBugReporterKind;
358  }
359};
360
361class DiagBugReport : public RangedBugReport {
362  std::list<std::string> Strs;
363  FullSourceLoc L;
364public:
365  DiagBugReport(BugType& D, const char* desc, FullSourceLoc l) :
366  RangedBugReport(D, desc, 0), L(l) {}
367
368  virtual ~DiagBugReport() {}
369
370  // FIXME: Move out-of-line (virtual function).
371  SourceLocation getLocation() const { return L; }
372
373  void addString(const std::string& s) { Strs.push_back(s); }
374
375  typedef std::list<std::string>::const_iterator str_iterator;
376  str_iterator str_begin() const { return Strs.begin(); }
377  str_iterator str_end() const { return Strs.end(); }
378};
379
380} // end clang namespace
381
382#endif
383