xref: /minix3/external/bsd/llvm/dist/clang/test/Analysis/inlining/InlineObjCClassMethod.m (revision f4a2713ac843a11c696ec80c0a5e3e5d80b4d338)
1*f4a2713aSLionel Sambuc// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-config ipa=dynamic-bifurcate -verify %s
2*f4a2713aSLionel Sambuc
3*f4a2713aSLionel Sambucvoid clang_analyzer_checkInlined(int);
4*f4a2713aSLionel Sambuc
5*f4a2713aSLionel Sambuc// Test inlining of ObjC class methods.
6*f4a2713aSLionel Sambuc
7*f4a2713aSLionel Sambuctypedef signed char BOOL;
8*f4a2713aSLionel Sambuctypedef struct objc_class *Class;
9*f4a2713aSLionel Sambuctypedef struct objc_object {
10*f4a2713aSLionel Sambuc    Class isa;
11*f4a2713aSLionel Sambuc} *id;
12*f4a2713aSLionel Sambuc@protocol NSObject  - (BOOL)isEqual:(id)object; @end
13*f4a2713aSLionel Sambuc@interface NSObject <NSObject> {}
14*f4a2713aSLionel Sambuc+(id)alloc;
15*f4a2713aSLionel Sambuc-(id)init;
16*f4a2713aSLionel Sambuc-(id)autorelease;
17*f4a2713aSLionel Sambuc-(id)copy;
18*f4a2713aSLionel Sambuc- (Class)class;
19*f4a2713aSLionel Sambuc-(id)retain;
20*f4a2713aSLionel Sambuc@end
21*f4a2713aSLionel Sambuc
22*f4a2713aSLionel Sambuc// Vanila: ObjC class method is called by name.
23*f4a2713aSLionel Sambuc@interface MyParent : NSObject
24*f4a2713aSLionel Sambuc+ (int)getInt;
25*f4a2713aSLionel Sambuc@end
26*f4a2713aSLionel Sambuc@interface MyClass : MyParent
27*f4a2713aSLionel Sambuc+ (int)getInt;
28*f4a2713aSLionel Sambuc@end
29*f4a2713aSLionel Sambuc@implementation MyClass
30*f4a2713aSLionel Sambuc+ (int)testClassMethodByName {
31*f4a2713aSLionel Sambuc    int y = [MyClass getInt];
32*f4a2713aSLionel Sambuc    return 5/y; // expected-warning {{Division by zero}}
33*f4a2713aSLionel Sambuc}
34*f4a2713aSLionel Sambuc+ (int)getInt {
35*f4a2713aSLionel Sambuc  return 0;
36*f4a2713aSLionel Sambuc}
37*f4a2713aSLionel Sambuc@end
38*f4a2713aSLionel Sambuc
39*f4a2713aSLionel Sambuc// The definition is defined by the parent. Make sure we find it and inline.
40*f4a2713aSLionel Sambuc@interface MyParentDIP : NSObject
41*f4a2713aSLionel Sambuc+ (int)getInt;
42*f4a2713aSLionel Sambuc@end
43*f4a2713aSLionel Sambuc@interface MyClassDIP : MyParentDIP
44*f4a2713aSLionel Sambuc@end
45*f4a2713aSLionel Sambuc@implementation MyClassDIP
46*f4a2713aSLionel Sambuc+ (int)testClassMethodByName {
47*f4a2713aSLionel Sambuc    int y = [MyClassDIP getInt];
48*f4a2713aSLionel Sambuc    return 5/y; // expected-warning {{Division by zero}}
49*f4a2713aSLionel Sambuc}
50*f4a2713aSLionel Sambuc@end
51*f4a2713aSLionel Sambuc@implementation MyParentDIP
52*f4a2713aSLionel Sambuc+ (int)getInt {
53*f4a2713aSLionel Sambuc    return 0;
54*f4a2713aSLionel Sambuc}
55*f4a2713aSLionel Sambuc@end
56*f4a2713aSLionel Sambuc
57*f4a2713aSLionel Sambuc// ObjC class method is called by name. Definition is in the category.
58*f4a2713aSLionel Sambuc@interface AAA : NSObject
59*f4a2713aSLionel Sambuc@end
60*f4a2713aSLionel Sambuc@interface AAA (MyCat)
61*f4a2713aSLionel Sambuc+ (int)getInt;
62*f4a2713aSLionel Sambuc@end
63*f4a2713aSLionel Sambucint foo() {
64*f4a2713aSLionel Sambuc    int y = [AAA getInt];
65*f4a2713aSLionel Sambuc    return 5/y; // expected-warning {{Division by zero}}
66*f4a2713aSLionel Sambuc}
67*f4a2713aSLionel Sambuc@implementation AAA
68*f4a2713aSLionel Sambuc@end
69*f4a2713aSLionel Sambuc@implementation AAA (MyCat)
70*f4a2713aSLionel Sambuc+ (int)getInt {
71*f4a2713aSLionel Sambuc    return 0;
72*f4a2713aSLionel Sambuc}
73*f4a2713aSLionel Sambuc@end
74*f4a2713aSLionel Sambuc
75*f4a2713aSLionel Sambuc// ObjC class method is called by name. Definition is in the parent category.
76*f4a2713aSLionel Sambuc@interface PPP : NSObject
77*f4a2713aSLionel Sambuc@end
78*f4a2713aSLionel Sambuc@interface PPP (MyCat)
79*f4a2713aSLionel Sambuc+ (int)getInt;
80*f4a2713aSLionel Sambuc@end
81*f4a2713aSLionel Sambuc@interface CCC : PPP
82*f4a2713aSLionel Sambuc@end
83*f4a2713aSLionel Sambucint foo4() {
84*f4a2713aSLionel Sambuc    int y = [CCC getInt];
85*f4a2713aSLionel Sambuc    return 5/y; // expected-warning {{Division by zero}}
86*f4a2713aSLionel Sambuc}
87*f4a2713aSLionel Sambuc@implementation PPP
88*f4a2713aSLionel Sambuc@end
89*f4a2713aSLionel Sambuc@implementation PPP (MyCat)
90*f4a2713aSLionel Sambuc+ (int)getInt {
91*f4a2713aSLionel Sambuc    return 0;
92*f4a2713aSLionel Sambuc}
93*f4a2713aSLionel Sambuc@end
94*f4a2713aSLionel Sambuc
95*f4a2713aSLionel Sambuc// There is no declaration in the class but there is one in the parent. Make
96*f4a2713aSLionel Sambuc// sure we pick the definition from the class and not the parent.
97*f4a2713aSLionel Sambuc@interface MyParentTricky : NSObject
98*f4a2713aSLionel Sambuc+ (int)getInt;
99*f4a2713aSLionel Sambuc@end
100*f4a2713aSLionel Sambuc@interface MyClassTricky : MyParentTricky
101*f4a2713aSLionel Sambuc@end
102*f4a2713aSLionel Sambuc@implementation MyParentTricky
103*f4a2713aSLionel Sambuc+ (int)getInt {
104*f4a2713aSLionel Sambuc    return 0;
105*f4a2713aSLionel Sambuc}
106*f4a2713aSLionel Sambuc@end
107*f4a2713aSLionel Sambuc@implementation MyClassTricky
108*f4a2713aSLionel Sambuc+ (int)getInt {
109*f4a2713aSLionel Sambuc  return 1;
110*f4a2713aSLionel Sambuc}
111*f4a2713aSLionel Sambuc+ (int)testClassMethodByName {
112*f4a2713aSLionel Sambuc    int y = [MyClassTricky getInt];
113*f4a2713aSLionel Sambuc    return 5/y; // no-warning
114*f4a2713aSLionel Sambuc}
115*f4a2713aSLionel Sambuc@end
116*f4a2713aSLionel Sambuc
117*f4a2713aSLionel Sambuc// ObjC class method is called by unknown class declaration (passed in as a
118*f4a2713aSLionel Sambuc// parameter). We should not inline in such case.
119*f4a2713aSLionel Sambuc@interface MyParentUnknown : NSObject
120*f4a2713aSLionel Sambuc+ (int)getInt;
121*f4a2713aSLionel Sambuc@end
122*f4a2713aSLionel Sambuc@interface MyClassUnknown : MyParentUnknown
123*f4a2713aSLionel Sambuc+ (int)getInt;
124*f4a2713aSLionel Sambuc@end
125*f4a2713aSLionel Sambuc@implementation MyClassUnknown
126*f4a2713aSLionel Sambuc+ (int)testClassVariableByUnknownVarDecl: (Class)cl  {
127*f4a2713aSLionel Sambuc  int y = [cl getInt];
128*f4a2713aSLionel Sambuc  return 3/y; // no-warning
129*f4a2713aSLionel Sambuc}
130*f4a2713aSLionel Sambuc+ (int)getInt {
131*f4a2713aSLionel Sambuc  return 0;
132*f4a2713aSLionel Sambuc}
133*f4a2713aSLionel Sambuc@end
134*f4a2713aSLionel Sambuc
135*f4a2713aSLionel Sambuc
136*f4a2713aSLionel Sambuc// False negative.
137*f4a2713aSLionel Sambuc// ObjC class method call through a decl with a known type.
138*f4a2713aSLionel Sambuc// We should be able to track the type of currentClass and inline this call.
139*f4a2713aSLionel Sambuc// Note, [self class] could be a subclass. Do we still want to inline here?
140*f4a2713aSLionel Sambuc@interface MyClassKT : NSObject
141*f4a2713aSLionel Sambuc@end
142*f4a2713aSLionel Sambuc@interface MyClassKT (MyCatKT)
143*f4a2713aSLionel Sambuc+ (int)getInt;
144*f4a2713aSLionel Sambuc@end
145*f4a2713aSLionel Sambuc@implementation MyClassKT (MyCatKT)
146*f4a2713aSLionel Sambuc+ (int)getInt {
147*f4a2713aSLionel Sambuc    return 0;
148*f4a2713aSLionel Sambuc}
149*f4a2713aSLionel Sambuc@end
150*f4a2713aSLionel Sambuc@implementation MyClassKT
151*f4a2713aSLionel Sambuc- (int)testClassMethodByKnownVarDecl {
152*f4a2713aSLionel Sambuc  Class currentClass = [self class];
153*f4a2713aSLionel Sambuc  int y = [currentClass getInt];
154*f4a2713aSLionel Sambuc  return 5/y; // Would be great to get a warning here.
155*f4a2713aSLionel Sambuc}
156*f4a2713aSLionel Sambuc@end
157*f4a2713aSLionel Sambuc
158*f4a2713aSLionel Sambuc// Another false negative due to us not reasoning about self, which in this
159*f4a2713aSLionel Sambuc// case points to the object of the class in the call site and should be equal
160*f4a2713aSLionel Sambuc// to [MyParent class].
161*f4a2713aSLionel Sambuc@interface MyParentSelf : NSObject
162*f4a2713aSLionel Sambuc+ (int)testSelf;
163*f4a2713aSLionel Sambuc@end
164*f4a2713aSLionel Sambuc@implementation MyParentSelf
165*f4a2713aSLionel Sambuc+ (int)testSelf {
166*f4a2713aSLionel Sambuc  if (self == [MyParentSelf class])
167*f4a2713aSLionel Sambuc      return 0;
168*f4a2713aSLionel Sambuc    else
169*f4a2713aSLionel Sambuc      return 1;
170*f4a2713aSLionel Sambuc}
171*f4a2713aSLionel Sambuc@end
172*f4a2713aSLionel Sambuc@interface MyClassSelf : MyParentSelf
173*f4a2713aSLionel Sambuc@end
174*f4a2713aSLionel Sambuc@implementation MyClassSelf
175*f4a2713aSLionel Sambuc+ (int)testClassMethodByKnownVarDecl {
176*f4a2713aSLionel Sambuc  int y = [MyParentSelf testSelf];
177*f4a2713aSLionel Sambuc  return 5/y; // Should warn here.
178*f4a2713aSLionel Sambuc}
179*f4a2713aSLionel Sambuc@end
180*f4a2713aSLionel Sambucint foo2() {
181*f4a2713aSLionel Sambuc  int y = [MyParentSelf testSelf];
182*f4a2713aSLionel Sambuc  return 5/y; // Should warn here.
183*f4a2713aSLionel Sambuc}
184*f4a2713aSLionel Sambuc
185*f4a2713aSLionel Sambuc// TODO: We do not inline 'getNum' in the following case, where the value of
186*f4a2713aSLionel Sambuc// 'self' in call '[self getNum]' is available and evaualtes to
187*f4a2713aSLionel Sambuc// 'SelfUsedInParentChild' if it's called from fooA.
188*f4a2713aSLionel Sambuc// Self region should get created before we call foo and yje call to super
189*f4a2713aSLionel Sambuc// should keep it live.
190*f4a2713aSLionel Sambuc@interface SelfUsedInParent : NSObject
191*f4a2713aSLionel Sambuc+ (int)getNum;
192*f4a2713aSLionel Sambuc+ (int)foo;
193*f4a2713aSLionel Sambuc@end
194*f4a2713aSLionel Sambuc@implementation SelfUsedInParent
195*f4a2713aSLionel Sambuc+ (int)getNum {return 5;}
196*f4a2713aSLionel Sambuc+ (int)foo {
197*f4a2713aSLionel Sambuc  return [self getNum];
198*f4a2713aSLionel Sambuc}
199*f4a2713aSLionel Sambuc@end
200*f4a2713aSLionel Sambuc@interface SelfUsedInParentChild : SelfUsedInParent
201*f4a2713aSLionel Sambuc+ (int)getNum;
202*f4a2713aSLionel Sambuc+ (int)fooA;
203*f4a2713aSLionel Sambuc@end
204*f4a2713aSLionel Sambuc@implementation SelfUsedInParentChild
205*f4a2713aSLionel Sambuc+ (int)getNum {return 0;}
206*f4a2713aSLionel Sambuc+ (int)fooA {
207*f4a2713aSLionel Sambuc  return [super foo];
208*f4a2713aSLionel Sambuc}
209*f4a2713aSLionel Sambuc@end
210*f4a2713aSLionel Sambucint checkSelfUsedInparentClassMethod() {
211*f4a2713aSLionel Sambuc    return 5/[SelfUsedInParentChild fooA];
212*f4a2713aSLionel Sambuc}
213*f4a2713aSLionel Sambuc
214*f4a2713aSLionel Sambuc
215*f4a2713aSLionel Sambuc@interface Rdar15037033 : NSObject
216*f4a2713aSLionel Sambuc@end
217*f4a2713aSLionel Sambuc
218*f4a2713aSLionel Sambucvoid rdar15037033() {
219*f4a2713aSLionel Sambuc  [Rdar15037033 forwardDeclaredMethod]; // expected-warning {{class method '+forwardDeclaredMethod' not found}}
220*f4a2713aSLionel Sambuc  [Rdar15037033 forwardDeclaredVariadicMethod:1, 2, 3, 0]; // expected-warning {{class method '+forwardDeclaredVariadicMethod:' not found}}
221*f4a2713aSLionel Sambuc}
222*f4a2713aSLionel Sambuc
223*f4a2713aSLionel Sambuc@implementation Rdar15037033
224*f4a2713aSLionel Sambuc
225*f4a2713aSLionel Sambuc+ (void)forwardDeclaredMethod {
226*f4a2713aSLionel Sambuc  clang_analyzer_checkInlined(1); // expected-warning{{TRUE}}
227*f4a2713aSLionel Sambuc}
228*f4a2713aSLionel Sambuc
229*f4a2713aSLionel Sambuc+ (void)forwardDeclaredVariadicMethod:(int)x, ... {
230*f4a2713aSLionel Sambuc  clang_analyzer_checkInlined(0); // no-warning
231*f4a2713aSLionel Sambuc}
232*f4a2713aSLionel Sambuc
233*f4a2713aSLionel Sambuc@end
234*f4a2713aSLionel Sambuc
235*f4a2713aSLionel Sambuc
236*f4a2713aSLionel Sambuc
237