// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.Loops,debug.ExprInspection -verify %s void clang_analyzer_eval(int); #define nil ((id)0) typedef unsigned long NSUInteger; @protocol NSFastEnumeration - (int)countByEnumeratingWithState:(void *)state objects:(id *)objects count:(unsigned)count; @end @interface NSObject + (instancetype)testObject; @end @interface NSEnumerator <NSFastEnumeration> @end @interface NSArray : NSObject <NSFastEnumeration> - (NSUInteger)count; - (NSEnumerator *)objectEnumerator; @end @interface NSDictionary : NSObject <NSFastEnumeration> - (NSUInteger)count; @end @interface NSMutableDictionary : NSDictionary @end @interface NSSet : NSObject <NSFastEnumeration> - (NSUInteger)count; @end @interface NSPointerArray : NSObject <NSFastEnumeration> @end @interface NSString : NSObject @end void test() { id x; for (x in [NSArray testObject]) clang_analyzer_eval(x != nil); // expected-warning{{TRUE}} for (x in [NSMutableDictionary testObject]) clang_analyzer_eval(x != nil); // expected-warning{{TRUE}} for (x in [NSSet testObject]) clang_analyzer_eval(x != nil); // expected-warning{{TRUE}} for (x in [[NSArray testObject] objectEnumerator]) clang_analyzer_eval(x != nil); // expected-warning{{TRUE}} for (x in [NSPointerArray testObject]) clang_analyzer_eval(x != nil); // expected-warning{{UNKNOWN}} } void testWithVarInFor() { for (id x in [NSArray testObject]) clang_analyzer_eval(x != nil); // expected-warning{{TRUE}} for (id x in [NSPointerArray testObject]) clang_analyzer_eval(x != nil); // expected-warning{{UNKNOWN}} } void testNonNil(id a, id b) { clang_analyzer_eval(a != nil); // expected-warning{{UNKNOWN}} for (id x in a) clang_analyzer_eval(a != nil); // expected-warning{{TRUE}} if (b != nil) return; for (id x in b) *(volatile int *)0 = 1; // no-warning clang_analyzer_eval(b != nil); // expected-warning{{FALSE}} } void collectionIsEmpty(NSMutableDictionary *D){ if ([D count] == 0) { // Count is zero. NSString *s = 0; for (NSString *key in D) { s = key; // Loop is never entered. } clang_analyzer_eval(s == 0); //expected-warning{{TRUE}} } } void processCollection(NSMutableDictionary *D); void collectionIsEmptyCollectionIsModified(NSMutableDictionary *D){ if ([D count] == 0) { // Count is zero. NSString *s = 0; processCollection(D); // However, the collection has changed. for (NSString *key in D) { s = key; // Loop might be entered. } clang_analyzer_eval(s == 0); //expected-warning{{FALSE}} //expected-warning{{TRUE}} } } int collectionIsEmptyNSSet(NSSet *S){ if ([S count] == 2) { // Count is non zero. int tapCounts[2]; int i = 0; for (NSString *elem in S) { tapCounts[i]= 1; // Loop is entered. i++; } return (tapCounts[0]); //no warning } return 0; } int collectionIsNotEmptyNSArray(NSArray *A) { int count = [A count]; if (count > 0) { int i; int j; for (NSString *a in A) { i = 1; j++; } clang_analyzer_eval(i == 1); // expected-warning {{TRUE}} } return 0; } void onlySuppressExitAfterZeroIterations(NSMutableDictionary *D) { if (D.count > 0) { int *x; int i; for (NSString *key in D) { x = 0; i++; } // Test that this is reachable. int y = *x; // expected-warning {{Dereference of null pointer}} y++; } } void onlySuppressLoopExitAfterZeroIterations_WithContinue(NSMutableDictionary *D) { if (D.count > 0) { int *x; int i; for (NSString *key in D) { x = 0; i++; continue; } // Test that this is reachable. int y = *x; // expected-warning {{Dereference of null pointer}} y++; } } int* getPtr(); void onlySuppressLoopExitAfterZeroIterations_WithBreak(NSMutableDictionary *D) { if (D.count > 0) { int *x; int i; for (NSString *key in D) { x = 0; break; x = getPtr(); i++; } int y = *x; // expected-warning {{Dereference of null pointer}} y++; } } int consistencyBetweenLoopsWhenCountIsUnconstrained(NSMutableDictionary *D) { // Note, The current limitation is that we need to have a count. // TODO: This should work even when we do not call count. int count = [D count]; int i; int j = 0; for (NSString *key in D) { i = 5; j++; } for (NSString *key in D) { return i; // no-warning } return 0; } int consistencyBetweenLoopsWhenCountIsUnconstrained_dual(NSMutableDictionary *D) { int count = [D count]; int i = 8; int j = 1; for (NSString *key in D) { i = 0; j++; } for (NSString *key in D) { i = 5; j++; } return 5/i; }