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