[TableGen] Fix validateOperandClass for non Phyical Reg (#118146)
[llvm-project.git] / clang / test / Analysis / inlining / InlineObjCClassMethod.m
blob7ce8ea8f5687b58f9c2f66126db4bdbf8d0b3890
1 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-config ipa=dynamic-bifurcate -verify -analyzer-config eagerly-assume=false %s
3 void clang_analyzer_checkInlined(int);
4 void clang_analyzer_eval(int);
6 // Test inlining of ObjC class methods.
8 typedef signed char BOOL;
9 #define YES ((BOOL)1)
10 #define NO ((BOOL)0)
11 typedef struct objc_class *Class;
12 typedef 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
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}}
42 + (int)getInt {
43   return 0;
45 @end
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}}
58 @end
59 @implementation MyParentDIP
60 + (int)getInt {
61     return 0;
63 @end
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
71 int foo(void) {
72     int y = [AAA getInt];
73     return 5/y; // expected-warning {{Division by zero}}
75 @implementation AAA
76 @end
77 @implementation AAA (MyCat)
78 + (int)getInt {
79     return 0;
81 @end
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
91 int foo4(void) {
92     int y = [CCC getInt];
93     return 5/y; // expected-warning {{Division by zero}}
95 @implementation PPP
96 @end
97 @implementation PPP (MyCat)
98 + (int)getInt {
99     return 0;
101 @end
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;
114 @end
115 @implementation MyClassTricky
116 + (int)getInt {
117   return 1;
119 + (int)testClassMethodByName {
120     int y = [MyClassTricky getInt];
121     return 5/y; // no-warning
123 @end
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
138 + (int)getInt {
139   return 0;
141 @end
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;
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}}
161 @end
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;
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}}
184 @end
185 int foo2(void) {
186   int y = [MyParentSelf testSelf];
187   return 5/y; // expected-warning{{Division by zero}}
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;
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];
216 @end
217 int checkSelfUsedInparentClassMethod(void) {
218     return 5/[SelfUsedInParentChild fooA];
222 @interface Rdar15037033 : NSObject
223 @end
225 void rdar15037033(void) {
226   [Rdar15037033 forwardDeclaredMethod]; // expected-warning {{class method '+forwardDeclaredMethod' not found}}
227   [Rdar15037033 forwardDeclaredVariadicMethod:1, 2, 3, 0]; // expected-warning {{class method '+forwardDeclaredVariadicMethod:' not found}}
230 @implementation Rdar15037033
232 + (void)forwardDeclaredMethod {
233   clang_analyzer_checkInlined(1); // expected-warning{{TRUE}}
236 + (void)forwardDeclaredVariadicMethod:(int)x, ... {
237   clang_analyzer_checkInlined(0); // no-warning
239 @end
241 @interface SelfClassTestParent : NSObject
242 -(unsigned)returns10;
243 +(unsigned)returns20;
244 +(unsigned)returns30;
245 @end
247 @interface SelfClassTest : SelfClassTestParent
248 - (unsigned)returns10;
249 + (unsigned)returns20;
250 + (unsigned)returns30;
251 @end
253 @implementation SelfClassTestParent
254 - (unsigned)returns10 {
255   return 100;
257 + (unsigned)returns20 {
258   return 100;
260 + (unsigned)returns30 {
261   return 100;
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}}
271 @end
273 @implementation SelfClassTest
274 - (unsigned)returns10 {
275   return 10;
277 + (unsigned)returns20 {
278   return 20;
280 + (unsigned)returns30 {
281   return 30;
283 + (BOOL)isClass {
284   return YES;
286 - (BOOL)isClass {
287   return NO;
289 + (SelfClassTest *)create {
290   return [[self alloc] init];
292 + (void)classMethod {
293   unsigned result1 = [self returns20];
294   clang_analyzer_eval(result1 == 20); // expected-warning{{TRUE}}
296   unsigned result2 = [[self class] returns30];
297   clang_analyzer_eval(result2 == 30); // expected-warning{{TRUE}}
299   unsigned result3 = [[super class] returns30];
300   clang_analyzer_eval(result3 == 100); // expected-warning{{TRUE}}
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}}
308   Class class51 = [super class];
309   Class class52 = class51;
310   unsigned result5 = [class52 returns30];
311   clang_analyzer_eval(result5 == 100); // expected-warning{{TRUE}}
313 - (void)instanceMethod {
314   unsigned result0 = [self returns10];
315   clang_analyzer_eval(result0 == 10); // expected-warning{{TRUE}}
317   unsigned result2 = [[self class] returns30];
318   clang_analyzer_eval(result2 == 30); // expected-warning{{TRUE}}
320   unsigned result3 = [[super class] returns30];
321   clang_analyzer_eval(result3 == 100); // expected-warning{{TRUE}}
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}}
329   Class class51 = [super class];
330   Class class52 = class51;
331   unsigned result5 = [class52 returns30];
332   clang_analyzer_eval(result5 == 100); // expected-warning{{TRUE}}
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}}
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}}
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}}
351   Class class9 = [SelfClassTest superclass];
352   unsigned result9 = [class9 returns30];
353   clang_analyzer_eval(result9 == 100); // expected-warning{{TRUE}}
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}}
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}}
366 @end
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
377 int main(int argc, const char * argv[]) {
378   @autoreleasepool {
379     [Other run];
380   }
381   return 0;
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}}
389 @end
390 @implementation Parent
391 + (int)a; {
392   return [self b];
394 + (int)b; {
395   return 12;
397 @end
398 @implementation Child
399 + (int)b; {
400   return 100;
402 @end