blob: 960449758bfc941834b8c0e61b2ccfe403c7679c [file] [log] [blame]
// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-ipa=dynamic -verify %s
typedef signed char BOOL;
typedef struct objc_class *Class;
typedef struct objc_object {
Class isa;
} *id;
void clang_analyzer_eval(BOOL);
@protocol NSObject - (BOOL)isEqual:(id)object; @end
@interface NSObject <NSObject> {}
+(id)alloc;
-(id)init;
+(id)new;
-(id)autorelease;
-(id)copy;
- (Class)class;
-(id)retain;
@end
@interface MyParent : NSObject
- (int)getZeroOverridden;
@end
@implementation MyParent
- (int) getZeroOverridden {
return 1;
}
- (int) getZero {
return 0;
}
@end
@interface MyClass : MyParent
- (int) getZeroOverridden;
@end
MyClass *getObj();
@implementation MyClass
- (int) getZeroOverridden {
return 0;
}
/* Test that we get the right type from call to alloc. */
+ (void) testAllocSelf {
id a = [self alloc];
clang_analyzer_eval([a getZeroOverridden] == 0); // expected-warning{{TRUE}}
}
+ (void) testAllocClass {
id a = [MyClass alloc];
clang_analyzer_eval([a getZeroOverridden] == 0); // expected-warning{{TRUE}}
}
+ (void) testAllocSuperOverriden {
id a = [super alloc];
// Evaluates to 1 in the parent.
clang_analyzer_eval([a getZeroOverridden] == 0); // expected-warning{{FALSE}}
}
+ (void) testAllocSuper {
id a = [super alloc];
clang_analyzer_eval([a getZero] == 0); // expected-warning{{TRUE}}
}
+ (void) testAllocInit {
id a = [[self alloc] init];
clang_analyzer_eval([a getZeroOverridden] == 0); // expected-warning{{TRUE}}
}
+ (void) testNewSelf {
id a = [self new];
clang_analyzer_eval([a getZeroOverridden] == 0); // expected-warning{{TRUE}}
}
// Casting to parent should not pessimize the dynamic type.
+ (void) testCastToParent {
id a = [[self alloc] init];
MyParent *p = a;
clang_analyzer_eval([p getZeroOverridden] == 0); // expected-warning{{TRUE}}
}
// The type of parameter gets used.
+ (void)testTypeFromParam:(MyParent*) p {
clang_analyzer_eval([p getZero] == 0); // expected-warning{{TRUE}}
}
// Test implicit cast.
// Note, in this case, p could also be a subclass of MyParent.
+ (void) testCastFromId:(id) a {
MyParent *p = a;
clang_analyzer_eval([p getZero] == 0); // expected-warning{{TRUE}}
}
@end
// TODO: Would be nice to handle the case of dynamically obtained class info
// as well. We need a MemRegion for class types for this.
int testDynamicClass(BOOL coin) {
Class AllocClass = (coin ? [NSObject class] : [MyClass class]);
id x = [[AllocClass alloc] init];
if (coin)
return [x getZero];
return 1;
}