// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.Loops,debug.ExprInspection -verify %s
void clang_analyzer_eval(int);
void clang_analyzer_warnIfReached();
#define nil ((id)0)
typedef unsigned long NSUInteger;
@protocol NSFastEnumeration
- (int)countByEnumeratingWithState:(void *)state objects:(id *)objects count:(unsigned)count;
- (void)protocolMethod;
@end
@interface NSObject
+ (instancetype)testObject;
@end
@interface NSEnumerator <NSFastEnumeration>
@end
@interface NSArray : NSObject <NSFastEnumeration>
- (NSUInteger)count;
- (NSEnumerator *)objectEnumerator;
+ (NSArray *)arrayWithObjects:(const id [])objects count:(NSUInteger)count;
@end
@interface NSDictionary : NSObject <NSFastEnumeration>
- (NSUInteger)count;
- (id)objectForKey:(id)key;
+ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id /* <NSCopying> */ [])keys count:(NSUInteger)count;
@end
@interface NSDictionary (SomeCategory)
- (void)categoryMethodOnNSDictionary;
- (id) allKeys;
@end
@interface NSMutableDictionary : NSDictionary
- (void)setObject:(id)obj forKey:(id)key;
@end
@interface NSMutableArray : NSArray
- (void)addObject:(id)obj;
@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 = 0;
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 = 0;
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 = 0;
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,
int shouldUseCount) {
// Test with or without an initial count.
int count;
if (shouldUseCount)
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 shouldUseCount) {
int count;
if (shouldUseCount)
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;
}
int consistencyCountThenLoop(NSArray *array) {
if ([array count] == 0)
return 0;
int x;
for (id y in array)
x = 0;
return x; // no-warning
}
int consistencyLoopThenCount(NSArray *array) {
int x;
for (id y in array)
x = 0;
if ([array count] == 0)
return 0;
return x; // no-warning
}
void nonMutatingMethodsDoNotInvalidateCountDictionary(NSMutableDictionary *dict,
NSMutableArray *other) {
if ([dict count])
return;
for (id key in dict)
clang_analyzer_eval(0); // no-warning
(void)[dict objectForKey:@""];
for (id key in dict)
clang_analyzer_eval(0); // no-warning
[dict categoryMethodOnNSDictionary];
for (id key in dict)
clang_analyzer_eval(0); // no-warning
[dict setObject:@"" forKey:@""];
for (id key in dict)
clang_analyzer_eval(0); // expected-warning{{FALSE}}
// Reset.
if ([dict count])
return;
for (id key in dict)
clang_analyzer_eval(0); // no-warning
[other addObject:dict];
for (id key in dict)
clang_analyzer_eval(0); // expected-warning{{FALSE}}
}
void nonMutatingMethodsDoNotInvalidateCountArray(NSMutableArray *array,
NSMutableArray *other) {
if ([array count])
return;
for (id key in array)
clang_analyzer_eval(0); // no-warning
(void)[array objectEnumerator];
for (id key in array)
clang_analyzer_eval(0); // no-warning
[array addObject:@""];
for (id key in array)
clang_analyzer_eval(0); // expected-warning{{FALSE}}
// Reset.
if ([array count])
return;
for (id key in array)
clang_analyzer_eval(0); // no-warning
[other addObject:array];
for (id key in array)
clang_analyzer_eval(0); // expected-warning{{FALSE}}
}
void protocolMethods(NSMutableArray *array) {
if ([array count])
return;
for (id key in array)
clang_analyzer_eval(0); // no-warning
NSArray *immutableArray = array;
[immutableArray protocolMethod];
for (id key in array)
clang_analyzer_eval(0); // no-warning
[array protocolMethod];
for (id key in array)
clang_analyzer_eval(0); // expected-warning{{FALSE}}
}
NSArray *globalArray;
NSDictionary *globalDictionary;
void boxedArrayEscape(NSMutableArray *array) {
if ([array count])
return;
globalArray = @[array];
for (id key in array)
clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
if ([array count])
return;
globalDictionary = @{ @"array" : array };
for (id key in array)
clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
}
int not_reachable_on_iteration_through_nil() {
NSDictionary* d = nil;
for (NSString* s in [d allKeys])
clang_analyzer_warnIfReached(); // no-warning
return 0;
}