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