1// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-config ipa=dynamic-bifurcate -verify %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; 9typedef struct objc_class *Class; 10typedef struct objc_object { 11 Class isa; 12} *id; 13@protocol NSObject - (BOOL)isEqual:(id)object; @end 14@interface NSObject <NSObject> {} 15+(id)alloc; 16-(id)init; 17-(id)autorelease; 18-(id)copy; 19- (Class)class; 20-(id)retain; 21@end 22 23// Vanila: ObjC class method is called by name. 24@interface MyParent : NSObject 25+ (int)getInt; 26@end 27@interface MyClass : MyParent 28+ (int)getInt; 29@end 30@implementation MyClass 31+ (int)testClassMethodByName { 32 int y = [MyClass getInt]; 33 return 5/y; // expected-warning {{Division by zero}} 34} 35+ (int)getInt { 36 return 0; 37} 38@end 39 40// The definition is defined by the parent. Make sure we find it and inline. 41@interface MyParentDIP : NSObject 42+ (int)getInt; 43@end 44@interface MyClassDIP : MyParentDIP 45@end 46@implementation MyClassDIP 47+ (int)testClassMethodByName { 48 int y = [MyClassDIP getInt]; 49 return 5/y; // expected-warning {{Division by zero}} 50} 51@end 52@implementation MyParentDIP 53+ (int)getInt { 54 return 0; 55} 56@end 57 58// ObjC class method is called by name. Definition is in the category. 59@interface AAA : NSObject 60@end 61@interface AAA (MyCat) 62+ (int)getInt; 63@end 64int foo() { 65 int y = [AAA getInt]; 66 return 5/y; // expected-warning {{Division by zero}} 67} 68@implementation AAA 69@end 70@implementation AAA (MyCat) 71+ (int)getInt { 72 return 0; 73} 74@end 75 76// ObjC class method is called by name. Definition is in the parent category. 77@interface PPP : NSObject 78@end 79@interface PPP (MyCat) 80+ (int)getInt; 81@end 82@interface CCC : PPP 83@end 84int foo4() { 85 int y = [CCC getInt]; 86 return 5/y; // expected-warning {{Division by zero}} 87} 88@implementation PPP 89@end 90@implementation PPP (MyCat) 91+ (int)getInt { 92 return 0; 93} 94@end 95 96// There is no declaration in the class but there is one in the parent. Make 97// sure we pick the definition from the class and not the parent. 98@interface MyParentTricky : NSObject 99+ (int)getInt; 100@end 101@interface MyClassTricky : MyParentTricky 102@end 103@implementation MyParentTricky 104+ (int)getInt { 105 return 0; 106} 107@end 108@implementation MyClassTricky 109+ (int)getInt { 110 return 1; 111} 112+ (int)testClassMethodByName { 113 int y = [MyClassTricky getInt]; 114 return 5/y; // no-warning 115} 116@end 117 118// ObjC class method is called by unknown class declaration (passed in as a 119// parameter). We should not inline in such case. 120@interface MyParentUnknown : NSObject 121+ (int)getInt; 122@end 123@interface MyClassUnknown : MyParentUnknown 124+ (int)getInt; 125@end 126@implementation MyClassUnknown 127+ (int)testClassVariableByUnknownVarDecl: (Class)cl { 128 int y = [cl getInt]; 129 return 3/y; // no-warning 130} 131+ (int)getInt { 132 return 0; 133} 134@end 135 136 137// False negative. 138// ObjC class method call through a decl with a known type. 139// We should be able to track the type of currentClass and inline this call. 140// Note, [self class] could be a subclass. Do we still want to inline here? 141@interface MyClassKT : NSObject 142@end 143@interface MyClassKT (MyCatKT) 144+ (int)getInt; 145@end 146@implementation MyClassKT (MyCatKT) 147+ (int)getInt { 148 return 0; 149} 150@end 151@implementation MyClassKT 152- (int)testClassMethodByKnownVarDecl { 153 Class currentClass = [self class]; 154 int y = [currentClass getInt]; 155 return 5/y; // Would be great to get a warning here. 156} 157@end 158 159// Another false negative due to us not reasoning about self, which in this 160// case points to the object of the class in the call site and should be equal 161// to [MyParent class]. 162@interface MyParentSelf : NSObject 163+ (int)testSelf; 164@end 165@implementation MyParentSelf 166+ (int)testSelf { 167 if (self == [MyParentSelf class]) 168 return 0; 169 else 170 return 1; 171} 172@end 173@interface MyClassSelf : MyParentSelf 174@end 175@implementation MyClassSelf 176+ (int)testClassMethodByKnownVarDecl { 177 int y = [MyParentSelf testSelf]; 178 return 5/y; // expected-warning{{Division by zero}} 179} 180@end 181int foo2() { 182 int y = [MyParentSelf testSelf]; 183 return 5/y; // expected-warning{{Division by zero}} 184} 185 186// TODO: We do not inline 'getNum' in the following case, where the value of 187// 'self' in call '[self getNum]' is available and evaualtes to 188// 'SelfUsedInParentChild' if it's called from fooA. 189// Self region should get created before we call foo and yje call to super 190// should keep it live. 191@interface SelfUsedInParent : NSObject 192+ (int)getNum; 193+ (int)foo; 194@end 195@implementation SelfUsedInParent 196+ (int)getNum {return 5;} 197+ (int)foo { 198 int r = [self getNum]; 199 clang_analyzer_eval(r == 5); // expected-warning{{TRUE}} 200 return r; 201} 202@end 203@interface SelfUsedInParentChild : SelfUsedInParent 204+ (int)getNum; 205+ (int)fooA; 206@end 207@implementation SelfUsedInParentChild 208+ (int)getNum {return 0;} 209+ (int)fooA { 210 return [super foo]; 211} 212@end 213int checkSelfUsedInparentClassMethod() { 214 return 5/[SelfUsedInParentChild fooA]; 215} 216 217 218@interface Rdar15037033 : NSObject 219@end 220 221void rdar15037033() { 222 [Rdar15037033 forwardDeclaredMethod]; // expected-warning {{class method '+forwardDeclaredMethod' not found}} 223 [Rdar15037033 forwardDeclaredVariadicMethod:1, 2, 3, 0]; // expected-warning {{class method '+forwardDeclaredVariadicMethod:' not found}} 224} 225 226@implementation Rdar15037033 227 228+ (void)forwardDeclaredMethod { 229 clang_analyzer_checkInlined(1); // expected-warning{{TRUE}} 230} 231 232+ (void)forwardDeclaredVariadicMethod:(int)x, ... { 233 clang_analyzer_checkInlined(0); // no-warning 234} 235@end 236 237@interface SelfClassTestParent : NSObject 238-(unsigned)returns10; 239+(unsigned)returns20; 240+(unsigned)returns30; 241@end 242 243@implementation SelfClassTestParent 244-(unsigned)returns10 { return 100; } 245+(unsigned)returns20 { return 100; } 246+(unsigned)returns30 { return 100; } 247@end 248 249@interface SelfClassTest : SelfClassTestParent 250-(unsigned)returns10; 251+(unsigned)returns20; 252+(unsigned)returns30; 253@end 254 255@implementation SelfClassTest 256-(unsigned)returns10 { return 10; } 257+(unsigned)returns20 { return 20; } 258+(unsigned)returns30 { return 30; } 259+(void)classMethod { 260 unsigned result1 = [self returns20]; 261 clang_analyzer_eval(result1 == 20); // expected-warning{{TRUE}} 262 unsigned result2 = [[self class] returns30]; 263 clang_analyzer_eval(result2 == 30); // expected-warning{{TRUE}} 264 unsigned result3 = [[super class] returns30]; 265 clang_analyzer_eval(result3 == 100); // expected-warning{{UNKNOWN}} 266} 267-(void)instanceMethod { 268 unsigned result0 = [self returns10]; 269 clang_analyzer_eval(result0 == 10); // expected-warning{{TRUE}} 270 unsigned result2 = [[self class] returns30]; 271 clang_analyzer_eval(result2 == 30); // expected-warning{{TRUE}} 272 unsigned result3 = [[super class] returns30]; 273 clang_analyzer_eval(result3 == 100); // expected-warning{{UNKNOWN}} 274} 275@end 276 277@interface Parent : NSObject 278+ (int)a; 279+ (int)b; 280@end 281@interface Child : Parent 282@end 283@interface Other : NSObject 284+(void)run; 285@end 286int main(int argc, const char * argv[]) { 287 @autoreleasepool { 288 [Other run]; 289 } 290 return 0; 291} 292@implementation Other 293+(void)run { 294 int result = [Child a]; 295 // TODO: This should return 100. 296 clang_analyzer_eval(result == 12); // expected-warning{{TRUE}} 297} 298@end 299@implementation Parent 300+ (int)a; { 301 return [self b]; 302} 303+ (int)b; { 304 return 12; 305} 306@end 307@implementation Child 308+ (int)b; { 309 return 100; 310} 311@end 312