diff options
author | Anna Zaks <ganna@apple.com> | 2011-10-24 18:26:19 +0000 |
---|---|---|
committer | Anna Zaks <ganna@apple.com> | 2011-10-24 18:26:19 +0000 |
commit | ebae6d0209e1ec3d5ea14f9e63bd0d740218ed14 (patch) | |
tree | 7271eba1485f3319db7907cc5ec2bcc2d6524509 /lib/StaticAnalyzer/Core/ExprEngine.cpp | |
parent | d231d0130a95336610ab9a42eaeb2cdac19992f3 (diff) |
[analyzer] Convert ExprEngine::visit() to use short lived builders.
This commit removes the major functional dependency on the ExprEngine::Builder
member variable.
In some cases the code became more verbose. Particularly, we call takeNodes()
and addNodes() to move responsibility for the nodes from one builder to another.
This will get simplified later on.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@142831 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/StaticAnalyzer/Core/ExprEngine.cpp')
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngine.cpp | 305 |
1 files changed, 212 insertions, 93 deletions
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index 5999dc6bb1..0b40c9aa4d 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -197,30 +197,77 @@ void ExprEngine::processEndWorklist(bool hasWorkRemaining) { getCheckerManager().runCheckersForEndAnalysis(G, BR, *this); } -void ExprEngine::processCFGElement(const CFGElement E, - StmtNodeBuilder& Bldr, - ExplodedNode *Pred) { +void ExprEngine::processCFGElement(const CFGElement E, ExplodedNode *Pred, + unsigned StmtIdx, NodeBuilderContext *Ctx) { + currentStmtIdx = StmtIdx; + currentBuilderContext = Ctx; + switch (E.getKind()) { case CFGElement::Invalid: llvm_unreachable("Unexpected CFGElement kind."); case CFGElement::Statement: - ProcessStmt(const_cast<Stmt*>(E.getAs<CFGStmt>()->getStmt()), Bldr, Pred); + ProcessStmt(const_cast<Stmt*>(E.getAs<CFGStmt>()->getStmt()), Pred); return; case CFGElement::Initializer: - ProcessInitializer(E.getAs<CFGInitializer>()->getInitializer(), - Bldr, Pred); + ProcessInitializer(E.getAs<CFGInitializer>()->getInitializer(), Pred); return; case CFGElement::AutomaticObjectDtor: case CFGElement::BaseDtor: case CFGElement::MemberDtor: case CFGElement::TemporaryDtor: - ProcessImplicitDtor(*E.getAs<CFGImplicitDtor>(), Bldr, Pred); + ProcessImplicitDtor(*E.getAs<CFGImplicitDtor>(), Pred); return; } } -void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder, +const Stmt *ExprEngine::getStmt() const { + const CFGStmt *CS = (*currentBuilderContext->getBlock())[currentStmtIdx].getAs<CFGStmt>(); + return CS ? CS->getStmt() : 0; +} + +// TODO: Adding nodes to the worklist shoudl be a function inside CoreEngine. +void ExprEngine::GenerateAutoTransition(ExplodedNode *N) { + assert (!N->isSink()); + const CFGBlock *Block = currentBuilderContext->getBlock(); + unsigned Idx = currentStmtIdx; + + // Check if this node entered a callee. + if (isa<CallEnter>(N->getLocation())) { + // Still use the index of the CallExpr. It's needed to create the callee + // StackFrameContext. + Engine.WList->enqueue(N, Block, Idx); + return; + } + + // Do not create extra nodes. Move to the next CFG element. + if (isa<PostInitializer>(N->getLocation())) { + Engine.WList->enqueue(N, Block, Idx+1); + return; + } + + PostStmt Loc(getStmt(), N->getLocationContext()); + + if (Loc == N->getLocation()) { + // Note: 'N' should be a fresh node because otherwise it shouldn't be + // a member of Deferred. + Engine.WList->enqueue(N, Block, Idx+1); + return; + } + + bool IsNew; + ExplodedNode *Succ = Engine.G->getNode(Loc, N->getState(), &IsNew); + Succ->addPredecessor(N, *Engine.G); + + if (IsNew) + Engine.WList->enqueue(Succ, Block, Idx+1); +} + + +void ExprEngine::ProcessStmt(const CFGStmt S, ExplodedNode *Pred) { + ExplodedNodeSet TopDst; + StmtNodeBuilder builder(Pred, TopDst, currentStmtIdx, *currentBuilderContext); + // TODO: Use RAII to remove the unnecessary, tagged nodes. //RegisterCreatedNodes registerCreatedNodes(getGraph()); @@ -230,9 +277,6 @@ void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder, StateMgr.recycleUnusedStates(); currentStmt = S.getStmt(); - currentStmtIdx = builder.getIndex(); - currentBuilderContext = &builder.getContext(); - PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), currentStmt->getLocStart(), "Error evaluating statement"); @@ -268,15 +312,15 @@ void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder, // up. Since no symbols are dead, we can optimize and not clean out // the constraint manager. CleanedNode = - Builder->generateNode(currentStmt, CleanedState, EntryNode, &cleanupTag); + builder.generateNode(currentStmt, CleanedState, EntryNode, &cleanupTag); Tmp.Add(CleanedNode); } else { - SaveAndRestore<bool> OldSink(Builder->BuildSinks); - SaveOr OldHasGen(Builder->hasGeneratedNode); + SaveAndRestore<bool> OldSink(builder.BuildSinks); + SaveOr OldHasGen(builder.hasGeneratedNode); - SaveAndRestore<bool> OldPurgeDeadSymbols(Builder->PurgingDeadSymbols); - Builder->PurgingDeadSymbols = true; + SaveAndRestore<bool> OldPurgeDeadSymbols(builder.PurgingDeadSymbols); + builder.PurgingDeadSymbols = true; // Call checkers with the non-cleaned state so that they could query the // values of the soon to be dead symbols. @@ -306,18 +350,25 @@ void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder, // generate a transition to that state. const ProgramState *CleanedCheckerSt = StateMgr.getPersistentStateWithGDM(CleanedState, CheckerState); - ExplodedNode *CleanedNode = Builder->generateNode(currentStmt, + ExplodedNode *CleanedNode = builder.generateNode(currentStmt, CleanedCheckerSt, *I, &cleanupTag); Tmp.Add(CleanedNode); } } + ExplodedNodeSet AllDst; for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { - // TODO: Remove Dest set, it's no longer needed. ExplodedNodeSet Dst; // Visit the statement. Visit(currentStmt, *I, Dst); + AllDst.insert(Dst); + } + + for (ExplodedNodeSet::iterator I = AllDst.begin(), + E = AllDst.end(); I != E; ++I) { + assert(!(*I)->isSink()); + GenerateAutoTransition(*I); } // NULL out these variables to cleanup. @@ -328,8 +379,10 @@ void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder, } void ExprEngine::ProcessInitializer(const CFGInitializer Init, - StmtNodeBuilder &builder, ExplodedNode *pred) { + ExplodedNodeSet Dst; + StmtNodeBuilder Bldr(pred, Dst, currentStmtIdx, *currentBuilderContext); + // We don't set EntryNode and currentStmt. And we don't clean up state. const CXXCtorInitializer *BMI = Init.getInitializer(); const StackFrameContext *stackFrame = cast<StackFrameContext>(pred->getLocationContext()); @@ -358,7 +411,7 @@ void ExprEngine::ProcessInitializer(const CFGInitializer Init, PostInitializer PP(BMI, stackFrame); // Builder automatically add the generated node to the deferred set, // which are processed in the builder's dtor. - builder.generateNode(PP, state, Pred); + Bldr.generateNode(PP, state, Pred); } return; } @@ -373,14 +426,20 @@ void ExprEngine::ProcessInitializer(const CFGInitializer Init, getStoreManager().evalDerivedToBase(thisVal, ctorExpr->getType()); const MemRegion *baseReg = baseVal.getAsRegion(); assert(baseReg); - Builder = &builder; + Builder = &Bldr; ExplodedNodeSet dst; VisitCXXConstructExpr(ctorExpr, baseReg, pred, dst); + for (ExplodedNodeSet::iterator I = dst.begin(), + E = dst.end(); I != E; ++I) { + GenerateAutoTransition(*I); + } } void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D, - StmtNodeBuilder &builder, - ExplodedNode *Pred) { + ExplodedNode *Pred) { + ExplodedNodeSet Dst; + StmtNodeBuilder builder(Pred, Dst, currentStmtIdx, *currentBuilderContext); + Builder = &builder; switch (D.getKind()) { @@ -399,6 +458,11 @@ void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D, default: llvm_unreachable("Unexpected dtor kind."); } + + for (ExplodedNodeSet::iterator I = Dst.begin(), + E = Dst.end(); I != E; ++I) { + GenerateAutoTransition(*I); + } } void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor dtor, @@ -440,6 +504,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), S->getLocStart(), "Error evaluating statement"); + PureStmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext); // Expressions to ignore. if (const Expr *Ex = dyn_cast<Expr>(S)) @@ -449,10 +514,8 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, // this check when we KNOW that there is no block-level subexpression. // The motivation is that this check requires a hashtable lookup. - if (S != currentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(S)) { - Dst.Add(Pred); + if (S != currentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(S)) return; - } switch (S->getStmtClass()) { // C++ and ARC stuff we don't support yet. @@ -479,22 +542,17 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::SubstNonTypeTemplateParmPackExprClass: case Stmt::SEHTryStmtClass: case Stmt::SEHExceptStmtClass: - case Stmt::SEHFinallyStmtClass: - { - SaveAndRestore<bool> OldSink(Builder->BuildSinks); - Builder->BuildSinks = true; - const ExplodedNode *node = MakeNode(Dst, S, Pred, Pred->getState()); - Engine.addAbortedBlock(node, Builder->getBlock()); + case Stmt::SEHFinallyStmtClass: { + const ExplodedNode *node = Bldr.generateNode(S, Pred, Pred->getState()); + Engine.addAbortedBlock(node, currentBuilderContext->getBlock()); break; } // We don't handle default arguments either yet, but we can fake it // for now by just skipping them. case Stmt::SubstNonTypeTemplateParmExprClass: - case Stmt::CXXDefaultArgExprClass: { - Dst.Add(Pred); + case Stmt::CXXDefaultArgExprClass: break; - } case Stmt::ParenExprClass: llvm_unreachable("ParenExprs already handled."); @@ -525,31 +583,33 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, // GNU __null is a pointer-width integer, not an actual pointer. const ProgramState *state = Pred->getState(); state = state->BindExpr(S, svalBuilder.makeIntValWithPtrWidth(0, false)); - MakeNode(Dst, S, Pred, state); + Bldr.generateNode(S, Pred, state); break; } case Stmt::ObjCAtSynchronizedStmtClass: + Bldr.takeNodes(Pred); VisitObjCAtSynchronizedStmt(cast<ObjCAtSynchronizedStmt>(S), Pred, Dst); + Bldr.addNodes(Dst); break; case Stmt::ObjCPropertyRefExprClass: // Implicitly handled by Environment::getSVal(). - Dst.Add(Pred); break; case Stmt::ImplicitValueInitExprClass: { const ProgramState *state = Pred->getState(); QualType ty = cast<ImplicitValueInitExpr>(S)->getType(); SVal val = svalBuilder.makeZeroVal(ty); - MakeNode(Dst, S, Pred, state->BindExpr(S, val)); + Bldr.generateNode(S, Pred, state->BindExpr(S, val)); break; } - case Stmt::ExprWithCleanupsClass: { + case Stmt::ExprWithCleanupsClass: + Bldr.takeNodes(Pred); Visit(cast<ExprWithCleanups>(S)->getSubExpr(), Pred, Dst); + Bldr.addNodes(Dst); break; - } // Cases not handled yet; but will handle some day. case Stmt::DesignatedInitExprClass: @@ -583,39 +643,52 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::FloatingLiteralClass: case Stmt::SizeOfPackExprClass: case Stmt::CXXNullPtrLiteralExprClass: - Dst.Add(Pred); // No-op. Simply propagate the current state unchanged. + // No-op. Simply propagate the current state unchanged. break; case Stmt::ArraySubscriptExprClass: + Bldr.takeNodes(Pred); VisitLvalArraySubscriptExpr(cast<ArraySubscriptExpr>(S), Pred, Dst); + Bldr.addNodes(Dst); break; case Stmt::AsmStmtClass: + Bldr.takeNodes(Pred); VisitAsmStmt(cast<AsmStmt>(S), Pred, Dst); + Bldr.addNodes(Dst); break; case Stmt::BlockDeclRefExprClass: { + Bldr.takeNodes(Pred); const BlockDeclRefExpr *BE = cast<BlockDeclRefExpr>(S); VisitCommonDeclRefExpr(BE, BE->getDecl(), Pred, Dst); + Bldr.addNodes(Dst); break; } case Stmt::BlockExprClass: + Bldr.takeNodes(Pred); VisitBlockExpr(cast<BlockExpr>(S), Pred, Dst); + Bldr.addNodes(Dst); break; case Stmt::BinaryOperatorClass: { const BinaryOperator* B = cast<BinaryOperator>(S); if (B->isLogicalOp()) { + Bldr.takeNodes(Pred); VisitLogicalExpr(B, Pred, Dst); + Bldr.addNodes(Dst); break; } else if (B->getOpcode() == BO_Comma) { const ProgramState *state = Pred->getState(); - MakeNode(Dst, B, Pred, state->BindExpr(B, state->getSVal(B->getRHS()))); + Bldr.generateNode(B, Pred, + state->BindExpr(B, state->getSVal(B->getRHS()))); break; } + Bldr.takeNodes(Pred); + if (AMgr.shouldEagerlyAssume() && (B->isRelationalOp() || B->isEqualityOp())) { ExplodedNodeSet Tmp; @@ -625,13 +698,16 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, else VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst); + Bldr.addNodes(Dst); break; } case Stmt::CallExprClass: case Stmt::CXXOperatorCallExprClass: case Stmt::CXXMemberCallExprClass: { + Bldr.takeNodes(Pred); VisitCallExpr(cast<CallExpr>(S), Pred, Dst); + Bldr.addNodes(Dst); break; } @@ -640,58 +716,78 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, const CXXConstructExpr *C = cast<CXXConstructExpr>(S); // For block-level CXXConstructExpr, we don't have a destination region. // Let VisitCXXConstructExpr() create one. + Bldr.takeNodes(Pred); VisitCXXConstructExpr(C, 0, Pred, Dst); + Bldr.addNodes(Dst); break; } case Stmt::CXXNewExprClass: { + Bldr.takeNodes(Pred); const CXXNewExpr *NE = cast<CXXNewExpr>(S); VisitCXXNewExpr(NE, Pred, Dst); + Bldr.addNodes(Dst); break; } case Stmt::CXXDeleteExprClass: { + Bldr.takeNodes(Pred); const CXXDeleteExpr *CDE = cast<CXXDeleteExpr>(S); VisitCXXDeleteExpr(CDE, Pred, Dst); + Bldr.addNodes(Dst); break; } // FIXME: ChooseExpr is really a constant. We need to fix // the CFG do not model them as explicit control-flow. case Stmt::ChooseExprClass: { // __builtin_choose_expr + Bldr.takeNodes(Pred); const ChooseExpr *C = cast<ChooseExpr>(S); VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst); + Bldr.addNodes(Dst); break; } case Stmt::CompoundAssignOperatorClass: + Bldr.takeNodes(Pred); VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst); + Bldr.addNodes(Dst); break; case Stmt::CompoundLiteralExprClass: + Bldr.takeNodes(Pred); VisitCompoundLiteralExpr(cast<CompoundLiteralExpr>(S), Pred, Dst); + Bldr.addNodes(Dst); break; case Stmt::BinaryConditionalOperatorClass: case Stmt::ConditionalOperatorClass: { // '?' operator + Bldr.takeNodes(Pred); const AbstractConditionalOperator *C = cast<AbstractConditionalOperator>(S); VisitGuardedExpr(C, C->getTrueExpr(), C->getFalseExpr(), Pred, Dst); + Bldr.addNodes(Dst); break; } case Stmt::CXXThisExprClass: + Bldr.takeNodes(Pred); VisitCXXThisExpr(cast<CXXThisExpr>(S), Pred, Dst); + Bldr.addNodes(Dst); break; case Stmt::DeclRefExprClass: { + Bldr.takeNodes(Pred); const DeclRefExpr *DE = cast<DeclRefExpr>(S); VisitCommonDeclRefExpr(DE, DE->getDecl(), Pred, Dst); + Bldr.addNodes(Dst); break; } case Stmt::DeclStmtClass: + Bldr.takeNodes(Pred); VisitDeclStmt(cast<DeclStmt>(S), Pred, Dst); + Bldr.addNodes(Dst); break; case Stmt::ImplicitCastExprClass: @@ -702,6 +798,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::CXXConstCastExprClass: case Stmt::CXXFunctionalCastExprClass: case Stmt::ObjCBridgedCastExprClass: { + Bldr.takeNodes(Pred); const CastExpr *C = cast<CastExpr>(S); // Handle the previsit checks. ExplodedNodeSet dstPrevisit; @@ -716,58 +813,76 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, // Handle the postvisit checks. getCheckerManager().runCheckersForPostStmt(Dst, dstExpr, C, *this); + Bldr.addNodes(Dst); break; } case Expr::MaterializeTemporaryExprClass: { + Bldr.takeNodes(Pred); const MaterializeTemporaryExpr *Materialize = cast<MaterializeTemporaryExpr>(S); if (!Materialize->getType()->isRecordType()) CreateCXXTemporaryObject(Materialize, Pred, Dst); else Visit(Materialize->GetTemporaryExpr(), Pred, Dst); + Bldr.addNodes(Dst); break; } case Stmt::InitListExprClass: + Bldr.takeNodes(Pred); VisitInitListExpr(cast<InitListExpr>(S), Pred, Dst); + Bldr.addNodes(Dst); break; case Stmt::MemberExprClass: + Bldr.takeNodes(Pred); VisitMemberExpr(cast<MemberExpr>(S), Pred, Dst); + Bldr.addNodes(Dst); break; + case Stmt::ObjCIvarRefExprClass: + Bldr.takeNodes(Pred); VisitLvalObjCIvarRefExpr(cast<ObjCIvarRefExpr>(S), Pred, Dst); + Bldr.addNodes(Dst); break; case Stmt::ObjCForCollectionStmtClass: + Bldr.takeNodes(Pred); VisitObjCForCollectionStmt(cast<ObjCForCollectionStmt>(S), Pred, Dst); + Bldr.addNodes(Dst); break; case Stmt::ObjCMessageExprClass: + Bldr.takeNodes(Pred); VisitObjCMessage(cast<ObjCMessageExpr>(S), Pred, Dst); + Bldr.addNodes(Dst); break; case Stmt::ObjCAtThrowStmtClass: { // FIXME: This is not complete. We basically treat @throw as // an abort. - SaveAndRestore<bool> OldSink(Builder->BuildSinks); - Builder->BuildSinks = true; - MakeNode(Dst, S, Pred, Pred->getState()); + Bldr.generateNode(S, Pred, Pred->getState()); break; } case Stmt::ReturnStmtClass: + Bldr.takeNodes(Pred); VisitReturnStmt(cast<ReturnStmt>(S), Pred, Dst); + Bldr.addNodes(Dst); break; case Stmt::OffsetOfExprClass: + Bldr.takeNodes(Pred); VisitOffsetOfExpr(cast<OffsetOfExpr>(S), Pred, Dst); + Bldr.addNodes(Dst); break; case Stmt::UnaryExprOrTypeTraitExprClass: + Bldr.takeNodes(Pred); VisitUnaryExprOrTypeTraitExpr(cast<UnaryExprOrTypeTraitExpr>(S), Pred, Dst); + Bldr.addNodes(Dst); break; case Stmt::StmtExprClass: { @@ -777,36 +892,35 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, // Empty statement expression. assert(SE->getType() == getContext().VoidTy && "Empty statement expression must have void type."); - Dst.Add(Pred); break; } if (Expr *LastExpr = dyn_cast<Expr>(*SE->getSubStmt()->body_rbegin())) { const ProgramState *state = Pred->getState(); - MakeNode(Dst, SE, Pred, state->BindExpr(SE, state->getSVal(LastExpr))); + Bldr.generateNode(SE, Pred, + state->BindExpr(SE, state->getSVal(LastExpr))); } - else - Dst.Add(Pred); - break; } case Stmt::StringLiteralClass: { const ProgramState *state = Pred->getState(); SVal V = state->getLValue(cast<StringLiteral>(S)); - MakeNode(Dst, S, Pred, state->BindExpr(S, V)); + Bldr.generateNode(S, Pred, state->BindExpr(S, V)); return; } case Stmt::UnaryOperatorClass: { + Bldr.takeNodes(Pred); const UnaryOperator *U = cast<UnaryOperator>(S); - if (AMgr.shouldEagerlyAssume()&&(U->getOpcode() == UO_LNot)) { + if (AMgr.shouldEagerlyAssume() && (U->getOpcode() == UO_LNot)) { ExplodedNodeSet Tmp; VisitUnaryOperator(U, Pred, Tmp); evalEagerlyAssume(Dst, Tmp, U); } else VisitUnaryOperator(U, Pred, Dst); + Bldr.addNodes(Dst); break; } } @@ -1189,6 +1303,8 @@ void ExprEngine::processSwitch(SwitchNodeBuilder& builder) { void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, ExplodedNode *Pred, ExplodedNodeSet &Dst) { + PureStmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext, Builder); + const ProgramState *state = Pred->getState(); if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { @@ -1204,20 +1320,20 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, V = UnknownVal(); } - MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V), - ProgramPoint::PostLValueKind); + Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, V), false, 0, + ProgramPoint::PostLValueKind); return; } if (const EnumConstantDecl *ED = dyn_cast<EnumConstantDecl>(D)) { assert(!Ex->isLValue()); SVal V = svalBuilder.makeIntVal(ED->getInitVal()); - MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V)); + Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, V)); return; } if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { SVal V = svalBuilder.getFunctionPointer(FD); - MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V), - ProgramPoint::PostLValueKind); + Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, V), false, 0, + ProgramPoint::PostLValueKind); return; } assert (false && @@ -1236,13 +1352,16 @@ void ExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr *A, ExplodedNodeSet checkerPreStmt; getCheckerManager().runCheckersForPreStmt(checkerPreStmt, Pred, A, *this); + PureStmtNodeBuilder Bldr(checkerPreStmt, Dst, *currentBuilderContext, Builder); + for (ExplodedNodeSet::iterator it = checkerPreStmt.begin(), ei = checkerPreStmt.end(); it != ei; ++it) { const ProgramState *state = (*it)->getState(); SVal V = state->getLValue(A->getType(), state->getSVal(Idx), state->getSVal(Base)); assert(A->isLValue()); - MakeNode(Dst, A, *it, state->BindExpr(A, V), ProgramPoint::PostLValueKind); + Bldr.generateNode(A, *it, state->BindExpr(A, V), + false, 0, ProgramPoint::PostLValueKind); } } @@ -1250,10 +1369,13 @@ void ExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr *A, void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred, ExplodedNodeSet &Dst) { + PureStmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext, Builder); Decl *member = M->getMemberDecl(); if (VarDecl *VD = dyn_cast<VarDecl>(member)) { assert(M->isLValue()); + Bldr.takeNodes(Pred); VisitCommonDeclRefExpr(M, VD, Pred, Dst); + Bldr.addNodes(Dst); return; } @@ -1270,7 +1392,7 @@ void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred, // temporary struct object, see test/Analysis/fields.c: // (p = getit()).x isa<nonloc::SymbolVal>(baseExprVal)) { - MakeNode(Dst, M, Pred, state->BindExpr(M, UnknownVal())); + Bldr.generateNode(M, Pred, state->BindExpr(M, UnknownVal())); return; } @@ -1281,25 +1403,29 @@ void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred, // For all other cases, compute an lvalue. SVal L = state->getLValue(field, baseExprVal); if (M->isLValue()) - MakeNode(Dst, M, Pred, state->BindExpr(M, L), ProgramPoint::PostLValueKind); - else + Bldr.generateNode(M, Pred, state->BindExpr(M, L), false, 0, + ProgramPoint::PostLValueKind); + else { + Bldr.takeNodes(Pred); evalLoad(Dst, M, Pred, state, L); + Bldr.addNodes(Dst); + } } /// evalBind - Handle the semantics of binding a value to a specific location. /// This method is used by evalStore and (soon) VisitDeclStmt, and others. void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE, ExplodedNode *Pred, - SVal location, SVal Val, bool atDeclInit) { + SVal location, SVal Val, bool atDeclInit, + ProgramPoint::Kind PointKind) { // Do a previsit of the bind. ExplodedNodeSet CheckedSet; getCheckerManager().runCheckersForBind(CheckedSet, Pred, location, Val, - StoreE, *this); + StoreE, *this, PointKind); // TODO:AZ Remove TmpDst after NB refactoring is done. ExplodedNodeSet TmpDst; - Builder->takeNodes(CheckedSet); PureStmtNodeBuilder Bldr(CheckedSet, TmpDst, *currentBuilderContext); for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end(); @@ -1315,9 +1441,9 @@ void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE, state = state->bindLoc(location, Val); } - Bldr.generateNode(StoreE, *I, state); + Bldr.generateNode(StoreE, *I, state, false, 0, PointKind); } - Builder->addNodes(TmpDst); + Dst.insert(TmpDst); } @@ -1357,11 +1483,9 @@ void ExprEngine::evalStore(ExplodedNodeSet &Dst, const Expr *AssignE, if (location.isUndef()) return; - SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind, - ProgramPoint::PostStoreKind); - for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) - evalBind(Dst, StoreE, *NI, location, Val); + evalBind(Dst, StoreE, *NI, location, Val, false, + ProgramPoint::PostStoreKind); } void ExprEngine::evalLoad(ExplodedNodeSet &Dst, const Expr *Ex, @@ -1411,30 +1535,28 @@ void ExprEngine::evalLoadCommon(ExplodedNodeSet &Dst, const Expr *Ex, // Evaluate the location (checks for bad dereferences). ExplodedNodeSet Tmp; evalLocation(Tmp, Ex, Pred, state, location, tag, true); - if (Tmp.empty()) return; + PureStmtNodeBuilder Bldr(Tmp, Dst, *currentBuilderContext, Builder); if (location.isUndef()) return; - SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind); - // Proceed with the load. for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) { state = (*NI)->getState(); if (location.isUnknown()) { // This is important. We must nuke the old binding. - MakeNode(Dst, Ex, *NI, state->BindExpr(Ex, UnknownVal()), - ProgramPoint::PostLoadKind, tag); + Bldr.generateNode(Ex, *NI, state->BindExpr(Ex, UnknownVal()), + false, tag, ProgramPoint::PostLoadKind); } else { if (LoadTy.isNull()) LoadTy = Ex->getType(); SVal V = state->getSVal(cast<Loc>(location), LoadTy); - MakeNode(Dst, Ex, *NI, state->bindExprAndLocation(Ex, location, V), - ProgramPoint::PostLoadKind, tag); + Bldr.generateNode(Ex, *NI, state->bindExprAndLocation(Ex, location, V), + false, tag, ProgramPoint::PostLoadKind); } } } @@ -1443,16 +1565,16 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst, const Stmt *S, ExplodedNode *Pred, const ProgramState *state, SVal location, const ProgramPointTag *tag, bool isLoad) { + PureStmtNodeBuilder BldrTop(Pred, Dst, *currentBuilderContext, Builder); // Early checks for performance reason. if (location.isUnknown()) { - Dst.Add(Pred); return; } ExplodedNodeSet Src; - if (Pred->getState() == state) { - Src.Add(Pred); - } else { + BldrTop.takeNodes(Pred); + PureStmtNodeBuilder Bldr(Pred, Src, *currentBuilderContext); + if (Pred->getState() != state) { // Associate this new state with an ExplodedNode. // FIXME: If I pass null tag, the graph is incorrect, e.g for // int *p; @@ -1465,11 +1587,12 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst, const Stmt *S, // FIXME: why is 'tag' not used instead of etag? static SimpleProgramPointTag etag("ExprEngine: Location"); - ExplodedNode *N = Builder->generateNode(S, state, Pred, &etag); - Src.Add(N ? N : Pred); + Bldr.generateNode(S, Pred, state, false, &etag); } - getCheckerManager().runCheckersForLocation(Dst, Src, location, isLoad, S, + ExplodedNodeSet Tmp; + getCheckerManager().runCheckersForLocation(Tmp, Src, location, isLoad, S, *this); + BldrTop.addNodes(Tmp); } bool ExprEngine::InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE, @@ -1558,17 +1681,15 @@ ExprEngine::getEagerlyAssumeTags() { void ExprEngine::evalEagerlyAssume(ExplodedNodeSet &Dst, ExplodedNodeSet &Src, const Expr *Ex) { - + PureStmtNodeBuilder Bldr(Src, Dst, *currentBuilderContext, Builder); for (ExplodedNodeSet::iterator I=Src.begin(), E=Src.end(); I!=E; ++I) { ExplodedNode *Pred = *I; - // Test if the previous node was as the same expression. This can happen // when the expression fails to evaluate to anything meaningful and // (as an optimization) we don't generate a node. ProgramPoint P = Pred->getLocation(); if (!isa<PostStmt>(P) || cast<PostStmt>(P).getStmt() != Ex) { - Dst.Add(Pred); continue; } @@ -1582,18 +1703,16 @@ void ExprEngine::evalEagerlyAssume(ExplodedNodeSet &Dst, ExplodedNodeSet &Src, if (const ProgramState *StateTrue = state->assume(*SEV, true)) { SVal Val = svalBuilder.makeIntVal(1U, Ex->getType()); StateTrue = StateTrue->BindExpr(Ex, Val); - Dst.Add(Builder->generateNode(Ex, StateTrue, Pred, tags.first)); + Bldr.generateNode(Ex, Pred, StateTrue, false, tags.first); } // Next, assume that the condition is false. if (const ProgramState *StateFalse = state->assume(*SEV, false)) { SVal Val = svalBuilder.makeIntVal(0U, Ex->getType()); StateFalse = StateFalse->BindExpr(Ex, Val); - Dst.Add(Builder->generateNode(Ex, StateFalse, Pred, tags.second)); + Bldr.generateNode(Ex, Pred, StateFalse, false, tags.second); } } - else - Dst.Add(Pred); } } @@ -1625,7 +1744,7 @@ void ExprEngine::VisitAsmStmtHelperInputs(const AsmStmt *A, ExplodedNode *Pred, ExplodedNodeSet &Dst) { if (I == E) { - + PureStmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext, Builder); // We have processed both the inputs and the outputs. All of the outputs // should evaluate to Locs. Nuke all of their values. @@ -1645,7 +1764,7 @@ void ExprEngine::VisitAsmStmtHelperInputs(const AsmStmt *A, state = state->bindLoc(cast<Loc>(X), UnknownVal()); } - MakeNode(Dst, A, Pred, state); + Bldr.generateNode(A, Pred, state); return; } |