xref: /aosp_15_r20/external/clang/test/Analysis/inlining/DynDispatchBifurcate.m (revision 67e74705e28f6214e480b399dd47ea732279e315)
1*67e74705SXin Li// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx -analyzer-config ipa=dynamic-bifurcate -verify %s
2*67e74705SXin Li
3*67e74705SXin Li#include "InlineObjCInstanceMethod.h"
4*67e74705SXin Li
5*67e74705SXin Li@interface MyParent : NSObject
6*67e74705SXin Li- (int)getZero;
7*67e74705SXin Li@end
8*67e74705SXin Li@implementation MyParent
9*67e74705SXin Li- (int)getZero {
10*67e74705SXin Li    return 0;
11*67e74705SXin Li}
12*67e74705SXin Li@end
13*67e74705SXin Li
14*67e74705SXin Li@interface PublicClass () {
15*67e74705SXin Li   int value2;
16*67e74705SXin Li}
17*67e74705SXin Li@property (readwrite) int value1;
18*67e74705SXin Li- (void)setValue2:(int)newValue2;
19*67e74705SXin Li@end
20*67e74705SXin Li
21*67e74705SXin Li@implementation PublicClass
22*67e74705SXin Li
23*67e74705SXin Li- (int)getZeroPublic {
24*67e74705SXin Li    return 0;
25*67e74705SXin Li}
26*67e74705SXin Li
27*67e74705SXin Li@synthesize value1;
28*67e74705SXin Li
29*67e74705SXin Li- (int)value2 {
30*67e74705SXin Li    return value2;
31*67e74705SXin Li}
32*67e74705SXin Li- (void)setValue2:(int)newValue {
33*67e74705SXin Li    value2 = newValue;
34*67e74705SXin Li}
35*67e74705SXin Li
36*67e74705SXin Li- (int)value3 {
37*67e74705SXin Li    return value3;
38*67e74705SXin Li}
39*67e74705SXin Li- (void)setValue3:(int)newValue {
40*67e74705SXin Li    value3 = newValue;
41*67e74705SXin Li}
42*67e74705SXin Li
43*67e74705SXin Li@end
44*67e74705SXin Li
45*67e74705SXin Li@interface MyClassWithPublicParent : PublicClass
46*67e74705SXin Li- (int)getZeroPublic;
47*67e74705SXin Li@end
48*67e74705SXin Li@implementation MyClassWithPublicParent
49*67e74705SXin Li- (int)getZeroPublic {
50*67e74705SXin Li    return 0;
51*67e74705SXin Li}
52*67e74705SXin Li@end
53*67e74705SXin Li
54*67e74705SXin Li// Category overrides a public method.
55*67e74705SXin Li@interface PublicSubClass (PrvateCat)
56*67e74705SXin Li  - (int) getZeroPublic;
57*67e74705SXin Li@end
58*67e74705SXin Li@implementation PublicSubClass (PrvateCat)
59*67e74705SXin Li- (int)getZeroPublic {
60*67e74705SXin Li    return 0;
61*67e74705SXin Li}
62*67e74705SXin Li@end
63*67e74705SXin Li
64*67e74705SXin Li
65*67e74705SXin Li@interface MyClass : MyParent {
66*67e74705SXin Li  int value;
67*67e74705SXin Li}
68*67e74705SXin Li- (int)getZero;
69*67e74705SXin Li@property int value;
70*67e74705SXin Li@end
71*67e74705SXin Li
72*67e74705SXin Li// Since class is private, we assume that it cannot be subclassed.
73*67e74705SXin Li// False negative: this class is "privately subclassed". this is very rare
74*67e74705SXin Li// in practice.
75*67e74705SXin Li@implementation MyClass
76*67e74705SXin Li+ (int) testTypeFromParam:(MyParent*) p {
77*67e74705SXin Li  int m = 0;
78*67e74705SXin Li  int z = [p getZero];
79*67e74705SXin Li  if (z)
80*67e74705SXin Li    return 5/m; // false negative
81*67e74705SXin Li  return 5/[p getZero];// expected-warning {{Division by zero}}
82*67e74705SXin Li}
83*67e74705SXin Li
84*67e74705SXin Li// Here only one definition is possible, since the declaration is not visible
85*67e74705SXin Li// from outside.
86*67e74705SXin Li+ (int) testTypeFromParamPrivateChild:(MyClass*) c {
87*67e74705SXin Li  int m = 0;
88*67e74705SXin Li  int z = [c getZero]; // MyClass overrides getZero to return '1'.
89*67e74705SXin Li  if (z)
90*67e74705SXin Li    return 5/m; // expected-warning {{Division by zero}}
91*67e74705SXin Li  return 5/[c getZero];//no warning
92*67e74705SXin Li}
93*67e74705SXin Li
94*67e74705SXin Li- (int)getZero {
95*67e74705SXin Li    return 1;
96*67e74705SXin Li}
97*67e74705SXin Li
98*67e74705SXin Li- (int)value {
99*67e74705SXin Li  return value;
100*67e74705SXin Li}
101*67e74705SXin Li
102*67e74705SXin Li- (void)setValue:(int)newValue {
103*67e74705SXin Li  value = newValue;
104*67e74705SXin Li}
105*67e74705SXin Li
106*67e74705SXin Li// Test ivar access.
107*67e74705SXin Li- (int) testIvarInSelf {
108*67e74705SXin Li  value = 0;
109*67e74705SXin Li  return 5/value; // expected-warning {{Division by zero}}
110*67e74705SXin Li}
111*67e74705SXin Li
112*67e74705SXin Li+ (int) testIvar: (MyClass*) p {
113*67e74705SXin Li  p.value = 0;
114*67e74705SXin Li  return 5/p.value; // expected-warning {{Division by zero}}
115*67e74705SXin Li}
116*67e74705SXin Li
117*67e74705SXin Li// Test simple property access.
118*67e74705SXin Li+ (int) testProperty: (MyClass*) p {
119*67e74705SXin Li  int x= 0;
120*67e74705SXin Li  [p setValue:0];
121*67e74705SXin Li  return 5/[p value]; // expected-warning {{Division by zero}}
122*67e74705SXin Li}
123*67e74705SXin Li
124*67e74705SXin Li@end
125*67e74705SXin Li
126*67e74705SXin Li// The class is prvate and is not subclassed.
127*67e74705SXin Liint testCallToPublicAPIInParent(MyClassWithPublicParent *p) {
128*67e74705SXin Li  int m = 0;
129*67e74705SXin Li  int z = [p getZeroPublic];
130*67e74705SXin Li  if (z)
131*67e74705SXin Li    return 5/m; // no warning
132*67e74705SXin Li  return 5/[p getZeroPublic];// expected-warning {{Division by zero}}
133*67e74705SXin Li}
134*67e74705SXin Li
135*67e74705SXin Li// When the called method is public (due to it being defined outside of main file),
136*67e74705SXin Li// split the path and analyze both branches.
137*67e74705SXin Li// In this case, p can be either the object of type MyParent* or MyClass*:
138*67e74705SXin Li// - If it's MyParent*, getZero returns 0.
139*67e74705SXin Li// - If it's MyClass*, getZero returns 1 and 'return 5/m' is reachable.
140*67e74705SXin Li// Declaration is provate, but p can be a subclass (MyClass*).
141*67e74705SXin Liint testCallToPublicAPI(PublicClass *p) {
142*67e74705SXin Li  int m = 0;
143*67e74705SXin Li  int z = [p getZeroPublic];
144*67e74705SXin Li  if (z)
145*67e74705SXin Li    return 5/m; // expected-warning {{Division by zero}}
146*67e74705SXin Li  return 5/[p getZeroPublic];// expected-warning {{Division by zero}}
147*67e74705SXin Li}
148*67e74705SXin Li
149*67e74705SXin Li// Even though the method is privately declared in the category, the parent
150*67e74705SXin Li// declares the method as public. Assume the instance can be subclassed.
151*67e74705SXin Liint testCallToPublicAPICat(PublicSubClass *p) {
152*67e74705SXin Li  int m = 0;
153*67e74705SXin Li  int z = [p getZeroPublic];
154*67e74705SXin Li  if (z)
155*67e74705SXin Li    return 5/m; // expected-warning {{Division by zero}}
156*67e74705SXin Li  return 5/[p getZeroPublic];// expected-warning {{Division by zero}}
157*67e74705SXin Li}
158*67e74705SXin Li
159*67e74705SXin Li// Test public property - properties should always be inlined, regardless
160*67e74705SXin Li// weither they are "public" or private.
161*67e74705SXin Liint testPublicProperty(PublicClass *p) {
162*67e74705SXin Li  int x = 0;
163*67e74705SXin Li  p.value3 = 0;
164*67e74705SXin Li  if (p.value3 != 0)
165*67e74705SXin Li    return 5/x;
166*67e74705SXin Li  return 5/p.value3;// expected-warning {{Division by zero}}
167*67e74705SXin Li}
168*67e74705SXin Li
169*67e74705SXin Liint testExtension(PublicClass *p) {
170*67e74705SXin Li  int x = 0;
171*67e74705SXin Li  [p setValue2:0];
172*67e74705SXin Li  if ([p value2] != 0)
173*67e74705SXin Li    return 5/x; // expected-warning {{Division by zero}}
174*67e74705SXin Li  return 5/[p value2]; // expected-warning {{Division by zero}}
175*67e74705SXin Li}
176*67e74705SXin Li
177*67e74705SXin Li// TODO: we do not handle synthesized properties yet.
178*67e74705SXin Liint testPropertySynthesized(PublicClass *p) {
179*67e74705SXin Li  [p setValue1:0];
180*67e74705SXin Li  return 5/[p value1];
181*67e74705SXin Li}
182*67e74705SXin Li
183*67e74705SXin Li// Test definition not available edge case.
184*67e74705SXin Li@interface DefNotAvailClass : NSObject // expected-note {{receiver is instance of class declared here}}
185*67e74705SXin Li@end
186*67e74705SXin Liid testDefNotAvailableInlined(DefNotAvailClass *C) {
187*67e74705SXin Li  return [C mem]; // expected-warning {{instance method '-mem' not found}}
188*67e74705SXin Li}
189*67e74705SXin Liid testDefNotAvailable(DefNotAvailClass *C) {
190*67e74705SXin Li  return testDefNotAvailableInlined(C);
191*67e74705SXin Li}
192