1// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.Loops,debug.ExprInspection -verify %s
2
3void clang_analyzer_eval(int);
4void clang_analyzer_warnIfReached();
5
6#define nil ((id)0)
7
8typedef unsigned long NSUInteger;
9@protocol NSFastEnumeration
10- (int)countByEnumeratingWithState:(void *)state objects:(id *)objects count:(unsigned)count;
11- (void)protocolMethod;
12@end
13
14@interface NSObject
15+ (instancetype)testObject;
16@end
17
18@interface NSEnumerator <NSFastEnumeration>
19@end
20
21@interface NSArray : NSObject <NSFastEnumeration>
22- (NSUInteger)count;
23- (NSEnumerator *)objectEnumerator;
24+ (NSArray *)arrayWithObjects:(const id [])objects count:(NSUInteger)count;
25@end
26
27@interface NSDictionary : NSObject <NSFastEnumeration>
28- (NSUInteger)count;
29- (id)objectForKey:(id)key;
30+ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id /* <NSCopying> */ [])keys count:(NSUInteger)count;
31@end
32
33@interface NSDictionary (SomeCategory)
34- (void)categoryMethodOnNSDictionary;
35@end
36
37@interface NSMutableDictionary : NSDictionary
38- (void)setObject:(id)obj forKey:(id)key;
39@end
40
41@interface NSMutableArray : NSArray
42- (void)addObject:(id)obj;
43@end
44
45@interface NSSet : NSObject <NSFastEnumeration>
46- (NSUInteger)count;
47@end
48
49@interface NSPointerArray : NSObject <NSFastEnumeration>
50@end
51
52@interface NSString : NSObject
53@end
54
55void test() {
56  id x;
57  for (x in [NSArray testObject])
58    clang_analyzer_eval(x != nil); // expected-warning{{TRUE}}
59
60  for (x in [NSMutableDictionary testObject])
61    clang_analyzer_eval(x != nil); // expected-warning{{TRUE}}
62
63  for (x in [NSSet testObject])
64    clang_analyzer_eval(x != nil); // expected-warning{{TRUE}}
65
66  for (x in [[NSArray testObject] objectEnumerator])
67    clang_analyzer_eval(x != nil); // expected-warning{{TRUE}}
68
69  for (x in [NSPointerArray testObject])
70    clang_analyzer_eval(x != nil); // expected-warning{{UNKNOWN}}
71}
72
73void testWithVarInFor() {
74  for (id x in [NSArray testObject])
75    clang_analyzer_eval(x != nil); // expected-warning{{TRUE}}
76  for (id x in [NSPointerArray testObject])
77    clang_analyzer_eval(x != nil); // expected-warning{{UNKNOWN}}
78}
79
80void testNonNil(id a, id b) {
81  clang_analyzer_eval(a != nil); // expected-warning{{UNKNOWN}}
82  for (id x in a)
83    clang_analyzer_eval(a != nil); // expected-warning{{TRUE}}
84
85  if (b != nil)
86    return;
87  for (id x in b)
88    *(volatile int *)0 = 1; // no-warning
89  clang_analyzer_eval(b != nil); // expected-warning{{FALSE}}
90}
91
92void collectionIsEmpty(NSMutableDictionary *D){
93  if ([D count] == 0) { // Count is zero.
94    NSString *s = 0;
95    for (NSString *key in D) {
96      s = key;       // Loop is never entered.
97    }
98    clang_analyzer_eval(s == 0); //expected-warning{{TRUE}}
99  }
100}
101
102void processCollection(NSMutableDictionary *D);
103void collectionIsEmptyCollectionIsModified(NSMutableDictionary *D){
104  if ([D count] == 0) {      // Count is zero.
105    NSString *s = 0;
106    processCollection(D);  // However, the collection has changed.
107    for (NSString *key in D) {
108      s = key;       // Loop might be entered.
109    }
110    clang_analyzer_eval(s == 0); //expected-warning{{FALSE}} //expected-warning{{TRUE}}
111  }
112}
113
114int collectionIsEmptyNSSet(NSSet *S){
115  if ([S count] == 2) { // Count is non-zero.
116    int tapCounts[2];
117    int i = 0;
118    for (NSString *elem in S) {
119      tapCounts[i]= 1;       // Loop is entered.
120      i++;
121    }
122    return (tapCounts[0]); //no warning
123  }
124  return 0;
125}
126
127int collectionIsNotEmptyNSArray(NSArray *A) {
128  int count = [A count];
129  if (count > 0) {
130    int i;
131    int j = 0;
132    for (NSString *a in A) {
133      i = 1;
134      j++;
135    }
136    clang_analyzer_eval(i == 1); // expected-warning {{TRUE}}
137  }
138  return 0;
139}
140
141void onlySuppressExitAfterZeroIterations(NSMutableDictionary *D) {
142  if (D.count > 0) {
143    int *x;
144    int i = 0;
145    for (NSString *key in D) {
146      x = 0;
147      i++;
148    }
149    // Test that this is reachable.
150    int y = *x; // expected-warning {{Dereference of null pointer}}
151    y++;
152  }
153}
154
155void onlySuppressLoopExitAfterZeroIterations_WithContinue(NSMutableDictionary *D) {
156  if (D.count > 0) {
157    int *x;
158    int i = 0;
159    for (NSString *key in D) {
160      x = 0;
161      i++;
162      continue;
163    }
164    // Test that this is reachable.
165    int y = *x; // expected-warning {{Dereference of null pointer}}
166    y++;
167  }
168}
169
170int* getPtr();
171void onlySuppressLoopExitAfterZeroIterations_WithBreak(NSMutableDictionary *D) {
172  if (D.count > 0) {
173    int *x;
174    int i;
175    for (NSString *key in D) {
176      x = 0;
177      break;
178      x = getPtr();
179      i++;
180    }
181    int y = *x; // expected-warning {{Dereference of null pointer}}
182    y++;
183  }
184}
185
186int consistencyBetweenLoopsWhenCountIsUnconstrained(NSMutableDictionary *D,
187                                                    int shouldUseCount) {
188  // Test with or without an initial count.
189  int count;
190  if (shouldUseCount)
191    count = [D count];
192
193  int i;
194  int j = 0;
195  for (NSString *key in D) {
196    i = 5;
197    j++;
198  }
199  for (NSString *key in D)  {
200    return i; // no-warning
201  }
202  return 0;
203}
204
205int consistencyBetweenLoopsWhenCountIsUnconstrained_dual(NSMutableDictionary *D,
206                                                         int shouldUseCount) {
207  int count;
208  if (shouldUseCount)
209    count = [D count];
210
211  int i = 8;
212  int j = 1;
213  for (NSString *key in D) {
214    i = 0;
215    j++;
216  }
217  for (NSString *key in D)  {
218    i = 5;
219    j++;
220  }
221  return 5/i;
222}
223
224int consistencyCountThenLoop(NSArray *array) {
225  if ([array count] == 0)
226    return 0;
227
228  int x;
229  for (id y in array)
230    x = 0;
231  return x; // no-warning
232}
233
234int consistencyLoopThenCount(NSArray *array) {
235  int x;
236  for (id y in array)
237    x = 0;
238
239  if ([array count] == 0)
240    return 0;
241
242  return x; // no-warning
243}
244
245void nonMutatingMethodsDoNotInvalidateCountDictionary(NSMutableDictionary *dict,
246                                                      NSMutableArray *other) {
247  if ([dict count])
248    return;
249
250  for (id key in dict)
251    clang_analyzer_eval(0); // no-warning
252
253  (void)[dict objectForKey:@""];
254
255  for (id key in dict)
256    clang_analyzer_eval(0); // no-warning
257
258  [dict categoryMethodOnNSDictionary];
259
260  for (id key in dict)
261    clang_analyzer_eval(0); // no-warning
262
263  [dict setObject:@"" forKey:@""];
264
265  for (id key in dict)
266    clang_analyzer_eval(0); // expected-warning{{FALSE}}
267
268  // Reset.
269  if ([dict count])
270    return;
271
272  for (id key in dict)
273    clang_analyzer_eval(0); // no-warning
274
275  [other addObject:dict];
276
277  for (id key in dict)
278    clang_analyzer_eval(0); // expected-warning{{FALSE}}
279}
280
281void nonMutatingMethodsDoNotInvalidateCountArray(NSMutableArray *array,
282                                                 NSMutableArray *other) {
283  if ([array count])
284    return;
285
286  for (id key in array)
287    clang_analyzer_eval(0); // no-warning
288
289  (void)[array objectEnumerator];
290
291  for (id key in array)
292    clang_analyzer_eval(0); // no-warning
293
294  [array addObject:@""];
295
296  for (id key in array)
297    clang_analyzer_eval(0); // expected-warning{{FALSE}}
298
299  // Reset.
300  if ([array count])
301    return;
302
303  for (id key in array)
304    clang_analyzer_eval(0); // no-warning
305
306  [other addObject:array];
307
308  for (id key in array)
309    clang_analyzer_eval(0); // expected-warning{{FALSE}}
310}
311
312void protocolMethods(NSMutableArray *array) {
313  if ([array count])
314    return;
315
316  for (id key in array)
317    clang_analyzer_eval(0); // no-warning
318
319  NSArray *immutableArray = array;
320  [immutableArray protocolMethod];
321
322  for (id key in array)
323    clang_analyzer_eval(0); // no-warning
324
325  [array protocolMethod];
326
327  for (id key in array)
328    clang_analyzer_eval(0); // expected-warning{{FALSE}}
329}
330
331NSArray *globalArray;
332NSDictionary *globalDictionary;
333void boxedArrayEscape(NSMutableArray *array) {
334  if ([array count])
335    return;
336  globalArray = @[array];
337  for (id key in array)
338    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
339
340  if ([array count])
341    return;
342  globalDictionary = @{ @"array" : array };
343  for (id key in array)
344    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
345}
346