Recognize attributes ns_returns_not_retained and cf_returns_not_retained
in the static analyzer.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@96539 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Checker/CFRefCount.cpp b/lib/Checker/CFRefCount.cpp
index 2eb9607..ecb98a0 100644
--- a/lib/Checker/CFRefCount.cpp
+++ b/lib/Checker/CFRefCount.cpp
@@ -1222,6 +1222,12 @@
     else if (FD->getAttr<CFReturnsRetainedAttr>()) {
       Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true));
     }
+    else if (FD->getAttr<NSReturnsNotRetainedAttr>()) {
+      Summ.setRetEffect(RetEffect::MakeNotOwned(RetEffect::ObjC));
+    }
+    else if (FD->getAttr<CFReturnsNotRetainedAttr>()) {
+      Summ.setRetEffect(RetEffect::MakeNotOwned(RetEffect::CF));
+    }
   }
   else if (RetTy->getAs<PointerType>()) {
     if (FD->getAttr<CFReturnsRetainedAttr>()) {
@@ -1244,6 +1250,10 @@
       Summ.setRetEffect(ObjCAllocRetE);
       return;
     }
+    if (MD->getAttr<NSReturnsNotRetainedAttr>()) {
+      Summ.setRetEffect(RetEffect::MakeNotOwned(RetEffect::ObjC));
+      return;
+    }
 
     isTrackedLoc = true;
   }
@@ -1251,8 +1261,12 @@
   if (!isTrackedLoc)
     isTrackedLoc = MD->getResultType()->getAs<PointerType>() != NULL;
 
-  if (isTrackedLoc && MD->getAttr<CFReturnsRetainedAttr>())
-    Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true));
+  if (isTrackedLoc) {
+    if (MD->getAttr<CFReturnsRetainedAttr>())
+      Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true));
+    else if (MD->getAttr<CFReturnsNotRetainedAttr>())
+      Summ.setRetEffect(RetEffect::MakeNotOwned(RetEffect::CF));
+  }
 }
 
 RetainSummary*
diff --git a/test/Analysis/retain-release.m b/test/Analysis/retain-release.m
index 1c41d85..675e9a6 100644
--- a/test/Analysis/retain-release.m
+++ b/test/Analysis/retain-release.m
@@ -7,6 +7,12 @@
 #if __has_feature(attribute_cf_returns_retained)
 #define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))
 #endif
+#if __has_feature(attribute_ns_returns_not_retained)
+#define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained))
+#endif
+#if __has_feature(attribute_cf_returns_not_retained)
+#define CF_RETURNS_NOT_RETAINED __attribute__((cf_returns_not_retained))
+#endif
 
 //===----------------------------------------------------------------------===//
 // The following code is reduced using delta-debugging from Mac OS X headers:
@@ -1188,6 +1194,8 @@
 - (NSString*) returnsAnOwnedString  NS_RETURNS_RETAINED; // no-warning
 - (NSString*) returnsAnOwnedCFString  CF_RETURNS_RETAINED; // no-warning
 - (MyStringTy) returnsAnOwnedTypedString NS_RETURNS_RETAINED; // no-warning
+- (NSString*) newString NS_RETURNS_NOT_RETAINED; // no-warning
+- (NSString*) newStringNoAttr;
 - (int) returnsAnOwnedInt NS_RETURNS_RETAINED; // expected-warning{{'ns_returns_retained' attribute only applies to functions or methods that return a pointer or Objective-C object}}
 @end
 
@@ -1201,9 +1209,16 @@
   NSString *str = [X returnsAnOwnedCFString]; // expected-warning{{leak}}
 }
 
+void test_attr1c(TestOwnershipAttr *X) {
+  NSString *str = [X newString]; // no-warning
+  NSString *str2 = [X newStringNoAttr]; // expected-warning{{leak}}
+}
+
 @interface MyClassTestCFAttr : NSObject {}
 - (NSDate*) returnsCFRetained CF_RETURNS_RETAINED;
 - (CFDateRef) returnsCFRetainedAsCF CF_RETURNS_RETAINED;
+- (CFDateRef) newCFRetainedAsCF CF_RETURNS_NOT_RETAINED;
+- (CFDateRef) newCFRetainedAsCFNoAttr;
 - (NSDate*) alsoReturnsRetained;
 - (CFDateRef) alsoReturnsRetainedAsCF;
 - (NSDate*) returnsNSRetained NS_RETURNS_RETAINED;
@@ -1223,6 +1238,13 @@
   return returnsRetainedCFDate(); // No leak.
 }
 
+- (CFDateRef) newCFRetainedAsCF {
+  return (CFDateRef)[(id)[self returnsCFRetainedAsCF] autorelease];
+}
+
+- (CFDateRef) newCFRetainedAsCFNoAttr {
+  return (CFDateRef)[(id)[self returnsCFRetainedAsCF] autorelease]; // expected-warning{{Object with +0 retain counts returned to caller where a +1 (owning) retain count is expected}}
+}
 
 - (NSDate*) alsoReturnsRetained {
   return (NSDate*) returnsRetainedCFDate(); // expected-warning{{leak}}