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

Ted Kremenek kremenek at apple.com
Thu Nov 12 17:54:21 PST 2009


Author: kremenek
Date: Thu Nov 12 19:54:21 2009
New Revision: 87062

URL: http://llvm.org/viewvc/llvm-project?rev=87062&view=rev
Log:
retain/release checker: refactor some of the summary lookup logic for instance method summaries.  No real functionality change, but it paves the way for new enhancements.

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=87062&r1=87061&r2=87062&view=diff

==============================================================================
--- cfe/trunk/lib/Analysis/CFRefCount.cpp (original)
+++ cfe/trunk/lib/Analysis/CFRefCount.cpp Thu Nov 12 19:54:21 2009
@@ -308,7 +308,232 @@
   }
 };
 
+//===----------------------------------------------------------------------===//
+// Reference-counting logic (typestate + counts).
+//===----------------------------------------------------------------------===//
+
+class VISIBILITY_HIDDEN RefVal {
+public:
+  enum Kind {
+    Owned = 0, // Owning reference.
+    NotOwned,  // Reference is not owned by still valid (not freed).
+    Released,  // Object has been released.
+    ReturnedOwned, // Returned object passes ownership to caller.
+    ReturnedNotOwned, // Return object does not pass ownership to caller.
+    ERROR_START,
+    ErrorDeallocNotOwned, // -dealloc called on non-owned object.
+    ErrorDeallocGC, // Calling -dealloc with GC enabled.
+    ErrorUseAfterRelease, // Object used after released.
+    ErrorReleaseNotOwned, // Release of an object that was not owned.
+    ERROR_LEAK_START,
+    ErrorLeak,  // A memory leak due to excessive reference counts.
+    ErrorLeakReturned, // A memory leak due to the returning method not having
+                       // the correct naming conventions.
+    ErrorGCLeakReturned,
+    ErrorOverAutorelease,
+    ErrorReturnedNotOwned
+  };
+  
+private:
+  Kind kind;
+  RetEffect::ObjKind okind;
+  unsigned Cnt;
+  unsigned ACnt;
+  QualType 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), ACnt(0) {}
+  
+public:
+  Kind getKind() const { return kind; }
+  
+  RetEffect::ObjKind getObjKind() const { return okind; }
+  
+  unsigned getCount() const { return Cnt; }
+  unsigned getAutoreleaseCount() const { return ACnt; }
+  unsigned getCombinedCounts() const { return Cnt + ACnt; }
+  void clearCounts() { Cnt = 0; ACnt = 0; }
+  void setCount(unsigned i) { Cnt = i; }
+  void setAutoreleaseCount(unsigned i) { ACnt = i; }
+  
+  QualType getType() const { return T; }
+  
+  // Useful predicates.
+  
+  static bool isError(Kind k) { return k >= ERROR_START; }
+  
+  static bool isLeak(Kind k) { return k >= ERROR_LEAK_START; }
+  
+  bool isOwned() const {
+    return getKind() == Owned;
+  }
+  
+  bool isNotOwned() const {
+    return getKind() == NotOwned;
+  }
+  
+  bool isReturnedOwned() const {
+    return getKind() == ReturnedOwned;
+  }
+  
+  bool isReturnedNotOwned() const {
+    return getKind() == ReturnedNotOwned;
+  }
+  
+  bool isNonLeakError() const {
+    Kind k = getKind();
+    return isError(k) && !isLeak(k);
+  }
+  
+  static RefVal makeOwned(RetEffect::ObjKind o, QualType t,
+                          unsigned Count = 1) {
+    return RefVal(Owned, o, Count, 0, t);
+  }
+  
+  static RefVal makeNotOwned(RetEffect::ObjKind o, QualType t,
+                             unsigned Count = 0) {
+    return RefVal(NotOwned, o, Count, 0, t);
+  }
+  
+  // Comparison, profiling, and pretty-printing.
+  
+  bool operator==(const RefVal& X) const {
+    return kind == X.kind && Cnt == X.Cnt && T == X.T && ACnt == X.ACnt;
+  }
+  
+  RefVal operator-(size_t i) const {
+    return RefVal(getKind(), getObjKind(), getCount() - i,
+                  getAutoreleaseCount(), getType());
+  }
+  
+  RefVal operator+(size_t i) const {
+    return RefVal(getKind(), getObjKind(), getCount() + i,
+                  getAutoreleaseCount(), getType());
+  }
+  
+  RefVal operator^(Kind k) const {
+    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);
+  }
+  
+  void print(llvm::raw_ostream& Out) const;
+};
+
+void RefVal::print(llvm::raw_ostream& Out) const {
+  if (!T.isNull())
+    Out << "Tracked Type:" << T.getAsString() << '\n';
+  
+  switch (getKind()) {
+    default: assert(false);
+    case Owned: {
+      Out << "Owned";
+      unsigned cnt = getCount();
+      if (cnt) Out << " (+ " << cnt << ")";
+      break;
+    }
+      
+    case NotOwned: {
+      Out << "NotOwned";
+      unsigned cnt = getCount();
+      if (cnt) Out << " (+ " << cnt << ")";
+      break;
+    }
+      
+    case ReturnedOwned: {
+      Out << "ReturnedOwned";
+      unsigned cnt = getCount();
+      if (cnt) Out << " (+ " << cnt << ")";
+      break;
+    }
+      
+    case ReturnedNotOwned: {
+      Out << "ReturnedNotOwned";
+      unsigned cnt = getCount();
+      if (cnt) Out << " (+ " << cnt << ")";
+      break;
+    }
+      
+    case Released:
+      Out << "Released";
+      break;
+      
+    case ErrorDeallocGC:
+      Out << "-dealloc (GC)";
+      break;
+      
+    case ErrorDeallocNotOwned:
+      Out << "-dealloc (not-owned)";
+      break;
+      
+    case ErrorLeak:
+      Out << "Leaked";
+      break;
+      
+    case ErrorLeakReturned:
+      Out << "Leaked (Bad naming)";
+      break;
+      
+    case ErrorGCLeakReturned:
+      Out << "Leaked (GC-ed at return)";
+      break;
+      
+    case ErrorUseAfterRelease:
+      Out << "Use-After-Release [ERROR]";
+      break;
+      
+    case ErrorReleaseNotOwned:
+      Out << "Release of Not-Owned [ERROR]";
+      break;
+      
+    case RefVal::ErrorOverAutorelease:
+      Out << "Over autoreleased";
+      break;
+      
+    case RefVal::ErrorReturnedNotOwned:
+      Out << "Non-owned object returned instead of owned";
+      break;
+  }
+  
+  if (ACnt) {
+    Out << " [ARC +" << ACnt << ']';
+  }
+}
+} //end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// RefBindings - State used to track object reference counts.
+//===----------------------------------------------------------------------===//
+
+typedef llvm::ImmutableMap<SymbolRef, RefVal> RefBindings;
+static int RefBIndex = 0;
+
+namespace clang {
+  template<>
+  struct GRStateTrait<RefBindings> : public GRStatePartialTrait<RefBindings> {
+    static inline void* GDMIndex() { return &RefBIndex; }
+  };
+}
 
+//===----------------------------------------------------------------------===//
+// Summaries
+//===----------------------------------------------------------------------===//
+
+namespace {
 class VISIBILITY_HIDDEN RetainSummary {
   /// Args - an ordered vector of (index, ArgEffect) pairs, where index
   ///  specifies the argument (starting from 0).  This can be sparsely
@@ -757,7 +982,11 @@
 
   RetainSummary* getSummary(FunctionDecl* FD);
 
-  RetainSummary* getInstanceMethodSummary(ObjCMessageExpr* ME,
+  RetainSummary *getInstanceMethodSummary(const ObjCMessageExpr *ME,
+                                          const GRState *state,
+                                          const LocationContext *LC);
+  
+  RetainSummary* getInstanceMethodSummary(const ObjCMessageExpr* ME,
                                           const ObjCInterfaceDecl* ID) {
     return getInstanceMethodSummary(ME->getSelector(), ME->getClassName(),
                             ID, ME->getMethodDecl(), ME->getType());
@@ -773,7 +1002,7 @@
                                        const ObjCMethodDecl *MD,
                                        QualType RetTy);
 
-  RetainSummary *getClassMethodSummary(ObjCMessageExpr *ME) {
+  RetainSummary *getClassMethodSummary(const ObjCMessageExpr *ME) {
     return getClassMethodSummary(ME->getSelector(), ME->getClassName(),
                                  ME->getClassInfo().first,
                                  ME->getMethodDecl(), ME->getType());
@@ -1350,6 +1579,61 @@
 }
 
 RetainSummary*
+RetainSummaryManager::getInstanceMethodSummary(const ObjCMessageExpr *ME,
+                                               const GRState *state,
+                                               const LocationContext *LC) {
+
+  // We need the type-information of the tracked receiver object
+  // Retrieve it from the state.
+  const Expr *Receiver = ME->getReceiver();
+  const ObjCInterfaceDecl* ID = 0;
+
+  // FIXME: Is this really working as expected?  There are cases where
+  //  we just use the 'ID' from the message expression.
+  SVal receiverV = state->getSValAsScalarOrLoc(Receiver);
+  
+  // FIXME: Eventually replace the use of state->get<RefBindings> with
+  // a generic API for reasoning about the Objective-C types of symbolic
+  // objects.
+  if (SymbolRef Sym = receiverV.getAsLocSymbol())
+    if (const RefVal *T = state->get<RefBindings>(Sym))
+      if (const ObjCObjectPointerType* PT = 
+            T->getType()->getAs<ObjCObjectPointerType>())
+        ID = PT->getInterfaceDecl();
+  
+  // FIXME: this is a hack.  This may or may not be the actual method
+  //  that is called.
+  if (!ID) {
+    if (const ObjCObjectPointerType *PT =
+        Receiver->getType()->getAs<ObjCObjectPointerType>())
+      ID = PT->getInterfaceDecl();
+  }
+  
+  // FIXME: The receiver could be a reference to a class, meaning that
+  //  we should use the class method.
+  RetainSummary *Summ = getInstanceMethodSummary(ME, ID);
+  
+  // Special-case: are we sending a mesage to "self"?
+  //  This is a hack.  When we have full-IP this should be removed.
+  if (isa<ObjCMethodDecl>(LC->getDecl())) {
+    if (const loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&receiverV)) {
+      // Get the region associated with 'self'.
+      if (const ImplicitParamDecl *SelfDecl = LC->getSelfDecl()) {
+        SVal SelfVal = state->getSVal(state->getRegion(SelfDecl, LC));
+        if (L->StripCasts() == SelfVal.getAsRegion()) {
+          // Update the summary to make the default argument effect
+          // 'StopTracking'.
+          Summ = copySummary(Summ);
+          Summ->setDefaultArgEffect(StopTracking);
+        }
+      }
+    }
+  }
+  
+  return Summ ? Summ : getDefaultSummary();
+}
+
+RetainSummary*
 RetainSummaryManager::getInstanceMethodSummary(Selector S,
                                                IdentifierInfo *ClsName,
                                                const ObjCInterfaceDecl* ID,
@@ -1569,230 +1853,6 @@
 }
 
 //===----------------------------------------------------------------------===//
-// Reference-counting logic (typestate + counts).
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-class VISIBILITY_HIDDEN RefVal {
-public:
-  enum Kind {
-    Owned = 0, // Owning reference.
-    NotOwned,  // Reference is not owned by still valid (not freed).
-    Released,  // Object has been released.
-    ReturnedOwned, // Returned object passes ownership to caller.
-    ReturnedNotOwned, // Return object does not pass ownership to caller.
-    ERROR_START,
-    ErrorDeallocNotOwned, // -dealloc called on non-owned object.
-    ErrorDeallocGC, // Calling -dealloc with GC enabled.
-    ErrorUseAfterRelease, // Object used after released.
-    ErrorReleaseNotOwned, // Release of an object that was not owned.
-    ERROR_LEAK_START,
-    ErrorLeak,  // A memory leak due to excessive reference counts.
-    ErrorLeakReturned, // A memory leak due to the returning method not having
-                      // the correct naming conventions.
-    ErrorGCLeakReturned,
-    ErrorOverAutorelease,
-    ErrorReturnedNotOwned
-  };
-
-private:
-  Kind kind;
-  RetEffect::ObjKind okind;
-  unsigned Cnt;
-  unsigned ACnt;
-  QualType 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), ACnt(0) {}
-
-public:
-  Kind getKind() const { return kind; }
-
-  RetEffect::ObjKind getObjKind() const { return okind; }
-
-  unsigned getCount() const { return Cnt; }
-  unsigned getAutoreleaseCount() const { return ACnt; }
-  unsigned getCombinedCounts() const { return Cnt + ACnt; }
-  void clearCounts() { Cnt = 0; ACnt = 0; }
-  void setCount(unsigned i) { Cnt = i; }
-  void setAutoreleaseCount(unsigned i) { ACnt = i; }
-
-  QualType getType() const { return T; }
-
-  // Useful predicates.
-
-  static bool isError(Kind k) { return k >= ERROR_START; }
-
-  static bool isLeak(Kind k) { return k >= ERROR_LEAK_START; }
-
-  bool isOwned() const {
-    return getKind() == Owned;
-  }
-
-  bool isNotOwned() const {
-    return getKind() == NotOwned;
-  }
-
-  bool isReturnedOwned() const {
-    return getKind() == ReturnedOwned;
-  }
-
-  bool isReturnedNotOwned() const {
-    return getKind() == ReturnedNotOwned;
-  }
-
-  bool isNonLeakError() const {
-    Kind k = getKind();
-    return isError(k) && !isLeak(k);
-  }
-
-  static RefVal makeOwned(RetEffect::ObjKind o, QualType t,
-                          unsigned Count = 1) {
-    return RefVal(Owned, o, Count, 0, t);
-  }
-
-  static RefVal makeNotOwned(RetEffect::ObjKind o, QualType t,
-                             unsigned Count = 0) {
-    return RefVal(NotOwned, o, Count, 0, t);
-  }
-
-  // Comparison, profiling, and pretty-printing.
-
-  bool operator==(const RefVal& X) const {
-    return kind == X.kind && Cnt == X.Cnt && T == X.T && ACnt == X.ACnt;
-  }
-
-  RefVal operator-(size_t i) const {
-    return RefVal(getKind(), getObjKind(), getCount() - i,
-                  getAutoreleaseCount(), getType());
-  }
-
-  RefVal operator+(size_t i) const {
-    return RefVal(getKind(), getObjKind(), getCount() + i,
-                  getAutoreleaseCount(), getType());
-  }
-
-  RefVal operator^(Kind k) const {
-    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);
-  }
-
-  void print(llvm::raw_ostream& Out) const;
-};
-
-void RefVal::print(llvm::raw_ostream& Out) const {
-  if (!T.isNull())
-    Out << "Tracked Type:" << T.getAsString() << '\n';
-
-  switch (getKind()) {
-    default: assert(false);
-    case Owned: {
-      Out << "Owned";
-      unsigned cnt = getCount();
-      if (cnt) Out << " (+ " << cnt << ")";
-      break;
-    }
-
-    case NotOwned: {
-      Out << "NotOwned";
-      unsigned cnt = getCount();
-      if (cnt) Out << " (+ " << cnt << ")";
-      break;
-    }
-
-    case ReturnedOwned: {
-      Out << "ReturnedOwned";
-      unsigned cnt = getCount();
-      if (cnt) Out << " (+ " << cnt << ")";
-      break;
-    }
-
-    case ReturnedNotOwned: {
-      Out << "ReturnedNotOwned";
-      unsigned cnt = getCount();
-      if (cnt) Out << " (+ " << cnt << ")";
-      break;
-    }
-
-    case Released:
-      Out << "Released";
-      break;
-
-    case ErrorDeallocGC:
-      Out << "-dealloc (GC)";
-      break;
-
-    case ErrorDeallocNotOwned:
-      Out << "-dealloc (not-owned)";
-      break;
-
-    case ErrorLeak:
-      Out << "Leaked";
-      break;
-
-    case ErrorLeakReturned:
-      Out << "Leaked (Bad naming)";
-      break;
-
-    case ErrorGCLeakReturned:
-      Out << "Leaked (GC-ed at return)";
-      break;
-
-    case ErrorUseAfterRelease:
-      Out << "Use-After-Release [ERROR]";
-      break;
-
-    case ErrorReleaseNotOwned:
-      Out << "Release of Not-Owned [ERROR]";
-      break;
-
-    case RefVal::ErrorOverAutorelease:
-      Out << "Over autoreleased";
-      break;
-
-    case RefVal::ErrorReturnedNotOwned:
-      Out << "Non-owned object returned instead of owned";
-      break;
-  }
-
-  if (ACnt) {
-    Out << " [ARC +" << ACnt << ']';
-  }
-}
-
-} // end anonymous namespace
-
-//===----------------------------------------------------------------------===//
-// RefBindings - State used to track object reference counts.
-//===----------------------------------------------------------------------===//
-
-typedef llvm::ImmutableMap<SymbolRef, RefVal> RefBindings;
-static int RefBIndex = 0;
-
-namespace clang {
-  template<>
-  struct GRStateTrait<RefBindings> : public GRStatePartialTrait<RefBindings> {
-    static inline void* GDMIndex() { return &RefBIndex; }
-  };
-}
-
-//===----------------------------------------------------------------------===//
 // AutoreleaseBindings - State used to track objects in autorelease pools.
 //===----------------------------------------------------------------------===//
 
@@ -3004,69 +3064,14 @@
                                      GRStmtNodeBuilder& Builder,
                                      ObjCMessageExpr* ME,
                                      ExplodedNode* Pred) {
-  RetainSummary* Summ = 0;
-
-  if (Expr* Receiver = ME->getReceiver()) {
-    // We need the type-information of the tracked receiver object
-    // Retrieve it from the state.
-    const ObjCInterfaceDecl* ID = 0;
-
-    // FIXME: Wouldn't it be great if this code could be reduced?  It's just
-    // a chain of lookups.
-    // FIXME: Is this really working as expected?  There are cases where
-    //  we just use the 'ID' from the message expression.
-    const GRState* St = Builder.GetState(Pred);
-    SVal V = St->getSValAsScalarOrLoc(Receiver);
-
-    SymbolRef Sym = V.getAsLocSymbol();
-
-    if (Sym) {
-      if (const RefVal* T  = St->get<RefBindings>(Sym)) {
-        if (const ObjCObjectPointerType* PT =
-            T->getType()->getAs<ObjCObjectPointerType>())
-          ID = PT->getInterfaceDecl();
-      }
-    }
-
-    // FIXME: this is a hack.  This may or may not be the actual method
-    //  that is called.
-    if (!ID) {
-      if (const ObjCObjectPointerType *PT =
-          Receiver->getType()->getAs<ObjCObjectPointerType>())
-        ID = PT->getInterfaceDecl();
-    }
-
-    // FIXME: The receiver could be a reference to a class, meaning that
-    //  we should use the class method.
-    Summ = Summaries.getInstanceMethodSummary(ME, ID);
-
-    // Special-case: are we sending a mesage to "self"?
-    //  This is a hack.  When we have full-IP this should be removed.
-    if (isa<ObjCMethodDecl>(Pred->getLocationContext()->getDecl())) {
-      if (Expr* Receiver = ME->getReceiver()) {
-        SVal X = St->getSValAsScalarOrLoc(Receiver);
-        if (loc::MemRegionVal* L = dyn_cast<loc::MemRegionVal>(&X)) {
-          // Get the region associated with 'self'.
-          const LocationContext *LC = Pred->getLocationContext();
-          if (const ImplicitParamDecl *SelfDecl = LC->getSelfDecl()) {
-            SVal SelfVal = St->getSVal(St->getRegion(SelfDecl, LC));
-            if (L->StripCasts() == SelfVal.getAsRegion()) {
-              // Update the summary to make the default argument effect
-              // 'StopTracking'.
-              Summ = Summaries.copySummary(Summ);
-              Summ->setDefaultArgEffect(StopTracking);
-            }
-          }
-        }
-      }
-    }
-  }
-  else
-    Summ = Summaries.getClassMethodSummary(ME);
-
-  if (!Summ)
-    Summ = Summaries.getDefaultSummary();
+  
+  RetainSummary *Summ =
+    ME->getReceiver()
+      ? Summaries.getInstanceMethodSummary(ME, Builder.GetState(Pred),
+                                           Pred->getLocationContext())
+      : Summaries.getClassMethodSummary(ME);
 
+  assert(Summ && "RetainSummary is null");
   EvalSummary(Dst, Eng, Builder, ME, ME->getReceiver(), *Summ,
               ME->arg_begin(), ME->arg_end(), Pred);
 }





More information about the cfe-commits mailing list