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