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