[cfe-commits] r64956 - /cfe/trunk/lib/Analysis/CFRefCount.cpp

Ted Kremenek kremenek at apple.com
Wed Feb 18 13:57:45 PST 2009


Author: kremenek
Date: Wed Feb 18 15:57:45 2009
New Revision: 64956

URL: http://llvm.org/viewvc/llvm-project?rev=64956&view=rev
Log:
retain/release checker: We now emit fancy diagnostics telling users about the
semantics of CFMakeCollectable and friends.

Modified:
    cfe/trunk/lib/Analysis/CFRefCount.cpp

Modified: cfe/trunk/lib/Analysis/CFRefCount.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFRefCount.cpp?rev=64956&r1=64955&r2=64956&view=diff

==============================================================================
--- cfe/trunk/lib/Analysis/CFRefCount.cpp (original)
+++ cfe/trunk/lib/Analysis/CFRefCount.cpp Wed Feb 18 15:57:45 2009
@@ -133,6 +133,7 @@
 /// particular argument.
 enum ArgEffect { IncRefMsg, IncRef,  
                  DecRefMsg, DecRef,
+                 MakeCollectable,
                  DoNothing, DoNothingByRef,
                  StopTracking, MayEscape, SelfOwn, Autorelease };
 
@@ -879,11 +880,8 @@
     }
       
     case cfmakecollectable: {
-      if (GCEnabled)
-        ScratchArgs.push_back(std::make_pair(0, DecRef));
-      
-      return getPersistentSummary(RetEffect::MakeAlias(0),
-                                  DoNothing, DoNothing);    
+      ScratchArgs.push_back(std::make_pair(0, MakeCollectable));
+      return getPersistentSummary(RetEffect::MakeAlias(0),DoNothing, DoNothing);    
     }
       
     default:
@@ -1944,6 +1942,7 @@
     default: break;
     case IncRefMsg: E = isGCEnabled() ? DoNothing : IncRef; break;
     case DecRefMsg: E = isGCEnabled() ? DoNothing : DecRef; break;
+    case MakeCollectable: E = isGCEnabled() ? DecRef : DoNothing; break;
   }
   
   switch (E) {
@@ -2230,6 +2229,15 @@
   }
 }
 
+static inline bool contains(const llvm::SmallVectorImpl<ArgEffect>& V,
+                              ArgEffect X) {
+  for (llvm::SmallVectorImpl<ArgEffect>::const_iterator I=V.begin(), E=V.end();
+        I!=E; ++I)
+    if (*I == X) return true;
+  
+  return false;
+}
+
 PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode<GRState>* N,
                                             const ExplodedNode<GRState>* PrevN,
                                             const ExplodedGraph<GRState>& G,
@@ -2247,12 +2255,14 @@
   const RefVal& CurrV = *CurrT;
   const RefVal* PrevT = PrevSt.get<RefBindings>(Sym);
 
+  // Create a string buffer to constain all the useful things we want
+  // to tell the user.
+  std::string sbuf;
+  llvm::raw_string_ostream os(sbuf);
+
   // This is the allocation site since the previous node had no bindings
   // for this symbol.
   if (!PrevT) {
-    std::string sbuf;
-    llvm::raw_string_ostream os(sbuf);
-    
     Stmt* S = cast<PostStmt>(N->getLocation()).getStmt();
 
     if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
@@ -2298,21 +2308,16 @@
     
     return P;    
   }
-
-  // Create a string buffer to constain all the useful things we want
-  // to tell the user.
-  std::string sbuf;
-  llvm::raw_string_ostream os(sbuf);
   
-  // Consult the summary to see if there is something special we
-  // should tell the user.
+  // Gather up the effects that were performed on the object at this
+  // program point
+  llvm::SmallVector<ArgEffect, 2> AEffects;
+
   if (const RetainSummary *Summ = TF.getSummaryOfNode(NR.getOriginalNode(N))) {
     // We only have summaries attached to nodes after evaluating CallExpr and
     // ObjCMessageExprs.
     Stmt* S = cast<PostStmt>(N->getLocation()).getStmt();
     
-    llvm::SmallVector<ArgEffect, 2> AEffects;
-    
     if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
       // Iterate through the parameter expressions and see if the symbol
       // was ever passed as an argument.
@@ -2320,10 +2325,10 @@
       
       for (CallExpr::arg_iterator AI=CE->arg_begin(), AE=CE->arg_end();
            AI!=AE; ++AI, ++i) {
-
+        
         // Retrieve the value of the arugment.
         SVal X = CurrSt.GetSVal(*AI);
-
+        
         // Is it the symbol we're interested in?
         if (!isa<loc::SymbolVal>(X) || 
             Sym != cast<loc::SymbolVal>(X).getSymbol())
@@ -2335,43 +2340,55 @@
     }
     else if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S)) {      
       if (Expr *receiver = ME->getReceiver()) {
-          SVal RetV = CurrSt.GetSVal(receiver);        
-          if (isa<loc::SymbolVal>(RetV) &&
-              Sym == cast<loc::SymbolVal>(RetV).getSymbol()) {
-            // The symbol we are tracking is the receiver.
-            AEffects.push_back(Summ->getReceiverEffect());
-          }
+        SVal RetV = CurrSt.GetSVal(receiver);        
+        if (isa<loc::SymbolVal>(RetV) &&
+            Sym == cast<loc::SymbolVal>(RetV).getSymbol()) {
+          // The symbol we are tracking is the receiver.
+          AEffects.push_back(Summ->getReceiverEffect());
+        }
       }
     }
-      
-    // Emit diagnostics for the argument effects (if any).
-    // FIXME: The typestate logic below should also be folded into
-    // this block.
-    for (llvm::SmallVectorImpl<ArgEffect>::iterator I=AEffects.begin(),
-          E=AEffects.end(); I != E; ++I) {
+  }
+  
+  do {
+    // Get the previous type state.
+    RefVal PrevV = *PrevT;
 
-      // A bunch of things have alternate behavior under GC.
-      if (TF.isGCEnabled())
-        switch (*I) {
-          default: break;
-          case Autorelease:
-            os << "In GC mode an 'autorelease' has no effect.";
-            continue;
-          case IncRefMsg:
-            os << "In GC mode the 'retain' message has no effect.";
-            continue;
-          case DecRefMsg:
-            os << "In GC mode the 'release' message has no effect.";
-            continue;
-        }
+    // Specially handle CFMakeCollectable and friends.
+    if (contains(AEffects, MakeCollectable)) {
+      // Get the name of the function.
+      Stmt* S = cast<PostStmt>(N->getLocation()).getStmt();
+      loc::FuncVal FV =
+        cast<loc::FuncVal>(CurrSt.GetSVal(cast<CallExpr>(S)->getCallee()));
+      const std::string& FName = FV.getDecl()->getNameAsString();
+      
+      if (TF.isGCEnabled()) {
+        // Determine if the object's reference count was pushed to zero.
+        assert(!(PrevV == CurrV) && "The typestate *must* have changed.");
+        
+        os << "In GC mode a call to '" << FName
+           <<  "' decrements an object's retain count and registers the "
+               "object with the garbage collector. ";
+
+        if (CurrV.getKind() == RefVal::Released)
+          os << "The object's visible retain count is now 0 and can be "
+                "automatically collected by the garbage collector.";
+        else
+          os << "An object must have a 0 retain count to be garbage collected. "
+                "After this call its retain count is +" << CurrV.getCount()
+             << '.';
+      }
+      else 
+        os << "When GC is not enabled a call to '" << FName
+           << "' has no effect on its argument.";
+
+      // Nothing more to say.
+      break;
     }
-  }
 
-  // Determine if the typestate has changed.  
-  RefVal PrevV = *PrevT;
-  
-  if (!(PrevV == CurrV)) // The typestate has changed.
-    switch (CurrV.getKind()) {
+    // Determine if the typestate has changed.  
+    if (!(PrevV == CurrV))
+      switch (CurrV.getKind()) {
       case RefVal::Owned:
       case RefVal::NotOwned:
 
@@ -2409,7 +2426,28 @@
 
       default:
         return NULL;
+      }
+    
+    // Emit any remaining diagnostics for the argument effects (if any).
+    for (llvm::SmallVectorImpl<ArgEffect>::iterator I=AEffects.begin(),
+         E=AEffects.end(); I != E; ++I) {
+      
+      // A bunch of things have alternate behavior under GC.
+      if (TF.isGCEnabled())
+        switch (*I) {
+          default: break;
+          case Autorelease:
+            os << "In GC mode an 'autorelease' has no effect.";
+            continue;
+          case IncRefMsg:
+            os << "In GC mode the 'retain' message has no effect.";
+            continue;
+          case DecRefMsg:
+            os << "In GC mode the 'release' message has no effect.";
+            continue;
+        }
     }
+  } while(0);
 
   if (os.str().empty())
     return 0; // We have nothing to say!





More information about the cfe-commits mailing list