| // RUN: %clang --analyze -Xanalyzer -analyzer-checker=osx.cocoa.IncompatibleMethodTypes,osx.coreFoundation.CFRetainRelease -Xclang -verify %s |
| |
| #include "InlineObjCInstanceMethod.h" |
| |
| typedef const struct __CFString * CFStringRef; |
| typedef const void * CFTypeRef; |
| extern CFTypeRef CFRetain(CFTypeRef cf); |
| extern void CFRelease(CFTypeRef cf); |
| extern CFStringRef getString(void); |
| |
| // Method is defined in the parent; called through self. |
| @interface MyParent : NSObject |
| - (int)getInt; |
| - (const struct __CFString *) testCovariantReturnType __attribute__((cf_returns_retained)); |
| @end |
| @implementation MyParent |
| - (int)getInt { |
| return 0; |
| } |
| |
| - (CFStringRef) testCovariantReturnType __attribute__((cf_returns_retained)) { |
| CFStringRef Str = ((void*)0); |
| Str = getString(); |
| if (Str) { |
| CFRetain(Str); |
| } |
| return Str; |
| } |
| |
| @end |
| |
| @interface MyClass : MyParent |
| @end |
| @implementation MyClass |
| - (int)testDynDispatchSelf { |
| int y = [self getInt]; |
| return 5/y; // expected-warning {{Division by zero}} |
| } |
| |
| // Get the dynamic type info from a cast (from id to MyClass*). |
| + (int)testAllocInit { |
| MyClass *a = [[self alloc] init]; |
| return 5/[a getInt]; // expected-warning {{Division by zero}} |
| } |
| |
| // Method is called on inited object. |
| + (int)testAllocInit2 { |
| MyClass *a = [[MyClass alloc] init]; |
| return 5/[a getInt]; // expected-warning {{Division by zero}} |
| } |
| |
| // Method is called on a parameter. |
| + (int)testParam: (MyClass*) a { |
| return 5/[a getInt]; // expected-warning {{Division by zero}} |
| } |
| |
| // Method is called on a parameter of unnown type. |
| + (int)testParamUnknownType: (id) a { |
| return 5/[a getInt]; // no warning |
| } |
| |
| @end |
| |
| // TODO: When method is inlined, the attribute reset should be visible. |
| @interface TestSettingAnAttributeInCallee : NSObject { |
| int _attribute; |
| } |
| - (void) method2; |
| @end |
| |
| @implementation TestSettingAnAttributeInCallee |
| - (int) method1 { |
| [self method2]; |
| return 5/_attribute; // expected-warning {{Division by zero}} |
| } |
| |
| - (void) method2 { |
| _attribute = 0; |
| } |
| @end |
| |
| @interface TestSettingAnAttributeInCaller : NSObject { |
| int _attribute; |
| } |
| - (int) method2; |
| @end |
| |
| @implementation TestSettingAnAttributeInCaller |
| - (void) method1 { |
| _attribute = 0; |
| [self method2]; |
| } |
| |
| - (int) method2 { |
| return 5/_attribute; // expected-warning {{Division by zero}} |
| } |
| @end |
| |
| |
| // Don't crash if we don't know the receiver's region. |
| void randomlyMessageAnObject(MyClass *arr[], int i) { |
| (void)[arr[i] getInt]; |
| } |
| |
| |
| @interface EvilChild : MyParent |
| - (id)getInt; |
| - (const struct __CFString *) testCovariantReturnType __attribute__((cf_returns_retained)); |
| @end |
| |
| @implementation EvilChild |
| - (id)getInt { // expected-warning {{types are incompatible}} |
| return self; |
| } |
| - (CFStringRef) testCovariantReturnType __attribute__((cf_returns_retained)) { |
| CFStringRef Str = ((void*)0); |
| Str = getString(); |
| if (Str) { |
| CFRetain(Str); |
| } |
| return Str; |
| } |
| |
| @end |
| |
| int testNonCovariantReturnType() { |
| MyParent *obj = [[EvilChild alloc] init]; |
| |
| // Devirtualization allows us to directly call -[EvilChild getInt], but |
| // that returns an id, not an int. There is an off-by-default warning for |
| // this, -Woverriding-method-mismatch, and an on-by-default analyzer warning, |
| // osx.cocoa.IncompatibleMethodTypes. This code would probably crash at |
| // runtime, but at least the analyzer shouldn't crash. |
| int x = 1 + [obj getInt]; |
| |
| [obj release]; |
| return 5/(x-1); // no-warning |
| } |
| |
| int testCovariantReturnTypeNoErrorSinceTypesMatch() { |
| MyParent *obj = [[EvilChild alloc] init]; |
| |
| CFStringRef S = ((void*)0); |
| S = [obj testCovariantReturnType]; |
| if (S) |
| CFRelease(S); |
| CFRelease(obj); |
| } |