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