]> granicus.if.org Git - clang/commitdiff
retain checker: Track the number of times a tracked object is sent
authorTed Kremenek <kremenek@apple.com>
Fri, 8 May 2009 20:01:42 +0000 (20:01 +0000)
committerTed Kremenek <kremenek@apple.com>
Fri, 8 May 2009 20:01:42 +0000 (20:01 +0000)
'autorelease'. This isn't used yet to flag errors.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@71244 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Analysis/CFRefCount.cpp

index 90b15a40b441423ec5fe4857d85807a13f5a868d..2d154759b252bb1bc1f98fb9a861c48c64fe2865 100644 (file)
@@ -1361,21 +1361,24 @@ private:
   Kind kind;
   RetEffect::ObjKind okind;
   unsigned Cnt;
+  unsigned ACnt;
   QualType T;
 
-  RefVal(Kind k, RetEffect::ObjKind o, unsigned cnt, QualType t)
-    : kind(k), okind(o), Cnt(cnt), T(t) {}
+  RefVal(Kind k, RetEffect::ObjKind o, unsigned cnt, unsigned acnt, QualType t)
+    : kind(k), okind(o), Cnt(cnt), ACnt(acnt), T(t) {}
 
   RefVal(Kind k, unsigned cnt = 0)
-    : kind(k), okind(RetEffect::AnyObj), Cnt(cnt) {}
+    : kind(k), okind(RetEffect::AnyObj), Cnt(cnt), ACnt(0) {}
 
 public:    
   Kind getKind() const { return kind; }
   
   RetEffect::ObjKind getObjKind() const { return okind; }
 
-  unsigned getCount() const { return Cnt; }    
-  void clearCounts() { Cnt = 0; }
+  unsigned getCount() const { return Cnt; }
+  unsigned getAutoreleaseCount() const { return ACnt; }
+  unsigned getCombinedCounts() const { return Cnt + ACnt; }
+  void clearCounts() { Cnt = 0; ACnt = 0; }
   
   QualType getType() const { return T; }
   
@@ -1408,12 +1411,12 @@ public:
   
   static RefVal makeOwned(RetEffect::ObjKind o, QualType t,
                           unsigned Count = 1) {
-    return RefVal(Owned, o, Count, t);
+    return RefVal(Owned, o, Count, 0, t);
   }
   
   static RefVal makeNotOwned(RetEffect::ObjKind o, QualType t,
                              unsigned Count = 0) {
-    return RefVal(NotOwned, o, Count, t);
+    return RefVal(NotOwned, o, Count, 0, t);
   }
 
   static RefVal makeReturnedOwned(unsigned Count) {
@@ -1431,20 +1434,29 @@ public:
   }
   
   RefVal operator-(size_t i) const {
-    return RefVal(getKind(), getObjKind(), getCount() - i, getType());
+    return RefVal(getKind(), getObjKind(), getCount() - i,
+                  getAutoreleaseCount(), getType());
   }
   
   RefVal operator+(size_t i) const {
-    return RefVal(getKind(), getObjKind(), getCount() + i, getType());
+    return RefVal(getKind(), getObjKind(), getCount() + i,
+                  getAutoreleaseCount(), getType());
   }
   
   RefVal operator^(Kind k) const {
-    return RefVal(k, getObjKind(), getCount(), getType());
+    return RefVal(k, getObjKind(), getCount(), getAutoreleaseCount(),
+                  getType());
+  }
+  
+  RefVal autorelease() const {
+    return RefVal(getKind(), getObjKind(), getCount(), getAutoreleaseCount()+1,
+                  getType());
   }
     
   void Profile(llvm::FoldingSetNodeID& ID) const {
     ID.AddInteger((unsigned) kind);
     ID.AddInteger(Cnt);
+    ID.AddInteger(ACnt);
     ID.Add(T);
   }
 
@@ -1513,6 +1525,10 @@ void RefVal::print(std::ostream& Out) const {
       Out << "Release of Not-Owned [ERROR]";
       break;
   }
+  
+  if (ACnt) {
+    Out << " [ARC +" << ACnt << ']';
+  }
 }
   
 } // end anonymous namespace
@@ -2102,7 +2118,7 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode<GRState>* N,
       // We may not have transitioned to 'release' if we hit an error.
       // This case is handled elsewhere.
       if (CurrV.getKind() == RefVal::Released) {
-        assert(CurrV.getCount() == 0);
+        assert(CurrV.getCombinedCounts() == 0);
         os << "Object released by directly sending the '-dealloc' message";
         break;
       }
@@ -2148,8 +2164,15 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode<GRState>* N,
         case RefVal::Owned:
         case RefVal::NotOwned:
           
-          if (PrevV.getCount() == CurrV.getCount())
-            return 0;
+          if (PrevV.getCount() == CurrV.getCount()) {
+            // Did an autorelease message get sent?
+            if (PrevV.getAutoreleaseCount() == CurrV.getAutoreleaseCount())
+              return 0;
+            
+            assert(PrevV.getAutoreleaseCount() < CurrV.getAutoreleaseCount());            
+            os << "Object added to autorelease pool.";
+            break;
+          }
           
           if (PrevV.getCount() > CurrV.getCount())
             os << "Reference count decremented.";
@@ -3040,8 +3063,7 @@ GRStateRef CFRefCount::Update(GRStateRef state, SymbolRef sym,
       
       // Update the autorelease counts.
       state = SendAutorelease(state, ARCountFactory, sym);
-
-      // Fall-through.
+      V = V.autorelease();
       
     case StopTracking:
       return state.remove<RefBindings>(sym);