1// RUN: %clang --analyze -Xanalyzer -analyzer-checker=osx.cocoa.IncompatibleMethodTypes,osx.coreFoundation.CFRetainRelease -Xclang -verify %s 2 3#include "InlineObjCInstanceMethod.h" 4 5typedef const struct __CFString * CFStringRef; 6typedef const void * CFTypeRef; 7extern CFTypeRef CFRetain(CFTypeRef cf); 8extern void CFRelease(CFTypeRef cf); 9extern CFStringRef getString(void); 10 11// Method is defined in the parent; called through self. 12@interface MyParent : NSObject 13- (int)getInt; 14- (const struct __CFString *) testCovariantReturnType __attribute__((cf_returns_retained)); 15@end 16@implementation MyParent 17- (int)getInt { 18 return 0; 19} 20 21- (CFStringRef) testCovariantReturnType __attribute__((cf_returns_retained)) { 22 CFStringRef Str = ((void*)0); 23 Str = getString(); 24 if (Str) { 25 CFRetain(Str); 26 } 27 return Str; 28} 29 30@end 31 32@interface MyClass : MyParent 33@end 34@implementation MyClass 35- (int)testDynDispatchSelf { 36 int y = [self getInt]; 37 return 5/y; // expected-warning {{Division by zero}} 38} 39 40// Get the dynamic type info from a cast (from id to MyClass*). 41+ (int)testAllocInit { 42 MyClass *a = [[self alloc] init]; 43 return 5/[a getInt]; // expected-warning {{Division by zero}} 44} 45 46// Method is called on inited object. 47+ (int)testAllocInit2 { 48 MyClass *a = [[MyClass alloc] init]; 49 return 5/[a getInt]; // expected-warning {{Division by zero}} 50} 51 52// Method is called on a parameter. 53+ (int)testParam: (MyClass*) a { 54 return 5/[a getInt]; // expected-warning {{Division by zero}} 55} 56 57// Method is called on a parameter of unnown type. 58+ (int)testParamUnknownType: (id) a { 59 return 5/[a getInt]; // no warning 60} 61 62@end 63 64// TODO: When method is inlined, the attribute reset should be visible. 65@interface TestSettingAnAttributeInCallee : NSObject { 66 int _attribute; 67} 68 - (void) method2; 69@end 70 71@implementation TestSettingAnAttributeInCallee 72- (int) method1 { 73 [self method2]; 74 return 5/_attribute; // expected-warning {{Division by zero}} 75} 76 77- (void) method2 { 78 _attribute = 0; 79} 80@end 81 82@interface TestSettingAnAttributeInCaller : NSObject { 83 int _attribute; 84} 85 - (int) method2; 86@end 87 88@implementation TestSettingAnAttributeInCaller 89- (void) method1 { 90 _attribute = 0; 91 [self method2]; 92} 93 94- (int) method2 { 95 return 5/_attribute; // expected-warning {{Division by zero}} 96} 97@end 98 99 100// Don't crash if we don't know the receiver's region. 101void randomlyMessageAnObject(MyClass *arr[], int i) { 102 (void)[arr[i] getInt]; 103} 104 105 106@interface EvilChild : MyParent 107- (id)getInt; 108- (const struct __CFString *) testCovariantReturnType __attribute__((cf_returns_retained)); 109@end 110 111@implementation EvilChild 112- (id)getInt { // expected-warning {{types are incompatible}} 113 return self; 114} 115- (CFStringRef) testCovariantReturnType __attribute__((cf_returns_retained)) { 116 CFStringRef Str = ((void*)0); 117 Str = getString(); 118 if (Str) { 119 CFRetain(Str); 120 } 121 return Str; 122} 123 124@end 125 126int testNonCovariantReturnType() { 127 MyParent *obj = [[EvilChild alloc] init]; 128 129 // Devirtualization allows us to directly call -[EvilChild getInt], but 130 // that returns an id, not an int. There is an off-by-default warning for 131 // this, -Woverriding-method-mismatch, and an on-by-default analyzer warning, 132 // osx.cocoa.IncompatibleMethodTypes. This code would probably crash at 133 // runtime, but at least the analyzer shouldn't crash. 134 int x = 1 + [obj getInt]; 135 136 [obj release]; 137 return 5/(x-1); // no-warning 138} 139 140int testCovariantReturnTypeNoErrorSinceTypesMatch() { 141 MyParent *obj = [[EvilChild alloc] init]; 142 143 CFStringRef S = ((void*)0); 144 S = [obj testCovariantReturnType]; 145 if (S) 146 CFRelease(S); 147 CFRelease(obj); 148} 149