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