[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