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;
11 typedef struct objc_class *Class;
12 typedef struct objc_object {
16 - (BOOL)isEqual:(id)object;
18 @interface NSObject <NSObject> {}
30 // Vanila: ObjC class method is called by name.
31 @interface MyParent : NSObject
34 @interface MyClass : MyParent
37 @implementation MyClass
38 + (int)testClassMethodByName {
39 int y = [MyClass getInt];
40 return 5/y; // expected-warning {{Division by zero}}
47 // The definition is defined by the parent. Make sure we find it and inline.
48 @interface MyParentDIP : NSObject
51 @interface MyClassDIP : MyParentDIP
53 @implementation MyClassDIP
54 + (int)testClassMethodByName {
55 int y = [MyClassDIP getInt];
56 return 5/y; // expected-warning {{Division by zero}}
59 @implementation MyParentDIP
65 // ObjC class method is called by name. Definition is in the category.
66 @interface AAA : NSObject
68 @interface AAA (MyCat)
73 return 5/y; // expected-warning {{Division by zero}}
77 @implementation AAA (MyCat)
83 // ObjC class method is called by name. Definition is in the parent category.
84 @interface PPP : NSObject
86 @interface PPP (MyCat)
93 return 5/y; // expected-warning {{Division by zero}}
97 @implementation PPP (MyCat)
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
108 @interface MyClassTricky : MyParentTricky
110 @implementation MyParentTricky
115 @implementation MyClassTricky
119 + (int)testClassMethodByName {
120 int y = [MyClassTricky getInt];
121 return 5/y; // no-warning
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
130 @interface MyClassUnknown : MyParentUnknown
133 @implementation MyClassUnknown
134 + (int)testClassVariableByUnknownVarDecl: (Class)cl {
136 return 3/y; // no-warning
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
147 @interface MyClassKT (MyCatKT)
150 @implementation MyClassKT (MyCatKT)
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}}
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
169 @implementation MyParentSelf
171 if (self == [MyParentSelf class])
177 @interface MyClassSelf : MyParentSelf
179 @implementation MyClassSelf
180 + (int)testClassMethodByKnownVarDecl {
181 int y = [MyParentSelf testSelf];
182 return 5/y; // expected-warning{{Division by zero}}
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
199 @implementation SelfUsedInParent
200 + (int)getNum {return 5;}
202 int r = [self getNum];
203 clang_analyzer_eval(r == 5); // expected-warning{{TRUE}}
207 @interface SelfUsedInParentChild : SelfUsedInParent
211 @implementation SelfUsedInParentChild
212 + (int)getNum {return 0;}
217 int checkSelfUsedInparentClassMethod(void) {
218 return 5/[SelfUsedInParentChild fooA];
222 @interface Rdar15037033 : NSObject
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
241 @interface SelfClassTestParent : NSObject
242 -(unsigned)returns10;
243 +(unsigned)returns20;
244 +(unsigned)returns30;
247 @interface SelfClassTest : SelfClassTestParent
248 - (unsigned)returns10;
249 + (unsigned)returns20;
250 + (unsigned)returns30;
253 @implementation SelfClassTestParent
254 - (unsigned)returns10 {
257 + (unsigned)returns20 {
260 + (unsigned)returns30 {
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}}
273 @implementation SelfClassTest
274 - (unsigned)returns10 {
277 + (unsigned)returns20 {
280 + (unsigned)returns30 {
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}}
368 @interface Parent : NSObject
372 @interface Child : Parent
374 @interface Other : NSObject
377 int main(int argc, const char * argv[]) {
383 @implementation Other
385 int result = [Child a];
386 // TODO: This should return 100.
387 clang_analyzer_eval(result == 12); // expected-warning{{TRUE}}
390 @implementation Parent
398 @implementation Child