aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Analysis/PathSensitive/BugReporter.h79
-rw-r--r--include/clang/Analysis/PathSensitive/ExplodedGraph.h14
-rw-r--r--include/clang/Analysis/PathSensitive/GRCoreEngine.h68
-rw-r--r--include/clang/Analysis/PathSensitive/GRExprEngine.h74
-rw-r--r--include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h4
-rw-r--r--include/clang/Analysis/PathSensitive/GRTransferFuncs.h2
-rw-r--r--lib/Analysis/BasicObjCFoundationChecks.cpp92
-rw-r--r--lib/Analysis/BugReporter.cpp76
-rw-r--r--lib/Analysis/CFRefCount.cpp12
-rw-r--r--lib/Analysis/GRExprEngine.cpp62
-rw-r--r--lib/Analysis/GRSimpleVals.cpp308
-rw-r--r--lib/Analysis/GRSimpleVals.h2
12 files changed, 474 insertions, 319 deletions
diff --git a/include/clang/Analysis/PathSensitive/BugReporter.h b/include/clang/Analysis/PathSensitive/BugReporter.h
index 7ff79fc53d..9f8b17ac00 100644
--- a/include/clang/Analysis/PathSensitive/BugReporter.h
+++ b/include/clang/Analysis/PathSensitive/BugReporter.h
@@ -19,9 +19,6 @@
#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
#include "llvm/ADT/SmallPtrSet.h"
-// FIXME: ExplodedGraph<> should be templated on state, not the checker engine.
-#include "clang/Analysis/PathSensitive/GRExprEngine.h"
-
namespace clang {
class PathDiagnostic;
@@ -29,61 +26,79 @@ class PathDiagnosticPiece;
class PathDiagnosticClient;
class ASTContext;
class Diagnostic;
-
-class BugDescription {
+class BugReporter;
+class GRExprEngine;
+class ValueState;
+
+class BugType {
public:
- BugDescription() {}
- virtual ~BugDescription() {}
+ BugType() {}
+ virtual ~BugType();
virtual const char* getName() const = 0;
+ virtual const char* getDescription() const { return getName(); }
+
+ virtual void EmitWarnings(BugReporter& BR) {}
+};
- virtual const char* getDescription() const = 0;
+class BugReport {
+ const BugType& Desc;
+
+public:
+ BugReport(const BugType& D) : Desc(D) {}
+ virtual ~BugReport();
+
+ const BugType& getBugType() const { return Desc; }
+
+ const char* getName() const { return getBugType().getName(); }
+ const char* getDescription() const { return getBugType().getDescription(); }
virtual PathDiagnosticPiece* getEndPath(ASTContext& Ctx,
ExplodedNode<ValueState> *N) const;
virtual void getRanges(const SourceRange*& beg,
const SourceRange*& end) const;
-};
-
-class BugReporterHelper {
-public:
- virtual ~BugReporterHelper() {}
virtual PathDiagnosticPiece* VisitNode(ExplodedNode<ValueState>* N,
ExplodedNode<ValueState>* PrevN,
- ExplodedGraph<GRExprEngine>& G,
- ASTContext& Ctx) = 0;
+ ExplodedGraph<ValueState>& G,
+ ASTContext& Ctx);
};
class BugReporter {
llvm::SmallPtrSet<void*,10> CachedErrors;
+ Diagnostic& Diag;
+ PathDiagnosticClient* PD;
+ ASTContext& Ctx;
+ GRExprEngine& Eng;
public:
- BugReporter() {}
+ BugReporter(Diagnostic& diag, PathDiagnosticClient* pd,
+ ASTContext& ctx, GRExprEngine& eng)
+ : Diag(diag), PD(pd), Ctx(ctx), Eng(eng) {}
+
~BugReporter();
- void EmitPathWarning(Diagnostic& Diag, PathDiagnosticClient* PDC,
- ASTContext& Ctx, const BugDescription& B,
- ExplodedGraph<GRExprEngine>& G,
- ExplodedNode<ValueState>* N,
- BugReporterHelper** BegHelpers = NULL,
- BugReporterHelper** EndHelpers = NULL);
+ Diagnostic& getDiagnostic() { return Diag; }
+
+ PathDiagnosticClient* getDiagnosticClient() { return PD; }
- void EmitWarning(Diagnostic& Diag, ASTContext& Ctx,
- const BugDescription& B,
- ExplodedNode<ValueState>* N);
+ ASTContext& getContext() { return Ctx; }
+ ExplodedGraph<ValueState>& getGraph();
-private:
+ GRExprEngine& getEngine() { return Eng; }
+
+ void EmitPathWarning(BugReport& R, ExplodedNode<ValueState>* N);
+
+ void EmitWarning(BugReport& R, ExplodedNode<ValueState>* N);
+
+ void clearCache() { CachedErrors.clear(); }
+
bool IsCached(ExplodedNode<ValueState>* N);
- void GeneratePathDiagnostic(PathDiagnostic& PD, ASTContext& Ctx,
- const BugDescription& B,
- ExplodedGraph<GRExprEngine>& G,
- ExplodedNode<ValueState>* N,
- BugReporterHelper** BegHelpers = NULL,
- BugReporterHelper** EndHelpers = NULL);
+ void GeneratePathDiagnostic(PathDiagnostic& PD, BugReport& R,
+ ExplodedNode<ValueState>* N);
};
} // end clang namespace
diff --git a/include/clang/Analysis/PathSensitive/ExplodedGraph.h b/include/clang/Analysis/PathSensitive/ExplodedGraph.h
index 30d95605ea..8db069639b 100644
--- a/include/clang/Analysis/PathSensitive/ExplodedGraph.h
+++ b/include/clang/Analysis/PathSensitive/ExplodedGraph.h
@@ -278,17 +278,14 @@ public:
};
-template <typename CHECKER>
+template <typename STATE>
class ExplodedGraph : public ExplodedGraphImpl {
public:
- typedef CHECKER CheckerTy;
- typedef typename CHECKER::StateTy StateTy;
+ typedef STATE StateTy;
typedef ExplodedNode<StateTy> NodeTy;
typedef llvm::FoldingSet<NodeTy> AllNodesTy;
protected:
- llvm::OwningPtr<CheckerTy> CheckerState;
-
/// Nodes - The nodes in the graph.
AllNodesTy Nodes;
@@ -305,12 +302,7 @@ protected:
public:
ExplodedGraph(CFG& c, Decl& cd, ASTContext& ctx)
- : ExplodedGraphImpl(c, cd, ctx), CheckerState(new CheckerTy(*this)) {}
-
- /// getCheckerState - Returns the internal checker state associated
- /// with the exploded graph. Ownership remains with the ExplodedGraph
- /// objecct.
- CheckerTy* getCheckerState() const { return CheckerState.get(); }
+ : ExplodedGraphImpl(c, cd, ctx) {}
/// getNode - Retrieve the node associated with a (Location,State) pair,
/// where the 'Location' is a ProgramPoint in the CFG. If no node for
diff --git a/include/clang/Analysis/PathSensitive/GRCoreEngine.h b/include/clang/Analysis/PathSensitive/GRCoreEngine.h
index 35fddadf33..5b7aeb5975 100644
--- a/include/clang/Analysis/PathSensitive/GRCoreEngine.h
+++ b/include/clang/Analysis/PathSensitive/GRCoreEngine.h
@@ -111,7 +111,7 @@ protected:
public:
/// ExecuteWorkList - Run the worklist algorithm for a maximum number of
/// steps. Returns true if there is still simulation state on the worklist.
- bool ExecuteWorkList(unsigned Steps = 1000000);
+ bool ExecuteWorkList(unsigned Steps);
virtual ~GRCoreEngineImpl() {}
@@ -309,11 +309,10 @@ public:
}
};
-template<typename CHECKER>
+template<typename STATE>
class GRBranchNodeBuilder {
- typedef CHECKER CheckerTy;
- typedef typename CheckerTy::StateTy StateTy;
- typedef ExplodedGraph<CheckerTy> GraphTy;
+ typedef STATE StateTy;
+ typedef ExplodedGraph<StateTy> GraphTy;
typedef typename GraphTy::NodeTy NodeTy;
GRBranchNodeBuilderImpl& NB;
@@ -392,11 +391,10 @@ public:
inline void* getState() const { return Pred->State; }
};
-template<typename CHECKER>
+template<typename STATE>
class GRIndirectGotoNodeBuilder {
- typedef CHECKER CheckerTy;
- typedef typename CheckerTy::StateTy StateTy;
- typedef ExplodedGraph<CheckerTy> GraphTy;
+ typedef STATE StateTy;
+ typedef ExplodedGraph<StateTy> GraphTy;
typedef typename GraphTy::NodeTy NodeTy;
GRIndirectGotoNodeBuilderImpl& NB;
@@ -459,11 +457,10 @@ public:
inline void* getState() const { return Pred->State; }
};
-template<typename CHECKER>
+template<typename STATE>
class GRSwitchNodeBuilder {
- typedef CHECKER CheckerTy;
- typedef typename CheckerTy::StateTy StateTy;
- typedef ExplodedGraph<CheckerTy> GraphTy;
+ typedef STATE StateTy;
+ typedef ExplodedGraph<StateTy> GraphTy;
typedef typename GraphTy::NodeTy NodeTy;
GRSwitchNodeBuilderImpl& NB;
@@ -492,21 +489,19 @@ public:
};
-template<typename CHECKER>
+template<typename SUBENGINE>
class GRCoreEngine : public GRCoreEngineImpl {
public:
- typedef CHECKER CheckerTy;
- typedef typename CheckerTy::StateTy StateTy;
- typedef ExplodedGraph<CheckerTy> GraphTy;
+ typedef SUBENGINE SubEngineTy;
+ typedef typename SubEngineTy::StateTy StateTy;
+ typedef ExplodedGraph<StateTy> GraphTy;
typedef typename GraphTy::NodeTy NodeTy;
protected:
- // A local reference to the checker that avoids an indirect access
- // via the Graph.
- CheckerTy* Checker;
+ SubEngineTy& SubEngine;
virtual void* getInitialState() {
- return getCheckerState().getInitialState();
+ return SubEngine.getInitialState();
}
virtual void* ProcessEOP(CFGBlock* Blk, void* State) {
@@ -516,44 +511,44 @@ protected:
virtual void ProcessStmt(Stmt* S, GRStmtNodeBuilderImpl& BuilderImpl) {
GRStmtNodeBuilder<StateTy> Builder(BuilderImpl);
- Checker->ProcessStmt(S, Builder);
+ SubEngine.ProcessStmt(S, Builder);
}
virtual bool ProcessBlockEntrance(CFGBlock* Blk, void* State,
GRBlockCounter BC) {
- return Checker->ProcessBlockEntrance(Blk,
- static_cast<StateTy*>(State), BC);
+ return SubEngine.ProcessBlockEntrance(Blk, static_cast<StateTy*>(State),BC);
}
virtual void ProcessBranch(Expr* Condition, Stmt* Terminator,
GRBranchNodeBuilderImpl& BuilderImpl) {
- GRBranchNodeBuilder<CHECKER> Builder(BuilderImpl);
- Checker->ProcessBranch(Condition, Terminator, Builder);
+ GRBranchNodeBuilder<StateTy> Builder(BuilderImpl);
+ SubEngine.ProcessBranch(Condition, Terminator, Builder);
}
virtual void ProcessIndirectGoto(GRIndirectGotoNodeBuilderImpl& BuilderImpl) {
- GRIndirectGotoNodeBuilder<CHECKER> Builder(BuilderImpl);
- Checker->ProcessIndirectGoto(Builder);
+ GRIndirectGotoNodeBuilder<StateTy> Builder(BuilderImpl);
+ SubEngine.ProcessIndirectGoto(Builder);
}
virtual void ProcessSwitch(GRSwitchNodeBuilderImpl& BuilderImpl) {
- GRSwitchNodeBuilder<CHECKER> Builder(BuilderImpl);
- Checker->ProcessSwitch(Builder);
+ GRSwitchNodeBuilder<StateTy> Builder(BuilderImpl);
+ SubEngine.ProcessSwitch(Builder);
}
public:
/// Construct a GRCoreEngine object to analyze the provided CFG using
/// a DFS exploration of the exploded graph.
- GRCoreEngine(CFG& cfg, Decl& cd, ASTContext& ctx)
+ GRCoreEngine(CFG& cfg, Decl& cd, ASTContext& ctx, SubEngineTy& subengine)
: GRCoreEngineImpl(new GraphTy(cfg, cd, ctx), GRWorkList::MakeDFS()),
- Checker(static_cast<GraphTy*>(G.get())->getCheckerState()) {}
+ SubEngine(subengine) {}
/// Construct a GRCoreEngine object to analyze the provided CFG and to
/// use the provided worklist object to execute the worklist algorithm.
/// The GRCoreEngine object assumes ownership of 'wlist'.
- GRCoreEngine(CFG& cfg, Decl& cd, ASTContext& ctx, GRWorkList* wlist)
+ GRCoreEngine(CFG& cfg, Decl& cd, ASTContext& ctx, GRWorkList* wlist,
+ SubEngineTy& subengine)
: GRCoreEngineImpl(new GraphTy(cfg, cd, ctx), wlist),
- Checker(static_cast<GraphTy*>(G.get())->getCheckerState()) {}
+ SubEngine(subengine) {}
virtual ~GRCoreEngine() {}
@@ -562,11 +557,6 @@ public:
return *static_cast<GraphTy*>(G.get());
}
- /// getCheckerState - Returns the internal checker state.
- CheckerTy& getCheckerState() {
- return *Checker;
- }
-
/// takeGraph - Returns the exploded graph. Ownership of the graph is
/// transfered to the caller.
GraphTy* takeGraph() {
diff --git a/include/clang/Analysis/PathSensitive/GRExprEngine.h b/include/clang/Analysis/PathSensitive/GRExprEngine.h
index e88b377a97..473b658b67 100644
--- a/include/clang/Analysis/PathSensitive/GRExprEngine.h
+++ b/include/clang/Analysis/PathSensitive/GRExprEngine.h
@@ -21,26 +21,30 @@
#include "clang/Analysis/PathSensitive/GRSimpleAPICheck.h"
#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
-namespace clang {
+namespace clang {
- class StatelessChecks;
+ class BugType;
+ class PathDiagnosticClient;
+ class Diagnostic;
class GRExprEngine {
public:
typedef ValueState StateTy;
- typedef ExplodedGraph<GRExprEngine> GraphTy;
+ typedef ExplodedGraph<StateTy> GraphTy;
typedef GraphTy::NodeTy NodeTy;
// Builders.
- typedef GRStmtNodeBuilder<StateTy> StmtNodeBuilder;
- typedef GRBranchNodeBuilder<GRExprEngine> BranchNodeBuilder;
- typedef GRIndirectGotoNodeBuilder<GRExprEngine> IndirectGotoNodeBuilder;
- typedef GRSwitchNodeBuilder<GRExprEngine> SwitchNodeBuilder;
- typedef ExplodedNodeSet<StateTy> NodeSet;
+ typedef GRStmtNodeBuilder<StateTy> StmtNodeBuilder;
+ typedef GRBranchNodeBuilder<StateTy> BranchNodeBuilder;
+ typedef GRIndirectGotoNodeBuilder<StateTy> IndirectGotoNodeBuilder;
+ typedef GRSwitchNodeBuilder<StateTy> SwitchNodeBuilder;
+ typedef ExplodedNodeSet<StateTy> NodeSet;
protected:
+ GRCoreEngine<GRExprEngine> CoreEngine;
+
/// G - the simulation graph.
GraphTy& G;
@@ -62,6 +66,10 @@ protected:
/// for manipulating and creating RVals.
GRTransferFuncs* TF;
+ /// BugTypes - Objects used for reporting bugs.
+ typedef std::vector<BugType*> BugTypeSet;
+ BugTypeSet BugTypes;
+
/// SymMgr - Object that manages the symbol information.
SymbolManager& SymMgr;
@@ -154,18 +162,11 @@ protected:
UndefArgsTy MsgExprUndefArgs;
public:
- GRExprEngine(GraphTy& g) :
- G(g), Liveness(G.getCFG()),
- Builder(NULL),
- StateMgr(G.getContext(), G.getAllocator()),
- BasicVals(StateMgr.getBasicValueFactory()),
- TF(NULL), // FIXME.
- SymMgr(StateMgr.getSymbolManager()),
- StmtEntryNode(NULL), CleanedState(NULL), CurrentStmt(NULL) {
-
- // Compute liveness information.
- Liveness.runOnCFG(G.getCFG());
- Liveness.runOnAllBlocks(G.getCFG(), NULL, true);
+ GRExprEngine(CFG& cfg, Decl& CD, ASTContext& Ctx);
+ ~GRExprEngine();
+
+ void ExecuteWorkList(unsigned Steps = 150000) {
+ CoreEngine.ExecuteWorkList(Steps);
}
/// getContext - Return the ASTContext associated with this analysis.
@@ -175,8 +176,11 @@ public:
CFG& getCFG() { return G.getCFG(); }
/// setTransferFunctions
- void setTransferFunctions(GRTransferFuncs* tf) { TF = tf; }
- void setTransferFunctions(GRTransferFuncs& tf) { TF = &tf; }
+ void setTransferFunctions(GRTransferFuncs* tf);
+
+ void setTransferFunctions(GRTransferFuncs& tf) {
+ setTransferFunctions(&tf);
+ }
/// ViewGraph - Visualize the ExplodedGraph created by executing the
/// simulation.
@@ -188,6 +192,24 @@ public:
/// in the ExplodedGraph.
ValueState* getInitialState();
+ GraphTy& getGraph() { return G; }
+ const GraphTy& getGraph() const { return G; }
+
+ typedef BugTypeSet::iterator bug_type_iterator;
+ typedef BugTypeSet::const_iterator const_bug_type_iterator;
+
+ bug_type_iterator bug_types_begin() { return BugTypes.begin(); }
+ bug_type_iterator bug_types_end() { return BugTypes.end(); }
+
+ const_bug_type_iterator bug_types_begin() const { return BugTypes.begin(); }
+ const_bug_type_iterator bug_types_end() const { return BugTypes.end(); }
+
+ void Register(BugType* B) {
+ BugTypes.push_back(B);
+ }
+
+ void EmitWarnings(Diagnostic& Diag, PathDiagnosticClient* PD);
+
bool isRetStackAddr(const NodeTy* N) const {
return N->isSink() && RetsStackAddr.count(const_cast<NodeTy*>(N)) != 0;
}
@@ -317,13 +339,9 @@ public:
return MsgExprChecks.end();
}
- void AddCallCheck(GRSimpleAPICheck* A) {
- CallChecks.push_back(A);
- }
+ void AddCallCheck(GRSimpleAPICheck* A);
- void AddObjCMessageExprCheck(GRSimpleAPICheck* A) {
- MsgExprChecks.push_back(A);
- }
+ void AddObjCMessageExprCheck(GRSimpleAPICheck* A);
/// ProcessStmt - Called by GRCoreEngine. Used to generate new successor
/// nodes by processing the 'effects' of a block-level statement.
diff --git a/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h b/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h
index 16b23c558c..782ddcfffe 100644
--- a/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h
+++ b/include/clang/Analysis/PathSensitive/GRSimpleAPICheck.h
@@ -33,9 +33,7 @@ class GRSimpleAPICheck : public GRAuditor<ValueState> {
public:
GRSimpleAPICheck() {}
virtual ~GRSimpleAPICheck() {}
- virtual void ReportResults(Diagnostic& Diag, PathDiagnosticClient* PD,
- ASTContext& Ctx, BugReporter& BR,
- ExplodedGraph<GRExprEngine>& G) = 0;
+ virtual void EmitWarnings(BugReporter& BR) = 0;
};
} // end namespace clang
diff --git a/include/clang/Analysis/PathSensitive/GRTransferFuncs.h b/include/clang/Analysis/PathSensitive/GRTransferFuncs.h
index 55a0fae273..9c68f20e74 100644
--- a/include/clang/Analysis/PathSensitive/GRTransferFuncs.h
+++ b/include/clang/Analysis/PathSensitive/GRTransferFuncs.h
@@ -32,6 +32,8 @@ public:
return NULL;
}
+ virtual void RegisterChecks(GRExprEngine& Eng) {}
+
// Casts.
virtual RVal EvalCast(GRExprEngine& Engine, NonLVal V, QualType CastT) =0;
diff --git a/lib/Analysis/BasicObjCFoundationChecks.cpp b/lib/Analysis/BasicObjCFoundationChecks.cpp
index 6149abefa3..154adcaa47 100644
--- a/lib/Analysis/BasicObjCFoundationChecks.cpp
+++ b/lib/Analysis/BasicObjCFoundationChecks.cpp
@@ -54,51 +54,61 @@ static const char* GetReceiverNameType(ObjCMessageExpr* ME) {
namespace {
-class VISIBILITY_HIDDEN NilArg : public BugDescription {
- std::string Msg;
- const char* s;
- SourceRange R;
+class VISIBILITY_HIDDEN NilArg : public BugType {
public:
- NilArg(ObjCMessageExpr* ME, unsigned Arg);
virtual ~NilArg() {}
virtual const char* getName() const {
return "nil argument";
}
- virtual const char* getDescription() const {
- return s;
- }
-
- virtual void getRanges(const SourceRange*& beg,
- const SourceRange*& end) const {
- beg = &R;
- end = beg+1;
- }
+ class Report : public BugReport {
+ std::string Msg;
+ const char* s;
+ SourceRange R;
+ public:
+ Report(NilArg& Desc, ObjCMessageExpr* ME, unsigned Arg) : BugReport(Desc) {
+
+ Expr* E = ME->getArg(Arg);
+ R = E->getSourceRange();
+
+ std::ostringstream os;
+
+ os << "Argument to '" << GetReceiverNameType(ME) << "' method '"
+ << ME->getSelector().getName() << "' cannot be nil.";
+
+ Msg = os.str();
+ s = Msg.c_str();
+ }
+
+ virtual ~Report() {}
+
+ virtual PathDiagnosticPiece* getEndPath(ASTContext& Ctx,
+ ExplodedNode<ValueState> *N) const {
+
+ Stmt* S = cast<PostStmt>(N->getLocation()).getStmt();
+
+ if (!S)
+ return NULL;
+
+ FullSourceLoc L(S->getLocStart(), Ctx.getSourceManager());
+ PathDiagnosticPiece* P = new PathDiagnosticPiece(L, s);
+
+ P->addRange(R);
+
+ return P;
+ }
+ };
};
-
-NilArg::NilArg(ObjCMessageExpr* ME, unsigned Arg) : s(NULL) {
-
- Expr* E = ME->getArg(Arg);
- R = E->getSourceRange();
-
- std::ostringstream os;
-
- os << "Argument to '" << GetReceiverNameType(ME) << "' method '"
- << ME->getSelector().getName() << "' cannot be nil.";
-
- Msg = os.str();
- s = Msg.c_str();
-}
-
+
class VISIBILITY_HIDDEN BasicObjCFoundationChecks : public GRSimpleAPICheck {
-
+ NilArg Desc;
ASTContext &Ctx;
ValueStateManager* VMgr;
- typedef std::vector<std::pair<NodeTy*,BugDescription*> > ErrorsTy;
+ typedef std::vector<std::pair<NodeTy*,BugReport*> > ErrorsTy;
ErrorsTy Errors;
RVal GetRVal(ValueState* St, Expr* E) { return VMgr->GetRVal(St, E); }
@@ -122,18 +132,16 @@ public:
virtual bool Audit(ExplodedNode<ValueState>* N);
- virtual void ReportResults(Diagnostic& Diag, PathDiagnosticClient* PD,
- ASTContext& Ctx, BugReporter& BR,
- ExplodedGraph<GRExprEngine>& G);
+ virtual void EmitWarnings(BugReporter& BR);
private:
- void AddError(NodeTy* N, BugDescription* D) {
- Errors.push_back(std::make_pair(N, D));
+ void AddError(NodeTy* N, BugReport* R) {
+ Errors.push_back(std::make_pair(N, R));
}
void WarnNilArg(NodeTy* N, ObjCMessageExpr* ME, unsigned Arg) {
- AddError(N, new NilArg(ME, Arg));
+ AddError(N, new NilArg::Report(Desc, ME, Arg));
}
};
@@ -186,13 +194,11 @@ static inline bool isNil(RVal X) {
//===----------------------------------------------------------------------===//
-void BasicObjCFoundationChecks::ReportResults(Diagnostic& Diag,
- PathDiagnosticClient* PD,
- ASTContext& Ctx, BugReporter& BR,
- ExplodedGraph<GRExprEngine>& G) {
-
+void BasicObjCFoundationChecks::EmitWarnings(BugReporter& BR) {
+
for (ErrorsTy::iterator I=Errors.begin(), E=Errors.end(); I!=E; ++I)
- BR.EmitPathWarning(Diag, PD, Ctx, *I->second, G, I->first);
+
+ BR.EmitPathWarning(*I->second, I->first);
}
bool BasicObjCFoundationChecks::CheckNilArg(NodeTy* N, unsigned Arg) {
diff --git a/lib/Analysis/BugReporter.cpp b/lib/Analysis/BugReporter.cpp
index 66b1b04c9d..c851696a30 100644
--- a/lib/Analysis/BugReporter.cpp
+++ b/lib/Analysis/BugReporter.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/AST/ASTContext.h"
@@ -25,6 +26,9 @@
using namespace clang;
BugReporter::~BugReporter() {}
+BugType::~BugType() {}
+BugReport::~BugReport() {}
+ExplodedGraph<ValueState>& BugReporter::getGraph() { return Eng.getGraph(); }
static inline Stmt* GetStmt(const ProgramPoint& P) {
if (const PostStmt* PS = dyn_cast<PostStmt>(&P)) {
@@ -48,7 +52,7 @@ static inline Stmt* GetStmt(const CFGBlock* B) {
PathDiagnosticPiece*
-BugDescription::getEndPath(ASTContext& Ctx, ExplodedNode<ValueState> *N) const {
+BugReport::getEndPath(ASTContext& Ctx, ExplodedNode<ValueState> *N) const {
Stmt* S = GetStmt(N->getLocation());
@@ -56,7 +60,9 @@ BugDescription::getEndPath(ASTContext& Ctx, ExplodedNode<ValueState> *N) const {
return NULL;
FullSourceLoc L(S->getLocStart(), Ctx.getSourceManager());
- PathDiagnosticPiece* P = new PathDiagnosticPiece(L, getDescription());
+
+ PathDiagnosticPiece* P =
+ new PathDiagnosticPiece(L, getDescription());
const SourceRange *Beg, *End;
getRanges(Beg, End);
@@ -74,34 +80,38 @@ BugDescription::getEndPath(ASTContext& Ctx, ExplodedNode<ValueState> *N) const {
return P;
}
-void BugDescription::getRanges(const SourceRange*& beg,
- const SourceRange*& end) const {
+void BugReport::getRanges(const SourceRange*& beg,
+ const SourceRange*& end) const {
beg = NULL;
end = NULL;
}
-void BugReporter::GeneratePathDiagnostic(PathDiagnostic& PD, ASTContext& Ctx,
- const BugDescription& B,
- ExplodedGraph<GRExprEngine>& G,
- ExplodedNode<ValueState>* N,
- BugReporterHelper** BegHelpers,
- BugReporterHelper** EndHelpers) {
-
- if (PathDiagnosticPiece* Piece = B.getEndPath(Ctx,N))
+PathDiagnosticPiece* BugReport::VisitNode(ExplodedNode<ValueState>* N,
+ ExplodedNode<ValueState>* PrevN,
+ ExplodedGraph<ValueState>& G,
+ ASTContext& Ctx) {
+ return NULL;
+}
+
+void BugReporter::GeneratePathDiagnostic(PathDiagnostic& PD,
+ BugReport& R,
+ ExplodedNode<ValueState>* N) {
+
+ if (PathDiagnosticPiece* Piece = R.getEndPath(Ctx,N))
PD.push_back(Piece);
else
return;
SourceManager& SMgr = Ctx.getSourceManager();
- llvm::OwningPtr<ExplodedGraph<GRExprEngine> > GTrim(G.Trim(&N, &N+1));
+ llvm::OwningPtr<ExplodedGraph<ValueState> > GTrim(getGraph().Trim(&N, &N+1));
// Find the sink in the trimmed graph.
// FIXME: Should we eventually have a sink iterator?
ExplodedNode<ValueState>* NewN = 0;
- for (ExplodedGraph<GRExprEngine>::node_iterator
+ for (ExplodedGraph<ValueState>::node_iterator
I = GTrim->nodes_begin(), E = GTrim->nodes_end(); I != E; ++I) {
if (I->isSink()) {
@@ -292,13 +302,8 @@ void BugReporter::GeneratePathDiagnostic(PathDiagnostic& PD, ASTContext& Ctx,
}
}
else
- for (BugReporterHelper** I = BegHelpers; I != EndHelpers; ++I) {
-
- PathDiagnosticPiece* piece = (*I)->VisitNode(N, NextNode, G, Ctx);
-
- if (piece)
- PD.push_front(piece);
- }
+ if (PathDiagnosticPiece* piece = R.VisitNode(N, NextNode, *GTrim, Ctx))
+ PD.push_front(piece);
}
}
@@ -318,39 +323,30 @@ bool BugReporter::IsCached(ExplodedNode<ValueState>* N) {
return false;
}
-void BugReporter::EmitPathWarning(Diagnostic& Diag,
- PathDiagnosticClient* PDC,
- ASTContext& Ctx,
- const BugDescription& B,
- ExplodedGraph<GRExprEngine>& G,
- ExplodedNode<ValueState>* N,
- BugReporterHelper** BegHelpers,
- BugReporterHelper** EndHelpers) {
+void BugReporter::EmitPathWarning(BugReport& R, ExplodedNode<ValueState>* N) {
- if (!PDC) {
- EmitWarning(Diag, Ctx, B, N);
+ if (!PD) {
+ EmitWarning(R, N);
return;
}
if (IsCached(N))
return;
- PathDiagnostic D(B.getName());
- GeneratePathDiagnostic(D, Ctx, B, G, N, BegHelpers, EndHelpers);
+ PathDiagnostic D(R.getName());
+ GeneratePathDiagnostic(D, R, N);
if (!D.empty())
- PDC->HandlePathDiagnostic(D);
+ PD->HandlePathDiagnostic(D);
}
-void BugReporter::EmitWarning(Diagnostic& Diag, ASTContext& Ctx,
- const BugDescription& B,
- ExplodedNode<ValueState>* N) {
+void BugReporter::EmitWarning(BugReport& R, ExplodedNode<ValueState>* N) {
if (IsCached(N))
return;
std::ostringstream os;
- os << "[CHECKER] " << B.getDescription();
+ os << "[CHECKER] " << R.getDescription();
unsigned ErrorDiag = Diag.getCustomDiagID(Diagnostic::Warning,
os.str().c_str());
@@ -362,8 +358,8 @@ void BugReporter::EmitWarning(Diagnostic& Diag, ASTContext& Ctx,
if (!S)
return;
- SourceRange R = S->getSourceRange();
+ SourceRange Range = S->getSourceRange();
Diag.Report(FullSourceLoc(S->getLocStart(), Ctx.getSourceManager()),
- ErrorDiag, NULL, 0, &R, 1);
+ ErrorDiag, NULL, 0, &Range, 1);
}
diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp
index d73b771b52..501a3f5a05 100644
--- a/lib/Analysis/CFRefCount.cpp
+++ b/lib/Analysis/CFRefCount.cpp
@@ -792,7 +792,7 @@ CFRefCount::RefBindings CFRefCount::Update(RefBindings B, SymbolID sym,
namespace {
-class VISIBILITY_HIDDEN UseAfterRelease : public BugDescription {
+class VISIBILITY_HIDDEN UseAfterRelease : public BugType {
public:
virtual const char* getName() const {
@@ -804,7 +804,7 @@ public:
}
};
-class VISIBILITY_HIDDEN BadRelease : public BugDescription {
+class VISIBILITY_HIDDEN BadRelease : public BugType {
public:
virtual const char* getName() const {
@@ -831,14 +831,12 @@ void CheckCFRefCount(CFG& cfg, Decl& CD, ASTContext& Ctx,
return;
// FIXME: Refactor some day so this becomes a single function invocation.
-
- GRCoreEngine<GRExprEngine> Eng(cfg, CD, Ctx);
- GRExprEngine* CS = &Eng.getCheckerState();
+ GRExprEngine Eng(cfg, CD, Ctx);
CFRefCount TF;
- CS->setTransferFunctions(TF);
+ Eng.setTransferFunctions(TF);
Eng.ExecuteWorkList();
- // Emit warnings.
+ // FIXME: Emit warnings.
}
diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp
index 36bae45cff..6d4217774d 100644
--- a/lib/Analysis/GRExprEngine.cpp
+++ b/lib/Analysis/GRExprEngine.cpp
@@ -14,6 +14,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/Support/Streams.h"
@@ -40,6 +41,67 @@ using llvm::cast;
using llvm::APSInt;
+GRExprEngine::GRExprEngine(CFG& cfg, Decl& CD, ASTContext& Ctx)
+ : CoreEngine(cfg, CD, Ctx, *this),
+ G(CoreEngine.getGraph()),
+ Liveness(G.getCFG()),
+ Builder(NULL),
+ StateMgr(G.getContext(), G.getAllocator()),
+ BasicVals(StateMgr.getBasicValueFactory()),
+ TF(NULL), // FIXME
+ SymMgr(StateMgr.getSymbolManager()),
+ StmtEntryNode(NULL), CleanedState(NULL), CurrentStmt(NULL) {
+
+ // Compute liveness information.
+ Liveness.runOnCFG(G.getCFG());
+ Liveness.runOnAllBlocks(G.getCFG(), NULL, true);
+}
+
+GRExprEngine::~GRExprEngine() {
+ for (BugTypeSet::iterator I = BugTypes.begin(), E = BugTypes.end(); I!=E; ++I)
+ delete *I;
+
+ for (SimpleChecksTy::iterator I = CallChecks.begin(), E = CallChecks.end();
+ I != E; ++I)
+ delete *I;
+
+ for (SimpleChecksTy::iterator I=MsgExprChecks.begin(), E=MsgExprChecks.end();
+ I != E; ++I)
+ delete *I;
+}
+
+void GRExprEngine::EmitWarnings(Diagnostic& Diag, PathDiagnosticClient* PD) {
+ for (bug_type_iterator I = bug_types_begin(), E = bug_types_end(); I!=E; ++I){
+ BugReporter BR(Diag, PD, getContext(), *this);
+ (*I)->EmitWarnings(BR);
+ }
+
+ for (SimpleChecksTy::iterator I = CallChecks.begin(), E = CallChecks.end();
+ I != E; ++I) {
+ BugReporter BR(Diag, PD, getContext(), *this);
+ (*I)->EmitWarnings(BR);
+ }
+
+ for (SimpleChecksTy::iterator I=MsgExprChecks.begin(), E=MsgExprChecks.end();
+ I != E; ++I) {
+ BugReporter BR(Diag, PD, getContext(), *this);
+ (*I)->EmitWarnings(BR);
+ }
+}
+
+void GRExprEngine::setTransferFunctions(GRTransferFuncs* tf) {
+ TF = tf;
+ TF->RegisterChecks(*this);
+}
+
+void GRExprEngine::AddCallCheck(GRSimpleAPICheck* A) {
+ CallChecks.push_back(A);
+}
+
+void GRExprEngine::AddObjCMessageExprCheck(GRSimpleAPICheck* A) {
+ MsgExprChecks.push_back(A);
+}
+
ValueState* GRExprEngine::getInitialState() {
// The LiveVariables information already has a compilation of all VarDecls
diff --git a/lib/Analysis/GRSimpleVals.cpp b/lib/Analysis/GRSimpleVals.cpp
index d7ee5606a8..e7b456ff21 100644
--- a/lib/Analysis/GRSimpleVals.cpp
+++ b/lib