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