Add (preliminary) transfer function support for ObjCForCollectionStmt. Still need to flesh out some logic.

When processing DeclStmt, use the new interface to StateManager::BindDecl.  Conjuring of symbols is now done in VisitDeclStmt.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@59155 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Ted Kremenek 2008-11-12 19:24:17 +00:00
Родитель b5abb429e7
Коммит af3374187c
4 изменённых файлов: 137 добавлений и 17 удалений

Просмотреть файл

@ -76,7 +76,7 @@ protected:
void HandlePostStmt(const PostStmt& S, CFGBlock* B,
unsigned StmtIdx, ExplodedNodeImpl *Pred);
void HandleBranch(Expr* Cond, Stmt* Term, CFGBlock* B,
void HandleBranch(Stmt* Cond, Stmt* Term, CFGBlock* B,
ExplodedNodeImpl* Pred);
virtual void ProcessEndPath(GREndPathNodeBuilderImpl& Builder) = 0;
@ -86,7 +86,7 @@ protected:
virtual void ProcessStmt(Stmt* S, GRStmtNodeBuilderImpl& Builder) = 0;
virtual void ProcessBranch(Expr* Condition, Stmt* Terminator,
virtual void ProcessBranch(Stmt* Condition, Stmt* Terminator,
GRBranchNodeBuilderImpl& Builder) = 0;
virtual void ProcessIndirectGoto(GRIndirectGotoNodeBuilderImpl& Builder) = 0;
@ -593,7 +593,7 @@ protected:
BC);
}
virtual void ProcessBranch(Expr* Condition, Stmt* Terminator,
virtual void ProcessBranch(Stmt* Condition, Stmt* Terminator,
GRBranchNodeBuilderImpl& BuilderImpl) {
GRBranchNodeBuilder<StateTy> Builder(BuilderImpl);
SubEngine.ProcessBranch(Condition, Terminator, Builder);

Просмотреть файл

@ -368,7 +368,7 @@ public:
/// ProcessBranch - Called by GRCoreEngine. Used to generate successor
/// nodes by processing the 'effects' of a branch condition.
void ProcessBranch(Expr* Condition, Stmt* Term, BranchNodeBuilder& builder);
void ProcessBranch(Stmt* Condition, Stmt* Term, BranchNodeBuilder& builder);
/// ProcessIndirectGoto - Called by GRCoreEngine. Used to generate successor
/// nodes by processing the 'effects' of a computed goto jump.
@ -423,17 +423,17 @@ protected:
return StateMgr.BindLoc(St, LV, V);
}
SVal GetSVal(const GRState* St, Expr* Ex) {
SVal GetSVal(const GRState* St, Stmt* Ex) {
return StateMgr.GetSVal(St, Ex);
}
SVal GetSVal(const GRState* St, const Expr* Ex) {
return GetSVal(St, const_cast<Expr*>(Ex));
SVal GetSVal(const GRState* St, const Stmt* Ex) {
return GetSVal(St, const_cast<Stmt*>(Ex));
}
SVal GetBlkExprSVal(const GRState* St, Expr* Ex) {
SVal GetBlkExprSVal(const GRState* St, Stmt* Ex) {
return StateMgr.GetBlkExprSVal(St, Ex);
}
}
SVal GetSVal(const GRState* St, Loc LV, QualType T = QualType()) {
return StateMgr.GetSVal(St, LV, T);
@ -537,6 +537,11 @@ protected:
/// VisitObjCIvarRefExpr - Transfer function logic for ObjCIvarRefExprs.
void VisitObjCIvarRefExpr(ObjCIvarRefExpr* DR, NodeTy* Pred, NodeSet& Dst,
bool asLValue);
/// VisitObjCForCollectionStmt - Transfer function logic for
/// ObjCForCollectionStmt.
void VisitObjCForCollectionStmt(ObjCForCollectionStmt* S, NodeTy* Pred,
NodeSet& Dst);
/// VisitObjCMessageExpr - Transfer function for ObjC message expressions.
void VisitObjCMessageExpr(ObjCMessageExpr* ME, NodeTy* Pred, NodeSet& Dst);

Просмотреть файл

@ -1,4 +1,4 @@
//==- GRCoreEngine.cpp - Path-Sensitive Dataflow Engine ----------------*- C++ -*-//
//==- GRCoreEngine.cpp - Path-Sensitive Dataflow Engine ------------*- C++ -*-//
//
// The LLVM Compiler Infrastructure
//
@ -212,6 +212,21 @@ void GRCoreEngineImpl::HandleBlockExit(CFGBlock * B, ExplodedNodeImpl* Pred) {
return;
}
case Stmt::ObjCForCollectionStmtClass: {
// In the case of ObjCForCollectionStmt, it appears twice in a CFG:
//
// (1) inside a basic block, which represents the binding of the
// 'element' variable to a value.
// (2) in a terminator, which represents the branch.
//
// For (1), subengines will bind a value (i.e., 0 or 1) indicating
// whether or not collection contains any more elements. We cannot
// just test to see if the element is nil because a container can
// contain nil elements.
HandleBranch(Term, Term, B, Pred);
return;
}
case Stmt::SwitchStmtClass: {
GRSwitchNodeBuilderImpl builder(Pred, B,
cast<SwitchStmt>(Term)->getCond(),
@ -233,8 +248,8 @@ void GRCoreEngineImpl::HandleBlockExit(CFGBlock * B, ExplodedNodeImpl* Pred) {
GenerateNode(BlockEdge(B, *(B->succ_begin())), Pred->State, Pred);
}
void GRCoreEngineImpl::HandleBranch(Expr* Cond, Stmt* Term, CFGBlock * B,
ExplodedNodeImpl* Pred) {
void GRCoreEngineImpl::HandleBranch(Stmt* Cond, Stmt* Term, CFGBlock * B,
ExplodedNodeImpl* Pred) {
assert (B->succ_size() == 2);
GRBranchNodeBuilderImpl Builder(B, *(B->succ_begin()), *(B->succ_begin()+1),

Просмотреть файл

@ -366,6 +366,10 @@ void GRExprEngine::Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst) {
case Stmt::ObjCIvarRefExprClass:
VisitObjCIvarRefExpr(cast<ObjCIvarRefExpr>(S), Pred, Dst, false);
break;
case Stmt::ObjCForCollectionStmtClass:
VisitObjCForCollectionStmt(cast<ObjCForCollectionStmt>(S), Pred, Dst);
break;
case Stmt::ObjCMessageExprClass: {
VisitObjCMessageExpr(cast<ObjCMessageExpr>(S), Pred, Dst);
@ -547,7 +551,7 @@ const GRState* GRExprEngine::MarkBranch(const GRState* St,
}
}
void GRExprEngine::ProcessBranch(Expr* Condition, Stmt* Term,
void GRExprEngine::ProcessBranch(Stmt* Condition, Stmt* Term,
BranchNodeBuilder& builder) {
// Remove old bindings for subexpressions.
@ -1343,6 +1347,79 @@ void GRExprEngine::VisitObjCIvarRefExpr(ObjCIvarRefExpr* Ex,
else
EvalLoad(Dst, Ex, *I, St, location);
}
}
//===----------------------------------------------------------------------===//
// Transfer function: Objective-C fast enumeration 'for' statements.
//===----------------------------------------------------------------------===//
void GRExprEngine::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S,
NodeTy* Pred, NodeSet& Dst) {
// ObjCForCollectionStmts are processed in two places. This method
// handles the case where an ObjCForCollectionStmt* occurs as one of the
// statements within a basic block. This transfer function does two things:
//
// (1) binds the next container value to 'element'. This creates a new
// node in the ExplodedGraph.
//
// (2) binds the value 0/1 to the ObjCForCollectionStmt* itself, indicating
// whether or not the container has any more elements. This value
// will be tested in ProcessBranch. We need to explicitly bind
// this value because a container can contain nil elements.
//
// FIXME: Eventually this logic should actually do dispatches to
// 'countByEnumeratingWithState:objects:count:' (NSFastEnumeration).
// This will require simulating a temporary NSFastEnumerationState, either
// through an SVal or through the use of MemRegions. This value can
// be affixed to the ObjCForCollectionStmt* instead of 0/1; when the loop
// terminates we reclaim the temporary (it goes out of scope) and we
// we can test if the SVal is 0 or if the MemRegion is null (depending
// on what approach we take).
//
// For now: simulate (1) by assigning either a symbol or nil if the
// container is empty. Thus this transfer function will by default
// result in state splitting.
Stmt* elem = S->getElement();
VarDecl* ElemD;
bool bindDecl = false;
if (DeclStmt* DS = dyn_cast<DeclStmt>(elem)) {
ElemD = cast<VarDecl>(DS->getSolitaryDecl());
assert (ElemD->getInit() == 0);
bindDecl = true;
}
else
ElemD = cast<VarDecl>(cast<DeclRefExpr>(elem)->getDecl());
// Get the current state, as well as the QualType for 'int' and the
// type of the element.
GRStateRef state = GRStateRef(GetState(Pred), getStateManager());
QualType IntTy = getContext().IntTy;
QualType ElemTy = ElemD->getType();
// Handle the case where the container still has elements.
SVal TrueV = NonLoc::MakeVal(getBasicVals(), 1, IntTy);
GRStateRef hasElems = state.BindExpr(S, TrueV);
assert (Loc::IsLocType(ElemTy));
unsigned Count = Builder->getCurrentBlockCount();
loc::SymbolVal SymV(SymMgr.getConjuredSymbol(elem, ElemTy, Count));
if (bindDecl)
hasElems = hasElems.BindDecl(ElemD, &SymV, Count);
else
hasElems = hasElems.BindLoc(hasElems.GetLValue(ElemD), SymV);
// Handle the case where the container has no elements.
}
//===----------------------------------------------------------------------===//
@ -1630,21 +1707,44 @@ void GRExprEngine::VisitDeclStmt(DeclStmt* DS, NodeTy* Pred, NodeSet& Dst) {
const VarDecl* VD = dyn_cast<VarDecl>(D);
Expr* Ex = const_cast<Expr*>(VD->getInit());
Expr* InitEx = const_cast<Expr*>(VD->getInit());
// FIXME: static variables may have an initializer, but the second
// time a function is called those values may not be current.
NodeSet Tmp;
if (Ex)
Visit(Ex, Pred, Tmp);
if (InitEx)
Visit(InitEx, Pred, Tmp);
if (Tmp.empty())
Tmp.Add(Pred);
for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
const GRState* St = GetState(*I);
St = StateMgr.BindDecl(St, VD, Ex, Builder->getCurrentBlockCount());
unsigned Count = Builder->getCurrentBlockCount();
if (InitEx) {
SVal InitVal = GetSVal(St, InitEx);
QualType T = VD->getType();
// Recover some path-sensitivity if a scalar value evaluated to
// UnknownVal.
if (InitVal.isUnknown()) {
if (Loc::IsLocType(T)) {
SymbolID Sym = SymMgr.getConjuredSymbol(InitEx, Count);
InitVal = loc::SymbolVal(Sym);
}
else if (T->isIntegerType()) {
SymbolID Sym = SymMgr.getConjuredSymbol(InitEx, Count);
InitVal = nonloc::SymbolVal(Sym);
}
}
St = StateMgr.BindDecl(St, VD, &InitVal, Count);
}
else
St = StateMgr.BindDecl(St, VD, 0, Count);
MakeNode(Dst, DS, *I, St);
}
}