1 //==- CoreEngine.cpp - Path-Sensitive Dataflow Engine ------------*- C++ -*-//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file defines a generic engine for intraprocedural, path-sensitive,
11 // dataflow analysis via graph reachability engine.
13 //===----------------------------------------------------------------------===//
15 #include "clang/StaticAnalyzer/PathSensitive/AnalysisManager.h"
16 #include "clang/StaticAnalyzer/PathSensitive/CoreEngine.h"
17 #include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
18 #include "clang/Index/TranslationUnit.h"
19 #include "clang/AST/Expr.h"
20 #include "llvm/Support/Casting.h"
21 #include "llvm/ADT/DenseMap.h"
27 using namespace clang
;
30 // This should be removed in the future.
33 TransferFuncs
* MakeCFRefCountTF(ASTContext
& Ctx
, bool GCEnabled
,
34 const LangOptions
& lopts
);
38 //===----------------------------------------------------------------------===//
39 // Worklist classes for exploration of reachable states.
40 //===----------------------------------------------------------------------===//
42 WorkList::Visitor::~Visitor() {}
45 class DFS
: public WorkList
{
46 llvm::SmallVector
<WorkListUnit
,20> Stack
;
48 virtual bool hasWork() const {
49 return !Stack
.empty();
52 virtual void enqueue(const WorkListUnit
& U
) {
56 virtual WorkListUnit
dequeue() {
57 assert (!Stack
.empty());
58 const WorkListUnit
& U
= Stack
.back();
59 Stack
.pop_back(); // This technically "invalidates" U, but we are fine.
63 virtual bool visitItemsInWorkList(Visitor
&V
) {
64 for (llvm::SmallVectorImpl
<WorkListUnit
>::iterator
65 I
= Stack
.begin(), E
= Stack
.end(); I
!= E
; ++I
) {
73 class BFS
: public WorkList
{
74 std::deque
<WorkListUnit
> Queue
;
76 virtual bool hasWork() const {
77 return !Queue
.empty();
80 virtual void enqueue(const WorkListUnit
& U
) {
84 virtual WorkListUnit
dequeue() {
85 WorkListUnit U
= Queue
.front();
90 virtual bool visitItemsInWorkList(Visitor
&V
) {
91 for (std::deque
<WorkListUnit
>::iterator
92 I
= Queue
.begin(), E
= Queue
.end(); I
!= E
; ++I
) {
100 } // end anonymous namespace
102 // Place the dstor for WorkList here because it contains virtual member
103 // functions, and we the code for the dstor generated in one compilation unit.
104 WorkList::~WorkList() {}
106 WorkList
*WorkList::makeDFS() { return new DFS(); }
107 WorkList
*WorkList::makeBFS() { return new BFS(); }
110 class BFSBlockDFSContents
: public WorkList
{
111 std::deque
<WorkListUnit
> Queue
;
112 llvm::SmallVector
<WorkListUnit
,20> Stack
;
114 virtual bool hasWork() const {
115 return !Queue
.empty() || !Stack
.empty();
118 virtual void enqueue(const WorkListUnit
& U
) {
119 if (isa
<BlockEntrance
>(U
.getNode()->getLocation()))
125 virtual WorkListUnit
dequeue() {
126 // Process all basic blocks to completion.
127 if (!Stack
.empty()) {
128 const WorkListUnit
& U
= Stack
.back();
129 Stack
.pop_back(); // This technically "invalidates" U, but we are fine.
133 assert(!Queue
.empty());
134 // Don't use const reference. The subsequent pop_back() might make it
136 WorkListUnit U
= Queue
.front();
140 virtual bool visitItemsInWorkList(Visitor
&V
) {
141 for (llvm::SmallVectorImpl
<WorkListUnit
>::iterator
142 I
= Stack
.begin(), E
= Stack
.end(); I
!= E
; ++I
) {
146 for (std::deque
<WorkListUnit
>::iterator
147 I
= Queue
.begin(), E
= Queue
.end(); I
!= E
; ++I
) {
155 } // end anonymous namespace
157 WorkList
* WorkList::makeBFSBlockDFSContents() {
158 return new BFSBlockDFSContents();
161 //===----------------------------------------------------------------------===//
162 // Core analysis engine.
163 //===----------------------------------------------------------------------===//
165 /// ExecuteWorkList - Run the worklist algorithm for a maximum number of steps.
166 bool CoreEngine::ExecuteWorkList(const LocationContext
*L
, unsigned Steps
,
167 const GRState
*InitState
) {
169 if (G
->num_roots() == 0) { // Initialize the analysis by constructing
170 // the root if none exists.
172 const CFGBlock
* Entry
= &(L
->getCFG()->getEntry());
174 assert (Entry
->empty() &&
175 "Entry block must be empty.");
177 assert (Entry
->succ_size() == 1 &&
178 "Entry block must have 1 successor.");
180 // Get the solitary successor.
181 const CFGBlock
* Succ
= *(Entry
->succ_begin());
183 // Construct an edge representing the
184 // starting location in the function.
185 BlockEdge
StartLoc(Entry
, Succ
, L
);
187 // Set the current block counter to being empty.
188 WList
->setBlockCounter(BCounterFactory
.GetEmptyCounter());
191 // Generate the root.
192 generateNode(StartLoc
, SubEng
.getInitialState(L
), 0);
194 generateNode(StartLoc
, InitState
, 0);
197 // Check if we have a steps limit
198 bool UnlimitedSteps
= Steps
== 0;
200 while (WList
->hasWork()) {
201 if (!UnlimitedSteps
) {
207 const WorkListUnit
& WU
= WList
->dequeue();
209 // Set the current block counter.
210 WList
->setBlockCounter(WU
.getBlockCounter());
212 // Retrieve the node.
213 ExplodedNode
* Node
= WU
.getNode();
215 // Dispatch on the location type.
216 switch (Node
->getLocation().getKind()) {
217 case ProgramPoint::BlockEdgeKind
:
218 HandleBlockEdge(cast
<BlockEdge
>(Node
->getLocation()), Node
);
221 case ProgramPoint::BlockEntranceKind
:
222 HandleBlockEntrance(cast
<BlockEntrance
>(Node
->getLocation()), Node
);
225 case ProgramPoint::BlockExitKind
:
226 assert (false && "BlockExit location never occur in forward analysis.");
229 case ProgramPoint::CallEnterKind
:
230 HandleCallEnter(cast
<CallEnter
>(Node
->getLocation()), WU
.getBlock(),
231 WU
.getIndex(), Node
);
234 case ProgramPoint::CallExitKind
:
235 HandleCallExit(cast
<CallExit
>(Node
->getLocation()), Node
);
239 assert(isa
<PostStmt
>(Node
->getLocation()) ||
240 isa
<PostInitializer
>(Node
->getLocation()));
241 HandlePostStmt(WU
.getBlock(), WU
.getIndex(), Node
);
246 SubEng
.processEndWorklist(hasWorkRemaining());
247 return WList
->hasWork();
250 void CoreEngine::ExecuteWorkListWithInitialState(const LocationContext
*L
,
252 const GRState
*InitState
,
253 ExplodedNodeSet
&Dst
) {
254 ExecuteWorkList(L
, Steps
, InitState
);
255 for (llvm::SmallVectorImpl
<ExplodedNode
*>::iterator I
= G
->EndNodes
.begin(),
256 E
= G
->EndNodes
.end(); I
!= E
; ++I
) {
261 void CoreEngine::HandleCallEnter(const CallEnter
&L
, const CFGBlock
*Block
,
262 unsigned Index
, ExplodedNode
*Pred
) {
263 CallEnterNodeBuilder
Builder(*this, Pred
, L
.getCallExpr(),
264 L
.getCalleeContext(), Block
, Index
);
265 SubEng
.processCallEnter(Builder
);
268 void CoreEngine::HandleCallExit(const CallExit
&L
, ExplodedNode
*Pred
) {
269 CallExitNodeBuilder
Builder(*this, Pred
);
270 SubEng
.processCallExit(Builder
);
273 void CoreEngine::HandleBlockEdge(const BlockEdge
& L
, ExplodedNode
* Pred
) {
275 const CFGBlock
* Blk
= L
.getDst();
277 // Check if we are entering the EXIT block.
278 if (Blk
== &(L
.getLocationContext()->getCFG()->getExit())) {
280 assert (L
.getLocationContext()->getCFG()->getExit().size() == 0
281 && "EXIT block cannot contain Stmts.");
283 // Process the final state transition.
284 EndOfFunctionNodeBuilder
Builder(Blk
, Pred
, this);
285 SubEng
.processEndOfFunction(Builder
);
287 // This path is done. Don't enqueue any more nodes.
291 // Call into the subengine to process entering the CFGBlock.
292 ExplodedNodeSet dstNodes
;
293 BlockEntrance
BE(Blk
, Pred
->getLocationContext());
294 GenericNodeBuilder
<BlockEntrance
> nodeBuilder(*this, Pred
, BE
);
295 SubEng
.processCFGBlockEntrance(dstNodes
, nodeBuilder
);
297 if (dstNodes
.empty()) {
298 if (!nodeBuilder
.hasGeneratedNode
) {
299 // Auto-generate a node and enqueue it to the worklist.
300 generateNode(BE
, Pred
->State
, Pred
);
304 for (ExplodedNodeSet::iterator I
= dstNodes
.begin(), E
= dstNodes
.end();
310 for (llvm::SmallVectorImpl
<ExplodedNode
*>::const_iterator
311 I
= nodeBuilder
.sinks().begin(), E
= nodeBuilder
.sinks().end();
313 blocksAborted
.push_back(std::make_pair(L
, *I
));
317 void CoreEngine::HandleBlockEntrance(const BlockEntrance
& L
,
318 ExplodedNode
* Pred
) {
320 // Increment the block counter.
321 BlockCounter Counter
= WList
->getBlockCounter();
322 Counter
= BCounterFactory
.IncrementCount(Counter
,
323 Pred
->getLocationContext()->getCurrentStackFrame(),
324 L
.getBlock()->getBlockID());
325 WList
->setBlockCounter(Counter
);
327 // Process the entrance of the block.
328 if (CFGElement E
= L
.getFirstElement()) {
329 StmtNodeBuilder
Builder(L
.getBlock(), 0, Pred
, this,
330 SubEng
.getStateManager());
331 SubEng
.processCFGElement(E
, Builder
);
334 HandleBlockExit(L
.getBlock(), Pred
);
337 void CoreEngine::HandleBlockExit(const CFGBlock
* B
, ExplodedNode
* Pred
) {
339 if (const Stmt
* Term
= B
->getTerminator()) {
340 switch (Term
->getStmtClass()) {
342 assert(false && "Analysis for this terminator not implemented.");
345 case Stmt::BinaryOperatorClass
: // '&&' and '||'
346 HandleBranch(cast
<BinaryOperator
>(Term
)->getLHS(), Term
, B
, Pred
);
349 case Stmt::ConditionalOperatorClass
:
350 HandleBranch(cast
<ConditionalOperator
>(Term
)->getCond(), Term
, B
, Pred
);
353 // FIXME: Use constant-folding in CFG construction to simplify this
356 case Stmt::ChooseExprClass
:
357 HandleBranch(cast
<ChooseExpr
>(Term
)->getCond(), Term
, B
, Pred
);
360 case Stmt::DoStmtClass
:
361 HandleBranch(cast
<DoStmt
>(Term
)->getCond(), Term
, B
, Pred
);
364 case Stmt::ForStmtClass
:
365 HandleBranch(cast
<ForStmt
>(Term
)->getCond(), Term
, B
, Pred
);
368 case Stmt::ContinueStmtClass
:
369 case Stmt::BreakStmtClass
:
370 case Stmt::GotoStmtClass
:
373 case Stmt::IfStmtClass
:
374 HandleBranch(cast
<IfStmt
>(Term
)->getCond(), Term
, B
, Pred
);
377 case Stmt::IndirectGotoStmtClass
: {
378 // Only 1 successor: the indirect goto dispatch block.
379 assert (B
->succ_size() == 1);
381 IndirectGotoNodeBuilder
382 builder(Pred
, B
, cast
<IndirectGotoStmt
>(Term
)->getTarget(),
383 *(B
->succ_begin()), this);
385 SubEng
.processIndirectGoto(builder
);
389 case Stmt::ObjCForCollectionStmtClass
: {
390 // In the case of ObjCForCollectionStmt, it appears twice in a CFG:
392 // (1) inside a basic block, which represents the binding of the
393 // 'element' variable to a value.
394 // (2) in a terminator, which represents the branch.
396 // For (1), subengines will bind a value (i.e., 0 or 1) indicating
397 // whether or not collection contains any more elements. We cannot
398 // just test to see if the element is nil because a container can
399 // contain nil elements.
400 HandleBranch(Term
, Term
, B
, Pred
);
404 case Stmt::SwitchStmtClass
: {
405 SwitchNodeBuilder
builder(Pred
, B
, cast
<SwitchStmt
>(Term
)->getCond(),
408 SubEng
.processSwitch(builder
);
412 case Stmt::WhileStmtClass
:
413 HandleBranch(cast
<WhileStmt
>(Term
)->getCond(), Term
, B
, Pred
);
418 assert (B
->succ_size() == 1 &&
419 "Blocks with no terminator should have at most 1 successor.");
421 generateNode(BlockEdge(B
, *(B
->succ_begin()), Pred
->getLocationContext()),
425 void CoreEngine::HandleBranch(const Stmt
* Cond
, const Stmt
* Term
,
426 const CFGBlock
* B
, ExplodedNode
* Pred
) {
427 assert(B
->succ_size() == 2);
428 BranchNodeBuilder
Builder(B
, *(B
->succ_begin()), *(B
->succ_begin()+1),
430 SubEng
.processBranch(Cond
, Term
, Builder
);
433 void CoreEngine::HandlePostStmt(const CFGBlock
* B
, unsigned StmtIdx
,
434 ExplodedNode
* Pred
) {
435 assert (!B
->empty());
437 if (StmtIdx
== B
->size())
438 HandleBlockExit(B
, Pred
);
440 StmtNodeBuilder
Builder(B
, StmtIdx
, Pred
, this,
441 SubEng
.getStateManager());
442 SubEng
.processCFGElement((*B
)[StmtIdx
], Builder
);
446 /// generateNode - Utility method to generate nodes, hook up successors,
447 /// and add nodes to the worklist.
448 void CoreEngine::generateNode(const ProgramPoint
& Loc
,
449 const GRState
* State
, ExplodedNode
* Pred
) {
452 ExplodedNode
* Node
= G
->getNode(Loc
, State
, &IsNew
);
455 Node
->addPredecessor(Pred
, *G
); // Link 'Node' with its predecessor.
458 G
->addRoot(Node
); // 'Node' has no predecessor. Make it a root.
461 // Only add 'Node' to the worklist if it was freshly generated.
462 if (IsNew
) WList
->enqueue(Node
);
466 GenericNodeBuilderImpl::generateNodeImpl(const GRState
*state
,
468 ProgramPoint programPoint
,
471 hasGeneratedNode
= true;
473 ExplodedNode
*node
= engine
.getGraph().getNode(programPoint
, state
, &isNew
);
475 node
->addPredecessor(pred
, engine
.getGraph());
479 sinksGenerated
.push_back(node
);
486 StmtNodeBuilder::StmtNodeBuilder(const CFGBlock
* b
, unsigned idx
,
487 ExplodedNode
* N
, CoreEngine
* e
,
489 : Eng(*e
), B(*b
), Idx(idx
), Pred(N
), Mgr(mgr
),
490 PurgingDeadSymbols(false), BuildSinks(false), hasGeneratedNode(false),
491 PointKind(ProgramPoint::PostStmtKind
), Tag(0) {
493 CleanedState
= Pred
->getState();
496 StmtNodeBuilder::~StmtNodeBuilder() {
497 for (DeferredTy::iterator I
=Deferred
.begin(), E
=Deferred
.end(); I
!=E
; ++I
)
499 GenerateAutoTransition(*I
);
502 void StmtNodeBuilder::GenerateAutoTransition(ExplodedNode
* N
) {
503 assert (!N
->isSink());
505 // Check if this node entered a callee.
506 if (isa
<CallEnter
>(N
->getLocation())) {
507 // Still use the index of the CallExpr. It's needed to create the callee
508 // StackFrameContext.
509 Eng
.WList
->enqueue(N
, &B
, Idx
);
513 // Do not create extra nodes. Move to the next CFG element.
514 if (isa
<PostInitializer
>(N
->getLocation())) {
515 Eng
.WList
->enqueue(N
, &B
, Idx
+1);
519 PostStmt
Loc(getStmt(), N
->getLocationContext());
521 if (Loc
== N
->getLocation()) {
522 // Note: 'N' should be a fresh node because otherwise it shouldn't be
523 // a member of Deferred.
524 Eng
.WList
->enqueue(N
, &B
, Idx
+1);
529 ExplodedNode
* Succ
= Eng
.G
->getNode(Loc
, N
->State
, &IsNew
);
530 Succ
->addPredecessor(N
, *Eng
.G
);
533 Eng
.WList
->enqueue(Succ
, &B
, Idx
+1);
536 ExplodedNode
* StmtNodeBuilder::MakeNode(ExplodedNodeSet
& Dst
, const Stmt
* S
,
537 ExplodedNode
* Pred
, const GRState
* St
,
538 ProgramPoint::Kind K
) {
540 ExplodedNode
* N
= generateNode(S
, St
, Pred
, K
);
552 static ProgramPoint
GetProgramPoint(const Stmt
*S
, ProgramPoint::Kind K
,
553 const LocationContext
*LC
, const void *tag
){
556 assert(false && "Unhandled ProgramPoint kind");
557 case ProgramPoint::PreStmtKind
:
558 return PreStmt(S
, LC
, tag
);
559 case ProgramPoint::PostStmtKind
:
560 return PostStmt(S
, LC
, tag
);
561 case ProgramPoint::PreLoadKind
:
562 return PreLoad(S
, LC
, tag
);
563 case ProgramPoint::PostLoadKind
:
564 return PostLoad(S
, LC
, tag
);
565 case ProgramPoint::PreStoreKind
:
566 return PreStore(S
, LC
, tag
);
567 case ProgramPoint::PostStoreKind
:
568 return PostStore(S
, LC
, tag
);
569 case ProgramPoint::PostLValueKind
:
570 return PostLValue(S
, LC
, tag
);
571 case ProgramPoint::PostPurgeDeadSymbolsKind
:
572 return PostPurgeDeadSymbols(S
, LC
, tag
);
577 StmtNodeBuilder::generateNodeInternal(const Stmt
* S
, const GRState
* state
,
579 ProgramPoint::Kind K
,
582 const ProgramPoint
&L
= GetProgramPoint(S
, K
, Pred
->getLocationContext(),tag
);
583 return generateNodeInternal(L
, state
, Pred
);
587 StmtNodeBuilder::generateNodeInternal(const ProgramPoint
&Loc
,
588 const GRState
* State
,
589 ExplodedNode
* Pred
) {
591 ExplodedNode
* N
= Eng
.G
->getNode(Loc
, State
, &IsNew
);
592 N
->addPredecessor(Pred
, *Eng
.G
);
593 Deferred
.erase(Pred
);
603 ExplodedNode
* BranchNodeBuilder::generateNode(const GRState
* State
,
606 // If the branch has been marked infeasible we should not generate a node.
607 if (!isFeasible(branch
))
613 Eng
.G
->getNode(BlockEdge(Src
,branch
? DstT
:DstF
,Pred
->getLocationContext()),
616 Succ
->addPredecessor(Pred
, *Eng
.G
);
619 GeneratedTrue
= true;
621 GeneratedFalse
= true;
624 Deferred
.push_back(Succ
);
631 BranchNodeBuilder::~BranchNodeBuilder() {
632 if (!GeneratedTrue
) generateNode(Pred
->State
, true);
633 if (!GeneratedFalse
) generateNode(Pred
->State
, false);
635 for (DeferredTy::iterator I
=Deferred
.begin(), E
=Deferred
.end(); I
!=E
; ++I
)
636 if (!(*I
)->isSink()) Eng
.WList
->enqueue(*I
);
641 IndirectGotoNodeBuilder::generateNode(const iterator
& I
, const GRState
* St
,
645 ExplodedNode
* Succ
= Eng
.G
->getNode(BlockEdge(Src
, I
.getBlock(),
646 Pred
->getLocationContext()), St
, &IsNew
);
648 Succ
->addPredecessor(Pred
, *Eng
.G
);
655 Eng
.WList
->enqueue(Succ
);
665 SwitchNodeBuilder::generateCaseStmtNode(const iterator
& I
, const GRState
* St
){
669 ExplodedNode
* Succ
= Eng
.G
->getNode(BlockEdge(Src
, I
.getBlock(),
670 Pred
->getLocationContext()), St
, &IsNew
);
671 Succ
->addPredecessor(Pred
, *Eng
.G
);
674 Eng
.WList
->enqueue(Succ
);
683 SwitchNodeBuilder::generateDefaultCaseNode(const GRState
* St
, bool isSink
) {
685 // Get the block for the default case.
686 assert (Src
->succ_rbegin() != Src
->succ_rend());
687 CFGBlock
* DefaultBlock
= *Src
->succ_rbegin();
691 ExplodedNode
* Succ
= Eng
.G
->getNode(BlockEdge(Src
, DefaultBlock
,
692 Pred
->getLocationContext()), St
, &IsNew
);
693 Succ
->addPredecessor(Pred
, *Eng
.G
);
699 Eng
.WList
->enqueue(Succ
);
707 EndOfFunctionNodeBuilder::~EndOfFunctionNodeBuilder() {
708 // Auto-generate an EOP node if one has not been generated.
709 if (!hasGeneratedNode
) {
710 // If we are in an inlined call, generate CallExit node.
711 if (Pred
->getLocationContext()->getParent())
712 GenerateCallExitNode(Pred
->State
);
714 generateNode(Pred
->State
);
719 EndOfFunctionNodeBuilder::generateNode(const GRState
* State
, const void *tag
,
721 hasGeneratedNode
= true;
724 ExplodedNode
* Node
= Eng
.G
->getNode(BlockEntrance(&B
,
725 Pred
->getLocationContext(), tag
), State
, &IsNew
);
727 Node
->addPredecessor(P
? P
: Pred
, *Eng
.G
);
730 Eng
.G
->addEndOfPath(Node
);
737 void EndOfFunctionNodeBuilder::GenerateCallExitNode(const GRState
*state
) {
738 hasGeneratedNode
= true;
739 // Create a CallExit node and enqueue it.
740 const StackFrameContext
*LocCtx
741 = cast
<StackFrameContext
>(Pred
->getLocationContext());
742 const Stmt
*CE
= LocCtx
->getCallSite();
744 // Use the the callee location context.
745 CallExit
Loc(CE
, LocCtx
);
748 ExplodedNode
*Node
= Eng
.G
->getNode(Loc
, state
, &isNew
);
749 Node
->addPredecessor(Pred
, *Eng
.G
);
752 Eng
.WList
->enqueue(Node
);
756 void CallEnterNodeBuilder::generateNode(const GRState
*state
) {
757 // Check if the callee is in the same translation unit.
758 if (CalleeCtx
->getTranslationUnit() !=
759 Pred
->getLocationContext()->getTranslationUnit()) {
760 // Create a new engine. We must be careful that the new engine should not
761 // reference data structures owned by the old engine.
763 AnalysisManager
&OldMgr
= Eng
.SubEng
.getAnalysisManager();
765 // Get the callee's translation unit.
766 idx::TranslationUnit
*TU
= CalleeCtx
->getTranslationUnit();
768 // Create a new AnalysisManager with components of the callee's
770 // The Diagnostic is actually shared when we create ASTUnits from AST files.
771 AnalysisManager
AMgr(TU
->getASTContext(), TU
->getDiagnostic(),
772 OldMgr
.getLangOptions(),
773 OldMgr
.getPathDiagnosticClient(),
774 OldMgr
.getStoreManagerCreator(),
775 OldMgr
.getConstraintManagerCreator(),
777 OldMgr
.getMaxNodes(), OldMgr
.getMaxVisit(),
778 OldMgr
.shouldVisualizeGraphviz(),
779 OldMgr
.shouldVisualizeUbigraph(),
780 OldMgr
.shouldPurgeDead(),
781 OldMgr
.shouldEagerlyAssume(),
782 OldMgr
.shouldTrimGraph(),
783 OldMgr
.shouldInlineCall(),
784 OldMgr
.getAnalysisContextManager().getUseUnoptimizedCFG(),
785 OldMgr
.getAnalysisContextManager().getAddImplicitDtors(),
786 OldMgr
.getAnalysisContextManager().getAddInitializers());
787 llvm::OwningPtr
<TransferFuncs
> TF(MakeCFRefCountTF(AMgr
.getASTContext(),
788 /* GCEnabled */ false,
789 AMgr
.getLangOptions()));
790 // Create the new engine.
791 ExprEngine
NewEng(AMgr
, TF
.take());
793 // Create the new LocationContext.
794 AnalysisContext
*NewAnaCtx
= AMgr
.getAnalysisContext(CalleeCtx
->getDecl(),
795 CalleeCtx
->getTranslationUnit());
796 const StackFrameContext
*OldLocCtx
= CalleeCtx
;
797 const StackFrameContext
*NewLocCtx
= AMgr
.getStackFrame(NewAnaCtx
,
798 OldLocCtx
->getParent(),
799 OldLocCtx
->getCallSite(),
800 OldLocCtx
->getCallSiteBlock(),
801 OldLocCtx
->getIndex());
803 // Now create an initial state for the new engine.
804 const GRState
*NewState
= NewEng
.getStateManager().MarshalState(state
,
806 ExplodedNodeSet ReturnNodes
;
807 NewEng
.ExecuteWorkListWithInitialState(NewLocCtx
, AMgr
.getMaxNodes(),
808 NewState
, ReturnNodes
);
812 // Get the callee entry block.
813 const CFGBlock
*Entry
= &(CalleeCtx
->getCFG()->getEntry());
814 assert(Entry
->empty());
815 assert(Entry
->succ_size() == 1);
817 // Get the solitary successor.
818 const CFGBlock
*SuccB
= *(Entry
->succ_begin());
820 // Construct an edge representing the starting location in the callee.
821 BlockEdge
Loc(Entry
, SuccB
, CalleeCtx
);
824 ExplodedNode
*Node
= Eng
.G
->getNode(Loc
, state
, &isNew
);
825 Node
->addPredecessor(const_cast<ExplodedNode
*>(Pred
), *Eng
.G
);
828 Eng
.WList
->enqueue(Node
);
831 void CallExitNodeBuilder::generateNode(const GRState
*state
) {
832 // Get the callee's location context.
833 const StackFrameContext
*LocCtx
834 = cast
<StackFrameContext
>(Pred
->getLocationContext());
835 // When exiting an implicit automatic obj dtor call, the callsite is the Stmt
836 // that triggers the dtor.
837 PostStmt
Loc(LocCtx
->getCallSite(), LocCtx
->getParent());
839 ExplodedNode
*Node
= Eng
.G
->getNode(Loc
, state
, &isNew
);
840 Node
->addPredecessor(const_cast<ExplodedNode
*>(Pred
), *Eng
.G
);
842 Eng
.WList
->enqueue(Node
, LocCtx
->getCallSiteBlock(),
843 LocCtx
->getIndex() + 1);