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