]> granicus.if.org Git - clang/commitdiff
Refine diagnostics for leaks reported when returning an object
authorTed Kremenek <kremenek@apple.com>
Thu, 6 Sep 2012 23:03:07 +0000 (23:03 +0000)
committerTed Kremenek <kremenek@apple.com>
Thu, 6 Sep 2012 23:03:07 +0000 (23:03 +0000)
via function/method with [CF,NS]_RETURNS_NOT_RETAINED.

Fixes <rdar://problem/11379000>.

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

lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
test/Analysis/retain-release.m

index 176f618a2bda02a979219aac3c422bcf94e8671a..e95ba52f6970b4adef5cf02da60b6852754dd4dd 100644 (file)
@@ -2262,21 +2262,29 @@ CFRefLeakReportVisitor::getEndPath(BugReporterContext &BRC,
     // objects.  Only "copy", "alloc", "retain" and "new" transfer ownership
     // to the caller for NS objects.
     const Decl *D = &EndN->getCodeDecl();
-    if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
-      os << " is returned from a method whose name ('"
-         << MD->getSelector().getAsString()
-         << "') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'."
-            "  This violates the naming convention rules"
-            " given in the Memory Management Guide for Cocoa";
-    }
+    
+    os << (isa<ObjCMethodDecl>(D) ? " is returned from a method "
+                                  : " is returned from a function ");
+    
+    if (D->getAttr<CFReturnsNotRetainedAttr>())
+      os << "that is annotated as CF_RETURNS_NOT_RETAINED";
+    else if (D->getAttr<NSReturnsNotRetainedAttr>())
+      os << "that is annotated as NS_RETURNS_NOT_RETAINED";
     else {
-      const FunctionDecl *FD = cast<FunctionDecl>(D);
-      os << " is returned from a function whose name ('"
-         << *FD
-         << "') does not contain 'Copy' or 'Create'.  This violates the naming"
-            " convention rules given in the Memory Management Guide for Core"
-            " Foundation";
-    }    
+      if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+        os << "whose name ('" << MD->getSelector().getAsString()
+           << "') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'."
+              "  This violates the naming convention rules"
+              " given in the Memory Management Guide for Cocoa";
+      }
+      else {
+        const FunctionDecl *FD = cast<FunctionDecl>(D);
+        os << "whose name ('" << *FD
+           << "') does not contain 'Copy' or 'Create'.  This violates the naming"
+              " convention rules given in the Memory Management Guide for Core"
+              " Foundation";
+      }
+    }
   }
   else if (RV->getKind() == RefVal::ErrorGCLeakReturned) {
     ObjCMethodDecl &MD = cast<ObjCMethodDecl>(EndN->getCodeDecl());
index 49a6bce4f3ef9d0387d9e54a9d218c583a053e60..9d2aa756b2823a7703314368fc94b9f4fee1b5ba 100644 (file)
@@ -1341,6 +1341,15 @@ void testattr4() {
   consume_cf(y);
 }
 
+@interface TestOwnershipAttr2 : NSObject
+- (NSString*) newString NS_RETURNS_NOT_RETAINED; // no-warning
+@end
+
+@implementation TestOwnershipAttr2
+- (NSString*) newString {
+  return [NSString alloc]; // expected-warning {{Potential leak of an object}}
+}
+@end
 
 @interface MyClassTestCFAttr : NSObject {}
 - (NSDate*) returnsCFRetained CF_RETURNS_RETAINED;