1// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.SuperDealloc,debug.ExprInspection -analyzer-output=text -verify %s
2
3void clang_analyzer_warnIfReached();
4
5#define nil ((id)0)
6
7typedef unsigned long NSUInteger;
8@protocol NSObject
9- (instancetype)retain;
10- (oneway void)release;
11@end
12
13@interface NSObject <NSObject> { }
14- (void)dealloc;
15- (instancetype)init;
16@end
17
18typedef struct objc_selector *SEL;
19
20//===------------------------------------------------------------------------===
21//  <rdar://problem/6953275>
22//  Check that 'self' is not referenced after calling '[super dealloc]'.
23
24@interface SuperDeallocThenReleaseIvarClass : NSObject {
25  NSObject *_ivar;
26}
27@end
28
29@implementation SuperDeallocThenReleaseIvarClass
30- (instancetype)initWithIvar:(NSObject *)ivar {
31  self = [super init];
32  if (!self)
33    return nil;
34  _ivar = [ivar retain];
35  return self;
36}
37- (void)dealloc {
38  [super dealloc]; // expected-note {{[super dealloc] called here}}
39  [_ivar release]; // expected-warning {{Use of instance variable '_ivar' after 'self' has been deallocated}}
40  // expected-note@-1 {{Use of instance variable '_ivar' after 'self' has been deallocated}}
41}
42@end
43
44@interface SuperDeallocThenAssignNilToIvarClass : NSObject {
45  NSObject *_delegate;
46}
47@end
48
49@implementation SuperDeallocThenAssignNilToIvarClass
50- (instancetype)initWithDelegate:(NSObject *)delegate {
51  self = [super init];
52  if (!self)
53    return nil;
54  _delegate = delegate;
55  return self;
56}
57- (void)dealloc {
58  [super dealloc]; // expected-note {{[super dealloc] called here}}
59  _delegate = nil; // expected-warning {{Use of instance variable '_delegate' after 'self' has been deallocated}}
60      // expected-note@-1 {{Use of instance variable '_delegate' after 'self' has been deallocated}}
61}
62@end
63
64
65struct SomeStruct {
66  int f;
67};
68
69@interface SuperDeallocThenAssignIvarField : NSObject {
70  struct SomeStruct _s;
71}
72@end
73
74@implementation SuperDeallocThenAssignIvarField
75- (void)dealloc {
76  [super dealloc]; // expected-note {{[super dealloc] called here}}
77  _s.f = 7; // expected-warning {{Use of instance variable '_s' after 'self' has been deallocated}}
78      // expected-note@-1 {{Use of instance variable '_s' after 'self' has been deallocated}}
79}
80@end
81
82@interface OtherClassWithIvar {
83@public
84  int _otherIvar;
85}
86@end;
87
88@interface SuperDeallocThenAssignIvarIvar : NSObject {
89  OtherClassWithIvar *_ivar;
90}
91@end
92
93@implementation SuperDeallocThenAssignIvarIvar
94- (void)dealloc {
95  [super dealloc]; // expected-note {{[super dealloc] called here}}
96  _ivar->_otherIvar = 7; // expected-warning {{Use of instance variable '_ivar' after 'self' has been deallocated}}
97      // expected-note@-1 {{Use of instance variable '_ivar' after 'self' has been deallocated}}
98}
99@end
100
101@interface SuperDeallocThenAssignSelfIvar : NSObject {
102  NSObject *_ivar;
103}
104@end
105
106@implementation SuperDeallocThenAssignSelfIvar
107- (void)dealloc {
108  [super dealloc]; // expected-note {{[super dealloc] called here}}
109  self->_ivar = nil; // expected-warning {{Use of instance variable '_ivar' after 'self' has been deallocated}}
110      // expected-note@-1 {{Use of instance variable '_ivar' after 'self' has been deallocated}}
111}
112@end
113
114@interface SuperDeallocThenReleasePropertyClass : NSObject { }
115@property (retain) NSObject *ivar;
116@end
117
118@implementation SuperDeallocThenReleasePropertyClass
119- (instancetype)initWithProperty:(NSObject *)ivar {
120  self = [super init];
121  if (!self)
122    return nil;
123  self.ivar = ivar;
124  return self;
125}
126- (void)dealloc {
127  [super dealloc]; // expected-note {{[super dealloc] called here}}
128  self.ivar = nil; // expected-warning {{Use of 'self' after it has been deallocated}}
129      // expected-note@-1 {{Use of 'self' after it has been deallocated}}
130}
131@end
132
133@interface SuperDeallocThenAssignNilToPropertyClass : NSObject { }
134@property (assign) NSObject *delegate;
135@end
136
137@implementation SuperDeallocThenAssignNilToPropertyClass
138- (instancetype)initWithDelegate:(NSObject *)delegate {
139  self = [super init];
140  if (!self)
141    return nil;
142  self.delegate = delegate;
143  return self;
144}
145- (void)dealloc {
146  [super dealloc]; // expected-note {{[super dealloc] called here}}
147  self.delegate = nil; // expected-warning {{Use of 'self' after it has been deallocated}}
148      // expected-note@-1 {{Use of 'self' after it has been deallocated}}
149}
150@end
151
152@interface SuperDeallocThenCallInstanceMethodClass : NSObject { }
153- (void)_invalidate;
154@end
155
156@implementation SuperDeallocThenCallInstanceMethodClass
157- (void)_invalidate {
158}
159- (void)dealloc {
160  [super dealloc]; // expected-note {{[super dealloc] called here}}
161  [self _invalidate]; // expected-warning {{Use of 'self' after it has been deallocated}}
162      // expected-note@-1 {{Use of 'self' after it has been deallocated}}
163}
164@end
165
166@interface SuperDeallocThenCallNonObjectiveCMethodClass : NSObject { }
167@end
168
169static void _invalidate(NSObject *object) {
170  (void)object;
171}
172
173@implementation SuperDeallocThenCallNonObjectiveCMethodClass
174- (void)dealloc {
175  [super dealloc]; // expected-note {{[super dealloc] called here}}
176  _invalidate(self); // expected-warning {{Use of 'self' after it has been deallocated}}
177      // expected-note@-1 {{Use of 'self' after it has been deallocated}}
178}
179@end
180
181@interface SuperDeallocThenCallObjectiveClassMethodClass : NSObject { }
182@end
183
184@implementation SuperDeallocThenCallObjectiveClassMethodClass
185+ (void) invalidate:(id)arg; {
186}
187
188- (void)dealloc {
189  [super dealloc]; // expected-note {{[super dealloc] called here}}
190  [SuperDeallocThenCallObjectiveClassMethodClass invalidate:self]; // expected-warning {{Use of 'self' after it has been deallocated}}
191      // expected-note@-1 {{Use of 'self' after it has been deallocated}}
192}
193@end
194
195@interface TwoSuperDeallocCallsClass : NSObject {
196  NSObject *_ivar;
197}
198- (void)_invalidate;
199@end
200
201@implementation TwoSuperDeallocCallsClass
202- (void)_invalidate {
203}
204- (void)dealloc {
205  if (_ivar) { // expected-note {{Assuming the condition is false}} expected-note {{Taking false branch}}
206    [_ivar release];
207    [super dealloc];
208    return;
209  }
210  [super dealloc];    // expected-note {{[super dealloc] called here}}
211  [self _invalidate]; // expected-warning {{Use of 'self' after it has been deallocated}}
212      // expected-note@-1 {{Use of 'self' after it has been deallocated}}
213}
214@end
215
216//===------------------------------------------------------------------------===
217// Warn about calling [super dealloc] twice due to missing return statement.
218
219@interface MissingReturnCausesDoubleSuperDeallocClass : NSObject {
220  NSObject *_ivar;
221}
222@end
223
224@implementation MissingReturnCausesDoubleSuperDeallocClass
225- (void)dealloc {
226  if (_ivar) { // expected-note {{Assuming the condition is true}} expected-note {{Taking true branch}}
227    [_ivar release];
228    [super dealloc]; // expected-note {{[super dealloc] called here}}
229    // return;
230  }
231  [super dealloc]; // expected-warning{{[super dealloc] should not be called multiple times}}
232  // expected-note@-1{{[super dealloc] should not be called multiple times}}
233}
234@end
235
236//===------------------------------------------------------------------------===
237// Warn about calling [super dealloc] twice in two different methods.
238
239@interface SuperDeallocInOtherMethodClass : NSObject {
240  NSObject *_ivar;
241}
242- (void)_cleanup;
243@end
244
245@implementation SuperDeallocInOtherMethodClass
246- (void)_cleanup {
247  [_ivar release];
248  [super dealloc]; // expected-note {{[super dealloc] called here}}
249}
250- (void)dealloc {
251  [self _cleanup]; // expected-note {{Calling '_cleanup'}}
252  //expected-note@-1 {{Returning from '_cleanup'}}
253  [super dealloc]; // expected-warning {{[super dealloc] should not be called multiple times}}
254  // expected-note@-1 {{[super dealloc] should not be called multiple times}}
255}
256@end
257
258//===------------------------------------------------------------------------===
259// Do not warn about calling [super dealloc] recursively for different objects
260// of the same type with custom retain counting.
261//
262// A class that contains an ivar of itself with custom retain counting (such
263// as provided by _OBJC_SUPPORTED_INLINE_REFCNT_WITH_DEALLOC2MAIN) can generate
264// a false positive that [super dealloc] is called twice if each object instance
265// is not tracked separately by the checker. This test case is just a simple
266// approximation to trigger the false positive.
267
268@class ClassWithOwnIvarInstanceClass;
269@interface ClassWithOwnIvarInstanceClass : NSObject {
270  ClassWithOwnIvarInstanceClass *_ivar;
271  NSUInteger _retainCount;
272}
273@end
274
275@implementation ClassWithOwnIvarInstanceClass
276- (instancetype)retain {
277  ++_retainCount;
278  return self;
279}
280- (oneway void)release {
281  --_retainCount;
282  if (!_retainCount)
283    [self dealloc];
284}
285- (void)dealloc {
286  [_ivar release];
287  [super dealloc]; // no warning: different instances of same class
288}
289@end
290
291//===------------------------------------------------------------------------===
292// Do not warn about calling [super dealloc] twice if +dealloc is a class
293// method.
294
295@interface SuperDeallocClassMethodIgnoredClass : NSObject { }
296+ (void)dealloc;
297@end
298
299@implementation SuperDeallocClassMethodIgnoredClass
300+ (void)dealloc { }
301@end
302
303@interface SuperDeallocClassMethodIgnoredSubClass : NSObject { }
304+ (void)dealloc;
305@end
306
307@implementation SuperDeallocClassMethodIgnoredSubClass
308+ (void)dealloc {
309  [super dealloc];
310  [super dealloc]; // no warning: class method
311}
312@end
313
314//===------------------------------------------------------------------------===
315// Do not warn about calling [super dealloc] twice if when the analyzer has
316// inlined the call to its super deallocator.
317
318@interface SuperClassCallingSuperDealloc : NSObject {
319  NSObject *_ivar;
320}
321@end
322
323@implementation SuperClassCallingSuperDealloc
324- (void)dealloc; {
325  [_ivar release]; // no-warning
326
327  [super dealloc];
328}
329@end
330
331@interface SubclassCallingSuperDealloc : SuperClassCallingSuperDealloc
332@end
333
334@implementation SubclassCallingSuperDealloc
335- (void)dealloc; {
336  [super dealloc];
337}
338@end
339
340//===------------------------------------------------------------------------===
341// Treat calling [super dealloc] twice as as a sink.
342
343@interface CallingSuperDeallocTwiceIsSink : NSObject
344@end
345
346@implementation CallingSuperDeallocTwiceIsSink
347- (void)dealloc; {
348  [super dealloc]; // expected-note {{[super dealloc] called here}}
349  [super dealloc]; // expected-warning {{[super dealloc] should not be called multiple times}}
350  // expected-note@-1 {{[super dealloc] should not be called multiple times}}
351
352  clang_analyzer_warnIfReached(); // no-warning
353}
354@end
355
356
357//===------------------------------------------------------------------------===
358// Test path notes with intervening method call on self.
359
360@interface InterveningMethodCallOnSelf : NSObject
361@end
362
363@implementation InterveningMethodCallOnSelf
364- (void)anotherMethod {
365}
366
367- (void)dealloc; {
368  [super dealloc]; // expected-note {{[super dealloc] called here}}
369  [self anotherMethod]; // expected-warning {{Use of 'self' after it has been deallocated}}
370      // expected-note@-1 {{Use of 'self' after it has been deallocated}}
371  [super dealloc];
372}
373@end
374