objc_invalidation.m revision 6de7daa60412744bcf168c6c0d521688435fe221
1// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.osx.cocoa.InstanceVariableInvalidation -fobjc-default-synthesize-properties -verify %s
2extern void __assert_fail (__const char *__assertion, __const char *__file,
3    unsigned int __line, __const char *__function)
4     __attribute__ ((__noreturn__));
5
6#define assert(expr) \
7  ((expr)  ? (void)(0)  : __assert_fail (#expr, __FILE__, __LINE__, __func__))
8
9@protocol NSObject
10@end
11@interface NSObject <NSObject> {}
12+(id)alloc;
13+(id)new;
14-(id)init;
15-(id)autorelease;
16-(id)copy;
17- (Class)class;
18-(id)retain;
19-(id)description;
20@end
21@class NSString;
22
23extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2)));
24
25@protocol Invalidation1 <NSObject> 
26- (void) invalidate __attribute__((annotate("objc_instance_variable_invalidator")));
27@end 
28
29@protocol Invalidation2 <NSObject> 
30- (void) invalidate __attribute__((annotate("objc_instance_variable_invalidator")));
31@end 
32
33@protocol Invalidation3 <NSObject>
34- (void) invalidate __attribute__((annotate("objc_instance_variable_invalidator")));
35- (void) invalidate2 __attribute__((annotate("objc_instance_variable_invalidator")));
36@end
37
38@protocol Invalidation3;
39@protocol Invalidation2;
40
41@interface Invalidation2Class <Invalidation2>
42@end
43
44@interface Invalidation1Class <Invalidation1>
45@end
46
47@interface ClassWithInvalidationMethodInCategory <NSObject>
48@end
49
50@interface ClassWithInvalidationMethodInCategory ()
51- (void) invalidate __attribute__((annotate("objc_instance_variable_invalidator")));
52@end
53
54@interface SomeInvalidationImplementingObject: NSObject <Invalidation3, Invalidation2> {
55  SomeInvalidationImplementingObject *ObjA; // invalidation in the parent
56}
57@end
58
59@implementation SomeInvalidationImplementingObject
60- (void)invalidate{
61  ObjA = 0;
62}
63- (void)invalidate2 {
64  [self invalidate];
65}
66@end
67
68@interface SomeSubclassInvalidatableObject : SomeInvalidationImplementingObject {
69  SomeInvalidationImplementingObject *Ivar1; // regular ivar
70  SomeInvalidationImplementingObject *Ivar2; // regular ivar, sending invalidate message
71  SomeInvalidationImplementingObject *_Ivar3; // no property, call -description
72  SomeInvalidationImplementingObject *_Ivar4; // no property, provide as argument to NSLog()
73
74  SomeInvalidationImplementingObject *_Prop1; // partially implemented property, set to 0 with dot syntax
75  SomeInvalidationImplementingObject *_Prop2; // fully implemented prop, set to 0 with dot syntax
76  SomeInvalidationImplementingObject *_propIvar; // property with custom named ivar, set to 0 via setter
77  Invalidation1Class *MultipleProtocols; // regular ivar belonging to a different class
78  Invalidation2Class *MultInheritance; // regular ivar belonging to a different class
79  SomeInvalidationImplementingObject *_Prop3; // property, invalidate via sending a message to a getter method
80  SomeInvalidationImplementingObject *_Prop4; // property with @synthesize, invalidate via property
81  SomeInvalidationImplementingObject *_Prop5; // property with @synthesize, invalidate via getter method
82  SomeInvalidationImplementingObject *_Prop8;
83  
84  // No warnings on these as they are not invalidatable.
85  NSObject *NIvar1;
86  NSObject *NObj2;
87  NSObject *_NProp1;
88  NSObject *_NpropIvar;
89}
90
91@property (assign) SomeInvalidationImplementingObject* Prop0;
92@property (nonatomic, assign) SomeInvalidationImplementingObject* Prop1;
93@property (assign) SomeInvalidationImplementingObject* Prop2;
94@property (assign) SomeInvalidationImplementingObject* Prop3;
95@property (assign) SomeInvalidationImplementingObject *Prop5;
96@property (assign) SomeInvalidationImplementingObject *Prop4;
97
98@property (assign) SomeInvalidationImplementingObject* Prop6; // automatically synthesized prop
99@property (assign) SomeInvalidationImplementingObject* Prop7; // automatically synthesized prop
100@property (assign) SomeInvalidationImplementingObject *SynthIvarProp;
101
102@property (assign) NSObject* NProp0;
103@property (nonatomic, assign) NSObject* NProp1;
104@property (assign) NSObject* NProp2;
105
106-(void)setProp1: (SomeInvalidationImplementingObject*) InO;
107-(void)setNProp1: (NSObject*) InO;
108
109-(void)invalidate;
110
111@end
112
113@interface SomeSubclassInvalidatableObject()
114@property (assign) SomeInvalidationImplementingObject* Prop8;
115@end
116
117@implementation SomeSubclassInvalidatableObject{
118  @private
119  SomeInvalidationImplementingObject *Ivar5;
120  ClassWithInvalidationMethodInCategory *Ivar13;
121}
122
123@synthesize Prop7 = _propIvar;
124@synthesize Prop3 = _Prop3;
125@synthesize Prop5 = _Prop5;
126@synthesize Prop4 = _Prop4;
127@synthesize Prop8 = _Prop8;
128
129
130- (void) setProp1: (SomeInvalidationImplementingObject*) InObj {
131  _Prop1 = InObj;
132}
133
134- (void) setProp2: (SomeInvalidationImplementingObject*) InObj {
135  _Prop2 = InObj;
136}
137- (SomeInvalidationImplementingObject*) Prop2 {
138  return _Prop2;
139}
140
141@synthesize NProp2 = _NpropIvar;
142
143- (void) setNProp1: (NSObject*) InObj {
144  _NProp1 = InObj;
145}
146
147- (void) invalidate {
148   [Ivar2 invalidate];
149   self.Prop0 = 0;
150   self.Prop1 = 0;
151   [self setProp2:0];
152   [self setProp3:0];
153   [[self Prop5] invalidate2];
154   [self.Prop4 invalidate];
155   [self.Prop8 invalidate];
156   self.Prop6 = 0;
157   [[self Prop7] invalidate];
158
159   [_Ivar3 description]; 
160   NSLog(@"%@", _Ivar4);
161   [super invalidate];
162}
163// expected-warning@-1 {{Instance variable Ivar1 needs to be invalidated}}
164 // expected-warning@-2 {{Instance variable MultipleProtocols needs to be invalidated}}
165 // expected-warning@-3 {{Instance variable MultInheritance needs to be invalidated}}
166 // expected-warning@-4 {{Property SynthIvarProp needs to be invalidated or set to nil}}
167 // expected-warning@-5 {{Instance variable _Ivar3 needs to be invalidated}}
168 // expected-warning@-6 {{Instance variable _Ivar4 needs to be invalidated}}
169 // expected-warning@-7 {{Instance variable Ivar5 needs to be invalidated or set to nil}}
170// expected-warning@-8 {{Instance variable Ivar13 needs to be invalidated or set to nil}}
171@end
172
173// Example, where the same property is inherited through 
174// the parent and directly through a protocol. If a property backing ivar is 
175// synthesized in the parent, let the parent invalidate it.
176
177@protocol IDEBuildable <NSObject>
178@property (readonly, strong) id <Invalidation2> ObjB;
179@end
180
181@interface Parent : NSObject <IDEBuildable, Invalidation2> {
182  Invalidation2Class *_ObjB; // Invalidation of ObjB happens in the parent.
183}
184@end
185
186@interface Child: Parent <Invalidation2, IDEBuildable> 
187@end
188
189@implementation Parent{
190  @private
191  Invalidation2Class *Ivar10;
192  Invalidation2Class *Ivar11;
193  Invalidation2Class *Ivar12;
194}
195
196@synthesize ObjB = _ObjB;
197- (void)invalidate{
198  _ObjB = ((void*)0);
199  
200  assert(Ivar10 == 0);
201
202  if (__builtin_expect(!(Ivar11 == ((void*)0)), 0))
203    assert(0);
204
205  assert(0 == Ivar12);
206
207}
208@end
209
210@implementation Child
211- (void)invalidate{ 
212  // no-warning
213} 
214@end
215
216@protocol Invalidation <NSObject>
217- (void)invalidate __attribute__((annotate("objc_instance_variable_invalidator")));
218@end
219
220@interface Foo : NSObject <Invalidation>
221@end
222
223@class FooBar;
224@protocol FooBar_Protocol <NSObject>
225@end
226
227@interface MissingInvalidationMethod : Foo <FooBar_Protocol>
228@property (assign) MissingInvalidationMethod *foobar15_warn; // expected-warning {{Property foobar15_warn needs to be invalidated; No invalidation method is defined in the @implementation for MissingInvalidationMethod}}
229@end
230@implementation MissingInvalidationMethod
231@end
232
233@interface MissingInvalidationMethod2 : Foo <FooBar_Protocol> {
234  Foo *Ivar1;// expected-warning {{Instance variable Ivar1 needs to be invalidated; No invalidation method is defined in the @implementation for MissingInvalidationMethod2}}
235}
236@end
237@implementation MissingInvalidationMethod2
238@end
239
240@interface MissingInvalidationMethodDecl : NSObject {
241  Foo *Ivar1;// expected-warning {{Instance variable Ivar1 needs to be invalidated; No invalidation method is declared for MissingInvalidationMethodDecl}}
242}
243@end
244@implementation MissingInvalidationMethodDecl
245@end
246
247@interface MissingInvalidationMethodDecl2 : NSObject {
248@private
249    Foo *_foo1; // expected-warning {{Instance variable _foo1 needs to be invalidated; No invalidation method is declared for MissingInvalidationMethodDecl2}} 
250}
251@property (strong) Foo *bar1; 
252@end
253@implementation MissingInvalidationMethodDecl2
254@end
255