diff options
Diffstat (limited to 'test/Analysis/inlining/InlineObjCClassMethod.m')
-rw-r--r-- | test/Analysis/inlining/InlineObjCClassMethod.m | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/test/Analysis/inlining/InlineObjCClassMethod.m b/test/Analysis/inlining/InlineObjCClassMethod.m new file mode 100644 index 0000000000000..7e8b51fe0be05 --- /dev/null +++ b/test/Analysis/inlining/InlineObjCClassMethod.m @@ -0,0 +1,181 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=dynamic-bifurcate -verify %s + +// Test inlining of ObjC class methods. + +typedef signed char BOOL; +typedef struct objc_class *Class; +typedef struct objc_object { + Class isa; +} *id; +@protocol NSObject - (BOOL)isEqual:(id)object; @end +@interface NSObject <NSObject> {} ++(id)alloc; +-(id)init; +-(id)autorelease; +-(id)copy; +- (Class)class; +-(id)retain; +@end + +// Vanila: ObjC class method is called by name. +@interface MyParent : NSObject ++ (int)getInt; +@end +@interface MyClass : MyParent ++ (int)getInt; +@end +@implementation MyClass ++ (int)testClassMethodByName { + int y = [MyClass getInt]; + return 5/y; // expected-warning {{Division by zero}} +} ++ (int)getInt { + return 0; +} +@end + +// The definition is defined by the parent. Make sure we find it and inline. +@interface MyParentDIP : NSObject ++ (int)getInt; +@end +@interface MyClassDIP : MyParentDIP +@end +@implementation MyClassDIP ++ (int)testClassMethodByName { + int y = [MyClassDIP getInt]; + return 5/y; // expected-warning {{Division by zero}} +} +@end +@implementation MyParentDIP ++ (int)getInt { + return 0; +} +@end + +// ObjC class method is called by name. Definition is in the category. +@interface AAA : NSObject +@end +@interface AAA (MyCat) ++ (int)getInt; +@end +int foo() { + int y = [AAA getInt]; + return 5/y; // expected-warning {{Division by zero}} +} +@implementation AAA +@end +@implementation AAA (MyCat) ++ (int)getInt { + return 0; +} +@end + +// ObjC class method is called by name. Definition is in the parent category. +@interface PPP : NSObject +@end +@interface PPP (MyCat) ++ (int)getInt; +@end +@interface CCC : PPP +@end +int foo4() { + int y = [CCC getInt]; + return 5/y; // expected-warning {{Division by zero}} +} +@implementation PPP +@end +@implementation PPP (MyCat) ++ (int)getInt { + return 0; +} +@end + +// There is no declaration in the class but there is one in the parent. Make +// sure we pick the definition from the class and not the parent. +@interface MyParentTricky : NSObject ++ (int)getInt; +@end +@interface MyClassTricky : MyParentTricky +@end +@implementation MyParentTricky ++ (int)getInt { + return 0; +} +@end +@implementation MyClassTricky ++ (int)getInt { + return 1; +} ++ (int)testClassMethodByName { + int y = [MyClassTricky getInt]; + return 5/y; // no-warning +} +@end + +// ObjC class method is called by unknown class declaration (passed in as a +// parameter). We should not inline in such case. +@interface MyParentUnknown : NSObject ++ (int)getInt; +@end +@interface MyClassUnknown : MyParentUnknown ++ (int)getInt; +@end +@implementation MyClassUnknown ++ (int)testClassVariableByUnknownVarDecl: (Class)cl { + int y = [cl getInt]; + return 3/y; // no-warning +} ++ (int)getInt { + return 0; +} +@end + + +// False negative. +// ObjC class method call through a decl with a known type. +// We should be able to track the type of currentClass and inline this call. +// Note, [self class] could be a subclass. Do we still want to inline here? +@interface MyClassKT : NSObject +@end +@interface MyClassKT (MyCatKT) ++ (int)getInt; +@end +@implementation MyClassKT (MyCatKT) ++ (int)getInt { + return 0; +} +@end +@implementation MyClassKT +- (int)testClassMethodByKnownVarDecl { + Class currentClass = [self class]; + int y = [currentClass getInt]; + return 5/y; // Would be great to get a warning here. +} +@end + +// Another false negative due to us not reasoning about self, which in this +// case points to the object of the class in the call site and should be equal +// to [MyParent class]. +@interface MyParentSelf : NSObject ++ (int)testSelf; +@end +@implementation MyParentSelf ++ (int)testSelf { + if (self == [MyParentSelf class]) + return 0; + else + return 1; +} +@end +@interface MyClassSelf : MyParentSelf +@end +@implementation MyClassSelf ++ (int)testClassMethodByKnownVarDecl { + int y = [MyParentSelf testSelf]; + return 5/y; // Should warn here. +} +@end +int foo2() { + int y = [MyParentSelf testSelf]; + return 5/y; // Should warn here. +} |