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