objc-for.m revision 2ffcd18b845d4f855074ff7011c46e20616e08fd
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@end
11
12@interface NSObject
13+ (instancetype)testObject;
14@end
15
16@interface NSEnumerator <NSFastEnumeration>
17@end
18
19@interface NSArray : NSObject <NSFastEnumeration>
20- (NSUInteger)count;
21- (NSEnumerator *)objectEnumerator;
22@end
23
24@interface NSDictionary : NSObject <NSFastEnumeration>
25- (NSUInteger)count;
26@end
27
28@interface NSMutableDictionary : NSDictionary
29@end
30
31@interface NSSet : NSObject <NSFastEnumeration>
32- (NSUInteger)count;
33@end
34
35@interface NSPointerArray : NSObject <NSFastEnumeration>
36@end
37
38@interface NSString : NSObject
39@end
40
41void test() {
42  id x;
43  for (x in [NSArray testObject])
44    clang_analyzer_eval(x != nil); // expected-warning{{TRUE}}
45
46  for (x in [NSMutableDictionary testObject])
47    clang_analyzer_eval(x != nil); // expected-warning{{TRUE}}
48
49  for (x in [NSSet testObject])
50    clang_analyzer_eval(x != nil); // expected-warning{{TRUE}}
51
52  for (x in [[NSArray testObject] objectEnumerator])
53    clang_analyzer_eval(x != nil); // expected-warning{{TRUE}}
54
55  for (x in [NSPointerArray testObject])
56    clang_analyzer_eval(x != nil); // expected-warning{{UNKNOWN}}
57}
58
59void testWithVarInFor() {
60  for (id x in [NSArray testObject])
61    clang_analyzer_eval(x != nil); // expected-warning{{TRUE}}
62  for (id x in [NSPointerArray testObject])
63    clang_analyzer_eval(x != nil); // expected-warning{{UNKNOWN}}
64}
65
66void testNonNil(id a, id b) {
67  clang_analyzer_eval(a != nil); // expected-warning{{UNKNOWN}}
68  for (id x in a)
69    clang_analyzer_eval(a != nil); // expected-warning{{TRUE}}
70
71  if (b != nil)
72    return;
73  for (id x in b)
74    *(volatile int *)0 = 1; // no-warning
75  clang_analyzer_eval(b != nil); // expected-warning{{FALSE}}
76}
77
78void collectionIsEmpty(NSMutableDictionary *D){
79  if ([D count] == 0) { // Count is zero.
80    NSString *s = 0;
81    for (NSString *key in D) {
82      s = key;       // Loop is never entered.
83    }
84    clang_analyzer_eval(s == 0); //expected-warning{{TRUE}}
85  }
86}
87
88void processCollection(NSMutableDictionary *D);
89void collectionIsEmptyCollectionIsModified(NSMutableDictionary *D){
90  if ([D count] == 0) {      // Count is zero.
91    NSString *s = 0;
92    processCollection(D);  // However, the collection has changed.
93    for (NSString *key in D) {
94      s = key;       // Loop might be entered.
95    }
96    clang_analyzer_eval(s == 0); //expected-warning{{FALSE}} //expected-warning{{TRUE}}
97  }
98}
99
100int collectionIsEmptyNSSet(NSSet *S){
101  if ([S count] == 2) { // Count is non zero.
102    int tapCounts[2];
103    int i = 0;
104    for (NSString *elem in S) {
105      tapCounts[i]= 1;       // Loop is entered.
106      i++;
107    }
108    return (tapCounts[0]); //no warning
109  }
110  return 0;
111}
112
113int collectionIsNotEmptyNSArray(NSArray *A) {
114  int count = [A count];
115  if (count > 0) {
116    int i;
117    int j;
118    for (NSString *a in A) {
119      i = 1;
120      j++;
121    }
122    clang_analyzer_eval(i == 1); // expected-warning {{TRUE}}
123  }
124  return 0;
125}
126
127void onlySuppressExitAfterZeroIterations(NSMutableDictionary *D) {
128  if (D.count > 0) {
129    int *x;
130    int i;
131    for (NSString *key in D) {
132      x = 0;
133      i++;
134    }
135    // Test that this is reachable.
136    int y = *x; // expected-warning {{Dereference of null pointer}}
137    y++;
138  }
139}
140
141void onlySuppressLoopExitAfterZeroIterations_WithContinue(NSMutableDictionary *D) {
142  if (D.count > 0) {
143    int *x;
144    int i;
145    for (NSString *key in D) {
146      x = 0;
147      i++;
148      continue;
149    }
150    // Test that this is reachable.
151    int y = *x; // expected-warning {{Dereference of null pointer}}
152    y++;
153  }
154}
155
156int* getPtr();
157void onlySuppressLoopExitAfterZeroIterations_WithBreak(NSMutableDictionary *D) {
158  if (D.count > 0) {
159    int *x;
160    int i;
161    for (NSString *key in D) {
162      x = 0;
163      break;
164      x = getPtr();
165      i++;
166    }
167    int y = *x; // expected-warning {{Dereference of null pointer}}
168    y++;
169  }
170}
171
172int consistencyBetweenLoopsWhenCountIsUnconstrained(NSMutableDictionary *D) {
173  // Note, The current limitation is that we need to have a count.
174  // TODO: This should work even when we do not call count.
175  int count = [D count];
176  int i;
177  int j = 0;
178  for (NSString *key in D) {
179    i = 5;
180    j++;
181  }
182  for (NSString *key in D)  {
183    return i; // no-warning
184  }
185  return 0;
186}
187
188int consistencyBetweenLoopsWhenCountIsUnconstrained_dual(NSMutableDictionary *D) {
189  int count = [D count];
190  int i = 8;
191  int j = 1;
192  for (NSString *key in D) {
193    i = 0;
194    j++;
195  }
196  for (NSString *key in D)  {
197    i = 5;
198    j++;
199  }
200  return 5/i;
201}
202