xref: /llvm-project/clang/test/Analysis/inlining/RetainCountExamples.m (revision 0f1c1be1968076d6f96f8a7bcc4a15cf195ecd97)
1// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-config ipa=dynamic-bifurcate -verify %s
2
3typedef signed char BOOL;
4typedef struct objc_class *Class;
5typedef struct objc_object {
6    Class isa;
7} *id;
8@protocol NSObject  - (BOOL)isEqual:(id)object; @end
9@interface NSObject <NSObject> {}
10+(id)alloc;
11+(id)new;
12- (oneway void)release;
13-(id)init;
14-(id)autorelease;
15-(id)copy;
16- (Class)class;
17-(id)retain;
18- (oneway void)release;
19@end
20
21@interface SelfStaysLive : NSObject
22- (id)init;
23@end
24
25@implementation SelfStaysLive
26- (id)init {
27  return [super init];
28}
29@end
30
31void selfStaysLive(void) {
32    SelfStaysLive *foo = [[SelfStaysLive alloc] init];
33    [foo release];
34}
35
36// Test that retain release checker warns on leaks and use-after-frees when
37// self init is not enabled.
38@interface ParentOfCell : NSObject
39- (id)initWithInt: (int)inInt;
40@end
41@interface Cell : ParentOfCell{
42  int x;
43}
44- (id)initWithInt: (int)inInt;
45+ (void)testOverRelease;
46+ (void)testLeak;
47@property int x;
48@end
49@implementation Cell
50@synthesize x;
51- (id) initWithInt: (int)inInt {
52  [super initWithInt: inInt];
53  self.x = inInt; // no-warning
54  return self; // Self Init checker would produce a warning here.
55}
56+ (void) testOverRelease {
57  Cell *sharedCell3 = [[Cell alloc] initWithInt: 3];
58  [sharedCell3 release];
59  [sharedCell3 release]; // expected-warning {{Reference-counted object is used after it is released}}
60}
61+ (void) testLeak {
62  Cell *sharedCell4 = [[Cell alloc] initWithInt: 3]; // expected-warning {{leak}}
63}
64@end
65
66// We should stop tracking some objects even when we inline the call.
67// Specialically, the objects passed into calls with delegate and callback
68// parameters.
69@class DelegateTest;
70typedef void (*ReleaseCallbackTy) (DelegateTest *c);
71
72@interface Delegate : NSObject
73@end
74
75@interface DelegateTest : NSObject {
76  Delegate *myDel;
77}
78// Object initialized with a delagate which could potentially release it.
79- (id)initWithDelegate: (id) d;
80
81- (void) setDelegate: (id) d;
82
83// Releases object through callback.
84+ (void)updateObject:(DelegateTest*)obj WithCallback:(ReleaseCallbackTy)rc;
85
86+ (void)test: (Delegate *)d;
87
88@property (assign) Delegate* myDel;
89@end
90
91void releaseObj(DelegateTest *c);
92
93// Releases object through callback.
94void updateObject(DelegateTest *c, ReleaseCallbackTy rel) {
95  rel(c);
96}
97
98@implementation DelegateTest
99@synthesize myDel;
100
101- (id) initWithDelegate: (id) d {
102    if ((self = [super init]))
103      myDel = d;
104    return self;
105}
106
107- (void) setDelegate: (id) d {
108    myDel = d;
109}
110
111+ (void)updateObject:(DelegateTest*)obj WithCallback:(ReleaseCallbackTy)rc {
112  rc(obj);
113}
114
115+ (void) test: (Delegate *)d {
116  DelegateTest *obj1 = [[DelegateTest alloc] initWithDelegate: d]; // no-warning
117  DelegateTest *obj2 = [[DelegateTest alloc] init]; // no-warning
118  DelegateTest *obj3 = [[DelegateTest alloc] init]; // no-warning
119  updateObject(obj2, releaseObj);
120  [DelegateTest updateObject: obj3
121        WithCallback: releaseObj];
122  DelegateTest *obj4 = [[DelegateTest alloc] init]; // no-warning
123  [obj4 setDelegate: d];
124}
125@end
126
127