aboutsummaryrefslogtreecommitdiff
path: root/lib/Analysis/GRExprEngine.cpp
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2008-11-12 19:24:17 +0000
committerTed Kremenek <kremenek@apple.com>2008-11-12 19:24:17 +0000
commitaf3374187c47acea45706eab6744be6b1c66a856 (patch)
treeaba0e93182f1d80e87d2f39b5211c2a7a4f1a69d /lib/Analysis/GRExprEngine.cpp
parentb5abb429e7aac731c3b4363a6118a6b3a6e27abc (diff)
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
Diffstat (limited to 'lib/Analysis/GRExprEngine.cpp')
-rw-r--r--lib/Analysis/GRExprEngine.cpp110
1 files changed, 105 insertions, 5 deletions
diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp
index 8e6d5ab5cc..2fa163ad23 100644
--- a/lib/Analysis/GRExprEngine.cpp
+++ b/lib/Analysis/GRExprEngine.cpp
@@ -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.
@@ -1346,6 +1350,79 @@ void GRExprEngine::VisitObjCIvarRefExpr(ObjCIvarRefExpr* Ex,
}
//===----------------------------------------------------------------------===//
+// 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 @@ 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);
}
}