1 //===--- BugReporter.h - Generate PathDiagnostics --------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file defines BugReporter, a utility class for generating
11 // PathDiagnostics for analyses based on GRState.
13 //===----------------------------------------------------------------------===//
15 #ifndef LLVM_CLANG_GR_BUGREPORTER
16 #define LLVM_CLANG_GR_BUGREPORTER
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"
36 class PathDiagnosticPiece;
37 class PathDiagnosticClient;
41 class BugReporterContext;
46 //===----------------------------------------------------------------------===//
47 // Interface for individual bug reports.
48 //===----------------------------------------------------------------------===//
50 class BugReporterVisitor : public llvm::FoldingSetNode {
52 virtual ~BugReporterVisitor();
53 virtual PathDiagnosticPiece* VisitNode(const ExplodedNode* N,
54 const ExplodedNode* PrevN,
55 BugReporterContext& BRC) = 0;
57 virtual bool isOwnedByReporterContext() { return true; }
58 virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0;
61 // FIXME: Combine this with RangedBugReport and remove RangedBugReport.
62 class BugReport : public BugReporterVisitor {
65 std::string ShortDescription;
66 std::string Description;
67 const ExplodedNode *ErrorNode;
68 mutable SourceRange R;
71 friend class BugReporter;
72 friend class BugReportEquivClass;
74 virtual void Profile(llvm::FoldingSetNodeID& hash) const {
76 hash.AddInteger(getLocation().getRawEncoding());
77 hash.AddString(Description);
83 virtual ~NodeResolver() {}
84 virtual const ExplodedNode*
85 getOriginalNode(const ExplodedNode* N) = 0;
88 BugReport(BugType& bt, llvm::StringRef desc, const ExplodedNode *errornode)
89 : BT(bt), Description(desc), ErrorNode(errornode) {}
91 BugReport(BugType& bt, llvm::StringRef shortDesc, llvm::StringRef desc,
92 const ExplodedNode *errornode)
93 : BT(bt), ShortDescription(shortDesc), Description(desc),
94 ErrorNode(errornode) {}
98 virtual bool isOwnedByReporterContext() { return false; }
100 const BugType& getBugType() const { return BT; }
101 BugType& getBugType() { return BT; }
103 // FIXME: Perhaps this should be moved into a subclass?
104 const ExplodedNode* getErrorNode() const { return ErrorNode; }
106 // FIXME: Do we need this? Maybe getLocation() should return a ProgramPoint
108 // FIXME: If we do need it, we can probably just make it private to
110 const Stmt* getStmt() const;
112 const llvm::StringRef getDescription() const { return Description; }
114 const llvm::StringRef getShortDescription() const {
115 return ShortDescription.empty() ? Description : ShortDescription;
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);
123 // FIXME: Perhaps move this into a subclass.
124 virtual PathDiagnosticPiece* getEndPath(BugReporterContext& BRC,
125 const ExplodedNode* N);
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;
133 typedef const SourceRange *ranges_iterator;
135 /// getRanges - Returns the source ranges associated with this bug.
136 virtual std::pair<ranges_iterator, ranges_iterator> getRanges() const;
138 virtual PathDiagnosticPiece* VisitNode(const ExplodedNode* N,
139 const ExplodedNode* PrevN,
140 BugReporterContext& BR);
142 virtual void registerInitialVisitors(BugReporterContext& BRC,
143 const ExplodedNode* N) {}
146 //===----------------------------------------------------------------------===//
147 // BugTypes (collections of related reports).
148 //===----------------------------------------------------------------------===//
150 class BugReportEquivClass : public llvm::FoldingSetNode {
151 // List of *owned* BugReport objects.
152 std::list<BugReport*> Reports;
154 friend class BugReporter;
155 void AddReport(BugReport* R) { Reports.push_back(R); }
157 BugReportEquivClass(BugReport* R) { Reports.push_back(R); }
158 ~BugReportEquivClass();
160 void Profile(llvm::FoldingSetNodeID& ID) const {
161 assert(!Reports.empty());
162 (*Reports.begin())->Profile(ID);
166 std::list<BugReport*>::iterator impl;
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; }
176 class const_iterator {
177 std::list<BugReport*>::const_iterator impl;
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; }
187 iterator begin() { return iterator(Reports.begin()); }
188 iterator end() { return iterator(Reports.end()); }
190 const_iterator begin() const { return const_iterator(Reports.begin()); }
191 const_iterator end() const { return const_iterator(Reports.end()); }
195 //===----------------------------------------------------------------------===//
196 // Specialized subclasses of BugReport.
197 //===----------------------------------------------------------------------===//
199 // FIXME: Collapse this with the default BugReport class.
200 class RangedBugReport : public BugReport {
201 llvm::SmallVector<SourceRange, 4> Ranges;
203 RangedBugReport(BugType& D, llvm::StringRef description,
204 ExplodedNode *errornode)
205 : BugReport(D, description, errornode) {}
207 RangedBugReport(BugType& D, llvm::StringRef shortDescription,
208 llvm::StringRef description, ExplodedNode *errornode)
209 : BugReport(D, shortDescription, description, errornode) {}
213 // FIXME: Move this out of line.
214 void addRange(SourceRange R) {
219 virtual std::pair<ranges_iterator, ranges_iterator> getRanges() const {
220 return std::make_pair(Ranges.begin(), Ranges.end());
224 class EnhancedBugReport : public RangedBugReport {
226 typedef void (*VisitorCreator)(BugReporterContext &BRcC, const void *data,
227 const ExplodedNode *N);
230 typedef std::vector<std::pair<VisitorCreator, const void*> > Creators;
234 EnhancedBugReport(BugType& D, llvm::StringRef description,
235 ExplodedNode *errornode)
236 : RangedBugReport(D, description, errornode) {}
238 EnhancedBugReport(BugType& D, llvm::StringRef shortDescription,
239 llvm::StringRef description, ExplodedNode *errornode)
240 : RangedBugReport(D, shortDescription, description, errornode) {}
242 ~EnhancedBugReport() {}
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);
249 void addVisitorCreator(VisitorCreator creator, const void *data) {
250 creators.push_back(std::make_pair(creator, data));
254 //===----------------------------------------------------------------------===//
255 // BugReporter and friends.
256 //===----------------------------------------------------------------------===//
258 class BugReporterData {
260 virtual ~BugReporterData();
261 virtual Diagnostic& getDiagnostic() = 0;
262 virtual PathDiagnosticClient* getPathDiagnosticClient() = 0;
263 virtual ASTContext& getASTContext() = 0;
264 virtual SourceManager& getSourceManager() = 0;
269 enum Kind { BaseBRKind, GRBugReporterKind };
272 typedef llvm::ImmutableSet<BugType*> BugTypesTy;
273 BugTypesTy::Factory F;
279 void FlushReport(BugReportEquivClass& EQ);
281 llvm::FoldingSet<BugReportEquivClass> EQClasses;
284 BugReporter(BugReporterData& d, Kind k) : BugTypes(F.getEmptySet()), kind(k),
288 BugReporter(BugReporterData& d) : BugTypes(F.getEmptySet()), kind(BaseBRKind),
290 virtual ~BugReporter();
294 Kind getKind() const { return kind; }
296 Diagnostic& getDiagnostic() {
297 return D.getDiagnostic();
300 PathDiagnosticClient* getPathDiagnosticClient() {
301 return D.getPathDiagnosticClient();
304 typedef BugTypesTy::iterator iterator;
305 iterator begin() { return BugTypes.begin(); }
306 iterator end() { return BugTypes.end(); }
308 typedef llvm::FoldingSet<BugReportEquivClass>::iterator EQClasses_iterator;
309 EQClasses_iterator EQClasses_begin() { return EQClasses.begin(); }
310 EQClasses_iterator EQClasses_end() { return EQClasses.end(); }
312 ASTContext& getContext() { return D.getASTContext(); }
314 SourceManager& getSourceManager() { return D.getSourceManager(); }
316 virtual void GeneratePathDiagnostic(PathDiagnostic& pathDiagnostic,
317 llvm::SmallVectorImpl<BugReport *> &bugReports) {}
319 void Register(BugType *BT);
321 void EmitReport(BugReport *R);
323 void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr,
325 SourceRange* RangeBeg, unsigned NumRanges);
327 void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugCategory,
328 llvm::StringRef BugStr, SourceLocation Loc,
329 SourceRange* RangeBeg, unsigned NumRanges);
332 void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr,
333 SourceLocation Loc) {
334 EmitBasicReport(BugName, BugStr, Loc, 0, 0);
337 void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugCategory,
338 llvm::StringRef BugStr, SourceLocation Loc) {
339 EmitBasicReport(BugName, BugCategory, BugStr, Loc, 0, 0);
342 void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr,
343 SourceLocation Loc, SourceRange R) {
344 EmitBasicReport(BugName, BugStr, Loc, &R, 1);
347 void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef Category,
348 llvm::StringRef BugStr, SourceLocation Loc,
350 EmitBasicReport(BugName, Category, BugStr, Loc, &R, 1);
353 static bool classof(const BugReporter* R) { return true; }
356 llvm::StringMap<BugType *> StrBugTypes;
358 /// \brief Returns a BugType that is associated with the given name and
360 BugType *getBugTypeForName(llvm::StringRef name, llvm::StringRef category);
363 // FIXME: Get rid of GRBugReporter. It's the wrong abstraction.
364 class GRBugReporter : public BugReporter {
366 llvm::SmallSet<SymbolRef, 10> NotableSymbols;
368 GRBugReporter(BugReporterData& d, ExprEngine& eng)
369 : BugReporter(d, GRBugReporterKind), Eng(eng) {}
371 virtual ~GRBugReporter();
373 /// getEngine - Return the analysis engine used to analyze a given
374 /// function or method.
375 ExprEngine &getEngine() { return Eng; }
377 /// getGraph - Get the exploded graph created by the analysis engine
378 /// for the analyzed method or function.
379 ExplodedGraph &getGraph();
381 /// getStateManager - Return the state manager used by the analysis
383 GRStateManager &getStateManager();
385 virtual void GeneratePathDiagnostic(PathDiagnostic &pathDiagnostic,
386 llvm::SmallVectorImpl<BugReport*> &bugReports);
388 void addNotableSymbol(SymbolRef Sym) {
389 NotableSymbols.insert(Sym);
392 bool isNotable(SymbolRef Sym) const {
393 return (bool) NotableSymbols.count(Sym);
396 /// classof - Used by isa<>, cast<>, and dyn_cast<>.
397 static bool classof(const BugReporter* R) {
398 return R->getKind() == GRBugReporterKind;
402 class BugReporterContext {
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;
410 BugReporterContext(GRBugReporter& br) : BR(br), Callbacks(F.getEmptyList()) {}
411 virtual ~BugReporterContext();
413 void addVisitor(BugReporterVisitor* visitor);
415 typedef llvm::ImmutableList<BugReporterVisitor*>::iterator visitor_iterator;
416 visitor_iterator visitor_begin() { return Callbacks.begin(); }
417 visitor_iterator visitor_end() { return Callbacks.end(); }
419 GRBugReporter& getBugReporter() { return BR; }
421 ExplodedGraph &getGraph() { return BR.getGraph(); }
423 void addNotableSymbol(SymbolRef Sym) {
424 // FIXME: For now forward to GRBugReporter.
425 BR.addNotableSymbol(Sym);
428 bool isNotable(SymbolRef Sym) const {
429 // FIXME: For now forward to GRBugReporter.
430 return BR.isNotable(Sym);
433 GRStateManager& getStateManager() {
434 return BR.getStateManager();
437 SValBuilder& getSValBuilder() {
438 return getStateManager().getSValBuilder();
441 ASTContext& getASTContext() {
442 return BR.getContext();
445 SourceManager& getSourceManager() {
446 return BR.getSourceManager();
449 virtual BugReport::NodeResolver& getNodeResolver() = 0;
452 class DiagBugReport : public RangedBugReport {
453 std::list<std::string> Strs;
456 DiagBugReport(BugType& D, llvm::StringRef desc, FullSourceLoc l) :
457 RangedBugReport(D, desc, 0), L(l) {}
459 virtual ~DiagBugReport() {}
461 // FIXME: Move out-of-line (virtual function).
462 SourceLocation getLocation() const { return L; }
464 void addString(llvm::StringRef s) { Strs.push_back(s); }
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(); }
471 //===----------------------------------------------------------------------===//
472 //===----------------------------------------------------------------------===//
474 namespace bugreporter {
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);
481 void registerTrackNullOrUndefValue(BugReporterContext& BRC, const void *stmt,
482 const ExplodedNode* N);
484 void registerFindLastStore(BugReporterContext& BRC, const void *memregion,
485 const ExplodedNode *N);
487 void registerNilReceiverVisitor(BugReporterContext &BRC);
489 void registerVarDeclsLastStore(BugReporterContext &BRC, const void *stmt,
490 const ExplodedNode *N);
492 } // end namespace clang::bugreporter
494 //===----------------------------------------------------------------------===//
496 } // end GR namespace
498 } // end clang namespace