Clang Project

clang_source_code/test/Analysis/inlining/InlineObjCClassMethod.m
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;
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