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