diff --git a/clang/test/Analysis/retain-release-gc-only.m b/clang/test/Analysis/retain-release-gc-only.m index 0340a3c2a140..1a5ed34c9f39 100644 --- a/clang/test/Analysis/retain-release-gc-only.m +++ b/clang/test/Analysis/retain-release-gc-only.m @@ -107,9 +107,14 @@ NSFastEnumerationState; @end @interface NSNumber : NSValue - (char)charValue; - (id)initWithInt:(int)value; @end @class NSString; -@interface NSArray : NSObject - (NSUInteger)count; -@end @interface NSArray (NSArrayCreation) + (id)array; -@end @interface NSAutoreleasePool : NSObject { +@interface NSArray : NSObject +- (NSUInteger)count; +@end +@interface NSArray (NSArrayCreation) ++ (id)array; ++ (id)arrayWithObjects:(const id [])objects count:(NSUInteger)cnt; +@end + @interface NSAutoreleasePool : NSObject { } - (void)drain; - (id)init; @@ -385,3 +390,45 @@ CFDateRef returnsRetainedCFDate() { return (NSDate*) returnsRetainedCFDate(); // expected-warning{{leak}} } @end + + +#if __has_feature(attribute_ns_consumed) +#define NS_CONSUMED __attribute__((ns_consumed)) +#endif +#if __has_feature(attribute_cf_consumed) +#define CF_CONSUMED __attribute__((cf_consumed)) +#endif + +void consumeAndStopTracking(id NS_CONSUMED obj, void (^callback)(void)); +void CFConsumeAndStopTracking(CFTypeRef CF_CONSUMED obj, void (^callback)(void)); + +void testConsumeAndStopTracking() { + id retained = [@[] retain]; // +0, GC + consumeAndStopTracking(retained, ^{}); // no-warning + + id doubleRetained = [[@[] retain] retain]; // +0, GC + consumeAndStopTracking(doubleRetained, ^{ + [doubleRetained release]; + }); // no-warning + + id unretained = @[]; // +0 + consumeAndStopTracking(unretained, ^{}); // no-warning, GC +} + +void testCFConsumeAndStopTrackingMsg() { + id retained = [@[] retain]; // +0, GC + CFConsumeAndStopTracking((CFTypeRef)retained, ^{}); // expected-warning {{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}} +} + +void testCFConsumeAndStopTracking() { + CFTypeRef retained = returnsRetainedCFDate(); // +1 + CFConsumeAndStopTracking(retained, ^{}); // no-warning + + CFTypeRef doubleRetained = CFRetain(returnsRetainedCFDate()); // +2 + CFConsumeAndStopTracking(doubleRetained, ^{ + CFRelease(doubleRetained); + }); // no-warning + + id unretained = @[]; // +0 + CFConsumeAndStopTracking((CFTypeRef)unretained, ^{}); // expected-warning {{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}} +} diff --git a/clang/test/Analysis/retain-release.m b/clang/test/Analysis/retain-release.m index efd053294554..da1477bb5888 100644 --- a/clang/test/Analysis/retain-release.m +++ b/clang/test/Analysis/retain-release.m @@ -1748,7 +1748,7 @@ extern id NSApp; @end //===----------------------------------------------------------------------===// // Test returning allocated memory in a struct. -// +// // We currently don't have a general way to track pointers that "escape". // Here we test that RetainCountChecker doesn't get excited about returning // allocated CF objects in struct fields. @@ -1856,7 +1856,10 @@ id makeCollectableNonLeak() { return [objCObject autorelease]; // +0 } + void consumeAndStopTracking(id NS_CONSUMED obj, void (^callback)(void)); +void CFConsumeAndStopTracking(CFTypeRef CF_CONSUMED obj, void (^callback)(void)); + void testConsumeAndStopTracking() { id retained = [@[] retain]; // +1 consumeAndStopTracking(retained, ^{}); // no-warning @@ -1869,3 +1872,16 @@ void testConsumeAndStopTracking() { id unretained = @[]; // +0 consumeAndStopTracking(unretained, ^{}); // expected-warning {{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}} } + +void testCFConsumeAndStopTracking() { + id retained = [@[] retain]; // +1 + CFConsumeAndStopTracking((CFTypeRef)retained, ^{}); // no-warning + + id doubleRetained = [[@[] retain] retain]; // +2 + CFConsumeAndStopTracking((CFTypeRef)doubleRetained, ^{ + [doubleRetained release]; + }); // no-warning + + id unretained = @[]; // +0 + CFConsumeAndStopTracking((CFTypeRef)unretained, ^{}); // expected-warning {{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}} +}