BugReporter.h revision e207558e9dbed963eebf5cf31fdb02616f1545a3
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 ValueState.
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/ValueState.h"
21#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
22#include "llvm/ADT/SmallPtrSet.h"
23#include "llvm/ADT/SmallSet.h"
24#include <vector>
25#include <list>
26
27
28namespace clang {
29
30class PathDiagnostic;
31class PathDiagnosticPiece;
32class PathDiagnosticClient;
33class ASTContext;
34class Diagnostic;
35class BugReporter;
36class GRExprEngine;
37class ValueState;
38class Stmt;
39class BugReport;
40class ParentMap;
41
42class BugType {
43public:
44  BugType() {}
45  virtual ~BugType();
46
47  virtual const char* getName() const = 0;
48  virtual const char* getDescription() const { return getName(); }
49
50  virtual std::pair<const char**,const char**> getExtraDescriptiveText() {
51    return std::pair<const char**, const char**>(0, 0);
52  }
53
54  virtual void EmitWarnings(BugReporter& BR) {}
55  virtual void GetErrorNodes(std::vector<ExplodedNode<ValueState>*>& Nodes) {}
56
57  virtual bool isCached(BugReport& R) = 0;
58};
59
60class BugTypeCacheLocation : public BugType {
61  llvm::SmallPtrSet<void*,10> CachedErrors;
62public:
63  BugTypeCacheLocation() {}
64  virtual ~BugTypeCacheLocation() {}
65  virtual bool isCached(BugReport& R);
66  bool isCached(ProgramPoint P);
67};
68
69
70class BugReport {
71  BugType& Desc;
72  ExplodedNode<ValueState> *EndNode;
73  SourceRange R;
74public:
75  BugReport(BugType& D, ExplodedNode<ValueState> *n) : Desc(D), EndNode(n) {}
76  virtual ~BugReport();
77
78  const BugType& getBugType() const { return Desc; }
79  BugType& getBugType() { return Desc; }
80
81  ExplodedNode<ValueState>* getEndNode() const { return EndNode; }
82
83  Stmt* getStmt(BugReporter& BR) const;
84
85  const char* getName() const { return getBugType().getName(); }
86
87  virtual const char* getDescription() const {
88    return getBugType().getDescription();
89  }
90
91  virtual std::pair<const char**,const char**> getExtraDescriptiveText() {
92    return getBugType().getExtraDescriptiveText();
93  }
94
95  virtual PathDiagnosticPiece* getEndPath(BugReporter& BR,
96                                          ExplodedNode<ValueState>* N);
97
98  virtual FullSourceLoc getLocation(SourceManager& Mgr);
99
100  virtual void getRanges(BugReporter& BR,const SourceRange*& beg,
101                         const SourceRange*& end);
102
103  virtual PathDiagnosticPiece* VisitNode(ExplodedNode<ValueState>* N,
104                                         ExplodedNode<ValueState>* PrevN,
105                                         ExplodedGraph<ValueState>& G,
106                                         BugReporter& BR);
107};
108
109class RangedBugReport : public BugReport {
110  std::vector<SourceRange> Ranges;
111public:
112  RangedBugReport(BugType& D, ExplodedNode<ValueState> *n)
113    : BugReport(D, n) {}
114
115  virtual ~RangedBugReport();
116
117  void addRange(SourceRange R) { Ranges.push_back(R); }
118
119  virtual void getRanges(BugReporter& BR,const SourceRange*& beg,
120                         const SourceRange*& end) {
121
122    if (Ranges.empty()) {
123      beg = NULL;
124      end = NULL;
125    }
126    else {
127      beg = &Ranges[0];
128      end = beg + Ranges.size();
129    }
130  }
131};
132
133class BugReporterData {
134public:
135  virtual ~BugReporterData();
136  virtual Diagnostic& getDiagnostic() = 0;
137  virtual PathDiagnosticClient* getPathDiagnosticClient() = 0;
138  virtual ASTContext& getContext() = 0;
139  virtual SourceManager& getSourceManager() = 0;
140  virtual CFG& getCFG() = 0;
141  virtual ParentMap& getParentMap() = 0;
142  virtual LiveVariables& getLiveVariables() = 0;
143};
144
145class BugReporter {
146public:
147  enum Kind { BaseBRKind, GRBugReporterKind };
148
149protected:
150  Kind kind;
151  BugReporterData& D;
152
153  BugReporter(BugReporterData& d, Kind k) : kind(k), D(d) {}
154
155public:
156  BugReporter(BugReporterData& d) : kind(BaseBRKind), D(d) {}
157  virtual ~BugReporter();
158
159  Kind getKind() const { return kind; }
160
161  Diagnostic& getDiagnostic() {
162    return D.getDiagnostic();
163  }
164
165  PathDiagnosticClient* getPathDiagnosticClient() {
166    return D.getPathDiagnosticClient();
167  }
168
169  ASTContext& getContext() {
170    return D.getContext();
171  }
172
173  SourceManager& getSourceManager() {
174    return D.getSourceManager();
175  }
176
177  CFG& getCFG() {
178    return D.getCFG();
179  }
180
181  ParentMap& getParentMap() {
182    return D.getParentMap();
183  }
184
185  LiveVariables& getLiveVariables() {
186    return D.getLiveVariables();
187  }
188
189  virtual void GeneratePathDiagnostic(PathDiagnostic& PD, BugReport& R) {}
190
191  void EmitWarning(BugReport& R);
192
193  static bool classof(const BugReporter* R) { return true; }
194};
195
196class GRBugReporter : public BugReporter {
197  GRExprEngine& Eng;
198  llvm::SmallSet<SymbolID, 10> NotableSymbols;
199public:
200
201  GRBugReporter(BugReporterData& d, GRExprEngine& eng)
202    : BugReporter(d, GRBugReporterKind), Eng(eng) {}
203
204  virtual ~GRBugReporter();
205
206  GRExprEngine& getEngine() {
207    return Eng;
208  }
209
210  ExplodedGraph<ValueState>& getGraph();
211
212  ValueStateManager& getStateManager();
213
214  virtual void GeneratePathDiagnostic(PathDiagnostic& PD, BugReport& R);
215
216  void addNotableSymbol(SymbolID Sym) {
217    NotableSymbols.insert(Sym);
218  }
219
220  bool isNotable(SymbolID Sym) const {
221    return (bool) NotableSymbols.count(Sym);
222  }
223
224  static bool classof(const BugReporter* R) {
225    return R->getKind() == GRBugReporterKind;
226  }
227};
228
229
230class DiagBugReport : public RangedBugReport {
231  std::list<std::string> Strs;
232  FullSourceLoc L;
233  const char* description;
234public:
235  DiagBugReport(const char* desc, BugType& D, FullSourceLoc l) :
236  RangedBugReport(D, NULL), L(l), description(desc) {}
237
238  virtual ~DiagBugReport() {}
239  virtual FullSourceLoc getLocation(SourceManager&) { return L; }
240
241  virtual const char* getDescription() const {
242    return description;
243  }
244
245  void addString(const std::string& s) { Strs.push_back(s); }
246
247  typedef std::list<std::string>::const_iterator str_iterator;
248  str_iterator str_begin() const { return Strs.begin(); }
249  str_iterator str_end() const { return Strs.end(); }
250};
251
252class DiagCollector : public DiagnosticClient {
253  std::list<DiagBugReport> Reports;
254  BugType& D;
255public:
256  DiagCollector(BugType& d) : D(d) {}
257
258  virtual ~DiagCollector() {}
259
260  virtual void HandleDiagnostic(Diagnostic &Diags,
261                                Diagnostic::Level DiagLevel,
262                                FullSourceLoc Pos,
263                                diag::kind ID,
264                                const std::string *Strs,
265                                unsigned NumStrs,
266                                const SourceRange *Ranges,
267                                unsigned NumRanges) {
268
269    // FIXME: Use a map from diag::kind to BugType, instead of having just
270    //  one BugType.
271
272    Reports.push_back(DiagBugReport(Diags.getDescription(ID), D, Pos));
273    DiagBugReport& R = Reports.back();
274
275    for ( ; NumRanges ; --NumRanges, ++Ranges)
276      R.addRange(*Ranges);
277
278    for ( ; NumStrs ; --NumStrs, ++Strs)
279      R.addString(*Strs);
280  }
281
282  // Iterators.
283
284  typedef std::list<DiagBugReport>::iterator iterator;
285  iterator begin() { return Reports.begin(); }
286  iterator end() { return Reports.end(); }
287};
288
289} // end clang namespace
290
291#endif
292