blob: 7e8b51fe0be05b56b263b87edc232ceb32c6ff61 [file] [log] [blame]
Anna Zaks54918ba2012-08-10 18:55:58 +00001// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=dynamic-bifurcate -verify %s
Anna Zaks9dc51672012-07-26 00:27:51 +00002
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
Anna Zakse13056a2012-07-30 20:31:18 +000073// ObjC class method is called by name. Definition is in the parent category.
74@interface PPP : NSObject
75@end
76@interface PPP (MyCat)
77+ (int)getInt;
78@end
79@interface CCC : PPP
80@end
81int foo4() {
82 int y = [CCC getInt];
83 return 5/y; // expected-warning {{Division by zero}}
84}
85@implementation PPP
86@end
87@implementation PPP (MyCat)
88+ (int)getInt {
89 return 0;
90}
91@end
92
Anna Zaks9dc51672012-07-26 00:27:51 +000093// There is no declaration in the class but there is one in the parent. Make
94// sure we pick the definition from the class and not the parent.
95@interface MyParentTricky : NSObject
96+ (int)getInt;
97@end
98@interface MyClassTricky : MyParentTricky
99@end
100@implementation MyParentTricky
101+ (int)getInt {
102 return 0;
103}
104@end
105@implementation MyClassTricky
106+ (int)getInt {
107 return 1;
108}
109+ (int)testClassMethodByName {
110 int y = [MyClassTricky getInt];
111 return 5/y; // no-warning
112}
113@end
114
115// ObjC class method is called by unknown class declaration (passed in as a
116// parameter). We should not inline in such case.
117@interface MyParentUnknown : NSObject
118+ (int)getInt;
119@end
120@interface MyClassUnknown : MyParentUnknown
121+ (int)getInt;
122@end
123@implementation MyClassUnknown
124+ (int)testClassVariableByUnknownVarDecl: (Class)cl {
125 int y = [cl getInt];
126 return 3/y; // no-warning
127}
128+ (int)getInt {
129 return 0;
130}
131@end
132
133
134// False negative.
135// ObjC class method call through a decl with a known type.
136// We should be able to track the type of currentClass and inline this call.
Anna Zaks6fbe0312012-07-27 19:07:32 +0000137// Note, [self class] could be a subclass. Do we still want to inline here?
Anna Zaks9dc51672012-07-26 00:27:51 +0000138@interface MyClassKT : NSObject
139@end
140@interface MyClassKT (MyCatKT)
141+ (int)getInt;
142@end
143@implementation MyClassKT (MyCatKT)
144+ (int)getInt {
145 return 0;
146}
147@end
148@implementation MyClassKT
149- (int)testClassMethodByKnownVarDecl {
150 Class currentClass = [self class];
151 int y = [currentClass getInt];
152 return 5/y; // Would be great to get a warning here.
153}
154@end
Anna Zaksbccc5942012-07-27 19:07:34 +0000155
156// Another false negative due to us not reasoning about self, which in this
157// case points to the object of the class in the call site and should be equal
158// to [MyParent class].
159@interface MyParentSelf : NSObject
160+ (int)testSelf;
161@end
162@implementation MyParentSelf
163+ (int)testSelf {
164 if (self == [MyParentSelf class])
165 return 0;
166 else
167 return 1;
168}
169@end
170@interface MyClassSelf : MyParentSelf
171@end
172@implementation MyClassSelf
173+ (int)testClassMethodByKnownVarDecl {
174 int y = [MyParentSelf testSelf];
175 return 5/y; // Should warn here.
176}
177@end
178int foo2() {
179 int y = [MyParentSelf testSelf];
180 return 5/y; // Should warn here.
181}