CoreEngine.h revision 520035439d7133064325c4df6378c5a8f2f05539
1//==- GRCoreEngine.h - Path-Sensitive Dataflow Engine ------------------*- C++ -*-//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10//  This file defines a generic engine for intraprocedural, path-sensitive,
11//  dataflow analysis via graph reachability.
12//
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_CLANG_ANALYSIS_GRENGINE
16#define LLVM_CLANG_ANALYSIS_GRENGINE
17
18#include "clang/AST/Expr.h"
19#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
20#include "clang/Analysis/PathSensitive/GRWorkList.h"
21#include "clang/Analysis/PathSensitive/GRBlockCounter.h"
22#include "clang/Analysis/PathSensitive/GRAuditor.h"
23#include "llvm/ADT/OwningPtr.h"
24
25namespace clang {
26
27class GRStmtNodeBuilderImpl;
28class GRBranchNodeBuilderImpl;
29class GRIndirectGotoNodeBuilderImpl;
30class GRSwitchNodeBuilderImpl;
31class GREndPathNodeBuilderImpl;
32class GRWorkList;
33
34//===----------------------------------------------------------------------===//
35/// GRCoreEngineImpl - Implements the core logic of the graph-reachability
36///   analysis. It traverses the CFG and generates the ExplodedGraph.
37///   Program "states" are treated as opaque void pointers.
38///   The template class GRCoreEngine (which subclasses GRCoreEngineImpl)
39///   provides the matching component to the engine that knows the actual types
40///   for states.  Note that this engine only dispatches to transfer functions
41///   at the statement and block-level.  The analyses themselves must implement
42///   any transfer function logic and the sub-expression level (if any).
43class GRCoreEngineImpl {
44protected:
45  friend class GRStmtNodeBuilderImpl;
46  friend class GRBranchNodeBuilderImpl;
47  friend class GRIndirectGotoNodeBuilderImpl;
48  friend class GRSwitchNodeBuilderImpl;
49  friend class GREndPathNodeBuilderImpl;
50
51  /// G - The simulation graph.  Each node is a (location,state) pair.
52  llvm::OwningPtr<ExplodedGraphImpl> G;
53
54  /// WList - A set of queued nodes that need to be processed by the
55  ///  worklist algorithm.  It is up to the implementation of WList to decide
56  ///  the order that nodes are processed.
57  GRWorkList* WList;
58
59  /// BCounterFactory - A factory object for created GRBlockCounter objects.
60  ///   These are used to record for key nodes in the ExplodedGraph the
61  ///   number of times different CFGBlocks have been visited along a path.
62  GRBlockCounter::Factory BCounterFactory;
63
64  void GenerateNode(const ProgramPoint& Loc, const void* State,
65                    ExplodedNodeImpl* Pred);
66
67  /// getInitialState - Gets the void* representing the initial 'state'
68  ///  of the analysis.  This is simply a wrapper (implemented
69  ///  in GRCoreEngine) that performs type erasure on the initial
70  ///  state returned by the checker object.
71  virtual const void* getInitialState() = 0;
72
73  void HandleBlockEdge(const BlockEdge& E, ExplodedNodeImpl* Pred);
74  void HandleBlockEntrance(const BlockEntrance& E, ExplodedNodeImpl* Pred);
75  void HandleBlockExit(CFGBlock* B, ExplodedNodeImpl* Pred);
76  void HandlePostStmt(const PostStmt& S, CFGBlock* B,
77                      unsigned StmtIdx, ExplodedNodeImpl *Pred);
78
79  void HandleBranch(Stmt* Cond, Stmt* Term, CFGBlock* B,
80                    ExplodedNodeImpl* Pred);
81
82  virtual void ProcessEndPath(GREndPathNodeBuilderImpl& Builder) = 0;
83
84  virtual bool ProcessBlockEntrance(CFGBlock* Blk, const void* State,
85                                    GRBlockCounter BC) = 0;
86
87  virtual void ProcessStmt(Stmt* S, GRStmtNodeBuilderImpl& Builder) = 0;
88
89  virtual void ProcessBranch(Stmt* Condition, Stmt* Terminator,
90                             GRBranchNodeBuilderImpl& Builder) = 0;
91
92  virtual void ProcessIndirectGoto(GRIndirectGotoNodeBuilderImpl& Builder) = 0;
93
94  virtual void ProcessSwitch(GRSwitchNodeBuilderImpl& Builder) = 0;
95
96private:
97  GRCoreEngineImpl(const GRCoreEngineImpl&); // Do not implement.
98  GRCoreEngineImpl& operator=(const GRCoreEngineImpl&);
99
100protected:
101  GRCoreEngineImpl(ExplodedGraphImpl* g, GRWorkList* wl)
102    : G(g), WList(wl), BCounterFactory(g->getAllocator()) {}
103
104public:
105  /// ExecuteWorkList - Run the worklist algorithm for a maximum number of
106  ///  steps.  Returns true if there is still simulation state on the worklist.
107  bool ExecuteWorkList(unsigned Steps);
108
109  virtual ~GRCoreEngineImpl();
110
111  CFG& getCFG() { return G->getCFG(); }
112};
113
114class GRStmtNodeBuilderImpl {
115  GRCoreEngineImpl& Eng;
116  CFGBlock& B;
117  const unsigned Idx;
118  ExplodedNodeImpl* Pred;
119  ExplodedNodeImpl* LastNode;
120
121  typedef llvm::SmallPtrSet<ExplodedNodeImpl*,5> DeferredTy;
122  DeferredTy Deferred;
123
124  void GenerateAutoTransition(ExplodedNodeImpl* N);
125
126public:
127  GRStmtNodeBuilderImpl(CFGBlock* b, unsigned idx,
128                    ExplodedNodeImpl* N, GRCoreEngineImpl* e);
129
130  ~GRStmtNodeBuilderImpl();
131
132  ExplodedNodeImpl* getBasePredecessor() const { return Pred; }
133
134  ExplodedNodeImpl* getLastNode() const {
135    return LastNode ? (LastNode->isSink() ? NULL : LastNode) : NULL;
136  }
137
138  GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
139
140  unsigned getCurrentBlockCount() const {
141    return getBlockCounter().getNumVisited(B.getBlockID());
142  }
143
144  ExplodedNodeImpl*
145  generateNodeImpl(PostStmt PP, const void* State, ExplodedNodeImpl* Pred);
146
147  ExplodedNodeImpl*
148  generateNodeImpl(Stmt* S, const void* State, ExplodedNodeImpl* Pred,
149                   ProgramPoint::Kind K = ProgramPoint::PostStmtKind,
150                   const void *tag = 0);
151
152  ExplodedNodeImpl*
153  generateNodeImpl(Stmt* S, const void* State,
154                   ProgramPoint::Kind K = ProgramPoint::PostStmtKind,
155                   const void *tag = 0) {
156    ExplodedNodeImpl* N = getLastNode();
157    assert (N && "Predecessor of new node is infeasible.");
158    return generateNodeImpl(S, State, N, K, tag);
159  }
160
161  ExplodedNodeImpl*
162  generateNodeImpl(Stmt* S, const void* State, const void *tag = 0) {
163    ExplodedNodeImpl* N = getLastNode();
164    assert (N && "Predecessor of new node is infeasible.");
165    return generateNodeImpl(S, State, N, ProgramPoint::PostStmtKind, tag);
166  }
167
168  /// getStmt - Return the current block-level expression associated with
169  ///  this builder.
170  Stmt* getStmt() const { return B[Idx]; }
171
172  /// getBlock - Return the CFGBlock associated with the block-level expression
173  ///  of this builder.
174  CFGBlock* getBlock() const { return &B; }
175};
176
177
178template<typename STATE>
179class GRStmtNodeBuilder  {
180public:
181  typedef STATE                       StateTy;
182  typedef typename StateTy::ManagerTy StateManagerTy;
183  typedef ExplodedNode<StateTy>       NodeTy;
184
185private:
186  GRStmtNodeBuilderImpl& NB;
187  StateManagerTy& Mgr;
188  const StateTy* CleanedState;
189  GRAuditor<StateTy>* Auditor;
190
191public:
192  GRStmtNodeBuilder(GRStmtNodeBuilderImpl& nb, StateManagerTy& mgr) :
193    NB(nb), Mgr(mgr), Auditor(0), PurgingDeadSymbols(false),
194    BuildSinks(false), HasGeneratedNode(false),
195    PointKind(ProgramPoint::PostStmtKind), Tag(0) {
196
197    CleanedState = getLastNode()->getState();
198  }
199
200  void setAuditor(GRAuditor<StateTy>* A) {
201    Auditor = A;
202  }
203
204  NodeTy* getLastNode() const {
205    return static_cast<NodeTy*>(NB.getLastNode());
206  }
207
208  NodeTy* generateNode(PostStmt PP, const StateTy* St, NodeTy* Pred) {
209    HasGeneratedNode = true;
210    return static_cast<NodeTy*>(NB.generateNodeImpl(PP, St, Pred));
211  }
212
213  NodeTy* generateNode(Stmt* S, const StateTy* St, NodeTy* Pred,
214                       ProgramPoint::Kind K) {
215    HasGeneratedNode = true;
216    if (PurgingDeadSymbols) K = ProgramPoint::PostPurgeDeadSymbolsKind;
217    return static_cast<NodeTy*>(NB.generateNodeImpl(S, St, Pred, K, Tag));
218  }
219
220  NodeTy* generateNode(Stmt* S, const StateTy* St, NodeTy* Pred) {
221    return generateNode(S, St, Pred, PointKind);
222  }
223
224  NodeTy* generateNode(Stmt* S, const StateTy* St, ProgramPoint::Kind K) {
225    HasGeneratedNode = true;
226    if (PurgingDeadSymbols) K = ProgramPoint::PostPurgeDeadSymbolsKind;
227    return static_cast<NodeTy*>(NB.generateNodeImpl(S, St, K, Tag));
228  }
229
230  NodeTy* generateNode(Stmt* S, const StateTy* St) {
231    return generateNode(S, St, PointKind);
232  }
233
234
235  GRBlockCounter getBlockCounter() const {
236    return NB.getBlockCounter();
237  }
238
239  unsigned getCurrentBlockCount() const {
240    return NB.getCurrentBlockCount();
241  }
242
243  const StateTy* GetState(NodeTy* Pred) const {
244    if ((ExplodedNodeImpl*) Pred == NB.getBasePredecessor())
245      return CleanedState;
246    else
247      return Pred->getState();
248  }
249
250  void SetCleanedState(const StateTy* St) {
251    CleanedState = St;
252  }
253
254  NodeTy* MakeNode(ExplodedNodeSet<StateTy>& Dst, Stmt* S,
255                   NodeTy* Pred, const StateTy* St) {
256    return MakeNode(Dst, S, Pred, St, PointKind);
257  }
258
259  NodeTy* MakeNode(ExplodedNodeSet<StateTy>& Dst, Stmt* S,
260                   NodeTy* Pred, const StateTy* St, ProgramPoint::Kind K) {
261
262    const StateTy* PredState = GetState(Pred);
263
264    // If the state hasn't changed, don't generate a new node.
265    if (!BuildSinks && St == PredState && Auditor == 0) {
266      Dst.Add(Pred);
267      return NULL;
268    }
269
270    NodeTy* N = generateNode(S, St, Pred, K);
271
272    if (N) {
273      if (BuildSinks)
274        N->markAsSink();
275      else {
276        if (Auditor && Auditor->Audit(N, Mgr))
277          N->markAsSink();
278
279        Dst.Add(N);
280      }
281    }
282
283    return N;
284  }
285
286  NodeTy* MakeSinkNode(ExplodedNodeSet<StateTy>& Dst, Stmt* S,
287                       NodeTy* Pred, const StateTy* St) {
288    bool Tmp = BuildSinks;
289    BuildSinks = true;
290    NodeTy* N = MakeNode(Dst, S, Pred, St);
291    BuildSinks = Tmp;
292    return N;
293  }
294
295  bool PurgingDeadSymbols;
296  bool BuildSinks;
297  bool HasGeneratedNode;
298  ProgramPoint::Kind PointKind;
299  const void *Tag;
300};
301
302class GRBranchNodeBuilderImpl {
303  GRCoreEngineImpl& Eng;
304  CFGBlock* Src;
305  CFGBlock* DstT;
306  CFGBlock* DstF;
307  ExplodedNodeImpl* Pred;
308
309  typedef llvm::SmallVector<ExplodedNodeImpl*,3> DeferredTy;
310  DeferredTy Deferred;
311
312  bool GeneratedTrue;
313  bool GeneratedFalse;
314  bool InFeasibleTrue;
315  bool InFeasibleFalse;
316
317public:
318  GRBranchNodeBuilderImpl(CFGBlock* src, CFGBlock* dstT, CFGBlock* dstF,
319                          ExplodedNodeImpl* pred, GRCoreEngineImpl* e)
320  : Eng(*e), Src(src), DstT(dstT), DstF(dstF), Pred(pred),
321    GeneratedTrue(false), GeneratedFalse(false),
322    InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) {}
323
324  ~GRBranchNodeBuilderImpl();
325
326  ExplodedNodeImpl* getPredecessor() const { return Pred; }
327  const ExplodedGraphImpl& getGraph() const { return *Eng.G; }
328  GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
329
330  ExplodedNodeImpl* generateNodeImpl(const void* State, bool branch);
331
332  CFGBlock* getTargetBlock(bool branch) const {
333    return branch ? DstT : DstF;
334  }
335
336  void markInfeasible(bool branch) {
337    if (branch)
338      InFeasibleTrue = GeneratedTrue = true;
339    else
340      InFeasibleFalse = GeneratedFalse = true;
341  }
342
343  bool isFeasible(bool branch) {
344    return branch ? !InFeasibleTrue : !InFeasibleFalse;
345  }
346};
347
348template<typename STATE>
349class GRBranchNodeBuilder {
350  typedef STATE                                  StateTy;
351  typedef ExplodedGraph<StateTy>                 GraphTy;
352  typedef typename GraphTy::NodeTy               NodeTy;
353
354  GRBranchNodeBuilderImpl& NB;
355
356public:
357  GRBranchNodeBuilder(GRBranchNodeBuilderImpl& nb) : NB(nb) {}
358
359  const GraphTy& getGraph() const {
360    return static_cast<const GraphTy&>(NB.getGraph());
361  }
362
363  NodeTy* getPredecessor() const {
364    return static_cast<NodeTy*>(NB.getPredecessor());
365  }
366
367  const StateTy* getState() const {
368    return getPredecessor()->getState();
369  }
370
371  NodeTy* generateNode(const StateTy* St, bool branch) {
372    return static_cast<NodeTy*>(NB.generateNodeImpl(St, branch));
373  }
374
375  GRBlockCounter getBlockCounter() const {
376    return NB.getBlockCounter();
377  }
378
379  CFGBlock* getTargetBlock(bool branch) const {
380    return NB.getTargetBlock(branch);
381  }
382
383  void markInfeasible(bool branch) {
384    NB.markInfeasible(branch);
385  }
386
387  bool isFeasible(bool branch) {
388    return NB.isFeasible(branch);
389  }
390};
391
392class GRIndirectGotoNodeBuilderImpl {
393  GRCoreEngineImpl& Eng;
394  CFGBlock* Src;
395  CFGBlock& DispatchBlock;
396  Expr* E;
397  ExplodedNodeImpl* Pred;
398public:
399  GRIndirectGotoNodeBuilderImpl(ExplodedNodeImpl* pred, CFGBlock* src,
400                                Expr* e, CFGBlock* dispatch,
401                                GRCoreEngineImpl* eng)
402  : Eng(*eng), Src(src), DispatchBlock(*dispatch), E(e), Pred(pred) {}
403
404
405  class Iterator {
406    CFGBlock::succ_iterator I;
407
408    friend class GRIndirectGotoNodeBuilderImpl;
409    Iterator(CFGBlock::succ_iterator i) : I(i) {}
410  public:
411
412    Iterator& operator++() { ++I; return *this; }
413    bool operator!=(const Iterator& X) const { return I != X.I; }
414
415    LabelStmt* getLabel() const {
416      return llvm::cast<LabelStmt>((*I)->getLabel());
417    }
418
419    CFGBlock*  getBlock() const {
420      return *I;
421    }
422  };
423
424  Iterator begin() { return Iterator(DispatchBlock.succ_begin()); }
425  Iterator end() { return Iterator(DispatchBlock.succ_end()); }
426
427  ExplodedNodeImpl* generateNodeImpl(const Iterator& I, const void* State,
428                                     bool isSink);
429
430  Expr* getTarget() const { return E; }
431  const void* getState() const { return Pred->State; }
432};
433
434template<typename STATE>
435class GRIndirectGotoNodeBuilder {
436  typedef STATE                                  StateTy;
437  typedef ExplodedGraph<StateTy>                 GraphTy;
438  typedef typename GraphTy::NodeTy               NodeTy;
439
440  GRIndirectGotoNodeBuilderImpl& NB;
441
442public:
443  GRIndirectGotoNodeBuilder(GRIndirectGotoNodeBuilderImpl& nb) : NB(nb) {}
444
445  typedef GRIndirectGotoNodeBuilderImpl::Iterator     iterator;
446
447  iterator begin() { return NB.begin(); }
448  iterator end() { return NB.end(); }
449
450  Expr* getTarget() const { return NB.getTarget(); }
451
452  NodeTy* generateNode(const iterator& I, const StateTy* St, bool isSink=false){
453    return static_cast<NodeTy*>(NB.generateNodeImpl(I, St, isSink));
454  }
455
456  const StateTy* getState() const {
457    return static_cast<const StateTy*>(NB.getState());
458  }
459};
460
461class GRSwitchNodeBuilderImpl {
462  GRCoreEngineImpl& Eng;
463  CFGBlock* Src;
464  Expr* Condition;
465  ExplodedNodeImpl* Pred;
466public:
467  GRSwitchNodeBuilderImpl(ExplodedNodeImpl* pred, CFGBlock* src,
468                          Expr* condition, GRCoreEngineImpl* eng)
469  : Eng(*eng), Src(src), Condition(condition), Pred(pred) {}
470
471  class Iterator {
472    CFGBlock::succ_reverse_iterator I;
473
474    friend class GRSwitchNodeBuilderImpl;
475    Iterator(CFGBlock::succ_reverse_iterator i) : I(i) {}
476  public:
477
478    Iterator& operator++() { ++I; return *this; }
479    bool operator!=(const Iterator& X) const { return I != X.I; }
480
481    CaseStmt* getCase() const {
482      return llvm::cast<CaseStmt>((*I)->getLabel());
483    }
484
485    CFGBlock* getBlock() const {
486      return *I;
487    }
488  };
489
490  Iterator begin() { return Iterator(Src->succ_rbegin()+1); }
491  Iterator end() { return Iterator(Src->succ_rend()); }
492
493  ExplodedNodeImpl* generateCaseStmtNodeImpl(const Iterator& I,
494                                             const void* State);
495
496  ExplodedNodeImpl* generateDefaultCaseNodeImpl(const void* State,
497                                                bool isSink);
498
499  Expr* getCondition() const { return Condition; }
500  const void* getState() const { return Pred->State; }
501};
502
503template<typename STATE>
504class GRSwitchNodeBuilder {
505  typedef STATE                                  StateTy;
506  typedef ExplodedGraph<StateTy>                 GraphTy;
507  typedef typename GraphTy::NodeTy               NodeTy;
508
509  GRSwitchNodeBuilderImpl& NB;
510
511public:
512  GRSwitchNodeBuilder(GRSwitchNodeBuilderImpl& nb) : NB(nb) {}
513
514  typedef GRSwitchNodeBuilderImpl::Iterator     iterator;
515
516  iterator begin() { return NB.begin(); }
517  iterator end() { return NB.end(); }
518
519  Expr* getCondition() const { return NB.getCondition(); }
520
521  NodeTy* generateCaseStmtNode(const iterator& I, const StateTy* St) {
522    return static_cast<NodeTy*>(NB.generateCaseStmtNodeImpl(I, St));
523  }
524
525  NodeTy* generateDefaultCaseNode(const StateTy* St, bool isSink = false) {
526    return static_cast<NodeTy*>(NB.generateDefaultCaseNodeImpl(St, isSink));
527  }
528
529  const StateTy* getState() const {
530    return static_cast<const StateTy*>(NB.getState());
531  }
532};
533
534
535class GREndPathNodeBuilderImpl {
536  GRCoreEngineImpl& Eng;
537  CFGBlock& B;
538  ExplodedNodeImpl* Pred;
539  bool HasGeneratedNode;
540
541public:
542  GREndPathNodeBuilderImpl(CFGBlock* b, ExplodedNodeImpl* N,
543                           GRCoreEngineImpl* e)
544    : Eng(*e), B(*b), Pred(N), HasGeneratedNode(false) {}
545
546  ~GREndPathNodeBuilderImpl();
547
548  ExplodedNodeImpl* getPredecessor() const { return Pred; }
549
550  GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
551
552  unsigned getCurrentBlockCount() const {
553    return getBlockCounter().getNumVisited(B.getBlockID());
554  }
555
556  ExplodedNodeImpl* generateNodeImpl(const void* State,
557                                     const void *tag = 0,
558                                     ExplodedNodeImpl *P = 0);
559
560  CFGBlock* getBlock() const { return &B; }
561};
562
563
564template<typename STATE>
565class GREndPathNodeBuilder  {
566  typedef STATE                   StateTy;
567  typedef ExplodedNode<StateTy>   NodeTy;
568
569  GREndPathNodeBuilderImpl& NB;
570
571public:
572  GREndPathNodeBuilder(GREndPathNodeBuilderImpl& nb) : NB(nb) {}
573
574  NodeTy* getPredecessor() const {
575    return static_cast<NodeTy*>(NB.getPredecessor());
576  }
577
578  GRBlockCounter getBlockCounter() const {
579    return NB.getBlockCounter();
580  }
581
582  unsigned getCurrentBlockCount() const {
583    return NB.getCurrentBlockCount();
584  }
585
586  const StateTy* getState() const {
587    return getPredecessor()->getState();
588  }
589
590  NodeTy* MakeNode(const StateTy* St, const void *tag = 0) {
591    return static_cast<NodeTy*>(NB.generateNodeImpl(St, tag));
592  }
593
594  NodeTy *generateNode(const StateTy *St, NodeTy *Pred, const void *tag = 0) {
595    return static_cast<NodeTy*>(NB.generateNodeImpl(St, tag, Pred));
596  }
597};
598
599
600template<typename SUBENGINE>
601class GRCoreEngine : public GRCoreEngineImpl {
602public:
603  typedef SUBENGINE                              SubEngineTy;
604  typedef typename SubEngineTy::StateTy          StateTy;
605  typedef typename StateTy::ManagerTy            StateManagerTy;
606  typedef ExplodedGraph<StateTy>                 GraphTy;
607  typedef typename GraphTy::NodeTy               NodeTy;
608
609protected:
610  SubEngineTy& SubEngine;
611
612  virtual const void* getInitialState() {
613    return SubEngine.getInitialState();
614  }
615
616  virtual void ProcessEndPath(GREndPathNodeBuilderImpl& BuilderImpl) {
617    GREndPathNodeBuilder<StateTy> Builder(BuilderImpl);
618    SubEngine.ProcessEndPath(Builder);
619  }
620
621  virtual void ProcessStmt(Stmt* S, GRStmtNodeBuilderImpl& BuilderImpl) {
622    GRStmtNodeBuilder<StateTy> Builder(BuilderImpl,SubEngine.getStateManager());
623    SubEngine.ProcessStmt(S, Builder);
624  }
625
626  virtual bool ProcessBlockEntrance(CFGBlock* Blk, const void* State,
627                                    GRBlockCounter BC) {
628    return SubEngine.ProcessBlockEntrance(Blk,
629                                          static_cast<const StateTy*>(State),
630                                          BC);
631  }
632
633  virtual void ProcessBranch(Stmt* Condition, Stmt* Terminator,
634                             GRBranchNodeBuilderImpl& BuilderImpl) {
635    GRBranchNodeBuilder<StateTy> Builder(BuilderImpl);
636    SubEngine.ProcessBranch(Condition, Terminator, Builder);
637  }
638
639  virtual void ProcessIndirectGoto(GRIndirectGotoNodeBuilderImpl& BuilderImpl) {
640    GRIndirectGotoNodeBuilder<StateTy> Builder(BuilderImpl);
641    SubEngine.ProcessIndirectGoto(Builder);
642  }
643
644  virtual void ProcessSwitch(GRSwitchNodeBuilderImpl& BuilderImpl) {
645    GRSwitchNodeBuilder<StateTy> Builder(BuilderImpl);
646    SubEngine.ProcessSwitch(Builder);
647  }
648
649public:
650  /// Construct a GRCoreEngine object to analyze the provided CFG using
651  ///  a DFS exploration of the exploded graph.
652  GRCoreEngine(CFG& cfg, Decl& cd, ASTContext& ctx, SubEngineTy& subengine)
653    : GRCoreEngineImpl(new GraphTy(cfg, cd, ctx),
654                       GRWorkList::MakeBFS()),
655      SubEngine(subengine) {}
656
657  /// Construct a GRCoreEngine object to analyze the provided CFG and to
658  ///  use the provided worklist object to execute the worklist algorithm.
659  ///  The GRCoreEngine object assumes ownership of 'wlist'.
660  GRCoreEngine(CFG& cfg, Decl& cd, ASTContext& ctx, GRWorkList* wlist,
661               SubEngineTy& subengine)
662    : GRCoreEngineImpl(new GraphTy(cfg, cd, ctx), wlist),
663      SubEngine(subengine) {}
664
665  virtual ~GRCoreEngine() {}
666
667  /// getGraph - Returns the exploded graph.
668  GraphTy& getGraph() {
669    return *static_cast<GraphTy*>(G.get());
670  }
671
672  /// takeGraph - Returns the exploded graph.  Ownership of the graph is
673  ///  transfered to the caller.
674  GraphTy* takeGraph() {
675    return static_cast<GraphTy*>(G.take());
676  }
677};
678
679} // end clang namespace
680
681#endif
682