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_ANALYSIS_BUGREPORTER
16 #define LLVM_CLANG_ANALYSIS_BUGREPORTER
18 #include "clang/Basic/SourceLocation.h"
19 #include "clang/GR/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"
29 class PathDiagnosticPiece
;
30 class PathDiagnosticClient
;
36 class BugReporterContext
;
43 //===----------------------------------------------------------------------===//
44 // Interface for individual bug reports.
45 //===----------------------------------------------------------------------===//
47 class BugReporterVisitor
: public llvm::FoldingSetNode
{
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
{
62 std::string ShortDescription
;
63 std::string Description
;
64 const ExplodedNode
*ErrorNode
;
65 mutable SourceRange R
;
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
);
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
) {}
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
104 // FIXME: If we do need it, we can probably just make it private to
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
); }
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
);
162 std::list
<BugReport
*>::iterator impl
;
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
;
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
;
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
) {}
209 // FIXME: Move this out of line.
210 void addRange(SourceRange 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
{
222 typedef void (*VisitorCreator
)(BugReporterContext
&BRcC
, const void *data
,
223 const ExplodedNode
*N
);
226 typedef std::vector
<std::pair
<VisitorCreator
, const void*> > Creators
;
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
{
256 virtual ~BugReporterData();
257 virtual Diagnostic
& getDiagnostic() = 0;
258 virtual PathDiagnosticClient
* getPathDiagnosticClient() = 0;
259 virtual ASTContext
& getASTContext() = 0;
260 virtual SourceManager
& getSourceManager() = 0;
265 enum Kind
{ BaseBRKind
, GRBugReporterKind
};
268 typedef llvm::ImmutableSet
<BugType
*> BugTypesTy
;
269 BugTypesTy::Factory F
;
275 void FlushReport(BugReportEquivClass
& EQ
);
278 BugReporter(BugReporterData
& d
, Kind k
) : BugTypes(F
.getEmptySet()), kind(k
),
282 BugReporter(BugReporterData
& d
) : BugTypes(F
.getEmptySet()), kind(BaseBRKind
),
284 virtual ~BugReporter();
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
,
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
,
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
{
349 llvm::SmallSet
<SymbolRef
, 10> NotableSymbols
;
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
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
{
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
;
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
;
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