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