retain-release-path-notes.m revision 8919e688dc610d1f632a4d43f7f1489f67255476
1// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -analyzer-output=text -verify %s
2
3/***
4This file is for testing the path-sensitive notes for retain/release errors.
5Its goal is to have simple branch coverage of any path-based diagnostics,
6not to actually check all possible retain/release errors.
7
8This file includes notes that only appear in a ref-counted analysis. 
9GC-specific notes should go in retain-release-path-notes-gc.m.
10***/
11
12@interface NSObject
13+ (id)alloc;
14- (id)init;
15- (void)dealloc;
16
17- (Class)class;
18
19- (id)retain;
20- (void)release;
21- (void)autorelease;
22@end
23
24@interface Foo : NSObject
25- (id)methodWithValue;
26@property(retain) id propertyValue;
27
28- (id)objectAtIndexedSubscript:(unsigned)index;
29- (id)objectForKeyedSubscript:(id)key;
30@end
31
32typedef struct CFType *CFTypeRef;
33CFTypeRef CFRetain(CFTypeRef);
34void CFRelease(CFTypeRef);
35
36id NSMakeCollectable(CFTypeRef);
37CFTypeRef CFMakeCollectable(CFTypeRef);
38
39CFTypeRef CFCreateSomething();
40CFTypeRef CFGetSomething();
41
42
43void creationViaAlloc () {
44  id leaked = [[NSObject alloc] init]; // expected-warning{{leak}} expected-note{{Method returns an Objective-C object with a +1 retain count}}
45  return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}}
46}
47
48void creationViaCFCreate () {
49  CFTypeRef leaked = CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count}}
50  return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}}
51}
52
53void acquisitionViaMethod (Foo *foo) {
54  id leaked = [foo methodWithValue]; // expected-warning{{leak}} expected-note{{Method returns an Objective-C object with a +0 retain count}}
55  [leaked retain]; // expected-note{{Reference count incremented. The object now has a +1 retain count}}
56  [leaked retain]; // expected-note{{Reference count incremented. The object now has a +2 retain count}}
57  [leaked release]; // expected-note{{Reference count decremented. The object now has a +1 retain count}}
58  return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}}
59}
60
61void acquisitionViaProperty (Foo *foo) {
62  id leaked = foo.propertyValue; // expected-warning{{leak}} expected-note{{Property returns an Objective-C object with a +0 retain count}}
63  [leaked retain]; // expected-note{{Reference count incremented. The object now has a +1 retain count}}
64  return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}}
65}
66
67void acquisitionViaCFFunction () {
68  CFTypeRef leaked = CFGetSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFGetSomething' returns a Core Foundation object with a +0 retain count}}
69  CFRetain(leaked); // expected-note{{Reference count incremented. The object now has a +1 retain count}}
70  return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}}
71}
72
73void explicitDealloc () {
74  id object = [[NSObject alloc] init]; // expected-note{{Method returns an Objective-C object with a +1 retain count}}
75  [object dealloc]; // expected-note{{Object released by directly sending the '-dealloc' message}}
76  [object class]; // expected-warning{{Reference-counted object is used after it is released}} // expected-note{{Reference-counted object is used after it is released}}
77}
78
79void implicitDealloc () {
80  id object = [[NSObject alloc] init]; // expected-note{{Method returns an Objective-C object with a +1 retain count}}
81  [object release]; // expected-note{{Object released}}
82  [object class]; // expected-warning{{Reference-counted object is used after it is released}} // expected-note{{Reference-counted object is used after it is released}}
83}
84
85void overAutorelease () {
86  id object = [[NSObject alloc] init]; // expected-note{{Method returns an Objective-C object with a +1 retain count}}
87  [object autorelease]; // expected-note{{Object sent -autorelease message}}
88  [object autorelease]; // expected-note{{Object sent -autorelease message}} 
89  return; // expected-warning{{Object sent -autorelease too many times}} expected-note{{Object over-autoreleased: object was sent -autorelease 2 times but the object has a +1 retain count}} 
90}
91
92void autoreleaseUnowned (Foo *foo) {
93  id object = foo.propertyValue; // expected-note{{Property returns an Objective-C object with a +0 retain count}}
94  [object autorelease]; // expected-note{{Object sent -autorelease message}} 
95  return; // expected-warning{{Object sent -autorelease too many times}} expected-note{{Object over-autoreleased: object was sent -autorelease but the object has a +0 retain count}}
96}
97
98void makeCollectableIgnored () {
99  CFTypeRef leaked = CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count}}
100  CFMakeCollectable(leaked); // expected-note{{When GC is not enabled a call to 'CFMakeCollectable' has no effect on its argument}}
101  NSMakeCollectable(leaked); // expected-note{{When GC is not enabled a call to 'NSMakeCollectable' has no effect on its argument}}
102  return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}}
103}
104
105CFTypeRef CFCopyRuleViolation () {
106  CFTypeRef object = CFGetSomething(); // expected-note{{Call to function 'CFGetSomething' returns a Core Foundation object with a +0 retain count}}
107  return object; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} expected-note{{Object returned to caller with a +0 retain count}} expected-note{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}
108}
109
110CFTypeRef CFGetRuleViolation () {
111  CFTypeRef object = CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count}}
112  return object; // expected-note{{Object returned to caller as an owning reference (single retain count transferred to caller)}} expected-note{{Object leaked: object allocated and stored into 'object' is returned from a function whose name ('CFGetRuleViolation') does not contain 'Copy' or 'Create'.  This violates the naming convention rules given in the Memory Management Guide for Core Foundation}}
113}
114
115@implementation Foo (FundamentalMemoryManagementRules)
116- (id)copyViolation {
117  id result = self.propertyValue; // expected-note{{Property returns an Objective-C object with a +0 retain count}}
118  return result; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} expected-note{{Object returned to caller with a +0 retain count}} expected-note{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}
119}
120
121- (id)copyViolationIndexedSubscript {
122  id result = self[0]; // expected-note{{Subscript returns an Objective-C object with a +0 retain count}}
123  return result; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} expected-note{{Object returned to caller with a +0 retain count}} expected-note{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}
124}
125
126- (id)copyViolationKeyedSubscript {
127  id result = self[self]; // expected-note{{Subscript returns an Objective-C object with a +0 retain count}}
128  return result; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} expected-note{{Object returned to caller with a +0 retain count}} expected-note{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}
129}
130
131- (id)getViolation {
132  id result = [[Foo alloc] init]; // expected-warning{{leak}} expected-note{{Method returns an Objective-C object with a +1 retain count}}
133  return result; // expected-note{{Object returned to caller as an owning reference (single retain count transferred to caller)}} expected-note{{Object leaked: object allocated and stored into 'result' is returned from a method whose name ('getViolation') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'.  This violates the naming convention rules given in the Memory Management Guide for Cocoa}}
134}
135
136- (id)copyAutorelease {
137  id result = [[Foo alloc] init]; // expected-note{{Method returns an Objective-C object with a +1 retain count}}
138  [result autorelease]; // expected-note{{Object sent -autorelease message}}
139  return result; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} expected-note{{Object returned to caller with a +0 retain count}} expected-note{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}
140}
141@end
142
143
144typedef unsigned long NSUInteger;
145
146@interface NSValue : NSObject
147@end
148
149@interface NSNumber : NSValue
150+ (NSNumber *)numberWithInt:(int)i;
151@end
152
153@interface NSString : NSObject
154+ (NSString *)stringWithUTF8String:(const char *)str;
155@end
156
157@interface NSArray : NSObject
158+ (NSArray *)arrayWithObjects:(const id [])objects count:(NSUInteger)count;
159@end
160
161@interface NSDictionary : NSObject
162+ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id /* <NSCopying> */ [])keys count:(NSUInteger)count;
163@end
164
165
166void testNumericLiteral() {
167  id result = @1; // expected-note{{NSNumber literal is an object with a +0 retain count}}
168  [result release]; // expected-warning{{decrement}} expected-note{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
169}
170
171void testBoxedInt(int x) {
172  id result = @(x); // expected-note{{NSNumber boxed expression produces an object with a +0 retain count}}
173  [result release]; // expected-warning{{decrement}} expected-note{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
174}
175
176void testBoxedString(const char *str) {
177  id result = @(str); // expected-note{{NSString boxed expression produces an object with a +0 retain count}}
178  [result release]; // expected-warning{{decrement}} expected-note{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
179}
180
181void testArray(id obj) {
182  id result = @[obj]; // expected-note{{NSArray literal is an object with a +0 retain count}}
183  [result release]; // expected-warning{{decrement}} expected-note{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
184}
185
186void testDictionary(id key, id value) {
187  id result = @{key: value}; // expected-note{{NSDictionary literal is an object with a +0 retain count}}
188  [result release]; // expected-warning{{decrement}} expected-note{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
189}
190