aboutsummaryrefslogtreecommitdiff
path: root/include/clang/Analysis/PathSensitive/BugReporter.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/clang/Analysis/PathSensitive/BugReporter.h')
-rw-r--r--include/clang/Analysis/PathSensitive/BugReporter.h266
1 files changed, 139 insertions, 127 deletions
diff --git a/include/clang/Analysis/PathSensitive/BugReporter.h b/include/clang/Analysis/PathSensitive/BugReporter.h
index bcc28bdc5c..e0c3792323 100644
--- a/include/clang/Analysis/PathSensitive/BugReporter.h
+++ b/include/clang/Analysis/PathSensitive/BugReporter.h
@@ -23,6 +23,7 @@
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/ImmutableSet.h"
#include <list>
namespace clang {
@@ -36,100 +37,143 @@ class BugReporter;
class GRExprEngine;
class GRState;
class Stmt;
-class BugReport;
+class BugType;
class ParentMap;
-class BugType {
-public:
- BugType() {}
- virtual ~BugType();
+//===----------------------------------------------------------------------===//
+// Interface for individual bug reports.
+//===----------------------------------------------------------------------===//
- virtual const char* getName() const = 0;
- virtual const char* getDescription() const { return getName(); }
- virtual const char* getCategory() const { return ""; }
+// FIXME: Combine this with RangedBugReport and remove RangedBugReport.
+class BugReport {
+ BugType& BT;
+ std::string Description;
+ const ExplodedNode<GRState> *EndNode;
+ SourceRange R;
- virtual std::pair<const char**,const char**> getExtraDescriptiveText() {
- return std::pair<const char**, const char**>(0, 0);
+protected:
+ friend class BugReporter;
+ friend class BugReportEquivClass;
+
+ virtual void Profile(llvm::FoldingSetNodeID& hash) const {
+ hash.AddInteger(getLocation().getRawEncoding());
}
-
- virtual void EmitWarnings(BugReporter& BR) {}
- virtual void GetErrorNodes(std::vector<ExplodedNode<GRState>*>& Nodes) {}
- virtual bool isCached(BugReport& R) = 0;
-};
-
-class BugTypeCacheLocation : public BugType {
- llvm::SmallSet<ProgramPoint,10> CachedErrors;
-public:
- BugTypeCacheLocation() {}
- virtual ~BugTypeCacheLocation() {}
- virtual bool isCached(BugReport& R);
- bool isCached(ProgramPoint P);
-};
-
-
-class BugReport {
- BugType& Desc;
- const ExplodedNode<GRState> *EndNode;
- SourceRange R;
public:
- BugReport(BugType& D, const ExplodedNode<GRState> *n) : Desc(D), EndNode(n) {}
+ BugReport(BugType& bt, const char* desc, const ExplodedNode<GRState> *n)
+ : BT(bt), Description(desc), EndNode(n) {}
+
virtual ~BugReport();
+
+ const BugType& getBugType() const { return BT; }
+ BugType& getBugType() { return BT; }
- const BugType& getBugType() const { return Desc; }
- BugType& getBugType() { return Desc; }
-
+ // FIXME: Perhaps this should be moved into a subclass?
const ExplodedNode<GRState>* getEndNode() const { return EndNode; }
+ // FIXME: Do we need this? Maybe getLocation() should return a ProgramPoint
+ // object.
Stmt* getStmt(BugReporter& BR) const;
-
- const char* getName() const { return getBugType().getName(); }
-
- virtual const char* getDescription() const {
- return getBugType().getDescription();
- }
- virtual const char* getCategory() const {
- return getBugType().getCategory();
- }
+ const std::string& getDescription() const { return Description; }
+ // FIXME: Is this needed?
virtual std::pair<const char**,const char**> getExtraDescriptiveText() {
- return getBugType().getExtraDescriptiveText();
+ return std::make_pair((const char**)0,(const char**)0);
}
+ // FIXME: Perhaps move this into a subclass.
virtual PathDiagnosticPiece* getEndPath(BugReporter& BR,
const ExplodedNode<GRState>* N);
- virtual FullSourceLoc getLocation(SourceManager& Mgr);
+ /// getLocation - Return the "definitive" location of the reported bug.
+ /// While a bug can span an entire path, usually there is a specific
+ /// location that can be used to identify where the key issue occured.
+ /// This location is used by clients rendering diagnostics.
+ virtual SourceLocation getLocation() const;
+ /// getRanges - Returns the source ranges associated with this bug.
virtual void getRanges(BugReporter& BR,const SourceRange*& beg,
const SourceRange*& end);
-
+
+ // FIXME: Perhaps this should be moved into a subclass?
virtual PathDiagnosticPiece* VisitNode(const ExplodedNode<GRState>* N,
const ExplodedNode<GRState>* PrevN,
const ExplodedGraph<GRState>& G,
BugReporter& BR);
};
+
+//===----------------------------------------------------------------------===//
+// BugTypes (collections of related reports).
+//===----------------------------------------------------------------------===//
+
+class BugReportEquivClass : public llvm::FoldingSetNode {
+ // List of *owned* BugReport objects.
+ std::list<BugReport*> Reports;
+
+ friend class BugReporter;
+ void AddReport(BugReport* R) { Reports.push_back(R); }
+public:
+ BugReportEquivClass(BugReport* R) { Reports.push_back(R); }
+ ~BugReportEquivClass();
+
+ void Profile(llvm::FoldingSetNodeID& ID) const {
+ assert(!Reports.empty());
+ (*Reports.begin())->Profile(ID);
+ }
+
+ class iterator {
+ std::list<BugReport*>::iterator impl;
+ public:
+ iterator(std::list<BugReport*>::iterator i) : impl(i) {}
+ iterator& operator++() { ++impl; return *this; }
+ bool operator==(const iterator& I) const { return I.impl == impl; }
+ bool operator!=(const iterator& I) const { return I.impl != impl; }
+ BugReport* operator*() const { return *impl; }
+ BugReport* operator->() const { return *impl; }
+ };
+
+ iterator begin() { return iterator(Reports.begin()); }
+ iterator end() { return iterator(Reports.end()); }
+};
+
+class BugType {
+private:
+ const std::string Name;
+ const std::string Category;
+ llvm::FoldingSet<BugReportEquivClass> EQClasses;
+ friend class BugReporter;
+public:
+ BugType(const char *name, const char* cat) : Name(name), Category(cat) {}
+ virtual ~BugType();
+ // FIXME: Should these be made strings as well?
+ const std::string& getName() const { return Name; }
+ const std::string& getCategory() const { return Category; }
+
+ virtual void FlushReports(BugReporter& BR);
+ void AddReport(BugReport* BR);
+};
+
+//===----------------------------------------------------------------------===//
+// Specialized subclasses of BugReport.
+//===----------------------------------------------------------------------===//
+
+// FIXME: Collapse this with the default BugReport class.
class RangedBugReport : public BugReport {
std::vector<SourceRange> Ranges;
- const char* desc;
public:
- RangedBugReport(BugType& D, ExplodedNode<GRState> *n,
- const char* description = 0)
- : BugReport(D, n), desc(description) {}
+ RangedBugReport(BugType& D, const char* description, ExplodedNode<GRState> *n)
+ : BugReport(D, description, n) {}
- virtual ~RangedBugReport();
+ ~RangedBugReport();
- virtual const char* getDescription() const {
- return desc ? desc : BugReport::getDescription();
- }
-
+ // FIXME: Move this out of line.
void addRange(SourceRange R) { Ranges.push_back(R); }
-
- virtual void getRanges(BugReporter& BR,const SourceRange*& beg,
- const SourceRange*& end) {
+ // FIXME: Move this out of line.
+ void getRanges(BugReporter& BR,const SourceRange*& beg,
+ const SourceRange*& end) {
if (Ranges.empty()) {
beg = NULL;
@@ -142,6 +186,10 @@ public:
}
};
+//===----------------------------------------------------------------------===//
+// BugReporter and friends.
+//===----------------------------------------------------------------------===//
+
class BugReporterData {
public:
virtual ~BugReporterData();
@@ -158,16 +206,25 @@ class BugReporter {
public:
enum Kind { BaseBRKind, GRBugReporterKind };
-protected:
- Kind kind;
+private:
+ typedef llvm::ImmutableSet<BugType*> BugTypesTy;
+ BugTypesTy::Factory F;
+ BugTypesTy BugTypes;
+
+ const Kind kind;
BugReporterData& D;
- BugReporter(BugReporterData& d, Kind k) : kind(k), D(d) {}
-
+ void FlushReport(BugReportEquivClass& EQ);
+
+protected:
+ BugReporter(BugReporterData& d, Kind k) : BugTypes(F.GetEmptySet()), kind(k), D(d) {}
+
public:
- BugReporter(BugReporterData& d) : kind(BaseBRKind), D(d) {}
+ BugReporter(BugReporterData& d) : BugTypes(F.GetEmptySet()), kind(BaseBRKind), D(d) {}
virtual ~BugReporter();
+ void FlushReports();
+
Kind getKind() const { return kind; }
Diagnostic& getDiagnostic() {
@@ -178,29 +235,22 @@ public:
return D.getPathDiagnosticClient();
}
- ASTContext& getContext() {
- return D.getContext();
- }
+ ASTContext& getContext() { return D.getContext(); }
- SourceManager& getSourceManager() {
- return D.getSourceManager();
- }
+ SourceManager& getSourceManager() { return D.getSourceManager(); }
- CFG* getCFG() {
- return D.getCFG();
- }
+ CFG* getCFG() { return D.getCFG(); }
- ParentMap& getParentMap() {
- return D.getParentMap();
- }
+ ParentMap& getParentMap() { return D.getParentMap(); }
- LiveVariables* getLiveVariables() {
- return D.getLiveVariables();
- }
+ LiveVariables* getLiveVariables() { return D.getLiveVariables(); }
- virtual void GeneratePathDiagnostic(PathDiagnostic& PD, BugReport& R) {}
+ virtual void GeneratePathDiagnostic(PathDiagnostic& PD,
+ BugReportEquivClass& EQ) {}
- void EmitWarning(BugReport& R);
+ void Register(BugType *BT);
+
+ void EmitReport(BugReport *R);
void EmitBasicReport(const char* BugName, const char* BugStr,
SourceLocation Loc,
@@ -234,11 +284,11 @@ public:
static bool classof(const BugReporter* R) { return true; }
};
+// FIXME: Get rid of GRBugReporter. It's the wrong abstraction.
class GRBugReporter : public BugReporter {
GRExprEngine& Eng;
llvm::SmallSet<SymbolRef, 10> NotableSymbols;
-public:
-
+public:
GRBugReporter(BugReporterData& d, GRExprEngine& eng)
: BugReporter(d, GRBugReporterKind), Eng(eng) {}
@@ -246,9 +296,7 @@ public:
/// getEngine - Return the analysis engine used to analyze a given
/// function or method.
- GRExprEngine& getEngine() {
- return Eng;
- }
+ GRExprEngine& getEngine() { return Eng; }
/// getGraph - Get the exploded graph created by the analysis engine
/// for the analyzed method or function.
@@ -258,7 +306,8 @@ public:
/// engine.
GRStateManager& getStateManager();
- virtual void GeneratePathDiagnostic(PathDiagnostic& PD, BugReport& R);
+ virtual void GeneratePathDiagnostic(PathDiagnostic& PD,
+ BugReportEquivClass& R);
void addNotableSymbol(SymbolRef Sym) {
NotableSymbols.insert(Sym);
@@ -273,22 +322,18 @@ public:
return R->getKind() == GRBugReporterKind;
}
};
-
class DiagBugReport : public RangedBugReport {
std::list<std::string> Strs;
FullSourceLoc L;
- const char* description;
public:
- DiagBugReport(const char* desc, BugType& D, FullSourceLoc l) :
- RangedBugReport(D, NULL), L(l), description(desc) {}
+ DiagBugReport(BugType& D, const char* desc, FullSourceLoc l) :
+ RangedBugReport(D, desc, 0), L(l) {}
virtual ~DiagBugReport() {}
- virtual FullSourceLoc getLocation(SourceManager&) { return L; }
- virtual const char* getDescription() const {
- return description;
- }
+ // FIXME: Move out-of-line (virtual function).
+ SourceLocation getLocation() const { return L; }
void addString(const std::string& s) { Strs.push_back(s); }
@@ -297,39 +342,6 @@ public:
str_iterator str_end() const { return Strs.end(); }
};
-class DiagCollector : public DiagnosticClient {
- std::list<DiagBugReport> Reports;
- BugType& D;
-public:
- DiagCollector(BugType& d) : D(d) {}
-
- virtual ~DiagCollector() {}
-
- bool IncludeInDiagnosticCounts() const { return false; }
-
- void HandleDiagnostic(Diagnostic::Level DiagLevel,
- const DiagnosticInfo &Info);
-
- // Iterators.
- typedef std::list<DiagBugReport>::iterator iterator;
- iterator begin() { return Reports.begin(); }
- iterator end() { return Reports.end(); }
-};
-
-class SimpleBugType : public BugTypeCacheLocation {
- const char* name;
- const char* category;
- const char* desc;
-public:
- SimpleBugType(const char* n) : name(n), category(""), desc(0) {}
- SimpleBugType(const char* n, const char* c, const char* d)
- : name(n), category(c), desc(d) {}
-
- virtual const char* getName() const { return name; }
- virtual const char* getDescription() const { return desc ? desc : name; }
- virtual const char* getCategory() const { return category; }
-};
-
} // end clang namespace
#endif