Implicitly expand argument packs when performing template argument
[clang.git] / include / clang / Checker / BugReporter / BugReporter.h
blob031693d6d7b69337862f16f9371086c2b6a5fb19
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.
13 //===----------------------------------------------------------------------===//
15 #ifndef LLVM_CLANG_ANALYSIS_BUGREPORTER
16 #define LLVM_CLANG_ANALYSIS_BUGREPORTER
18 #include "clang/Basic/SourceLocation.h"
19 #include "clang/Checker/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>
26 namespace clang {
28 class PathDiagnostic;
29 class PathDiagnosticPiece;
30 class PathDiagnosticClient;
31 class ASTContext;
32 class Diagnostic;
33 class ExplodedNode;
34 class ExplodedGraph;
35 class BugReporter;
36 class BugReporterContext;
37 class GRExprEngine;
38 class GRState;
39 class Stmt;
40 class BugType;
41 class ParentMap;
43 //===----------------------------------------------------------------------===//
44 // Interface for individual bug reports.
45 //===----------------------------------------------------------------------===//
47 class BugReporterVisitor : public llvm::FoldingSetNode {
48 public:
49 virtual ~BugReporterVisitor();
50 virtual PathDiagnosticPiece* VisitNode(const ExplodedNode* N,
51 const ExplodedNode* PrevN,
52 BugReporterContext& BRC) = 0;
54 virtual bool isOwnedByReporterContext() { return true; }
55 virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0;
58 // FIXME: Combine this with RangedBugReport and remove RangedBugReport.
59 class BugReport : public BugReporterVisitor {
60 protected:
61 BugType& BT;
62 std::string ShortDescription;
63 std::string Description;
64 const ExplodedNode *ErrorNode;
65 mutable SourceRange R;
67 protected:
68 friend class BugReporter;
69 friend class BugReportEquivClass;
71 virtual void Profile(llvm::FoldingSetNodeID& hash) const {
72 hash.AddInteger(getLocation().getRawEncoding());
73 hash.AddString(Description);
76 public:
77 class NodeResolver {
78 public:
79 virtual ~NodeResolver() {}
80 virtual const ExplodedNode*
81 getOriginalNode(const ExplodedNode* N) = 0;
84 BugReport(BugType& bt, llvm::StringRef desc, const ExplodedNode *errornode)
85 : BT(bt), Description(desc), ErrorNode(errornode) {}
87 BugReport(BugType& bt, llvm::StringRef shortDesc, llvm::StringRef desc,
88 const ExplodedNode *errornode)
89 : BT(bt), ShortDescription(shortDesc), Description(desc),
90 ErrorNode(errornode) {}
92 virtual ~BugReport();
94 virtual bool isOwnedByReporterContext() { return false; }
96 const BugType& getBugType() const { return BT; }
97 BugType& getBugType() { return BT; }
99 // FIXME: Perhaps this should be moved into a subclass?
100 const ExplodedNode* getErrorNode() const { return ErrorNode; }
102 // FIXME: Do we need this? Maybe getLocation() should return a ProgramPoint
103 // object.
104 // FIXME: If we do need it, we can probably just make it private to
105 // BugReporter.
106 const Stmt* getStmt() const;
108 const llvm::StringRef getDescription() const { return Description; }
110 const llvm::StringRef getShortDescription() const {
111 return ShortDescription.empty() ? Description : ShortDescription;
114 // FIXME: Is this needed?
115 virtual std::pair<const char**,const char**> getExtraDescriptiveText() {
116 return std::make_pair((const char**)0,(const char**)0);
119 // FIXME: Perhaps move this into a subclass.
120 virtual PathDiagnosticPiece* getEndPath(BugReporterContext& BRC,
121 const ExplodedNode* N);
123 /// getLocation - Return the "definitive" location of the reported bug.
124 /// While a bug can span an entire path, usually there is a specific
125 /// location that can be used to identify where the key issue occured.
126 /// This location is used by clients rendering diagnostics.
127 virtual SourceLocation getLocation() const;
129 typedef const SourceRange *ranges_iterator;
131 /// getRanges - Returns the source ranges associated with this bug.
132 virtual std::pair<ranges_iterator, ranges_iterator> getRanges() const;
134 virtual PathDiagnosticPiece* VisitNode(const ExplodedNode* N,
135 const ExplodedNode* PrevN,
136 BugReporterContext& BR);
138 virtual void registerInitialVisitors(BugReporterContext& BRC,
139 const ExplodedNode* N) {}
142 //===----------------------------------------------------------------------===//
143 // BugTypes (collections of related reports).
144 //===----------------------------------------------------------------------===//
146 class BugReportEquivClass : public llvm::FoldingSetNode {
147 // List of *owned* BugReport objects.
148 std::list<BugReport*> Reports;
150 friend class BugReporter;
151 void AddReport(BugReport* R) { Reports.push_back(R); }
152 public:
153 BugReportEquivClass(BugReport* R) { Reports.push_back(R); }
154 ~BugReportEquivClass();
156 void Profile(llvm::FoldingSetNodeID& ID) const {
157 assert(!Reports.empty());
158 (*Reports.begin())->Profile(ID);
161 class iterator {
162 std::list<BugReport*>::iterator impl;
163 public:
164 iterator(std::list<BugReport*>::iterator i) : impl(i) {}
165 iterator& operator++() { ++impl; return *this; }
166 bool operator==(const iterator& I) const { return I.impl == impl; }
167 bool operator!=(const iterator& I) const { return I.impl != impl; }
168 BugReport* operator*() const { return *impl; }
169 BugReport* operator->() const { return *impl; }
172 class const_iterator {
173 std::list<BugReport*>::const_iterator impl;
174 public:
175 const_iterator(std::list<BugReport*>::const_iterator i) : impl(i) {}
176 const_iterator& operator++() { ++impl; return *this; }
177 bool operator==(const const_iterator& I) const { return I.impl == impl; }
178 bool operator!=(const const_iterator& I) const { return I.impl != impl; }
179 const BugReport* operator*() const { return *impl; }
180 const BugReport* operator->() const { return *impl; }
183 iterator begin() { return iterator(Reports.begin()); }
184 iterator end() { return iterator(Reports.end()); }
186 const_iterator begin() const { return const_iterator(Reports.begin()); }
187 const_iterator end() const { return const_iterator(Reports.end()); }
191 //===----------------------------------------------------------------------===//
192 // Specialized subclasses of BugReport.
193 //===----------------------------------------------------------------------===//
195 // FIXME: Collapse this with the default BugReport class.
196 class RangedBugReport : public BugReport {
197 llvm::SmallVector<SourceRange, 4> Ranges;
198 public:
199 RangedBugReport(BugType& D, llvm::StringRef description,
200 ExplodedNode *errornode)
201 : BugReport(D, description, errornode) {}
203 RangedBugReport(BugType& D, llvm::StringRef shortDescription,
204 llvm::StringRef description, ExplodedNode *errornode)
205 : BugReport(D, shortDescription, description, errornode) {}
207 ~RangedBugReport();
209 // FIXME: Move this out of line.
210 void addRange(SourceRange R) {
211 assert(R.isValid());
212 Ranges.push_back(R);
215 virtual std::pair<ranges_iterator, ranges_iterator> getRanges() const {
216 return std::make_pair(Ranges.begin(), Ranges.end());
220 class EnhancedBugReport : public RangedBugReport {
221 public:
222 typedef void (*VisitorCreator)(BugReporterContext &BRcC, const void *data,
223 const ExplodedNode *N);
225 private:
226 typedef std::vector<std::pair<VisitorCreator, const void*> > Creators;
227 Creators creators;
229 public:
230 EnhancedBugReport(BugType& D, llvm::StringRef description,
231 ExplodedNode *errornode)
232 : RangedBugReport(D, description, errornode) {}
234 EnhancedBugReport(BugType& D, llvm::StringRef shortDescription,
235 llvm::StringRef description, ExplodedNode *errornode)
236 : RangedBugReport(D, shortDescription, description, errornode) {}
238 ~EnhancedBugReport() {}
240 void registerInitialVisitors(BugReporterContext& BRC, const ExplodedNode* N) {
241 for (Creators::iterator I = creators.begin(), E = creators.end(); I!=E; ++I)
242 I->first(BRC, I->second, N);
245 void addVisitorCreator(VisitorCreator creator, const void *data) {
246 creators.push_back(std::make_pair(creator, data));
250 //===----------------------------------------------------------------------===//
251 // BugReporter and friends.
252 //===----------------------------------------------------------------------===//
254 class BugReporterData {
255 public:
256 virtual ~BugReporterData();
257 virtual Diagnostic& getDiagnostic() = 0;
258 virtual PathDiagnosticClient* getPathDiagnosticClient() = 0;
259 virtual ASTContext& getASTContext() = 0;
260 virtual SourceManager& getSourceManager() = 0;
263 class BugReporter {
264 public:
265 enum Kind { BaseBRKind, GRBugReporterKind };
267 private:
268 typedef llvm::ImmutableSet<BugType*> BugTypesTy;
269 BugTypesTy::Factory F;
270 BugTypesTy BugTypes;
272 const Kind kind;
273 BugReporterData& D;
275 void FlushReport(BugReportEquivClass& EQ);
277 protected:
278 BugReporter(BugReporterData& d, Kind k) : BugTypes(F.getEmptySet()), kind(k),
279 D(d) {}
281 public:
282 BugReporter(BugReporterData& d) : BugTypes(F.getEmptySet()), kind(BaseBRKind),
283 D(d) {}
284 virtual ~BugReporter();
286 void FlushReports();
288 Kind getKind() const { return kind; }
290 Diagnostic& getDiagnostic() {
291 return D.getDiagnostic();
294 PathDiagnosticClient* getPathDiagnosticClient() {
295 return D.getPathDiagnosticClient();
298 typedef BugTypesTy::iterator iterator;
299 iterator begin() { return BugTypes.begin(); }
300 iterator end() { return BugTypes.end(); }
302 ASTContext& getContext() { return D.getASTContext(); }
304 SourceManager& getSourceManager() { return D.getSourceManager(); }
306 virtual void GeneratePathDiagnostic(PathDiagnostic& pathDiagnostic,
307 llvm::SmallVectorImpl<BugReport *> &bugReports) {}
309 void Register(BugType *BT);
311 void EmitReport(BugReport *R);
313 void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr,
314 SourceLocation Loc,
315 SourceRange* RangeBeg, unsigned NumRanges);
317 void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugCategory,
318 llvm::StringRef BugStr, SourceLocation Loc,
319 SourceRange* RangeBeg, unsigned NumRanges);
322 void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr,
323 SourceLocation Loc) {
324 EmitBasicReport(BugName, BugStr, Loc, 0, 0);
327 void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugCategory,
328 llvm::StringRef BugStr, SourceLocation Loc) {
329 EmitBasicReport(BugName, BugCategory, BugStr, Loc, 0, 0);
332 void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr,
333 SourceLocation Loc, SourceRange R) {
334 EmitBasicReport(BugName, BugStr, Loc, &R, 1);
337 void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef Category,
338 llvm::StringRef BugStr, SourceLocation Loc,
339 SourceRange R) {
340 EmitBasicReport(BugName, Category, BugStr, Loc, &R, 1);
343 static bool classof(const BugReporter* R) { return true; }
346 // FIXME: Get rid of GRBugReporter. It's the wrong abstraction.
347 class GRBugReporter : public BugReporter {
348 GRExprEngine& Eng;
349 llvm::SmallSet<SymbolRef, 10> NotableSymbols;
350 public:
351 GRBugReporter(BugReporterData& d, GRExprEngine& eng)
352 : BugReporter(d, GRBugReporterKind), Eng(eng) {}
354 virtual ~GRBugReporter();
356 /// getEngine - Return the analysis engine used to analyze a given
357 /// function or method.
358 GRExprEngine &getEngine() { return Eng; }
360 /// getGraph - Get the exploded graph created by the analysis engine
361 /// for the analyzed method or function.
362 ExplodedGraph &getGraph();
364 /// getStateManager - Return the state manager used by the analysis
365 /// engine.
366 GRStateManager &getStateManager();
368 virtual void GeneratePathDiagnostic(PathDiagnostic &pathDiagnostic,
369 llvm::SmallVectorImpl<BugReport*> &bugReports);
371 void addNotableSymbol(SymbolRef Sym) {
372 NotableSymbols.insert(Sym);
375 bool isNotable(SymbolRef Sym) const {
376 return (bool) NotableSymbols.count(Sym);
379 /// classof - Used by isa<>, cast<>, and dyn_cast<>.
380 static bool classof(const BugReporter* R) {
381 return R->getKind() == GRBugReporterKind;
385 class BugReporterContext {
386 GRBugReporter &BR;
387 // Not the most efficient data structure, but we use an ImmutableList for the
388 // Callbacks because it is safe to make additions to list during iteration.
389 llvm::ImmutableList<BugReporterVisitor*>::Factory F;
390 llvm::ImmutableList<BugReporterVisitor*> Callbacks;
391 llvm::FoldingSet<BugReporterVisitor> CallbacksSet;
392 public:
393 BugReporterContext(GRBugReporter& br) : BR(br), Callbacks(F.getEmptyList()) {}
394 virtual ~BugReporterContext();
396 void addVisitor(BugReporterVisitor* visitor);
398 typedef llvm::ImmutableList<BugReporterVisitor*>::iterator visitor_iterator;
399 visitor_iterator visitor_begin() { return Callbacks.begin(); }
400 visitor_iterator visitor_end() { return Callbacks.end(); }
402 GRBugReporter& getBugReporter() { return BR; }
404 ExplodedGraph &getGraph() { return BR.getGraph(); }
406 void addNotableSymbol(SymbolRef Sym) {
407 // FIXME: For now forward to GRBugReporter.
408 BR.addNotableSymbol(Sym);
411 bool isNotable(SymbolRef Sym) const {
412 // FIXME: For now forward to GRBugReporter.
413 return BR.isNotable(Sym);
416 GRStateManager& getStateManager() {
417 return BR.getStateManager();
420 SValBuilder& getSValBuilder() {
421 return getStateManager().getSValBuilder();
424 ASTContext& getASTContext() {
425 return BR.getContext();
428 SourceManager& getSourceManager() {
429 return BR.getSourceManager();
432 virtual BugReport::NodeResolver& getNodeResolver() = 0;
435 class DiagBugReport : public RangedBugReport {
436 std::list<std::string> Strs;
437 FullSourceLoc L;
438 public:
439 DiagBugReport(BugType& D, llvm::StringRef desc, FullSourceLoc l) :
440 RangedBugReport(D, desc, 0), L(l) {}
442 virtual ~DiagBugReport() {}
444 // FIXME: Move out-of-line (virtual function).
445 SourceLocation getLocation() const { return L; }
447 void addString(llvm::StringRef s) { Strs.push_back(s); }
449 typedef std::list<std::string>::const_iterator str_iterator;
450 str_iterator str_begin() const { return Strs.begin(); }
451 str_iterator str_end() const { return Strs.end(); }
454 //===----------------------------------------------------------------------===//
455 //===----------------------------------------------------------------------===//
457 namespace bugreporter {
459 const Stmt *GetDerefExpr(const ExplodedNode *N);
460 const Stmt *GetDenomExpr(const ExplodedNode *N);
461 const Stmt *GetCalleeExpr(const ExplodedNode *N);
462 const Stmt *GetRetValExpr(const ExplodedNode *N);
464 void registerTrackNullOrUndefValue(BugReporterContext& BRC, const void *stmt,
465 const ExplodedNode* N);
467 void registerFindLastStore(BugReporterContext& BRC, const void *memregion,
468 const ExplodedNode *N);
470 void registerNilReceiverVisitor(BugReporterContext &BRC);
472 void registerVarDeclsLastStore(BugReporterContext &BRC, const void *stmt,
473 const ExplodedNode *N);
475 } // end namespace clang::bugreporter
477 //===----------------------------------------------------------------------===//
479 } // end clang namespace
481 #endif