Home | History | Annotate | Download | only in inlining
      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