зеркало из https://github.com/microsoft/clang.git
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:
Родитель
b5abb429e7
Коммит
af3374187c
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче