InlineObjCClassMethod.m revision 6fbe0317aa38dbac22a29f7519c52db838aa1990
1// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify %s
2
3// Test inlining of ObjC class methods.
4
5typedef signed char BOOL;
6typedef struct objc_class *Class;
7typedef struct objc_object {
8    Class isa;
9} *id;
10@protocol NSObject  - (BOOL)isEqual:(id)object; @end
11@interface NSObject <NSObject> {}
12+(id)alloc;
13-(id)init;
14-(id)autorelease;
15-(id)copy;
16- (Class)class;
17-(id)retain;
18@end
19
20// Vanila: ObjC class method is called by name.
21@interface MyParent : NSObject
22+ (int)getInt;
23@end
24@interface MyClass : MyParent
25+ (int)getInt;
26@end
27@implementation MyClass
28+ (int)testClassMethodByName {
29    int y = [MyClass getInt];
30    return 5/y; // expected-warning {{Division by zero}}
31}
32+ (int)getInt {
33  return 0;
34}
35@end
36
37// The definition is defined by the parent. Make sure we find it and inline.
38@interface MyParentDIP : NSObject
39+ (int)getInt;
40@end
41@interface MyClassDIP : MyParentDIP
42@end
43@implementation MyClassDIP
44+ (int)testClassMethodByName {
45    int y = [MyClassDIP getInt];
46    return 5/y; // expected-warning {{Division by zero}}
47}
48@end
49@implementation MyParentDIP
50+ (int)getInt {
51    return 0;
52}
53@end
54
55// ObjC class method is called by name. Definition is in the category.
56@interface AAA : NSObject
57@end
58@interface AAA (MyCat)
59+ (int)getInt;
60@end
61int foo() {
62    int y = [AAA getInt];
63    return 5/y; // expected-warning {{Division by zero}}
64}
65@implementation AAA
66@end
67@implementation AAA (MyCat)
68+ (int)getInt {
69    return 0;
70}
71@end
72
73// There is no declaration in the class but there is one in the parent. Make 
74// sure we pick the definition from the class and not the parent.
75@interface MyParentTricky : NSObject
76+ (int)getInt;
77@end
78@interface MyClassTricky : MyParentTricky
79@end
80@implementation MyParentTricky
81+ (int)getInt {
82    return 0;
83}
84@end
85@implementation MyClassTricky
86+ (int)getInt {
87  return 1;
88}
89+ (int)testClassMethodByName {
90    int y = [MyClassTricky getInt];
91    return 5/y; // no-warning
92}
93@end
94
95// ObjC class method is called by unknown class declaration (passed in as a 
96// parameter). We should not inline in such case.
97@interface MyParentUnknown : NSObject
98+ (int)getInt;
99@end
100@interface MyClassUnknown : MyParentUnknown
101+ (int)getInt;
102@end
103@implementation MyClassUnknown
104+ (int)testClassVariableByUnknownVarDecl: (Class)cl  {
105  int y = [cl getInt];
106  return 3/y; // no-warning
107}
108+ (int)getInt {
109  return 0;
110}
111@end
112
113
114// False negative.
115// ObjC class method call through a decl with a known type.
116// We should be able to track the type of currentClass and inline this call.
117// Note, [self class] could be a subclass. Do we still want to inline here?
118@interface MyClassKT : NSObject
119@end
120@interface MyClassKT (MyCatKT)
121+ (int)getInt;
122@end
123@implementation MyClassKT (MyCatKT)
124+ (int)getInt {
125    return 0;
126}
127@end
128@implementation MyClassKT
129- (int)testClassMethodByKnownVarDecl {
130  Class currentClass = [self class];
131  int y = [currentClass getInt];
132  return 5/y; // Would be great to get a warning here.
133}
134@end
135