[cfe-commits] r59155 - in /cfe/trunk: include/clang/Analysis/PathSensitive/GRCoreEngine.h include/clang/Analysis/PathSensitive/GRExprEngine.h lib/Analysis/GRCoreEngine.cpp lib/Analysis/GRExprEngine.cpp
Ted Kremenek
kremenek at apple.com
Wed Nov 12 11:24:19 PST 2008
Author: kremenek
Date: Wed Nov 12 13:24:17 2008
New Revision: 59155
URL: http://llvm.org/viewvc/llvm-project?rev=59155&view=rev
Log:
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.
Modified:
cfe/trunk/include/clang/Analysis/PathSensitive/GRCoreEngine.h
cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h
cfe/trunk/lib/Analysis/GRCoreEngine.cpp
cfe/trunk/lib/Analysis/GRExprEngine.cpp
Modified: cfe/trunk/include/clang/Analysis/PathSensitive/GRCoreEngine.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/PathSensitive/GRCoreEngine.h?rev=59155&r1=59154&r2=59155&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/PathSensitive/GRCoreEngine.h (original)
+++ cfe/trunk/include/clang/Analysis/PathSensitive/GRCoreEngine.h Wed Nov 12 13:24:17 2008
@@ -76,7 +76,7 @@
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 @@
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 @@
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);
Modified: cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h?rev=59155&r1=59154&r2=59155&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h (original)
+++ cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h Wed Nov 12 13:24:17 2008
@@ -368,7 +368,7 @@
/// 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 @@
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 @@
/// 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);
Modified: cfe/trunk/lib/Analysis/GRCoreEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/GRCoreEngine.cpp?rev=59155&r1=59154&r2=59155&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/GRCoreEngine.cpp (original)
+++ cfe/trunk/lib/Analysis/GRCoreEngine.cpp Wed Nov 12 13:24:17 2008
@@ -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 @@
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 @@
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),
Modified: cfe/trunk/lib/Analysis/GRExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/GRExprEngine.cpp?rev=59155&r1=59154&r2=59155&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/GRExprEngine.cpp (original)
+++ cfe/trunk/lib/Analysis/GRExprEngine.cpp Wed Nov 12 13:24:17 2008
@@ -366,6 +366,10 @@
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 @@
}
}
-void GRExprEngine::ProcessBranch(Expr* Condition, Stmt* Term,
+void GRExprEngine::ProcessBranch(Stmt* Condition, Stmt* Term,
BranchNodeBuilder& builder) {
// Remove old bindings for subexpressions.
@@ -1346,6 +1350,79 @@
}
//===----------------------------------------------------------------------===//
+// 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.
+
+
+
+
+
+}
+
+//===----------------------------------------------------------------------===//
// Transfer function: Objective-C message expressions.
//===----------------------------------------------------------------------===//
@@ -1630,21 +1707,44 @@
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);
}
}
More information about the cfe-commits
mailing list