CoreEngine.h revision 6b6152ba96c164a292cc0b8d8b1d4cecbec27a60
1//==- CoreEngine.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_GR_COREENGINE 16#define LLVM_CLANG_GR_COREENGINE 17 18#include "clang/AST/Expr.h" 19#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" 20#include "clang/StaticAnalyzer/Core/PathSensitive/WorkList.h" 21#include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h" 22#include "llvm/ADT/OwningPtr.h" 23 24namespace clang { 25 26class ProgramPointTag; 27 28namespace ento { 29 30class NodeBuilder; 31 32//===----------------------------------------------------------------------===// 33/// CoreEngine - Implements the core logic of the graph-reachability 34/// analysis. It traverses the CFG and generates the ExplodedGraph. 35/// Program "states" are treated as opaque void pointers. 36/// The template class CoreEngine (which subclasses CoreEngine) 37/// provides the matching component to the engine that knows the actual types 38/// for states. Note that this engine only dispatches to transfer functions 39/// at the statement and block-level. The analyses themselves must implement 40/// any transfer function logic and the sub-expression level (if any). 41class CoreEngine { 42 friend class CommonNodeBuilder; 43 friend class NodeBuilder; 44 friend class StmtNodeBuilder; 45 friend class GenericNodeBuilderImpl; 46 friend class BranchNodeBuilder; 47 friend class IndirectGotoNodeBuilder; 48 friend class SwitchNodeBuilder; 49 friend class EndOfFunctionNodeBuilder; 50 friend class CallEnterNodeBuilder; 51 friend class CallExitNodeBuilder; 52 53public: 54 typedef std::vector<std::pair<BlockEdge, const ExplodedNode*> > 55 BlocksExhausted; 56 57 typedef std::vector<std::pair<const CFGBlock*, const ExplodedNode*> > 58 BlocksAborted; 59 60private: 61 62 SubEngine& SubEng; 63 64 /// G - The simulation graph. Each node is a (location,state) pair. 65 llvm::OwningPtr<ExplodedGraph> G; 66 67 /// WList - A set of queued nodes that need to be processed by the 68 /// worklist algorithm. It is up to the implementation of WList to decide 69 /// the order that nodes are processed. 70 WorkList* WList; 71 72 /// BCounterFactory - A factory object for created BlockCounter objects. 73 /// These are used to record for key nodes in the ExplodedGraph the 74 /// number of times different CFGBlocks have been visited along a path. 75 BlockCounter::Factory BCounterFactory; 76 77 /// The locations where we stopped doing work because we visited a location 78 /// too many times. 79 BlocksExhausted blocksExhausted; 80 81 /// The locations where we stopped because the engine aborted analysis, 82 /// usually because it could not reason about something. 83 BlocksAborted blocksAborted; 84 85 void generateNode(const ProgramPoint &Loc, 86 const ProgramState *State, 87 ExplodedNode *Pred); 88 89 void HandleBlockEdge(const BlockEdge &E, ExplodedNode *Pred); 90 void HandleBlockEntrance(const BlockEntrance &E, ExplodedNode *Pred); 91 void HandleBlockExit(const CFGBlock *B, ExplodedNode *Pred); 92 void HandlePostStmt(const CFGBlock *B, unsigned StmtIdx, ExplodedNode *Pred); 93 94 void HandleBranch(const Stmt *Cond, const Stmt *Term, const CFGBlock *B, 95 ExplodedNode *Pred); 96 void HandleCallEnter(const CallEnter &L, const CFGBlock *Block, 97 unsigned Index, ExplodedNode *Pred); 98 void HandleCallExit(const CallExit &L, ExplodedNode *Pred); 99 100private: 101 CoreEngine(const CoreEngine&); // Do not implement. 102 CoreEngine& operator=(const CoreEngine&); 103 104public: 105 /// Construct a CoreEngine object to analyze the provided CFG using 106 /// a DFS exploration of the exploded graph. 107 CoreEngine(SubEngine& subengine) 108 : SubEng(subengine), G(new ExplodedGraph()), 109 WList(WorkList::makeBFS()), 110 BCounterFactory(G->getAllocator()) {} 111 112 /// Construct a CoreEngine object to analyze the provided CFG and to 113 /// use the provided worklist object to execute the worklist algorithm. 114 /// The CoreEngine object assumes ownership of 'wlist'. 115 CoreEngine(WorkList* wlist, SubEngine& subengine) 116 : SubEng(subengine), G(new ExplodedGraph()), WList(wlist), 117 BCounterFactory(G->getAllocator()) {} 118 119 ~CoreEngine() { 120 delete WList; 121 } 122 123 /// getGraph - Returns the exploded graph. 124 ExplodedGraph& getGraph() { return *G.get(); } 125 126 /// takeGraph - Returns the exploded graph. Ownership of the graph is 127 /// transferred to the caller. 128 ExplodedGraph* takeGraph() { return G.take(); } 129 130 /// ExecuteWorkList - Run the worklist algorithm for a maximum number of 131 /// steps. Returns true if there is still simulation state on the worklist. 132 bool ExecuteWorkList(const LocationContext *L, unsigned Steps, 133 const ProgramState *InitState); 134 void ExecuteWorkListWithInitialState(const LocationContext *L, 135 unsigned Steps, 136 const ProgramState *InitState, 137 ExplodedNodeSet &Dst); 138 139 // Functions for external checking of whether we have unfinished work 140 bool wasBlockAborted() const { return !blocksAborted.empty(); } 141 bool wasBlocksExhausted() const { return !blocksExhausted.empty(); } 142 bool hasWorkRemaining() const { return wasBlocksExhausted() || 143 WList->hasWork() || 144 wasBlockAborted(); } 145 146 /// Inform the CoreEngine that a basic block was aborted because 147 /// it could not be completely analyzed. 148 void addAbortedBlock(const ExplodedNode *node, const CFGBlock *block) { 149 blocksAborted.push_back(std::make_pair(block, node)); 150 } 151 152 WorkList *getWorkList() const { return WList; } 153 154 BlocksExhausted::const_iterator blocks_exhausted_begin() const { 155 return blocksExhausted.begin(); 156 } 157 BlocksExhausted::const_iterator blocks_exhausted_end() const { 158 return blocksExhausted.end(); 159 } 160 BlocksAborted::const_iterator blocks_aborted_begin() const { 161 return blocksAborted.begin(); 162 } 163 BlocksAborted::const_iterator blocks_aborted_end() const { 164 return blocksAborted.end(); 165 } 166 167 /// Enqueue the results of the node builder onto the work list. 168 void enqueue(ExplodedNodeSet &NB); 169}; 170 171struct NodeBuilderContext { 172 CoreEngine &Eng; 173 const CFGBlock *Block; 174 ExplodedNode *ContextPred; 175 NodeBuilderContext(CoreEngine &E, const CFGBlock *B, ExplodedNode *N) 176 : Eng(E), Block(B), ContextPred(N) { assert(B); assert(!N->isSink()); } 177}; 178 179/// This is the simplest builder which generates nodes in the ExplodedGraph. 180class NodeBuilder { 181protected: 182 friend class StmtNodeBuilder; 183 184 const NodeBuilderContext &C; 185 186 /// Specifies if the builder results have been finalized. For example, if it 187 /// is set to false, autotransitions are yet to be generated. 188 bool Finalized; 189 190 bool HasGeneratedNodes; 191 192 /// \brief The frontier set - a set of nodes which need to be propagated after 193 /// the builder dies. 194 ExplodedNodeSet &Frontier; 195 196 BlockCounter getBlockCounter() const { return C.Eng.WList->getBlockCounter();} 197 198 /// Checkes if the results are ready. 199 virtual bool checkResults() { 200 if (!Finalized) 201 return false; 202 return true; 203 } 204 205 bool haveNoSinksInFrontier() { 206 for (iterator I = Frontier.begin(), E = Frontier.end(); I != E; ++I) { 207 if ((*I)->isSink()) 208 return false; 209 } 210 return true; 211 } 212 213 /// Allow subclasses to finalize results before result_begin() is executed. 214 virtual void finalizeResults() {} 215 216 ExplodedNode *generateNodeImpl(const ProgramPoint &PP, 217 const ProgramState *State, 218 ExplodedNode *Pred, 219 bool MarkAsSink = false); 220 221public: 222 NodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet, 223 const NodeBuilderContext &Ctx, bool F = true) 224 : C(Ctx), Finalized(F), HasGeneratedNodes(false), Frontier(DstSet) { 225 // assert(DstSet.empty()); 226 Frontier.Add(SrcNode); 227 } 228 229 NodeBuilder(const ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet, 230 const NodeBuilderContext &Ctx, bool F = true) 231 : C(Ctx), Finalized(F), HasGeneratedNodes(false), Frontier(DstSet) { 232 //assert(DstSet.empty()); 233 //assert(!SrcSet.empty()); 234 Frontier.insert(SrcSet); 235 assert(haveNoSinksInFrontier()); 236 } 237 238 virtual ~NodeBuilder() {} 239 240 /// \brief Generates a node in the ExplodedGraph. 241 /// 242 /// When a node is marked as sink, the exploration from the node is stopped - 243 /// the node becomes the last node on the path. 244 ExplodedNode *generateNode(const ProgramPoint &PP, 245 const ProgramState *State, 246 ExplodedNode *Pred, 247 bool MarkAsSink = false) { 248 return generateNodeImpl(PP, State, Pred, MarkAsSink); 249 } 250 251 // TODO: will get removed. 252 bool hasGeneratedNodes() const { 253 return HasGeneratedNodes; 254 } 255 256 const ExplodedNodeSet &getResults() { 257 finalizeResults(); 258 assert(checkResults()); 259 return Frontier; 260 } 261 262 typedef ExplodedNodeSet::iterator iterator; 263 /// \brief Iterators through the results frontier. 264 inline iterator begin() { 265 finalizeResults(); 266 assert(checkResults()); 267 return Frontier.begin(); 268 } 269 inline iterator end() { 270 finalizeResults(); 271 return Frontier.end(); 272 } 273 274 /// \brief Return the CFGBlock associated with this builder. 275 const CFGBlock *getBlock() const { return C.Block; } 276 277 const NodeBuilderContext &getContext() { return C; } 278 279 /// \brief Returns the number of times the current basic block has been 280 /// visited on the exploded graph path. 281 unsigned getCurrentBlockCount() const { 282 return getBlockCounter().getNumVisited( 283 C.ContextPred->getLocationContext()->getCurrentStackFrame(), 284 C.Block->getBlockID()); 285 } 286}; 287 288class CommonNodeBuilder { 289protected: 290 ExplodedNode *Pred; 291 CoreEngine& Eng; 292 293 CommonNodeBuilder(CoreEngine* E, ExplodedNode *P) : Pred(P), Eng(*E) {} 294 BlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter(); } 295}; 296 297 298class PureStmtNodeBuilder: public NodeBuilder { 299public: 300 PureStmtNodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet, 301 const NodeBuilderContext &Ctx) 302 : NodeBuilder(SrcNode, DstSet, Ctx) {} 303 304 PureStmtNodeBuilder(ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet, 305 const NodeBuilderContext &Ctx) 306 : NodeBuilder(SrcSet, DstSet, Ctx) {} 307 308 ExplodedNode *generateNode(const Stmt *S, 309 ExplodedNode *Pred, 310 const ProgramState *St, 311 ProgramPoint::Kind K = ProgramPoint::PostStmtKind, 312 bool MarkAsSink = false, 313 const ProgramPointTag *tag = 0, 314 bool Purging = false) { 315 if (Purging) { 316 assert(K == ProgramPoint::PostStmtKind); 317 K = ProgramPoint::PostPurgeDeadSymbolsKind; 318 } 319 320 const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K, 321 Pred->getLocationContext(), tag); 322 return generateNodeImpl(L, St, Pred, MarkAsSink); 323 } 324}; 325 326class StmtNodeBuilder : public NodeBuilder { 327 const unsigned Idx; 328 329public: 330 bool PurgingDeadSymbols; 331 bool BuildSinks; 332 // TODO: Remove the flag. We should be able to use the method in the parent. 333 bool hasGeneratedNode; 334 ProgramPoint::Kind PointKind; 335 const ProgramPointTag *Tag; 336 337 void GenerateAutoTransition(ExplodedNode *N); 338 339 StmtNodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet, 340 unsigned idx, const NodeBuilderContext &Ctx) 341 : NodeBuilder(SrcNode, DstSet, Ctx), Idx(idx), 342 PurgingDeadSymbols(false), BuildSinks(false), hasGeneratedNode(false), 343 PointKind(ProgramPoint::PostStmtKind), Tag(0) {} 344 345 virtual ~StmtNodeBuilder(); 346 347 ExplodedNode *generateNode(const Stmt *S, 348 const ProgramState *St, 349 ExplodedNode *Pred, 350 ProgramPoint::Kind K, 351 const ProgramPointTag *tag = 0, 352 bool MarkAsSink = false) { 353 if (PurgingDeadSymbols) 354 K = ProgramPoint::PostPurgeDeadSymbolsKind; 355 356 const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K, 357 Pred->getLocationContext(), tag ? tag : Tag); 358 return generateNodeImpl(L, St, Pred, MarkAsSink); 359 } 360 361 ExplodedNode *generateNode(const Stmt *S, 362 const ProgramState *St, 363 ExplodedNode *Pred, 364 const ProgramPointTag *tag = 0) { 365 return generateNode(S, St, Pred, PointKind, tag); 366 } 367 368 ExplodedNode *generateNode(const ProgramPoint &PP, 369 const ProgramState *State, 370 ExplodedNode *Pred) { 371 return generateNodeImpl(PP, State, Pred, false); 372 } 373 374 /// getStmt - Return the current block-level expression associated with 375 /// this builder. 376 const Stmt *getStmt() const { 377 const CFGStmt *CS = (*C.Block)[Idx].getAs<CFGStmt>(); 378 return CS ? CS->getStmt() : 0; 379 } 380 381 unsigned getIndex() const { return Idx; } 382 383 ExplodedNode *MakeNode(ExplodedNodeSet &Dst, 384 const Stmt *S, 385 ExplodedNode *Pred, 386 const ProgramState *St) { 387 return MakeNode(Dst, S, Pred, St, PointKind); 388 } 389 390 ExplodedNode *MakeNode(ExplodedNodeSet &Dst, 391 const Stmt *S, 392 ExplodedNode *Pred, 393 const ProgramState *St, 394 ProgramPoint::Kind K); 395 396 ExplodedNode *MakeSinkNode(ExplodedNodeSet &Dst, 397 const Stmt *S, 398 ExplodedNode *Pred, 399 const ProgramState *St) { 400 bool Tmp = BuildSinks; 401 BuildSinks = true; 402 ExplodedNode *N = MakeNode(Dst, S, Pred, St); 403 BuildSinks = Tmp; 404 return N; 405 } 406 407 void takeNodes(const ExplodedNodeSet &S) { 408 for (ExplodedNodeSet::iterator I = S.begin(), E = S.end(); I != E; ++I ) 409 Frontier.erase(*I); 410 } 411 412 void takeNodes(ExplodedNode *N) { 413 Frontier.erase(N); 414 } 415 416 void addNodes(const ExplodedNodeSet &S) { 417 Frontier.insert(S); 418 } 419 420 void addNodes(ExplodedNode *N) { 421 Frontier.Add(N); 422 } 423}; 424 425class BranchNodeBuilder: public NodeBuilder { 426 const CFGBlock *DstT; 427 const CFGBlock *DstF; 428 429 bool InFeasibleTrue; 430 bool InFeasibleFalse; 431 432public: 433 BranchNodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet, 434 const NodeBuilderContext &C, 435 const CFGBlock *dstT, const CFGBlock *dstF) 436 : NodeBuilder(SrcNode, DstSet, C), DstT(dstT), DstF(dstF), 437 InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) {} 438 439 BranchNodeBuilder(const ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet, 440 const NodeBuilderContext &C, 441 const CFGBlock *dstT, const CFGBlock *dstF) 442 : NodeBuilder(SrcSet, DstSet, C), DstT(dstT), DstF(dstF), 443 InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) {} 444 445 ExplodedNode *generateNode(const ProgramState *State, bool branch, 446 ExplodedNode *Pred); 447 448 const CFGBlock *getTargetBlock(bool branch) const { 449 return branch ? DstT : DstF; 450 } 451 452 void markInfeasible(bool branch) { 453 if (branch) 454 InFeasibleTrue = true; 455 else 456 InFeasibleFalse = true; 457 } 458 459 bool isFeasible(bool branch) { 460 return branch ? !InFeasibleTrue : !InFeasibleFalse; 461 } 462}; 463 464class IndirectGotoNodeBuilder { 465 CoreEngine& Eng; 466 const CFGBlock *Src; 467 const CFGBlock &DispatchBlock; 468 const Expr *E; 469 ExplodedNode *Pred; 470 471public: 472 IndirectGotoNodeBuilder(ExplodedNode *pred, const CFGBlock *src, 473 const Expr *e, const CFGBlock *dispatch, CoreEngine* eng) 474 : Eng(*eng), Src(src), DispatchBlock(*dispatch), E(e), Pred(pred) {} 475 476 class iterator { 477 CFGBlock::const_succ_iterator I; 478 479 friend class IndirectGotoNodeBuilder; 480 iterator(CFGBlock::const_succ_iterator i) : I(i) {} 481 public: 482 483 iterator &operator++() { ++I; return *this; } 484 bool operator!=(const iterator &X) const { return I != X.I; } 485 486 const LabelDecl *getLabel() const { 487 return llvm::cast<LabelStmt>((*I)->getLabel())->getDecl(); 488 } 489 490 const CFGBlock *getBlock() const { 491 return *I; 492 } 493 }; 494 495 iterator begin() { return iterator(DispatchBlock.succ_begin()); } 496 iterator end() { return iterator(DispatchBlock.succ_end()); } 497 498 ExplodedNode *generateNode(const iterator &I, 499 const ProgramState *State, 500 bool isSink = false); 501 502 const Expr *getTarget() const { return E; } 503 504 const ProgramState *getState() const { return Pred->State; } 505}; 506 507class SwitchNodeBuilder { 508 CoreEngine& Eng; 509 const CFGBlock *Src; 510 const Expr *Condition; 511 ExplodedNode *Pred; 512 513public: 514 SwitchNodeBuilder(ExplodedNode *pred, const CFGBlock *src, 515 const Expr *condition, CoreEngine* eng) 516 : Eng(*eng), Src(src), Condition(condition), Pred(pred) {} 517 518 class iterator { 519 CFGBlock::const_succ_reverse_iterator I; 520 521 friend class SwitchNodeBuilder; 522 iterator(CFGBlock::const_succ_reverse_iterator i) : I(i) {} 523 524 public: 525 iterator &operator++() { ++I; return *this; } 526 bool operator!=(const iterator &X) const { return I != X.I; } 527 bool operator==(const iterator &X) const { return I == X.I; } 528 529 const CaseStmt *getCase() const { 530 return llvm::cast<CaseStmt>((*I)->getLabel()); 531 } 532 533 const CFGBlock *getBlock() const { 534 return *I; 535 } 536 }; 537 538 iterator begin() { return iterator(Src->succ_rbegin()+1); } 539 iterator end() { return iterator(Src->succ_rend()); } 540 541 const SwitchStmt *getSwitch() const { 542 return llvm::cast<SwitchStmt>(Src->getTerminator()); 543 } 544 545 ExplodedNode *generateCaseStmtNode(const iterator &I, 546 const ProgramState *State); 547 548 ExplodedNode *generateDefaultCaseNode(const ProgramState *State, 549 bool isSink = false); 550 551 const Expr *getCondition() const { return Condition; } 552 553 const ProgramState *getState() const { return Pred->State; } 554}; 555 556class GenericNodeBuilderImpl { 557protected: 558 CoreEngine &engine; 559 ExplodedNode *pred; 560 ProgramPoint pp; 561 SmallVector<ExplodedNode*, 2> sinksGenerated; 562 563 ExplodedNode *generateNodeImpl(const ProgramState *state, 564 ExplodedNode *pred, 565 ProgramPoint programPoint, 566 bool asSink); 567 568 GenericNodeBuilderImpl(CoreEngine &eng, ExplodedNode *pr, ProgramPoint p) 569 : engine(eng), pred(pr), pp(p), hasGeneratedNode(false) {} 570 571public: 572 bool hasGeneratedNode; 573 574 WorkList &getWorkList() { return *engine.WList; } 575 576 ExplodedNode *getPredecessor() const { return pred; } 577 578 BlockCounter getBlockCounter() const { 579 return engine.WList->getBlockCounter(); 580 } 581 582 const SmallVectorImpl<ExplodedNode*> &sinks() const { 583 return sinksGenerated; 584 } 585}; 586 587template <typename PP_T> 588class GenericNodeBuilder : public GenericNodeBuilderImpl { 589public: 590 GenericNodeBuilder(CoreEngine &eng, ExplodedNode *pr, const PP_T &p) 591 : GenericNodeBuilderImpl(eng, pr, p) {} 592 593 ExplodedNode *generateNode(const ProgramState *state, ExplodedNode *pred, 594 const ProgramPointTag *tag, bool asSink) { 595 return generateNodeImpl(state, pred, cast<PP_T>(pp).withTag(tag), 596 asSink); 597 } 598 599 const PP_T &getProgramPoint() const { return cast<PP_T>(pp); } 600}; 601 602class EndOfFunctionNodeBuilder : public CommonNodeBuilder { 603 const CFGBlock &B; 604 const ProgramPointTag *Tag; 605 606public: 607 bool hasGeneratedNode; 608 609public: 610 EndOfFunctionNodeBuilder(const CFGBlock *b, ExplodedNode *N, CoreEngine* e, 611 const ProgramPointTag *tag = 0) 612 : CommonNodeBuilder(e, N), B(*b), Tag(tag), hasGeneratedNode(false) {} 613 614 ~EndOfFunctionNodeBuilder(); 615 616 EndOfFunctionNodeBuilder withCheckerTag(const ProgramPointTag *tag) { 617 return EndOfFunctionNodeBuilder(&B, Pred, &Eng, tag); 618 } 619 620 WorkList &getWorkList() { return *Eng.WList; } 621 622 ExplodedNode *getPredecessor() const { return Pred; } 623 624 unsigned getCurrentBlockCount() const { 625 return getBlockCounter().getNumVisited( 626 Pred->getLocationContext()->getCurrentStackFrame(), 627 B.getBlockID()); 628 } 629 630 ExplodedNode *generateNode(const ProgramState *State, 631 ExplodedNode *P = 0, 632 const ProgramPointTag *tag = 0); 633 634 void GenerateCallExitNode(const ProgramState *state); 635 636 const CFGBlock *getBlock() const { return &B; } 637 638 const ProgramState *getState() const { 639 return getPredecessor()->getState(); 640 } 641}; 642 643class CallEnterNodeBuilder { 644 CoreEngine &Eng; 645 646 const ExplodedNode *Pred; 647 648 // The call site. For implicit automatic object dtor, this is the trigger 649 // statement. 650 const Stmt *CE; 651 652 // The context of the callee. 653 const StackFrameContext *CalleeCtx; 654 655 // The parent block of the CallExpr. 656 const CFGBlock *Block; 657 658 // The CFGBlock index of the CallExpr. 659 unsigned Index; 660 661public: 662 CallEnterNodeBuilder(CoreEngine &eng, const ExplodedNode *pred, 663 const Stmt *s, const StackFrameContext *callee, 664 const CFGBlock *blk, unsigned idx) 665 : Eng(eng), Pred(pred), CE(s), CalleeCtx(callee), Block(blk), Index(idx) {} 666 667 const ProgramState *getState() const { return Pred->getState(); } 668 669 const LocationContext *getLocationContext() const { 670 return Pred->getLocationContext(); 671 } 672 673 const Stmt *getCallExpr() const { return CE; } 674 675 const StackFrameContext *getCalleeContext() const { return CalleeCtx; } 676 677 const CFGBlock *getBlock() const { return Block; } 678 679 unsigned getIndex() const { return Index; } 680 681 void generateNode(const ProgramState *state); 682}; 683 684class CallExitNodeBuilder { 685 CoreEngine &Eng; 686 const ExplodedNode *Pred; 687 688public: 689 CallExitNodeBuilder(CoreEngine &eng, const ExplodedNode *pred) 690 : Eng(eng), Pred(pred) {} 691 692 const ExplodedNode *getPredecessor() const { return Pred; } 693 694 const ProgramState *getState() const { return Pred->getState(); } 695 696 void generateNode(const ProgramState *state); 697}; 698 699} // end GR namespace 700 701} // end clang namespace 702 703#endif 704