1// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-config ipa=dynamic-bifurcate -verify -analyzer-config eagerly-assume=false %s 2 3void clang_analyzer_checkInlined(int); 4void clang_analyzer_eval(int); 5 6// Test inlining of ObjC class methods. 7 8typedef signed char BOOL; 9#define YES ((BOOL)1) 10#define NO ((BOOL)0) 11typedef struct objc_class *Class; 12typedef struct objc_object { 13 Class isa; 14} * id; 15@protocol NSObject 16- (BOOL)isEqual:(id)object; 17@end 18@interface NSObject <NSObject> {} 19+ (id)alloc; 20+ (Class)class; 21+ (Class)superclass; 22- (id)init; 23- (id)autorelease; 24- (id)copy; 25- (Class)class; 26- (instancetype)self; 27- (id)retain; 28@end 29 30// Vanila: ObjC class method is called by name. 31@interface MyParent : NSObject 32+ (int)getInt; 33@end 34@interface MyClass : MyParent 35+ (int)getInt; 36@end 37@implementation MyClass 38+ (int)testClassMethodByName { 39 int y = [MyClass getInt]; 40 return 5/y; // expected-warning {{Division by zero}} 41} 42+ (int)getInt { 43 return 0; 44} 45@end 46 47// The definition is defined by the parent. Make sure we find it and inline. 48@interface MyParentDIP : NSObject 49+ (int)getInt; 50@end 51@interface MyClassDIP : MyParentDIP 52@end 53@implementation MyClassDIP 54+ (int)testClassMethodByName { 55 int y = [MyClassDIP getInt]; 56 return 5/y; // expected-warning {{Division by zero}} 57} 58@end 59@implementation MyParentDIP 60+ (int)getInt { 61 return 0; 62} 63@end 64 65// ObjC class method is called by name. Definition is in the category. 66@interface AAA : NSObject 67@end 68@interface AAA (MyCat) 69+ (int)getInt; 70@end 71int foo() { 72 int y = [AAA getInt]; 73 return 5/y; // expected-warning {{Division by zero}} 74} 75@implementation AAA 76@end 77@implementation AAA (MyCat) 78+ (int)getInt { 79 return 0; 80} 81@end 82 83// ObjC class method is called by name. Definition is in the parent category. 84@interface PPP : NSObject 85@end 86@interface PPP (MyCat) 87+ (int)getInt; 88@end 89@interface CCC : PPP 90@end 91int foo4() { 92 int y = [CCC getInt]; 93 return 5/y; // expected-warning {{Division by zero}} 94} 95@implementation PPP 96@end 97@implementation PPP (MyCat) 98+ (int)getInt { 99 return 0; 100} 101@end 102 103// There is no declaration in the class but there is one in the parent. Make 104// sure we pick the definition from the class and not the parent. 105@interface MyParentTricky : NSObject 106+ (int)getInt; 107@end 108@interface MyClassTricky : MyParentTricky 109@end 110@implementation MyParentTricky 111+ (int)getInt { 112 return 0; 113} 114@end 115@implementation MyClassTricky 116+ (int)getInt { 117 return 1; 118} 119+ (int)testClassMethodByName { 120 int y = [MyClassTricky getInt]; 121 return 5/y; // no-warning 122} 123@end 124 125// ObjC class method is called by unknown class declaration (passed in as a 126// parameter). We should not inline in such case. 127@interface MyParentUnknown : NSObject 128+ (int)getInt; 129@end 130@interface MyClassUnknown : MyParentUnknown 131+ (int)getInt; 132@end 133@implementation MyClassUnknown 134+ (int)testClassVariableByUnknownVarDecl: (Class)cl { 135 int y = [cl getInt]; 136 return 3/y; // no-warning 137} 138+ (int)getInt { 139 return 0; 140} 141@end 142 143// ObjC class method call through a decl with a known type. 144// Note, [self class] could be a subclass. Do we still want to inline here? 145@interface MyClassKT : NSObject 146@end 147@interface MyClassKT (MyCatKT) 148+ (int)getInt; 149@end 150@implementation MyClassKT (MyCatKT) 151+ (int)getInt { 152 return 0; 153} 154@end 155@implementation MyClassKT 156- (int)testClassMethodByKnownVarDecl { 157 Class currentClass = [self class]; 158 int y = [currentClass getInt]; 159 return 5 / y; // expected-warning{{Division by zero}} 160} 161@end 162 163// Another false negative due to us not reasoning about self, which in this 164// case points to the object of the class in the call site and should be equal 165// to [MyParent class]. 166@interface MyParentSelf : NSObject 167+ (int)testSelf; 168@end 169@implementation MyParentSelf 170+ (int)testSelf { 171 if (self == [MyParentSelf class]) 172 return 0; 173 else 174 return 1; 175} 176@end 177@interface MyClassSelf : MyParentSelf 178@end 179@implementation MyClassSelf 180+ (int)testClassMethodByKnownVarDecl { 181 int y = [MyParentSelf testSelf]; 182 return 5/y; // expected-warning{{Division by zero}} 183} 184@end 185int foo2() { 186 int y = [MyParentSelf testSelf]; 187 return 5/y; // expected-warning{{Division by zero}} 188} 189 190// TODO: We do not inline 'getNum' in the following case, where the value of 191// 'self' in call '[self getNum]' is available and evaualtes to 192// 'SelfUsedInParentChild' if it's called from fooA. 193// Self region should get created before we call foo and yje call to super 194// should keep it live. 195@interface SelfUsedInParent : NSObject 196+ (int)getNum; 197+ (int)foo; 198@end 199@implementation SelfUsedInParent 200+ (int)getNum {return 5;} 201+ (int)foo { 202 int r = [self getNum]; 203 clang_analyzer_eval(r == 5); // expected-warning{{TRUE}} 204 return r; 205} 206@end 207@interface SelfUsedInParentChild : SelfUsedInParent 208+ (int)getNum; 209+ (int)fooA; 210@end 211@implementation SelfUsedInParentChild 212+ (int)getNum {return 0;} 213+ (int)fooA { 214 return [super foo]; 215} 216@end 217int checkSelfUsedInparentClassMethod() { 218 return 5/[SelfUsedInParentChild fooA]; 219} 220 221 222@interface Rdar15037033 : NSObject 223@end 224 225void rdar15037033() { 226 [Rdar15037033 forwardDeclaredMethod]; // expected-warning {{class method '+forwardDeclaredMethod' not found}} 227 [Rdar15037033 forwardDeclaredVariadicMethod:1, 2, 3, 0]; // expected-warning {{class method '+forwardDeclaredVariadicMethod:' not found}} 228} 229 230@implementation Rdar15037033 231 232+ (void)forwardDeclaredMethod { 233 clang_analyzer_checkInlined(1); // expected-warning{{TRUE}} 234} 235 236+ (void)forwardDeclaredVariadicMethod:(int)x, ... { 237 clang_analyzer_checkInlined(0); // no-warning 238} 239@end 240 241@interface SelfClassTestParent : NSObject 242-(unsigned)returns10; 243+(unsigned)returns20; 244+(unsigned)returns30; 245@end 246 247@interface SelfClassTest : SelfClassTestParent 248- (unsigned)returns10; 249+ (unsigned)returns20; 250+ (unsigned)returns30; 251@end 252 253@implementation SelfClassTestParent 254- (unsigned)returns10 { 255 return 100; 256} 257+ (unsigned)returns20 { 258 return 100; 259} 260+ (unsigned)returns30 { 261 return 100; 262} 263 264- (void)testSelfReassignment { 265 // Check that we didn't hardcode type for self. 266 self = [[[SelfClassTest class] alloc] init]; 267 Class actuallyChildClass = [self class]; 268 unsigned result = [actuallyChildClass returns30]; 269 clang_analyzer_eval(result == 30); // expected-warning{{TRUE}} 270} 271@end 272 273@implementation SelfClassTest 274- (unsigned)returns10 { 275 return 10; 276} 277+ (unsigned)returns20 { 278 return 20; 279} 280+ (unsigned)returns30 { 281 return 30; 282} 283+ (BOOL)isClass { 284 return YES; 285} 286- (BOOL)isClass { 287 return NO; 288} 289+ (SelfClassTest *)create { 290 return [[self alloc] init]; 291} 292+ (void)classMethod { 293 unsigned result1 = [self returns20]; 294 clang_analyzer_eval(result1 == 20); // expected-warning{{TRUE}} 295 296 unsigned result2 = [[self class] returns30]; 297 clang_analyzer_eval(result2 == 30); // expected-warning{{TRUE}} 298 299 unsigned result3 = [[super class] returns30]; 300 clang_analyzer_eval(result3 == 100); // expected-warning{{TRUE}} 301 302 // Check that class info is propagated with data 303 Class class41 = [self class]; 304 Class class42 = class41; 305 unsigned result4 = [class42 returns30]; 306 clang_analyzer_eval(result4 == 30); // expected-warning{{TRUE}} 307 308 Class class51 = [super class]; 309 Class class52 = class51; 310 unsigned result5 = [class52 returns30]; 311 clang_analyzer_eval(result5 == 100); // expected-warning{{TRUE}} 312} 313- (void)instanceMethod { 314 unsigned result0 = [self returns10]; 315 clang_analyzer_eval(result0 == 10); // expected-warning{{TRUE}} 316 317 unsigned result2 = [[self class] returns30]; 318 clang_analyzer_eval(result2 == 30); // expected-warning{{TRUE}} 319 320 unsigned result3 = [[super class] returns30]; 321 clang_analyzer_eval(result3 == 100); // expected-warning{{TRUE}} 322 323 // Check that class info is propagated with data 324 Class class41 = [self class]; 325 Class class42 = class41; 326 unsigned result4 = [class42 returns30]; 327 clang_analyzer_eval(result4 == 30); // expected-warning{{TRUE}} 328 329 Class class51 = [super class]; 330 Class class52 = class51; 331 unsigned result5 = [class52 returns30]; 332 clang_analyzer_eval(result5 == 100); // expected-warning{{TRUE}} 333 334 // Check that we inline class methods when class object is a receiver 335 Class class6 = [self class]; 336 BOOL calledClassMethod = [class6 isClass]; 337 clang_analyzer_eval(calledClassMethod == YES); // expected-warning{{TRUE}} 338 339 // Check that class info is propagated through the 'self' method 340 Class class71 = [self class]; 341 Class class72 = [class71 self]; 342 unsigned result7 = [class72 returns30]; 343 clang_analyzer_eval(result7 == 30); // expected-warning{{TRUE}} 344 345 // Check that 'class' and 'super' info from direct invocation of the 346 // corresponding class methods is propagated with data 347 Class class8 = [SelfClassTest class]; 348 unsigned result8 = [class8 returns30]; 349 clang_analyzer_eval(result8 == 30); // expected-warning{{TRUE}} 350 351 Class class9 = [SelfClassTest superclass]; 352 unsigned result9 = [class9 returns30]; 353 clang_analyzer_eval(result9 == 100); // expected-warning{{TRUE}} 354 355 // Check that we get class from a propagated type 356 SelfClassTestParent *selfAsParent10 = [[SelfClassTest alloc] init]; 357 Class class10 = [selfAsParent10 class]; 358 unsigned result10 = [class10 returns30]; 359 clang_analyzer_eval(result10 == 30); // expected-warning{{TRUE}} 360 361 SelfClassTestParent *selfAsParent11 = [[[self class] alloc] init]; 362 Class class11 = [selfAsParent11 class]; 363 unsigned result11 = [class11 returns30]; 364 clang_analyzer_eval(result11 == 30); // expected-warning{{TRUE}} 365} 366@end 367 368@interface Parent : NSObject 369+ (int)a; 370+ (int)b; 371@end 372@interface Child : Parent 373@end 374@interface Other : NSObject 375+(void)run; 376@end 377int main(int argc, const char * argv[]) { 378 @autoreleasepool { 379 [Other run]; 380 } 381 return 0; 382} 383@implementation Other 384+(void)run { 385 int result = [Child a]; 386 // TODO: This should return 100. 387 clang_analyzer_eval(result == 12); // expected-warning{{TRUE}} 388} 389@end 390@implementation Parent 391+ (int)a; { 392 return [self b]; 393} 394+ (int)b; { 395 return 12; 396} 397@end 398@implementation Child 399+ (int)b; { 400 return 100; 401} 402@end 403