1// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-config ipa=dynamic-bifurcate -verify %s 2 3// Test inlining of ObjC class methods. 4 5typedef signed char BOOL; 6typedef struct objc_class *Class; 7typedef struct objc_object { 8 Class isa; 9} *id; 10@protocol NSObject - (BOOL)isEqual:(id)object; @end 11@interface NSObject <NSObject> {} 12+(id)alloc; 13-(id)init; 14-(id)autorelease; 15-(id)copy; 16- (Class)class; 17-(id)retain; 18@end 19 20// Vanila: ObjC class method is called by name. 21@interface MyParent : NSObject 22+ (int)getInt; 23@end 24@interface MyClass : MyParent 25+ (int)getInt; 26@end 27@implementation MyClass 28+ (int)testClassMethodByName { 29 int y = [MyClass getInt]; 30 return 5/y; // expected-warning {{Division by zero}} 31} 32+ (int)getInt { 33 return 0; 34} 35@end 36 37// The definition is defined by the parent. Make sure we find it and inline. 38@interface MyParentDIP : NSObject 39+ (int)getInt; 40@end 41@interface MyClassDIP : MyParentDIP 42@end 43@implementation MyClassDIP 44+ (int)testClassMethodByName { 45 int y = [MyClassDIP getInt]; 46 return 5/y; // expected-warning {{Division by zero}} 47} 48@end 49@implementation MyParentDIP 50+ (int)getInt { 51 return 0; 52} 53@end 54 55// ObjC class method is called by name. Definition is in the category. 56@interface AAA : NSObject 57@end 58@interface AAA (MyCat) 59+ (int)getInt; 60@end 61int foo() { 62 int y = [AAA getInt]; 63 return 5/y; // expected-warning {{Division by zero}} 64} 65@implementation AAA 66@end 67@implementation AAA (MyCat) 68+ (int)getInt { 69 return 0; 70} 71@end 72 73// ObjC class method is called by name. Definition is in the parent category. 74@interface PPP : NSObject 75@end 76@interface PPP (MyCat) 77+ (int)getInt; 78@end 79@interface CCC : PPP 80@end 81int foo4() { 82 int y = [CCC getInt]; 83 return 5/y; // expected-warning {{Division by zero}} 84} 85@implementation PPP 86@end 87@implementation PPP (MyCat) 88+ (int)getInt { 89 return 0; 90} 91@end 92 93// There is no declaration in the class but there is one in the parent. Make 94// sure we pick the definition from the class and not the parent. 95@interface MyParentTricky : NSObject 96+ (int)getInt; 97@end 98@interface MyClassTricky : MyParentTricky 99@end 100@implementation MyParentTricky 101+ (int)getInt { 102 return 0; 103} 104@end 105@implementation MyClassTricky 106+ (int)getInt { 107 return 1; 108} 109+ (int)testClassMethodByName { 110 int y = [MyClassTricky getInt]; 111 return 5/y; // no-warning 112} 113@end 114 115// ObjC class method is called by unknown class declaration (passed in as a 116// parameter). We should not inline in such case. 117@interface MyParentUnknown : NSObject 118+ (int)getInt; 119@end 120@interface MyClassUnknown : MyParentUnknown 121+ (int)getInt; 122@end 123@implementation MyClassUnknown 124+ (int)testClassVariableByUnknownVarDecl: (Class)cl { 125 int y = [cl getInt]; 126 return 3/y; // no-warning 127} 128+ (int)getInt { 129 return 0; 130} 131@end 132 133 134// False negative. 135// ObjC class method call through a decl with a known type. 136// We should be able to track the type of currentClass and inline this call. 137// Note, [self class] could be a subclass. Do we still want to inline here? 138@interface MyClassKT : NSObject 139@end 140@interface MyClassKT (MyCatKT) 141+ (int)getInt; 142@end 143@implementation MyClassKT (MyCatKT) 144+ (int)getInt { 145 return 0; 146} 147@end 148@implementation MyClassKT 149- (int)testClassMethodByKnownVarDecl { 150 Class currentClass = [self class]; 151 int y = [currentClass getInt]; 152 return 5/y; // Would be great to get a warning here. 153} 154@end 155 156// Another false negative due to us not reasoning about self, which in this 157// case points to the object of the class in the call site and should be equal 158// to [MyParent class]. 159@interface MyParentSelf : NSObject 160+ (int)testSelf; 161@end 162@implementation MyParentSelf 163+ (int)testSelf { 164 if (self == [MyParentSelf class]) 165 return 0; 166 else 167 return 1; 168} 169@end 170@interface MyClassSelf : MyParentSelf 171@end 172@implementation MyClassSelf 173+ (int)testClassMethodByKnownVarDecl { 174 int y = [MyParentSelf testSelf]; 175 return 5/y; // Should warn here. 176} 177@end 178int foo2() { 179 int y = [MyParentSelf testSelf]; 180 return 5/y; // Should warn here. 181} 182 183// TODO: We do not inline 'getNum' in the following case, where the value of 184// 'self' in call '[self getNum]' is available and evaualtes to 185// 'SelfUsedInParentChild' if it's called from fooA. 186// Self region should get created before we call foo and yje call to super 187// should keep it live. 188@interface SelfUsedInParent : NSObject 189+ (int)getNum; 190+ (int)foo; 191@end 192@implementation SelfUsedInParent 193+ (int)getNum {return 5;} 194+ (int)foo { 195 return [self getNum]; 196} 197@end 198@interface SelfUsedInParentChild : SelfUsedInParent 199+ (int)getNum; 200+ (int)fooA; 201@end 202@implementation SelfUsedInParentChild 203+ (int)getNum {return 0;} 204+ (int)fooA { 205 return [super foo]; 206} 207@end 208int checkSelfUsedInparentClassMethod() { 209 return 5/[SelfUsedInParentChild fooA]; 210} 211 212