xref: /minix3/external/bsd/llvm/dist/clang/test/Analysis/properties.m (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,debug.ExprInspection -analyzer-store=region -verify -Wno-objc-root-class %s
2*0a6a1f1dSLionel Sambuc// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,debug.ExprInspection -analyzer-store=region -verify -Wno-objc-root-class -fobjc-arc %s
3*0a6a1f1dSLionel Sambuc
4*0a6a1f1dSLionel Sambucvoid clang_analyzer_eval(int);
5f4a2713aSLionel Sambuc
6f4a2713aSLionel Sambuctypedef signed char BOOL;
7f4a2713aSLionel Sambuctypedef unsigned int NSUInteger;
8f4a2713aSLionel Sambuctypedef struct _NSZone NSZone;
9f4a2713aSLionel Sambuc@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
10f4a2713aSLionel Sambuc@protocol NSObject  - (BOOL)isEqual:(id)object; @end
11f4a2713aSLionel Sambuc@protocol NSCopying  - (id)copyWithZone:(NSZone *)zone; @end
12f4a2713aSLionel Sambuc@protocol NSCoding  - (void)encodeWithCoder:(NSCoder *)aCoder; @end
13f4a2713aSLionel Sambuc@protocol NSMutableCopying  - (id)mutableCopyWithZone:(NSZone *)zone; @end
14f4a2713aSLionel Sambuc@interface NSObject <NSObject> {}
15f4a2713aSLionel Sambuc+(id)alloc;
16f4a2713aSLionel Sambuc-(id)init;
17f4a2713aSLionel Sambuc-(id)autorelease;
18f4a2713aSLionel Sambuc-(id)copy;
19f4a2713aSLionel Sambuc-(id)retain;
20*0a6a1f1dSLionel Sambuc-(oneway void)release;
21f4a2713aSLionel Sambuc@end
22f4a2713aSLionel Sambuc@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding>
23f4a2713aSLionel Sambuc- (NSUInteger)length;
24f4a2713aSLionel Sambuc-(id)initWithFormat:(NSString *)f,...;
25f4a2713aSLionel Sambuc-(BOOL)isEqualToString:(NSString *)s;
26f4a2713aSLionel Sambuc+ (id)string;
27f4a2713aSLionel Sambuc@end
28f4a2713aSLionel Sambuc@interface NSNumber : NSObject {}
29f4a2713aSLionel Sambuc+(id)alloc;
30f4a2713aSLionel Sambuc-(id)initWithInteger:(int)i;
31f4a2713aSLionel Sambuc@end
32f4a2713aSLionel Sambuc
33f4a2713aSLionel Sambuc// rdar://6946338
34f4a2713aSLionel Sambuc
35f4a2713aSLionel Sambuc@interface Test1 : NSObject {
36f4a2713aSLionel Sambuc  NSString *text;
37f4a2713aSLionel Sambuc}
38f4a2713aSLionel Sambuc-(id)myMethod;
39f4a2713aSLionel Sambuc@property (nonatomic, assign) NSString *text;
40f4a2713aSLionel Sambuc@end
41f4a2713aSLionel Sambuc
42f4a2713aSLionel Sambuc
43*0a6a1f1dSLionel Sambuc#if !__has_feature(objc_arc)
44*0a6a1f1dSLionel Sambuc
45f4a2713aSLionel Sambuc@implementation Test1
46f4a2713aSLionel Sambuc
47f4a2713aSLionel Sambuc@synthesize text;
48f4a2713aSLionel Sambuc
49f4a2713aSLionel Sambuc-(id)myMethod {
50f4a2713aSLionel Sambuc  Test1 *cell = [[[Test1 alloc] init] autorelease];
51f4a2713aSLionel Sambuc
52f4a2713aSLionel Sambuc  NSString *string1 = [[NSString alloc] initWithFormat:@"test %f", 0.0]; // expected-warning {{Potential leak}}
53f4a2713aSLionel Sambuc  cell.text = string1;
54f4a2713aSLionel Sambuc
55f4a2713aSLionel Sambuc  return cell;
56f4a2713aSLionel Sambuc}
57f4a2713aSLionel Sambuc
58f4a2713aSLionel Sambuc@end
59f4a2713aSLionel Sambuc
60f4a2713aSLionel Sambuc
61f4a2713aSLionel Sambuc// rdar://8824416
62f4a2713aSLionel Sambuc
63f4a2713aSLionel Sambuc@interface MyNumber : NSObject
64f4a2713aSLionel Sambuc{
65f4a2713aSLionel Sambuc  NSNumber* _myNumber;
66f4a2713aSLionel Sambuc}
67f4a2713aSLionel Sambuc
68f4a2713aSLionel Sambuc- (id)initWithNumber:(NSNumber *)number;
69f4a2713aSLionel Sambuc
70f4a2713aSLionel Sambuc@property (nonatomic, readonly) NSNumber* myNumber;
71f4a2713aSLionel Sambuc@property (nonatomic, readonly) NSNumber* newMyNumber;
72f4a2713aSLionel Sambuc
73f4a2713aSLionel Sambuc@end
74f4a2713aSLionel Sambuc
75f4a2713aSLionel Sambuc@implementation MyNumber
76f4a2713aSLionel Sambuc@synthesize myNumber=_myNumber;
77f4a2713aSLionel Sambuc
78f4a2713aSLionel Sambuc- (id)initWithNumber:(NSNumber *)number
79f4a2713aSLionel Sambuc{
80f4a2713aSLionel Sambuc  self = [super init];
81f4a2713aSLionel Sambuc
82f4a2713aSLionel Sambuc  if ( self )
83f4a2713aSLionel Sambuc  {
84f4a2713aSLionel Sambuc    _myNumber = [number copy];
85f4a2713aSLionel Sambuc  }
86f4a2713aSLionel Sambuc
87f4a2713aSLionel Sambuc  return self;
88f4a2713aSLionel Sambuc}
89f4a2713aSLionel Sambuc
90f4a2713aSLionel Sambuc- (NSNumber*)newMyNumber
91f4a2713aSLionel Sambuc{
92f4a2713aSLionel Sambuc  if ( _myNumber )
93f4a2713aSLionel Sambuc    return [_myNumber retain];
94f4a2713aSLionel Sambuc
95f4a2713aSLionel Sambuc  return [[NSNumber alloc] initWithInteger:1];
96f4a2713aSLionel Sambuc}
97f4a2713aSLionel Sambuc
98f4a2713aSLionel Sambuc- (id)valueForUndefinedKey:(NSString*)key
99f4a2713aSLionel Sambuc{
100f4a2713aSLionel Sambuc  id value = 0;
101f4a2713aSLionel Sambuc
102f4a2713aSLionel Sambuc  if ([key isEqualToString:@"MyIvarNumberAsPropertyOverReleased"])
103f4a2713aSLionel Sambuc    value = self.myNumber; // _myNumber will be over released, since the value returned from self.myNumber is not retained.
104f4a2713aSLionel Sambuc  else if ([key isEqualToString:@"MyIvarNumberAsPropertyOk"])
105f4a2713aSLionel Sambuc    value = [self.myNumber retain]; // this line fixes the over release
106f4a2713aSLionel Sambuc  else if ([key isEqualToString:@"MyIvarNumberAsNewMyNumber"])
107f4a2713aSLionel Sambuc    value = self.newMyNumber; // this one is ok, since value is returned retained
108f4a2713aSLionel Sambuc  else
109f4a2713aSLionel Sambuc    value = [[NSNumber alloc] initWithInteger:0];
110f4a2713aSLionel Sambuc
111f4a2713aSLionel Sambuc  return [value autorelease]; // expected-warning {{Object autoreleased too many times}}
112f4a2713aSLionel Sambuc}
113f4a2713aSLionel Sambuc
114f4a2713aSLionel Sambuc@end
115f4a2713aSLionel Sambuc
116f4a2713aSLionel SambucNSNumber* numberFromMyNumberProperty(MyNumber* aMyNumber)
117f4a2713aSLionel Sambuc{
118f4a2713aSLionel Sambuc  NSNumber* result = aMyNumber.myNumber;
119f4a2713aSLionel Sambuc
120f4a2713aSLionel Sambuc  return [result autorelease]; // expected-warning {{Object autoreleased too many times}}
121f4a2713aSLionel Sambuc}
122f4a2713aSLionel Sambuc
123*0a6a1f1dSLionel Sambuc#endif
124*0a6a1f1dSLionel Sambuc
125f4a2713aSLionel Sambuc
126f4a2713aSLionel Sambuc// rdar://6611873
127f4a2713aSLionel Sambuc
128f4a2713aSLionel Sambuc@interface Person : NSObject {
129f4a2713aSLionel Sambuc  NSString *_name;
130f4a2713aSLionel Sambuc}
131f4a2713aSLionel Sambuc@property (retain) NSString * name;
132*0a6a1f1dSLionel Sambuc@property (assign) id friend;
133f4a2713aSLionel Sambuc@end
134f4a2713aSLionel Sambuc
135f4a2713aSLionel Sambuc@implementation Person
136f4a2713aSLionel Sambuc@synthesize name = _name;
137f4a2713aSLionel Sambuc@end
138f4a2713aSLionel Sambuc
139*0a6a1f1dSLionel Sambuc#if !__has_feature(objc_arc)
140f4a2713aSLionel Sambucvoid rdar6611873() {
141f4a2713aSLionel Sambuc  Person *p = [[[Person alloc] init] autorelease];
142f4a2713aSLionel Sambuc
143f4a2713aSLionel Sambuc  p.name = [[NSString string] retain]; // expected-warning {{leak}}
144f4a2713aSLionel Sambuc  p.name = [[NSString alloc] init]; // expected-warning {{leak}}
145*0a6a1f1dSLionel Sambuc
146*0a6a1f1dSLionel Sambuc  p.friend = [[Person alloc] init]; // expected-warning {{leak}}
147f4a2713aSLionel Sambuc}
148*0a6a1f1dSLionel Sambuc#endif
149f4a2713aSLionel Sambuc
150f4a2713aSLionel Sambuc@interface SubPerson : Person
151f4a2713aSLionel Sambuc-(NSString *)foo;
152f4a2713aSLionel Sambuc@end
153f4a2713aSLionel Sambuc
154f4a2713aSLionel Sambuc@implementation SubPerson
155f4a2713aSLionel Sambuc-(NSString *)foo {
156f4a2713aSLionel Sambuc  return super.name;
157f4a2713aSLionel Sambuc}
158f4a2713aSLionel Sambuc@end
159f4a2713aSLionel Sambuc
160*0a6a1f1dSLionel Sambuc
161*0a6a1f1dSLionel Sambuc#if !__has_feature(objc_arc)
162f4a2713aSLionel Sambuc// <rdar://problem/9241180> Static analyzer doesn't detect uninitialized variable issues for property accesses
163f4a2713aSLionel Sambuc@interface RDar9241180
164f4a2713aSLionel Sambuc@property (readwrite,assign) id x;
165f4a2713aSLionel Sambuc-(id)testAnalyzer1:(int) y;
166f4a2713aSLionel Sambuc-(void)testAnalyzer2;
167f4a2713aSLionel Sambuc@end
168f4a2713aSLionel Sambuc
169f4a2713aSLionel Sambuc@implementation RDar9241180
170f4a2713aSLionel Sambuc@synthesize x;
171f4a2713aSLionel Sambuc-(id)testAnalyzer1:(int)y {
172f4a2713aSLionel Sambuc    RDar9241180 *o;
173f4a2713aSLionel Sambuc    if (y && o.x) // expected-warning {{Property access on an uninitialized object pointer}}
174f4a2713aSLionel Sambuc      return o;
175f4a2713aSLionel Sambuc    return o; // expected-warning {{Undefined or garbage value returned to caller}}
176f4a2713aSLionel Sambuc}
177f4a2713aSLionel Sambuc-(void)testAnalyzer2 {
178f4a2713aSLionel Sambuc  id y;
179f4a2713aSLionel Sambuc  self.x = y;  // expected-warning {{Argument for property setter is an uninitialized value}}
180f4a2713aSLionel Sambuc}
181f4a2713aSLionel Sambuc@end
182*0a6a1f1dSLionel Sambuc#endif
183f4a2713aSLionel Sambuc
184f4a2713aSLionel Sambuc
185*0a6a1f1dSLionel Sambuc//------
186*0a6a1f1dSLionel Sambuc// Property accessor synthesis
187*0a6a1f1dSLionel Sambuc//------
188*0a6a1f1dSLionel Sambuc
189*0a6a1f1dSLionel Sambucextern void doSomethingWithPerson(Person *p);
190*0a6a1f1dSLionel Sambucextern void doSomethingWithName(NSString *name);
191*0a6a1f1dSLionel Sambuc
192*0a6a1f1dSLionel Sambucvoid testConsistencyRetain(Person *p) {
193*0a6a1f1dSLionel Sambuc  clang_analyzer_eval(p.name == p.name); // expected-warning{{TRUE}}
194*0a6a1f1dSLionel Sambuc
195*0a6a1f1dSLionel Sambuc  id origName = p.name;
196*0a6a1f1dSLionel Sambuc  clang_analyzer_eval(p.name == origName); // expected-warning{{TRUE}}
197*0a6a1f1dSLionel Sambuc  doSomethingWithPerson(p);
198*0a6a1f1dSLionel Sambuc  clang_analyzer_eval(p.name == origName); // expected-warning{{UNKNOWN}}
199*0a6a1f1dSLionel Sambuc}
200*0a6a1f1dSLionel Sambuc
201*0a6a1f1dSLionel Sambucvoid testConsistencyAssign(Person *p) {
202*0a6a1f1dSLionel Sambuc  clang_analyzer_eval(p.friend == p.friend); // expected-warning{{TRUE}}
203*0a6a1f1dSLionel Sambuc
204*0a6a1f1dSLionel Sambuc  id origFriend = p.friend;
205*0a6a1f1dSLionel Sambuc  clang_analyzer_eval(p.friend == origFriend); // expected-warning{{TRUE}}
206*0a6a1f1dSLionel Sambuc  doSomethingWithPerson(p);
207*0a6a1f1dSLionel Sambuc  clang_analyzer_eval(p.friend == origFriend); // expected-warning{{UNKNOWN}}
208*0a6a1f1dSLionel Sambuc}
209*0a6a1f1dSLionel Sambuc
210*0a6a1f1dSLionel Sambuc#if !__has_feature(objc_arc)
211*0a6a1f1dSLionel Sambucvoid testOverrelease(Person *p, int coin) {
212*0a6a1f1dSLionel Sambuc  switch (coin) {
213*0a6a1f1dSLionel Sambuc  case 0:
214*0a6a1f1dSLionel Sambuc    [p.name release]; // expected-warning{{not owned}}
215*0a6a1f1dSLionel Sambuc    break;
216*0a6a1f1dSLionel Sambuc  case 1:
217*0a6a1f1dSLionel Sambuc    [p.friend release]; // expected-warning{{not owned}}
218*0a6a1f1dSLionel Sambuc    break;
219*0a6a1f1dSLionel Sambuc  case 2: {
220*0a6a1f1dSLionel Sambuc    id friend = p.friend;
221*0a6a1f1dSLionel Sambuc    doSomethingWithPerson(p);
222*0a6a1f1dSLionel Sambuc    [friend release]; // expected-warning{{not owned}}
223*0a6a1f1dSLionel Sambuc  }
224*0a6a1f1dSLionel Sambuc  }
225*0a6a1f1dSLionel Sambuc}
226*0a6a1f1dSLionel Sambuc
227*0a6a1f1dSLionel Sambuc// <rdar://problem/16333368>
228*0a6a1f1dSLionel Sambuc@implementation Person (Rdar16333368)
229*0a6a1f1dSLionel Sambuc
230*0a6a1f1dSLionel Sambuc- (void)testDeliberateRelease:(Person *)other {
231*0a6a1f1dSLionel Sambuc  doSomethingWithName(self.name);
232*0a6a1f1dSLionel Sambuc  [_name release]; // no-warning
233*0a6a1f1dSLionel Sambuc  self->_name = 0;
234*0a6a1f1dSLionel Sambuc
235*0a6a1f1dSLionel Sambuc  doSomethingWithName(other->_name);
236*0a6a1f1dSLionel Sambuc  [other.name release]; // expected-warning{{not owned}}
237*0a6a1f1dSLionel Sambuc}
238*0a6a1f1dSLionel Sambuc
239*0a6a1f1dSLionel Sambuc- (void)deliberateReleaseFalseNegative {
240*0a6a1f1dSLionel Sambuc  // This is arguably a false negative because the result of p.friend shouldn't
241*0a6a1f1dSLionel Sambuc  // be released, even though we are manipulating the ivar in between the two
242*0a6a1f1dSLionel Sambuc  // actions.
243*0a6a1f1dSLionel Sambuc  id name = self.name;
244*0a6a1f1dSLionel Sambuc  _name = 0;
245*0a6a1f1dSLionel Sambuc  [name release];
246*0a6a1f1dSLionel Sambuc}
247*0a6a1f1dSLionel Sambuc
248*0a6a1f1dSLionel Sambuc- (void)testRetainAndRelease {
249*0a6a1f1dSLionel Sambuc  [self.name retain];
250*0a6a1f1dSLionel Sambuc  [self.name release];
251*0a6a1f1dSLionel Sambuc  [self.name release]; // expected-warning{{not owned}}
252*0a6a1f1dSLionel Sambuc}
253*0a6a1f1dSLionel Sambuc
254*0a6a1f1dSLionel Sambuc- (void)testRetainAndReleaseIVar {
255*0a6a1f1dSLionel Sambuc  [self.name retain];
256*0a6a1f1dSLionel Sambuc  [_name release];
257*0a6a1f1dSLionel Sambuc  [_name release]; // expected-warning{{not owned}}
258*0a6a1f1dSLionel Sambuc}
259*0a6a1f1dSLionel Sambuc
260*0a6a1f1dSLionel Sambuc@end
261*0a6a1f1dSLionel Sambuc#endif
262*0a6a1f1dSLionel Sambuc
263*0a6a1f1dSLionel Sambuc@interface IntWrapper
264*0a6a1f1dSLionel Sambuc@property int value;
265*0a6a1f1dSLionel Sambuc@end
266*0a6a1f1dSLionel Sambuc
267*0a6a1f1dSLionel Sambuc@implementation IntWrapper
268*0a6a1f1dSLionel Sambuc@synthesize value;
269*0a6a1f1dSLionel Sambuc@end
270*0a6a1f1dSLionel Sambuc
271*0a6a1f1dSLionel Sambucvoid testConsistencyInt(IntWrapper *w) {
272*0a6a1f1dSLionel Sambuc  clang_analyzer_eval(w.value == w.value); // expected-warning{{TRUE}}
273*0a6a1f1dSLionel Sambuc
274*0a6a1f1dSLionel Sambuc  int origValue = w.value;
275*0a6a1f1dSLionel Sambuc  if (origValue != 42)
276*0a6a1f1dSLionel Sambuc    return;
277*0a6a1f1dSLionel Sambuc
278*0a6a1f1dSLionel Sambuc  clang_analyzer_eval(w.value == 42); // expected-warning{{TRUE}}
279*0a6a1f1dSLionel Sambuc}
280*0a6a1f1dSLionel Sambuc
281*0a6a1f1dSLionel Sambucvoid testConsistencyInt2(IntWrapper *w) {
282*0a6a1f1dSLionel Sambuc  if (w.value != 42)
283*0a6a1f1dSLionel Sambuc    return;
284*0a6a1f1dSLionel Sambuc
285*0a6a1f1dSLionel Sambuc  clang_analyzer_eval(w.value == 42); // expected-warning{{TRUE}}
286*0a6a1f1dSLionel Sambuc}
287*0a6a1f1dSLionel Sambuc
288*0a6a1f1dSLionel Sambuc
289*0a6a1f1dSLionel Sambuc@interface IntWrapperAuto
290*0a6a1f1dSLionel Sambuc@property int value;
291*0a6a1f1dSLionel Sambuc@end
292*0a6a1f1dSLionel Sambuc
293*0a6a1f1dSLionel Sambuc@implementation IntWrapperAuto
294*0a6a1f1dSLionel Sambuc@end
295*0a6a1f1dSLionel Sambuc
296*0a6a1f1dSLionel Sambucvoid testConsistencyIntAuto(IntWrapperAuto *w) {
297*0a6a1f1dSLionel Sambuc  clang_analyzer_eval(w.value == w.value); // expected-warning{{TRUE}}
298*0a6a1f1dSLionel Sambuc
299*0a6a1f1dSLionel Sambuc  int origValue = w.value;
300*0a6a1f1dSLionel Sambuc  if (origValue != 42)
301*0a6a1f1dSLionel Sambuc    return;
302*0a6a1f1dSLionel Sambuc
303*0a6a1f1dSLionel Sambuc  clang_analyzer_eval(w.value == 42); // expected-warning{{TRUE}}
304*0a6a1f1dSLionel Sambuc}
305*0a6a1f1dSLionel Sambuc
306*0a6a1f1dSLionel Sambucvoid testConsistencyIntAuto2(IntWrapperAuto *w) {
307*0a6a1f1dSLionel Sambuc  if (w.value != 42)
308*0a6a1f1dSLionel Sambuc    return;
309*0a6a1f1dSLionel Sambuc
310*0a6a1f1dSLionel Sambuc  clang_analyzer_eval(w.value == 42); // expected-warning{{TRUE}}
311*0a6a1f1dSLionel Sambuc}
312*0a6a1f1dSLionel Sambuc
313*0a6a1f1dSLionel Sambuc
314*0a6a1f1dSLionel Sambuctypedef struct {
315*0a6a1f1dSLionel Sambuc  int value;
316*0a6a1f1dSLionel Sambuc} IntWrapperStruct;
317*0a6a1f1dSLionel Sambuc
318*0a6a1f1dSLionel Sambuc@interface StructWrapper
319*0a6a1f1dSLionel Sambuc@property IntWrapperStruct inner;
320*0a6a1f1dSLionel Sambuc@end
321*0a6a1f1dSLionel Sambuc
322*0a6a1f1dSLionel Sambuc@implementation StructWrapper
323*0a6a1f1dSLionel Sambuc@synthesize inner;
324*0a6a1f1dSLionel Sambuc@end
325*0a6a1f1dSLionel Sambuc
326*0a6a1f1dSLionel Sambucvoid testConsistencyStruct(StructWrapper *w) {
327*0a6a1f1dSLionel Sambuc  clang_analyzer_eval(w.inner.value == w.inner.value); // expected-warning{{TRUE}}
328*0a6a1f1dSLionel Sambuc
329*0a6a1f1dSLionel Sambuc  int origValue = w.inner.value;
330*0a6a1f1dSLionel Sambuc  if (origValue != 42)
331*0a6a1f1dSLionel Sambuc    return;
332*0a6a1f1dSLionel Sambuc
333*0a6a1f1dSLionel Sambuc  clang_analyzer_eval(w.inner.value == 42); // expected-warning{{TRUE}}
334*0a6a1f1dSLionel Sambuc}
335*0a6a1f1dSLionel Sambuc
336*0a6a1f1dSLionel Sambuc
337*0a6a1f1dSLionel Sambuc@interface OpaqueIntWrapper
338*0a6a1f1dSLionel Sambuc@property int value;
339*0a6a1f1dSLionel Sambuc@end
340*0a6a1f1dSLionel Sambuc
341*0a6a1f1dSLionel Sambuc// For now, don't assume a property is implemented using an ivar unless we can
342*0a6a1f1dSLionel Sambuc// actually see that it is.
343*0a6a1f1dSLionel Sambucvoid testOpaqueConsistency(OpaqueIntWrapper *w) {
344*0a6a1f1dSLionel Sambuc  clang_analyzer_eval(w.value == w.value); // expected-warning{{UNKNOWN}}
345*0a6a1f1dSLionel Sambuc}
346*0a6a1f1dSLionel Sambuc
347