DynDispatchBifurcate.m revision 3f558af01643787d209a133215b0abec81b5fe30
1// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=dynamic-bifurcate -verify %s
2
3#include "InlineObjCInstanceMethod.h"
4
5@interface MyParent : NSObject
6- (int)getZero;
7@end
8@implementation MyParent
9- (int)getZero {
10    return 0;
11}
12@end
13
14@implementation PublicClass
15- (int)getZeroPublic {
16    return 0;
17}
18@end
19
20@interface MyClassWithPublicParent : PublicClass
21- (int)getZeroPublic;
22@end
23@implementation MyClassWithPublicParent
24- (int)getZeroPublic {
25    return 0;
26}
27@end
28
29// Category overrides a public method.
30@interface PublicSubClass (PrvateCat)
31  - (int) getZeroPublic;
32@end
33@implementation PublicSubClass (PrvateCat)
34- (int)getZeroPublic {
35    return 0;
36}
37@end
38
39
40@interface MyClass : MyParent
41- (int)getZero;
42@end
43
44// Since class is private, we assume that it cannot be subclassed.
45// False negative: this class is "privately subclassed". this is very rare 
46// in practice.
47@implementation MyClass
48+ (int) testTypeFromParam:(MyParent*) p {
49  int m = 0;
50  int z = [p getZero];
51  if (z)
52    return 5/m; // false negative
53  return 5/[p getZero];// expected-warning {{Division by zero}}
54}
55
56// Here only one definition is possible, since the declaration is not visible 
57// from outside. 
58+ (int) testTypeFromParamPrivateChild:(MyClass*) c {
59  int m = 0;
60  int z = [c getZero]; // MyClass overrides getZero to return '1'.
61  if (z)
62    return 5/m; // expected-warning {{Division by zero}}
63  return 5/[c getZero];//no warning
64}
65
66- (int)getZero {
67    return 1;
68}
69@end
70
71// The class is prvate and is not subclassed.
72int testCallToPublicAPIInParent(MyClassWithPublicParent *p) {
73  int m = 0;
74  int z = [p getZeroPublic];
75  if (z)
76    return 5/m; // no warning
77  return 5/[p getZeroPublic];// expected-warning {{Division by zero}}  
78}
79
80// When the called method is public (due to it being defined outside of main file),
81// split the path and analyze both branches.
82// In this case, p can be either the object of type MyParent* or MyClass*:
83// - If it's MyParent*, getZero returns 0.
84// - If it's MyClass*, getZero returns 1 and 'return 5/m' is reachable.
85// Declaration is provate, but p can be a subclass (MyClass*).
86int testCallToPublicAPI(PublicClass *p) {
87  int m = 0;
88  int z = [p getZeroPublic];
89  if (z)
90    return 5/m; // expected-warning {{Division by zero}}
91  return 5/[p getZeroPublic];// expected-warning {{Division by zero}}  
92}
93
94// Even though the method is privately declared in the category, the parent 
95// declares the method as public. Assume the instance can be subclassed.
96int testCallToPublicAPICat(PublicSubClass *p) {
97  int m = 0;
98  int z = [p getZeroPublic];
99  if (z)
100    return 5/m; // expected-warning {{Division by zero}}
101  return 5/[p getZeroPublic];// expected-warning {{Division by zero}}  
102}
103