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