forked from OSchip/llvm-project
202 lines
4.6 KiB
Objective-C
202 lines
4.6 KiB
Objective-C
// 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;
|
|
}
|