diff options
-rw-r--r-- | lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp | 36 | ||||
-rw-r--r-- | test/Analysis/retain-release.m | 9 |
2 files changed, 31 insertions, 14 deletions
diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp index 176f618a2b..e95ba52f69 100644 --- a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp @@ -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()); diff --git a/test/Analysis/retain-release.m b/test/Analysis/retain-release.m index 49a6bce4f3..9d2aa756b2 100644 --- a/test/Analysis/retain-release.m +++ b/test/Analysis/retain-release.m @@ -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; |