Issue warnings about owned objects returned from a method that does not match the established Cocoa naming conventions.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@58108 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp
index 51cadd9..20897ac 100644
--- a/lib/Analysis/CFRefCount.cpp
+++ b/lib/Analysis/CFRefCount.cpp
@@ -1096,7 +1096,7 @@
   
   static bool isError(Kind k) { return k >= ErrorUseAfterRelease; }
   
-  static bool isLeak(Kind k) { return k == ErrorLeak; }
+  static bool isLeak(Kind k) { return k >= ErrorLeak; }
   
   bool isOwned() const {
     return getKind() == Owned;
@@ -1266,7 +1266,8 @@
 
   typedef ReleasesNotOwnedTy UseAfterReleasesTy;
     
-  typedef llvm::DenseMap<GRExprEngine::NodeTy*, std::vector<SymbolID>*>
+  typedef llvm::DenseMap<GRExprEngine::NodeTy*,
+                         std::vector<std::pair<SymbolID,bool> >*>
           LeaksTy;
 
   class BindingsPrinter : public GRState::Printer {
@@ -1302,9 +1303,9 @@
                            const GRState* St,
                            RefVal::Kind hasErr, SymbolID Sym);
   
-  const GRState* HandleSymbolDeath(GRStateManager& VMgr, const GRState* St,
-                                   const Decl* CD, SymbolID sid, RefVal V,
-                                   bool& hasLeak);
+  std::pair<GRStateRef, bool>
+  HandleSymbolDeath(GRStateManager& VMgr, const GRState* St,
+                    const Decl* CD, SymbolID sid, RefVal V, bool& hasLeak);
   
 public:
   
@@ -1508,6 +1509,7 @@
   
   // Get the state.
   GRStateRef state(Builder.GetState(Pred), Eng.getStateManager());
+  ASTContext& Ctx = Eng.getStateManager().getContext();
 
   // Evaluate the effect of the arguments.
   RefVal::Kind hasErr = (RefVal::Kind) 0;
@@ -1560,7 +1562,7 @@
         if (R) {
           // Set the value of the variable to be a conjured symbol.
           unsigned Count = Builder.getCurrentBlockCount();
-          QualType T = R->getType();
+          QualType T = R->getType(Ctx);
           
           // FIXME: handle structs.
           if (T->isIntegerType() || Loc::IsLocType(T)) {
@@ -1743,7 +1745,7 @@
     }
     
     Summ = Summaries.getMethodSummary(ME, ID);
-#if 0    
+
     // Special-case: are we sending a mesage to "self"?
     //  This is a hack.  When we have full-IP this should be removed.
     if (!Summ) {
@@ -1754,17 +1756,15 @@
         if (Expr* Receiver = ME->getReceiver()) {
           SVal X = Eng.getStateManager().GetSVal(St, Receiver);
           if (loc::MemRegionVal* L = dyn_cast<loc::MemRegionVal>(&X))
-            if (const VarRegion* R = dyn_cast<VarRegion>(L->getRegion()))
-              if (R->getDecl() == MD->getSelfDecl()) {
-                // Create a summmary where all of the arguments "StopTracking".
-                Summ = Summaries.getPersistentSummary(RetEffect::MakeNoRet(),
-                                                      DoNothing,
-                                                      StopTracking);
-              }
+            if (L->getRegion() == Eng.getStateManager().getSelfRegion(St)) {
+              // Create a summmary where all of the arguments "StopTracking".
+              Summ = Summaries.getPersistentSummary(RetEffect::MakeNoRet(),
+                                                    DoNothing,
+                                                    StopTracking);
+            }
         }
       }
     }
-#endif
   }
   else
     Summ = Summaries.getClassMethodSummary(ME->getClassName(),
@@ -1846,32 +1846,30 @@
 //  or autorelease. Any other time you receive an object, you must
 //  not release it."
 //
-#if 0
 static bool followsFundamentalRule(const char* s) {
   return CStrInCStrNoCase(s, "create") || CStrInCStrNoCase(s, "copy")  || 
          CStrInCStrNoCase(s, "new");
 }  
-#endif
 
-const GRState* CFRefCount::HandleSymbolDeath(GRStateManager& VMgr,
-                                             const GRState* St, const Decl* CD,
-                                             SymbolID sid,
-                                             RefVal V, bool& hasLeak) {
+std::pair<GRStateRef,bool>
+CFRefCount::HandleSymbolDeath(GRStateManager& VMgr,
+                              const GRState* St, const Decl* CD,
+                              SymbolID sid,
+                              RefVal V, bool& hasLeak) {
 
   GRStateRef state(St, VMgr);
   assert (!V.isReturnedOwned() || CD &&
           "CodeDecl must be available for reporting ReturnOwned errors.");
 
-#if 0
   if (V.isReturnedOwned() && V.getCount() == 0)
     if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(CD)) {
       std::string s = MD->getSelector().getName();
       if (!followsFundamentalRule(s.c_str())) {
         hasLeak = true;
-        return state.set<RefBindings>(sid, V ^ RefVal::ErrorLeakReturned);
+        state = state.set<RefBindings>(sid, V ^ RefVal::ErrorLeakReturned);
+        return std::make_pair(state, true);
       }
     }
-#endif
   
   // All other cases.
   
@@ -1879,9 +1877,10 @@
             ((V.isNotOwned() || V.isReturnedOwned()) && V.getCount() > 0);
 
   if (!hasLeak)
-    return state.remove<RefBindings>(sid);
+    return std::make_pair(state.remove<RefBindings>(sid), false);
   
-  return state.set<RefBindings>(sid, V ^ RefVal::ErrorLeak);
+  return std::make_pair(state.set<RefBindings>(sid, V ^ RefVal::ErrorLeak),
+                        false);
 }
 
 void CFRefCount::EvalEndPath(GRExprEngine& Eng,
@@ -1890,16 +1889,18 @@
   const GRState* St = Builder.getState();
   RefBindings B = St->get<RefBindings>();
   
-  llvm::SmallVector<SymbolID, 10> Leaked;
+  llvm::SmallVector<std::pair<SymbolID, bool>, 10> Leaked;
   const Decl* CodeDecl = &Eng.getGraph().getCodeDecl();
   
   for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
     bool hasLeak = false;
     
-    St = HandleSymbolDeath(Eng.getStateManager(), St, CodeDecl,
-                           (*I).first, (*I).second, hasLeak);
+    std::pair<GRStateRef, bool> X =
+      HandleSymbolDeath(Eng.getStateManager(), St, CodeDecl,
+                        (*I).first, (*I).second, hasLeak);
     
-    if (hasLeak) Leaked.push_back((*I).first);
+    St = X.first;
+    if (hasLeak) Leaked.push_back(std::make_pair((*I).first, X.second));
   }
 
   if (Leaked.empty())
@@ -1910,12 +1911,12 @@
   if (!N)
     return;
     
-  std::vector<SymbolID>*& LeaksAtNode = Leaks[N];
+  std::vector<std::pair<SymbolID,bool> >*& LeaksAtNode = Leaks[N];
   assert (!LeaksAtNode);
-  LeaksAtNode = new std::vector<SymbolID>();
+  LeaksAtNode = new std::vector<std::pair<SymbolID,bool> >();
   
-  for (llvm::SmallVector<SymbolID, 10>::iterator I=Leaked.begin(),
-       E = Leaked.end(); I != E; ++I)
+  for (llvm::SmallVector<std::pair<SymbolID,bool>, 10>::iterator
+       I = Leaked.begin(), E = Leaked.end(); I != E; ++I)
     (*LeaksAtNode).push_back(*I);
 }
 
@@ -1932,7 +1933,7 @@
   // FIXME: a lot of copy-and-paste from EvalEndPath.  Refactor.
   
   RefBindings B = St->get<RefBindings>();
-  llvm::SmallVector<SymbolID, 10> Leaked;
+  llvm::SmallVector<std::pair<SymbolID,bool>, 10> Leaked;
   
   for (GRStateManager::DeadSymbolsTy::const_iterator
        I=Dead.begin(), E=Dead.end(); I!=E; ++I) {
@@ -1944,10 +1945,13 @@
     
     bool hasLeak = false;
     
-    St = HandleSymbolDeath(Eng.getStateManager(), St, 0, *I, *T, hasLeak);
+    std::pair<GRStateRef, bool> X
+      = HandleSymbolDeath(Eng.getStateManager(), St, 0, *I, *T, hasLeak);
+    
+    St = X.first;
     
     if (hasLeak)
-      Leaked.push_back(*I);    
+      Leaked.push_back(std::make_pair(*I,X.second));    
   }
   
   if (Leaked.empty())
@@ -1958,12 +1962,12 @@
   if (!N)
     return;
   
-  std::vector<SymbolID>*& LeaksAtNode = Leaks[N];
+  std::vector<std::pair<SymbolID,bool> >*& LeaksAtNode = Leaks[N];
   assert (!LeaksAtNode);
-  LeaksAtNode = new std::vector<SymbolID>();
+  LeaksAtNode = new std::vector<std::pair<SymbolID,bool> >();
   
-  for (llvm::SmallVector<SymbolID, 10>::iterator I=Leaked.begin(),
-       E = Leaked.end(); I != E; ++I)
+  for (llvm::SmallVector<std::pair<SymbolID,bool>, 10>::iterator
+       I = Leaked.begin(), E = Leaked.end(); I != E; ++I)
     (*LeaksAtNode).push_back(*I);    
 }
 
@@ -2196,19 +2200,34 @@
   };
   
   class VISIBILITY_HIDDEN Leak : public CFRefBug {
+    bool isReturn;
   public:
     Leak(CFRefCount& tf) : CFRefBug(tf) {}
     
+    void setIsReturn(bool x) { isReturn = x; }
+    
     virtual const char* getName() const {
       
-      if (getTF().isGCEnabled())
-        return "leak (GC)";
-      
-      if (getTF().getLangOptions().getGCMode() == LangOptions::HybridGC)
-        return "leak (hybrid MM, non-GC)";
-      
-      assert (getTF().getLangOptions().getGCMode() == LangOptions::NonGC);
-      return "leak";
+      if (!isReturn) {
+        if (getTF().isGCEnabled())
+          return "leak (GC)";
+        
+        if (getTF().getLangOptions().getGCMode() == LangOptions::HybridGC)
+          return "leak (hybrid MM, non-GC)";
+        
+        assert (getTF().getLangOptions().getGCMode() == LangOptions::NonGC);
+        return "leak";
+      }
+      else {
+        if (getTF().isGCEnabled())
+          return "leak of returned object (GC)";
+        
+        if (getTF().getLangOptions().getGCMode() == LangOptions::HybridGC)
+          return "leak of returned object (hybrid MM, non-GC)";
+        
+        assert (getTF().getLangOptions().getGCMode() == LangOptions::NonGC);
+        return "leak of returned object";        
+      }
     }
     
     virtual const char* getDescription() const {
@@ -2410,8 +2429,8 @@
       break;
       
     case RefVal::ReturnedOwned:
-      Msg = "Object returned to caller as owning reference (single retain count"
-            " transferred to caller).";
+      Msg = "Object returned to caller as an owning reference (single retain "
+            "count transferred to caller).";
       break;
       
     case RefVal::ReturnedNotOwned:
@@ -2630,11 +2649,12 @@
   for (CFRefCount::leaks_iterator I = TF.leaks_begin(),
        E = TF.leaks_end(); I != E; ++I) {
     
-    std::vector<SymbolID>& SymV = *(I->second);
+    std::vector<std::pair<SymbolID, bool> >& SymV = *(I->second);
     unsigned n = SymV.size();
     
     for (unsigned i = 0; i < n; ++i) {
-      CFRefReport report(*this, I->first, SymV[i]);
+      setIsReturn(SymV[i].second);
+      CFRefReport report(*this, I->first, SymV[i].first);
       BR.EmitWarning(report);
     }
   }  
@@ -2650,7 +2670,7 @@
   
   // Most bug reports are cached at the location where they occured.
   // With leaks, we want to unique them by the location where they were
-  // allocated, and only report only a single path.
+  // allocated, and only report a single path.
   
   SymbolID Sym = static_cast<CFRefReport&>(R).getSymbol();