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