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