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;
9#define YES ((BOOL)1)
10#define NO ((BOOL)0)
11typedef struct objc_class *Class;
12typedef 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
29
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}}
41}
42+ (int)getInt {
43  return 0;
44}
45@end
46
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}}
57}
58@end
59@implementation MyParentDIP
60+ (int)getInt {
61    return 0;
62}
63@end
64
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
71int foo() {
72    int y = [AAA getInt];
73    return 5/y; // expected-warning {{Division by zero}}
74}
75@implementation AAA
76@end
77@implementation AAA (MyCat)
78+ (int)getInt {
79    return 0;
80}
81@end
82
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
91int foo4() {
92    int y = [CCC getInt];
93    return 5/y; // expected-warning {{Division by zero}}
94}
95@implementation PPP
96@end
97@implementation PPP (MyCat)
98+ (int)getInt {
99    return 0;
100}
101@end
102
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;
113}
114@end
115@implementation MyClassTricky
116+ (int)getInt {
117  return 1;
118}
119+ (int)testClassMethodByName {
120    int y = [MyClassTricky getInt];
121    return 5/y; // no-warning
122}
123@end
124
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
137}
138+ (int)getInt {
139  return 0;
140}
141@end
142
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;
153}
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}}
160}
161@end
162
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;
175}
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}}
183}
184@end
185int foo2() {
186  int y = [MyParentSelf testSelf];
187  return 5/y; // expected-warning{{Division by zero}}
188}
189
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;
205}
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];
215}
216@end
217int checkSelfUsedInparentClassMethod() {
218    return 5/[SelfUsedInParentChild fooA];
219}
220
221
222@interface Rdar15037033 : NSObject
223@end
224
225void rdar15037033() {
226  [Rdar15037033 forwardDeclaredMethod]; // expected-warning {{class method '+forwardDeclaredMethod' not found}}
227  [Rdar15037033 forwardDeclaredVariadicMethod:1, 2, 3, 0]; // expected-warning {{class method '+forwardDeclaredVariadicMethod:' not found}}
228}
229
230@implementation Rdar15037033
231
232+ (void)forwardDeclaredMethod {
233  clang_analyzer_checkInlined(1); // expected-warning{{TRUE}}
234}
235
236+ (void)forwardDeclaredVariadicMethod:(int)x, ... {
237  clang_analyzer_checkInlined(0); // no-warning
238}
239@end
240
241@interface SelfClassTestParent : NSObject
242-(unsigned)returns10;
243+(unsigned)returns20;
244+(unsigned)returns30;
245@end
246
247@interface SelfClassTest : SelfClassTestParent
248- (unsigned)returns10;
249+ (unsigned)returns20;
250+ (unsigned)returns30;
251@end
252
253@implementation SelfClassTestParent
254- (unsigned)returns10 {
255  return 100;
256}
257+ (unsigned)returns20 {
258  return 100;
259}
260+ (unsigned)returns30 {
261  return 100;
262}
263
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}}
270}
271@end
272
273@implementation SelfClassTest
274- (unsigned)returns10 {
275  return 10;
276}
277+ (unsigned)returns20 {
278  return 20;
279}
280+ (unsigned)returns30 {
281  return 30;
282}
283+ (BOOL)isClass {
284  return YES;
285}
286- (BOOL)isClass {
287  return NO;
288}
289+ (SelfClassTest *)create {
290  return [[self alloc] init];
291}
292+ (void)classMethod {
293  unsigned result1 = [self returns20];
294  clang_analyzer_eval(result1 == 20); // expected-warning{{TRUE}}
295
296  unsigned result2 = [[self class] returns30];
297  clang_analyzer_eval(result2 == 30); // expected-warning{{TRUE}}
298
299  unsigned result3 = [[super class] returns30];
300  clang_analyzer_eval(result3 == 100); // expected-warning{{TRUE}}
301
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}}
307
308  Class class51 = [super class];
309  Class class52 = class51;
310  unsigned result5 = [class52 returns30];
311  clang_analyzer_eval(result5 == 100); // expected-warning{{TRUE}}
312}
313- (void)instanceMethod {
314  unsigned result0 = [self returns10];
315  clang_analyzer_eval(result0 == 10); // expected-warning{{TRUE}}
316
317  unsigned result2 = [[self class] returns30];
318  clang_analyzer_eval(result2 == 30); // expected-warning{{TRUE}}
319
320  unsigned result3 = [[super class] returns30];
321  clang_analyzer_eval(result3 == 100); // expected-warning{{TRUE}}
322
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}}
328
329  Class class51 = [super class];
330  Class class52 = class51;
331  unsigned result5 = [class52 returns30];
332  clang_analyzer_eval(result5 == 100); // expected-warning{{TRUE}}
333
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}}
338
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}}
344
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}}
350
351  Class class9 = [SelfClassTest superclass];
352  unsigned result9 = [class9 returns30];
353  clang_analyzer_eval(result9 == 100); // expected-warning{{TRUE}}
354
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}}
360
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}}
365}
366@end
367
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
377int main(int argc, const char * argv[]) {
378  @autoreleasepool {
379    [Other run];
380  }
381  return 0;
382}
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}}
388}
389@end
390@implementation Parent
391+ (int)a; {
392  return [self b];
393}
394+ (int)b; {
395  return 12;
396}
397@end
398@implementation Child
399+ (int)b; {
400  return 100;
401}
402@end
403