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