summaryrefslogtreecommitdiffstats
path: root/include/clang/Analysis/PathSensitive/GRCoreEngine.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/clang/Analysis/PathSensitive/GRCoreEngine.h')
-rw-r--r--include/clang/Analysis/PathSensitive/GRCoreEngine.h668
1 files changed, 668 insertions, 0 deletions
diff --git a/include/clang/Analysis/PathSensitive/GRCoreEngine.h b/include/clang/Analysis/PathSensitive/GRCoreEngine.h
new file mode 100644
index 0000000..0fbdbde
--- /dev/null
+++ b/include/clang/Analysis/PathSensitive/GRCoreEngine.h
@@ -0,0 +1,668 @@
+//==- GRCoreEngine.h - Path-Sensitive Dataflow Engine ------------------*- C++ -*-//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a generic engine for intraprocedural, path-sensitive,
+// dataflow analysis via graph reachability.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_GRENGINE
+#define LLVM_CLANG_ANALYSIS_GRENGINE
+
+#include "clang/AST/Expr.h"
+#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
+#include "clang/Analysis/PathSensitive/GRWorkList.h"
+#include "clang/Analysis/PathSensitive/GRBlockCounter.h"
+#include "clang/Analysis/PathSensitive/GRAuditor.h"
+#include "llvm/ADT/OwningPtr.h"
+
+namespace clang {
+
+class GRStmtNodeBuilderImpl;
+class GRBranchNodeBuilderImpl;
+class GRIndirectGotoNodeBuilderImpl;
+class GRSwitchNodeBuilderImpl;
+class GREndPathNodeBuilderImpl;
+class GRWorkList;
+
+//===----------------------------------------------------------------------===//
+/// GRCoreEngineImpl - Implements the core logic of the graph-reachability
+/// analysis. It traverses the CFG and generates the ExplodedGraph.
+/// Program "states" are treated as opaque void pointers.
+/// The template class GRCoreEngine (which subclasses GRCoreEngineImpl)
+/// provides the matching component to the engine that knows the actual types
+/// for states. Note that this engine only dispatches to transfer functions
+/// at the statement and block-level. The analyses themselves must implement
+/// any transfer function logic and the sub-expression level (if any).
+class GRCoreEngineImpl {
+protected:
+ friend class GRStmtNodeBuilderImpl;
+ friend class GRBranchNodeBuilderImpl;
+ friend class GRIndirectGotoNodeBuilderImpl;
+ friend class GRSwitchNodeBuilderImpl;
+ friend class GREndPathNodeBuilderImpl;
+
+ /// G - The simulation graph. Each node is a (location,state) pair.
+ llvm::OwningPtr<ExplodedGraphImpl> G;
+
+ /// WList - A set of queued nodes that need to be processed by the
+ /// worklist algorithm. It is up to the implementation of WList to decide
+ /// the order that nodes are processed.
+ GRWorkList* WList;
+
+ /// BCounterFactory - A factory object for created GRBlockCounter objects.
+ /// These are used to record for key nodes in the ExplodedGraph the
+ /// number of times different CFGBlocks have been visited along a path.
+ GRBlockCounter::Factory BCounterFactory;
+
+ void GenerateNode(const ProgramPoint& Loc, const void* State,
+ ExplodedNodeImpl* Pred);
+
+ /// getInitialState - Gets the void* representing the initial 'state'
+ /// of the analysis. This is simply a wrapper (implemented
+ /// in GRCoreEngine) that performs type erasure on the initial
+ /// state returned by the checker object.
+ virtual const void* getInitialState() = 0;
+
+ void HandleBlockEdge(const BlockEdge& E, ExplodedNodeImpl* Pred);
+ void HandleBlockEntrance(const BlockEntrance& E, ExplodedNodeImpl* Pred);
+ void HandleBlockExit(CFGBlock* B, ExplodedNodeImpl* Pred);
+ void HandlePostStmt(const PostStmt& S, CFGBlock* B,
+ unsigned StmtIdx, ExplodedNodeImpl *Pred);
+
+ void HandleBranch(Stmt* Cond, Stmt* Term, CFGBlock* B,
+ ExplodedNodeImpl* Pred);
+
+ virtual void ProcessEndPath(GREndPathNodeBuilderImpl& Builder) = 0;
+
+ virtual bool ProcessBlockEntrance(CFGBlock* Blk, const void* State,
+ GRBlockCounter BC) = 0;
+
+ virtual void ProcessStmt(Stmt* S, GRStmtNodeBuilderImpl& Builder) = 0;
+
+ virtual void ProcessBranch(Stmt* Condition, Stmt* Terminator,
+ GRBranchNodeBuilderImpl& Builder) = 0;
+
+ virtual void ProcessIndirectGoto(GRIndirectGotoNodeBuilderImpl& Builder) = 0;
+
+ virtual void ProcessSwitch(GRSwitchNodeBuilderImpl& Builder) = 0;
+
+private:
+ GRCoreEngineImpl(const GRCoreEngineImpl&); // Do not implement.
+ GRCoreEngineImpl& operator=(const GRCoreEngineImpl&);
+
+protected:
+ GRCoreEngineImpl(ExplodedGraphImpl* g, GRWorkList* wl)
+ : G(g), WList(wl), BCounterFactory(g->getAllocator()) {}
+
+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);
+
+ virtual ~GRCoreEngineImpl();
+
+ CFG& getCFG() { return G->getCFG(); }
+};
+
+class GRStmtNodeBuilderImpl {
+ GRCoreEngineImpl& Eng;
+ CFGBlock& B;
+ const unsigned Idx;
+ ExplodedNodeImpl* Pred;
+ ExplodedNodeImpl* LastNode;
+
+ typedef llvm::SmallPtrSet<ExplodedNodeImpl*,5> DeferredTy;
+ DeferredTy Deferred;
+
+ void GenerateAutoTransition(ExplodedNodeImpl* N);
+
+public:
+ GRStmtNodeBuilderImpl(CFGBlock* b, unsigned idx,
+ ExplodedNodeImpl* N, GRCoreEngineImpl* e);
+
+ ~GRStmtNodeBuilderImpl();
+
+ ExplodedNodeImpl* getBasePredecessor() const { return Pred; }
+
+ ExplodedNodeImpl* getLastNode() const {
+ return LastNode ? (LastNode->isSink() ? NULL : LastNode) : NULL;
+ }
+
+ GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
+
+ unsigned getCurrentBlockCount() const {
+ return getBlockCounter().getNumVisited(B.getBlockID());
+ }
+
+ ExplodedNodeImpl*
+ generateNodeImpl(PostStmt PP, const void* State, ExplodedNodeImpl* Pred);
+
+ ExplodedNodeImpl*
+ generateNodeImpl(Stmt* S, const void* State, ExplodedNodeImpl* Pred,
+ ProgramPoint::Kind K = ProgramPoint::PostStmtKind,
+ const void *tag = 0);
+
+ ExplodedNodeImpl*
+ generateNodeImpl(Stmt* S, const void* State,
+ ProgramPoint::Kind K = ProgramPoint::PostStmtKind,
+ const void *tag = 0) {
+ ExplodedNodeImpl* N = getLastNode();
+ assert (N && "Predecessor of new node is infeasible.");
+ return generateNodeImpl(S, State, N, K, tag);
+ }
+
+ ExplodedNodeImpl*
+ generateNodeImpl(Stmt* S, const void* State, const void *tag = 0) {
+ ExplodedNodeImpl* N = getLastNode();
+ assert (N && "Predecessor of new node is infeasible.");
+ return generateNodeImpl(S, State, N, ProgramPoint::PostStmtKind, tag);
+ }
+
+ /// getStmt - Return the current block-level expression associated with
+ /// this builder.
+ Stmt* getStmt() const { return B[Idx]; }
+
+ /// getBlock - Return the CFGBlock associated with the block-level expression
+ /// of this builder.
+ CFGBlock* getBlock() const { return &B; }
+};
+
+
+template<typename STATE>
+class GRStmtNodeBuilder {
+public:
+ typedef STATE StateTy;
+ typedef typename StateTy::ManagerTy StateManagerTy;
+ typedef ExplodedNode<StateTy> NodeTy;
+
+private:
+ GRStmtNodeBuilderImpl& NB;
+ StateManagerTy& Mgr;
+ const StateTy* CleanedState;
+ GRAuditor<StateTy>* Auditor;
+
+public:
+ GRStmtNodeBuilder(GRStmtNodeBuilderImpl& nb, StateManagerTy& mgr) :
+ NB(nb), Mgr(mgr), Auditor(0), PurgingDeadSymbols(false),
+ BuildSinks(false), HasGeneratedNode(false),
+ PointKind(ProgramPoint::PostStmtKind), Tag(0) {
+
+ CleanedState = getLastNode()->getState();
+ }
+
+ void setAuditor(GRAuditor<StateTy>* A) {
+ Auditor = A;
+ }
+
+ NodeTy* getLastNode() const {
+ return static_cast<NodeTy*>(NB.getLastNode());
+ }
+
+ NodeTy* generateNode(PostStmt PP, const StateTy* St, NodeTy* Pred) {
+ HasGeneratedNode = true;
+ return static_cast<NodeTy*>(NB.generateNodeImpl(PP, St, Pred));
+ }
+
+ NodeTy* generateNode(Stmt* S, const StateTy* St, NodeTy* Pred,
+ ProgramPoint::Kind K) {
+ HasGeneratedNode = true;
+ if (PurgingDeadSymbols) K = ProgramPoint::PostPurgeDeadSymbolsKind;
+ return static_cast<NodeTy*>(NB.generateNodeImpl(S, St, Pred, K, Tag));
+ }
+
+ NodeTy* generateNode(Stmt* S, const StateTy* St, NodeTy* Pred) {
+ return generateNode(S, St, Pred, PointKind);
+ }
+
+ NodeTy* generateNode(Stmt* S, const StateTy* St, ProgramPoint::Kind K) {
+ HasGeneratedNode = true;
+ if (PurgingDeadSymbols) K = ProgramPoint::PostPurgeDeadSymbolsKind;
+ return static_cast<NodeTy*>(NB.generateNodeImpl(S, St, K, Tag));
+ }
+
+ NodeTy* generateNode(Stmt* S, const StateTy* St) {
+ return generateNode(S, St, PointKind);
+ }
+
+
+ GRBlockCounter getBlockCounter() const {
+ return NB.getBlockCounter();
+ }
+
+ unsigned getCurrentBlockCount() const {
+ return NB.getCurrentBlockCount();
+ }
+
+ const StateTy* GetState(NodeTy* Pred) const {
+ if ((ExplodedNodeImpl*) Pred == NB.getBasePredecessor())
+ return CleanedState;
+ else
+ return Pred->getState();
+ }
+
+ void SetCleanedState(const StateTy* St) {
+ CleanedState = St;
+ }
+
+ NodeTy* MakeNode(ExplodedNodeSet<StateTy>& Dst, Stmt* S,
+ NodeTy* Pred, const StateTy* St) {
+ return MakeNode(Dst, S, Pred, St, PointKind);
+ }
+
+ NodeTy* MakeNode(ExplodedNodeSet<StateTy>& Dst, Stmt* S,
+ NodeTy* Pred, const StateTy* St, ProgramPoint::Kind K) {
+
+ const StateTy* PredState = GetState(Pred);
+
+ // If the state hasn't changed, don't generate a new node.
+ if (!BuildSinks && St == PredState && Auditor == 0) {
+ Dst.Add(Pred);
+ return NULL;
+ }
+
+ NodeTy* N = generateNode(S, St, Pred, K);
+
+ if (N) {
+ if (BuildSinks)
+ N->markAsSink();
+ else {
+ if (Auditor && Auditor->Audit(N, Mgr))
+ N->markAsSink();
+
+ Dst.Add(N);
+ }
+ }
+
+ return N;
+ }
+
+ NodeTy* MakeSinkNode(ExplodedNodeSet<StateTy>& Dst, Stmt* S,
+ NodeTy* Pred, const StateTy* St) {
+ bool Tmp = BuildSinks;
+ BuildSinks = true;
+ NodeTy* N = MakeNode(Dst, S, Pred, St);
+ BuildSinks = Tmp;
+ return N;
+ }
+
+ bool PurgingDeadSymbols;
+ bool BuildSinks;
+ bool HasGeneratedNode;
+ ProgramPoint::Kind PointKind;
+ const void *Tag;
+};
+
+class GRBranchNodeBuilderImpl {
+ GRCoreEngineImpl& Eng;
+ CFGBlock* Src;
+ CFGBlock* DstT;
+ CFGBlock* DstF;
+ ExplodedNodeImpl* Pred;
+
+ typedef llvm::SmallVector<ExplodedNodeImpl*,3> DeferredTy;
+ DeferredTy Deferred;
+
+ bool GeneratedTrue;
+ bool GeneratedFalse;
+
+public:
+ GRBranchNodeBuilderImpl(CFGBlock* src, CFGBlock* dstT, CFGBlock* dstF,
+ ExplodedNodeImpl* pred, GRCoreEngineImpl* e)
+ : Eng(*e), Src(src), DstT(dstT), DstF(dstF), Pred(pred),
+ GeneratedTrue(false), GeneratedFalse(false) {}
+
+ ~GRBranchNodeBuilderImpl();
+
+ ExplodedNodeImpl* getPredecessor() const { return Pred; }
+ const ExplodedGraphImpl& getGraph() const { return *Eng.G; }
+ GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
+
+ ExplodedNodeImpl* generateNodeImpl(const void* State, bool branch);
+
+ CFGBlock* getTargetBlock(bool branch) const {
+ return branch ? DstT : DstF;
+ }
+
+ void markInfeasible(bool branch) {
+ if (branch) GeneratedTrue = true;
+ else GeneratedFalse = true;
+ }
+};
+
+template<typename STATE>
+class GRBranchNodeBuilder {
+ typedef STATE StateTy;
+ typedef ExplodedGraph<StateTy> GraphTy;
+ typedef typename GraphTy::NodeTy NodeTy;
+
+ GRBranchNodeBuilderImpl& NB;
+
+public:
+ GRBranchNodeBuilder(GRBranchNodeBuilderImpl& nb) : NB(nb) {}
+
+ const GraphTy& getGraph() const {
+ return static_cast<const GraphTy&>(NB.getGraph());
+ }
+
+ NodeTy* getPredecessor() const {
+ return static_cast<NodeTy*>(NB.getPredecessor());
+ }
+
+ const StateTy* getState() const {
+ return getPredecessor()->getState();
+ }
+
+ NodeTy* generateNode(const StateTy* St, bool branch) {
+ return static_cast<NodeTy*>(NB.generateNodeImpl(St, branch));
+ }
+
+ GRBlockCounter getBlockCounter() const {
+ return NB.getBlockCounter();
+ }
+
+ CFGBlock* getTargetBlock(bool branch) const {
+ return NB.getTargetBlock(branch);
+ }
+
+ void markInfeasible(bool branch) {
+ NB.markInfeasible(branch);
+ }
+};
+
+class GRIndirectGotoNodeBuilderImpl {
+ GRCoreEngineImpl& Eng;
+ CFGBlock* Src;
+ CFGBlock& DispatchBlock;
+ Expr* E;
+ ExplodedNodeImpl* Pred;
+public:
+ GRIndirectGotoNodeBuilderImpl(ExplodedNodeImpl* pred, CFGBlock* src,
+ Expr* e, CFGBlock* dispatch,
+ GRCoreEngineImpl* eng)
+ : Eng(*eng), Src(src), DispatchBlock(*dispatch), E(e), Pred(pred) {}
+
+
+ class Iterator {
+ CFGBlock::succ_iterator I;
+
+ friend class GRIndirectGotoNodeBuilderImpl;
+ Iterator(CFGBlock::succ_iterator i) : I(i) {}
+ public:
+
+ Iterator& operator++() { ++I; return *this; }
+ bool operator!=(const Iterator& X) const { return I != X.I; }
+
+ LabelStmt* getLabel() const {
+ return llvm::cast<LabelStmt>((*I)->getLabel());
+ }
+
+ CFGBlock* getBlock() const {
+ return *I;
+ }
+ };
+
+ Iterator begin() { return Iterator(DispatchBlock.succ_begin()); }
+ Iterator end() { return Iterator(DispatchBlock.succ_end()); }
+
+ ExplodedNodeImpl* generateNodeImpl(const Iterator& I, const void* State,
+ bool isSink);
+
+ Expr* getTarget() const { return E; }
+ const void* getState() const { return Pred->State; }
+};
+
+template<typename STATE>
+class GRIndirectGotoNodeBuilder {
+ typedef STATE StateTy;
+ typedef ExplodedGraph<StateTy> GraphTy;
+ typedef typename GraphTy::NodeTy NodeTy;
+
+ GRIndirectGotoNodeBuilderImpl& NB;
+
+public:
+ GRIndirectGotoNodeBuilder(GRIndirectGotoNodeBuilderImpl& nb) : NB(nb) {}
+
+ typedef GRIndirectGotoNodeBuilderImpl::Iterator iterator;
+
+ iterator begin() { return NB.begin(); }
+ iterator end() { return NB.end(); }
+
+ Expr* getTarget() const { return NB.getTarget(); }
+
+ NodeTy* generateNode(const iterator& I, const StateTy* St, bool isSink=false){
+ return static_cast<NodeTy*>(NB.generateNodeImpl(I, St, isSink));
+ }
+
+ const StateTy* getState() const {
+ return static_cast<const StateTy*>(NB.getState());
+ }
+};
+
+class GRSwitchNodeBuilderImpl {
+ GRCoreEngineImpl& Eng;
+ CFGBlock* Src;
+ Expr* Condition;
+ ExplodedNodeImpl* Pred;
+public:
+ GRSwitchNodeBuilderImpl(ExplodedNodeImpl* pred, CFGBlock* src,
+ Expr* condition, GRCoreEngineImpl* eng)
+ : Eng(*eng), Src(src), Condition(condition), Pred(pred) {}
+
+ class Iterator {
+ CFGBlock::succ_reverse_iterator I;
+
+ friend class GRSwitchNodeBuilderImpl;
+ Iterator(CFGBlock::succ_reverse_iterator i) : I(i) {}
+ public:
+
+ Iterator& operator++() { ++I; return *this; }
+ bool operator!=(const Iterator& X) const { return I != X.I; }
+
+ CaseStmt* getCase() const {
+ return llvm::cast<CaseStmt>((*I)->getLabel());
+ }
+
+ CFGBlock* getBlock() const {
+ return *I;
+ }
+ };
+
+ Iterator begin() { return Iterator(Src->succ_rbegin()+1); }
+ Iterator end() { return Iterator(Src->succ_rend()); }
+
+ ExplodedNodeImpl* generateCaseStmtNodeImpl(const Iterator& I,
+ const void* State);
+
+ ExplodedNodeImpl* generateDefaultCaseNodeImpl(const void* State,
+ bool isSink);
+
+ Expr* getCondition() const { return Condition; }
+ const void* getState() const { return Pred->State; }
+};
+
+template<typename STATE>
+class GRSwitchNodeBuilder {
+ typedef STATE StateTy;
+ typedef ExplodedGraph<StateTy> GraphTy;
+ typedef typename GraphTy::NodeTy NodeTy;
+
+ GRSwitchNodeBuilderImpl& NB;
+
+public:
+ GRSwitchNodeBuilder(GRSwitchNodeBuilderImpl& nb) : NB(nb) {}
+
+ typedef GRSwitchNodeBuilderImpl::Iterator iterator;
+
+ iterator begin() { return NB.begin(); }
+ iterator end() { return NB.end(); }
+
+ Expr* getCondition() const { return NB.getCondition(); }
+
+ NodeTy* generateCaseStmtNode(const iterator& I, const StateTy* St) {
+ return static_cast<NodeTy*>(NB.generateCaseStmtNodeImpl(I, St));
+ }
+
+ NodeTy* generateDefaultCaseNode(const StateTy* St, bool isSink = false) {
+ return static_cast<NodeTy*>(NB.generateDefaultCaseNodeImpl(St, isSink));
+ }
+
+ const StateTy* getState() const {
+ return static_cast<const StateTy*>(NB.getState());
+ }
+};
+
+
+class GREndPathNodeBuilderImpl {
+ GRCoreEngineImpl& Eng;
+ CFGBlock& B;
+ ExplodedNodeImpl* Pred;
+ bool HasGeneratedNode;
+
+public:
+ GREndPathNodeBuilderImpl(CFGBlock* b, ExplodedNodeImpl* N,
+ GRCoreEngineImpl* e)
+ : Eng(*e), B(*b), Pred(N), HasGeneratedNode(false) {}
+
+ ~GREndPathNodeBuilderImpl();
+
+ ExplodedNodeImpl* getPredecessor() const { return Pred; }
+
+ GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
+
+ unsigned getCurrentBlockCount() const {
+ return getBlockCounter().getNumVisited(B.getBlockID());
+ }
+
+ ExplodedNodeImpl* generateNodeImpl(const void* State,
+ const void *tag = 0,
+ ExplodedNodeImpl *P = 0);
+
+ CFGBlock* getBlock() const { return &B; }
+};
+
+
+template<typename STATE>
+class GREndPathNodeBuilder {
+ typedef STATE StateTy;
+ typedef ExplodedNode<StateTy> NodeTy;
+
+ GREndPathNodeBuilderImpl& NB;
+
+public:
+ GREndPathNodeBuilder(GREndPathNodeBuilderImpl& nb) : NB(nb) {}
+
+ NodeTy* getPredecessor() const {
+ return static_cast<NodeTy*>(NB.getPredecessor());
+ }
+
+ GRBlockCounter getBlockCounter() const {
+ return NB.getBlockCounter();
+ }
+
+ unsigned getCurrentBlockCount() const {
+ return NB.getCurrentBlockCount();
+ }
+
+ const StateTy* getState() const {
+ return getPredecessor()->getState();
+ }
+
+ NodeTy* MakeNode(const StateTy* St, const void *tag = 0) {
+ return static_cast<NodeTy*>(NB.generateNodeImpl(St, tag));
+ }
+
+ NodeTy *generateNode(const StateTy *St, NodeTy *Pred, const void *tag = 0) {
+ return static_cast<NodeTy*>(NB.generateNodeImpl(St, tag, Pred));
+ }
+};
+
+
+template<typename SUBENGINE>
+class GRCoreEngine : public GRCoreEngineImpl {
+public:
+ typedef SUBENGINE SubEngineTy;
+ typedef typename SubEngineTy::StateTy StateTy;
+ typedef typename StateTy::ManagerTy StateManagerTy;
+ typedef ExplodedGraph<StateTy> GraphTy;
+ typedef typename GraphTy::NodeTy NodeTy;
+
+protected:
+ SubEngineTy& SubEngine;
+
+ virtual const void* getInitialState() {
+ return SubEngine.getInitialState();
+ }
+
+ virtual void ProcessEndPath(GREndPathNodeBuilderImpl& BuilderImpl) {
+ GREndPathNodeBuilder<StateTy> Builder(BuilderImpl);
+ SubEngine.ProcessEndPath(Builder);
+ }
+
+ virtual void ProcessStmt(Stmt* S, GRStmtNodeBuilderImpl& BuilderImpl) {
+ GRStmtNodeBuilder<StateTy> Builder(BuilderImpl,SubEngine.getStateManager());
+ SubEngine.ProcessStmt(S, Builder);
+ }
+
+ virtual bool ProcessBlockEntrance(CFGBlock* Blk, const void* State,
+ GRBlockCounter BC) {
+ return SubEngine.ProcessBlockEntrance(Blk,
+ static_cast<const StateTy*>(State),
+ BC);
+ }
+
+ virtual void ProcessBranch(Stmt* Condition, Stmt* Terminator,
+ GRBranchNodeBuilderImpl& BuilderImpl) {
+ GRBranchNodeBuilder<StateTy> Builder(BuilderImpl);
+ SubEngine.ProcessBranch(Condition, Terminator, Builder);
+ }
+
+ virtual void ProcessIndirectGoto(GRIndirectGotoNodeBuilderImpl& BuilderImpl) {
+ GRIndirectGotoNodeBuilder<StateTy> Builder(BuilderImpl);
+ SubEngine.ProcessIndirectGoto(Builder);
+ }
+
+ virtual void ProcessSwitch(GRSwitchNodeBuilderImpl& BuilderImpl) {
+ 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, SubEngineTy& subengine)
+ : GRCoreEngineImpl(new GraphTy(cfg, cd, ctx),
+ GRWorkList::MakeBFS()),
+ 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,
+ SubEngineTy& subengine)
+ : GRCoreEngineImpl(new GraphTy(cfg, cd, ctx), wlist),
+ SubEngine(subengine) {}
+
+ virtual ~GRCoreEngine() {}
+
+ /// getGraph - Returns the exploded graph.
+ GraphTy& getGraph() {
+ return *static_cast<GraphTy*>(G.get());
+ }
+
+ /// takeGraph - Returns the exploded graph. Ownership of the graph is
+ /// transfered to the caller.
+ GraphTy* takeGraph() {
+ return static_cast<GraphTy*>(G.take());
+ }
+};
+
+} // end clang namespace
+
+#endif
OpenPOWER on IntegriCloud