Home | History | Annotate | Download | only in SemaObjC
      1 // RUN: %clang_cc1 -fsyntax-only -fobjc-runtime-has-weak -fobjc-arc -fblocks -Wno-objc-root-class -std=c++11 -Warc-repeated-use-of-weak -verify %s
      2 
      3 @interface Test {
      4 @public
      5   Test *ivar;
      6   __weak id weakIvar;
      7 }
      8 @property(weak) Test *weakProp;
      9 @property(strong) Test *strongProp;
     10 
     11 - (__weak id)implicitProp;
     12 
     13 + (__weak id)weakProp;
     14 @end
     15 
     16 extern void use(id);
     17 extern id get();
     18 extern bool condition();
     19 #define nil ((id)0)
     20 
     21 void sanity(Test *a) {
     22   use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times in this function but may be unpredictably set to nil; assign to a strong variable to keep the object alive}}
     23   use(a.weakProp); // expected-note{{also accessed here}}
     24 
     25   use(a.strongProp);
     26   use(a.strongProp); // no-warning
     27 
     28   use(a.weakProp); // expected-note{{also accessed here}}
     29 }
     30 
     31 void singleUse(Test *a) {
     32   use(a.weakProp); // no-warning
     33   use(a.strongProp); // no-warning
     34 }
     35 
     36 void assignsOnly(Test *a) {
     37   a.weakProp = get(); // no-warning
     38 
     39   id next = get();
     40   if (next)
     41     a.weakProp = next; // no-warning
     42 
     43   a->weakIvar = get(); // no-warning
     44   next = get();
     45   if (next)
     46     a->weakIvar = next; // no-warning
     47 
     48   extern __weak id x;
     49   x = get(); // no-warning
     50   next = get();
     51   if (next)
     52     x = next; // no-warning
     53 }
     54 
     55 void assignThenRead(Test *a) {
     56   a.weakProp = get(); // expected-note{{also accessed here}}
     57   use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times}}
     58 }
     59 
     60 void twoVariables(Test *a, Test *b) {
     61   use(a.weakProp); // no-warning
     62   use(b.weakProp); // no-warning
     63 }
     64 
     65 void doubleLevelAccess(Test *a) {
     66   use(a.strongProp.weakProp); // expected-warning{{weak property 'weakProp' may be accessed multiple times in this function and may be unpredictably set to nil; assign to a strong variable to keep the object alive}}
     67   use(a.strongProp.weakProp); // expected-note{{also accessed here}}
     68 }
     69 
     70 void doubleLevelAccessIvar(Test *a) {
     71   use(a.strongProp.weakProp); // expected-warning{{weak property 'weakProp' may be accessed multiple times}}
     72   use(a.strongProp.weakProp); // expected-note{{also accessed here}}
     73 }
     74 
     75 void implicitProperties(Test *a) {
     76   use(a.implicitProp); // expected-warning{{weak implicit property 'implicitProp' is accessed multiple times}}
     77   use(a.implicitProp); // expected-note{{also accessed here}}
     78 }
     79 
     80 void classProperties() {
     81   use(Test.weakProp); // expected-warning{{weak implicit property 'weakProp' is accessed multiple times}}
     82   use(Test.weakProp); // expected-note{{also accessed here}}
     83 }
     84 
     85 void classPropertiesAreDifferent(Test *a) {
     86   use(Test.weakProp); // no-warning
     87   use(a.weakProp); // no-warning
     88   use(a.strongProp.weakProp); // no-warning
     89 }
     90 
     91 void ivars(Test *a) {
     92   use(a->weakIvar); // expected-warning{{weak instance variable 'weakIvar' is accessed multiple times}}
     93   use(a->weakIvar); // expected-note{{also accessed here}}
     94 }
     95 
     96 void globals() {
     97   extern __weak id a;
     98   use(a); // expected-warning{{weak variable 'a' is accessed multiple times}}
     99   use(a); // expected-note{{also accessed here}}
    100 }
    101 
    102 void messageGetter(Test *a) {
    103   use([a weakProp]); // expected-warning{{weak property 'weakProp' is accessed multiple times}}
    104   use([a weakProp]); // expected-note{{also accessed here}}
    105 }
    106 
    107 void messageSetter(Test *a) {
    108   [a setWeakProp:get()]; // no-warning
    109   [a setWeakProp:get()]; // no-warning
    110 }
    111 
    112 void messageSetterAndGetter(Test *a) {
    113   [a setWeakProp:get()]; // expected-note{{also accessed here}}
    114   use([a weakProp]); // expected-warning{{weak property 'weakProp' is accessed multiple times}}
    115 }
    116 
    117 void mixDotAndMessageSend(Test *a, Test *b) {
    118   use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times}}
    119   use([a weakProp]); // expected-note{{also accessed here}}
    120 
    121   use([b weakProp]); // expected-warning{{weak property 'weakProp' is accessed multiple times}}
    122   use(b.weakProp); // expected-note{{also accessed here}}
    123 }
    124 
    125 
    126 void assignToStrongWrongInit(Test *a) {
    127   id val = a.weakProp; // expected-note{{also accessed here}}
    128   use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times}}
    129 }
    130 
    131 void assignToStrongWrong(Test *a) {
    132   id val;
    133   val = a.weakProp; // expected-note{{also accessed here}}
    134   use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times}}
    135 }
    136 
    137 void assignToIvarWrong(Test *a) {
    138   a->weakIvar = get(); // expected-note{{also accessed here}}
    139   use(a->weakIvar); // expected-warning{{weak instance variable 'weakIvar' is accessed multiple times}}
    140 }
    141 
    142 void assignToGlobalWrong() {
    143   extern __weak id a;
    144   a = get(); // expected-note{{also accessed here}}
    145   use(a); // expected-warning{{weak variable 'a' is accessed multiple times}}
    146 }
    147 
    148 void assignToStrongOK(Test *a) {
    149   if (condition()) {
    150     id val = a.weakProp; // no-warning
    151     (void)val;
    152   } else {
    153     id val;
    154     val = a.weakProp; // no-warning
    155     (void)val;
    156   }
    157 }
    158 
    159 void assignToStrongConditional(Test *a) {
    160   id val = (condition() ? a.weakProp : a.weakProp); // no-warning
    161   id val2 = a.implicitProp ?: a.implicitProp; // no-warning
    162 }
    163 
    164 void testBlock(Test *a) {
    165   use(a.weakProp); // no-warning
    166 
    167   use(^{
    168     use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times in this block}}
    169     use(a.weakProp); // expected-note{{also accessed here}}
    170   });
    171 }
    172 
    173 void assignToStrongWithCasts(Test *a) {
    174   if (condition()) {
    175     Test *val = (Test *)a.weakProp; // no-warning
    176     (void)val;
    177   } else {
    178     id val;
    179     val = (Test *)a.weakProp; // no-warning
    180     (void)val;
    181   }
    182 }
    183 
    184 void assignToStrongWithMessages(Test *a) {
    185   if (condition()) {
    186     id val = [a weakProp]; // no-warning
    187     (void)val;
    188   } else {
    189     id val;
    190     val = [a weakProp]; // no-warning
    191     (void)val;
    192   }
    193 }
    194 
    195 
    196 void assignAfterRead(Test *a) {
    197   // Special exception for a single read before any writes.
    198   if (!a.weakProp) // no-warning
    199     a.weakProp = get(); // no-warning
    200 }
    201 
    202 void readOnceWriteMany(Test *a) {
    203   if (!a.weakProp) { // no-warning
    204     a.weakProp = get(); // no-warning
    205     a.weakProp = get(); // no-warning
    206   }
    207 }
    208 
    209 void readOnceAfterWrite(Test *a) {
    210   a.weakProp = get(); // expected-note{{also accessed here}}
    211   if (!a.weakProp) { // expected-warning{{weak property 'weakProp' is accessed multiple times in this function}}
    212     a.weakProp = get(); // expected-note{{also accessed here}}
    213   }
    214 }
    215 
    216 void readOnceWriteManyLoops(Test *a, Test *b, Test *c, Test *d, Test *e) {
    217   while (condition()) {
    218     if (!a.weakProp) { // expected-warning{{weak property 'weakProp' is accessed multiple times in this function}}
    219       a.weakProp = get(); // expected-note{{also accessed here}}
    220       a.weakProp = get(); // expected-note{{also accessed here}}
    221     }
    222   }
    223 
    224   do {
    225     if (!b.weakProp) { // expected-warning{{weak property 'weakProp' is accessed multiple times in this function}}
    226       b.weakProp = get(); // expected-note{{also accessed here}}
    227       b.weakProp = get(); // expected-note{{also accessed here}}
    228     }
    229   } while (condition());
    230 
    231   for (id x = get(); x; x = get()) {
    232     if (!c.weakProp) { // expected-warning{{weak property 'weakProp' is accessed multiple times in this function}}
    233       c.weakProp = get(); // expected-note{{also accessed here}}
    234       c.weakProp = get(); // expected-note{{also accessed here}}
    235     }
    236   }
    237 
    238   for (id x in get()) {
    239     if (!d.weakProp) { // expected-warning{{weak property 'weakProp' is accessed multiple times in this function}}
    240       d.weakProp = get(); // expected-note{{also accessed here}}
    241       d.weakProp = get(); // expected-note{{also accessed here}}
    242     }
    243   }
    244 
    245   int array[] = { 1, 2, 3 };
    246   for (int i : array) {
    247     if (!e.weakProp) { // expected-warning{{weak property 'weakProp' is accessed multiple times in this function}}
    248       e.weakProp = get(); // expected-note{{also accessed here}}
    249       e.weakProp = get(); // expected-note{{also accessed here}}
    250     }
    251   }
    252 }
    253 
    254 void readOnlyLoop(Test *a) {
    255   while (condition()) {
    256     use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times in this function}}
    257   }
    258 }
    259 
    260 void readInIterationLoop() {
    261   for (Test *a in get())
    262     use(a.weakProp); // no-warning
    263 }
    264 
    265 void readDoubleLevelAccessInLoop() {
    266   for (Test *a in get()) {
    267     use(a.strongProp.weakProp); // no-warning
    268   }
    269 }
    270 
    271 void readParameterInLoop(Test *a) {
    272   for (id unused in get()) {
    273     use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times in this function}}
    274     (void)unused;
    275   }
    276 }
    277 
    278 void readGlobalInLoop() {
    279   static __weak id a;
    280   for (id unused in get()) {
    281     use(a); // expected-warning{{weak variable 'a' is accessed multiple times in this function}}
    282     (void)unused;
    283   }
    284 }
    285 
    286 void doWhileLoop(Test *a) {
    287   do {
    288     use(a.weakProp); // no-warning
    289   } while(0);
    290 }
    291 
    292 
    293 @interface Test (Methods)
    294 @end
    295 
    296 @implementation Test (Methods)
    297 - (void)sanity {
    298   use(self.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times in this method but may be unpredictably set to nil; assign to a strong variable to keep the object alive}}
    299   use(self.weakProp); // expected-note{{also accessed here}}
    300 }
    301 
    302 - (void)ivars {
    303   use(weakIvar); // expected-warning{{weak instance variable 'weakIvar' is accessed multiple times in this method but may be unpredictably set to nil; assign to a strong variable to keep the object alive}}
    304   use(weakIvar); // expected-note{{also accessed here}}
    305 }
    306 
    307 - (void)doubleLevelAccessForSelf {
    308   use(self.strongProp.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times}}
    309   use(self.strongProp.weakProp); // expected-note{{also accessed here}}
    310 
    311   use(self->ivar.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times}}
    312   use(self->ivar.weakProp); // expected-note{{also accessed here}}
    313 
    314   use(self->ivar->weakIvar); // expected-warning{{weak instance variable 'weakIvar' is accessed multiple times}}
    315   use(self->ivar->weakIvar); // expected-note{{also accessed here}}
    316 }
    317 
    318 - (void)distinctFromOther:(Test *)other {
    319   use(self.strongProp.weakProp); // no-warning
    320   use(other.strongProp.weakProp); // no-warning
    321 
    322   use(self->ivar.weakProp); // no-warning
    323   use(other->ivar.weakProp); // no-warning
    324 
    325   use(self.strongProp->weakIvar); // no-warning
    326   use(other.strongProp->weakIvar); // no-warning
    327 }
    328 @end
    329 
    330 @interface Base1
    331 @end
    332 @interface Sub1 : Base1
    333 @end
    334 @interface Sub1(cat)
    335 -(id)prop;
    336 @end
    337 
    338 void test1(Sub1 *s) {
    339   use([s prop]);
    340   use([s prop]);
    341 }
    342 
    343 @interface Base1(cat)
    344 @property (weak) id prop;
    345 @end
    346 
    347 void test2(Sub1 *s) {
    348   // This does not warn because the "prop" in "Base1(cat)" was introduced
    349   // after the method declaration and we don't find it as overridden.
    350   // Always looking for overridden methods after the method declaration is expensive
    351   // and it's not clear it is worth it currently.
    352   use([s prop]);
    353   use([s prop]);
    354 }
    355 
    356 
    357 class Wrapper {
    358   Test *a;
    359 
    360 public:
    361   void fields() {
    362     use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times in this function but may be unpredictably set to nil; assign to a strong variable to keep the object alive}}
    363     use(a.weakProp); // expected-note{{also accessed here}}
    364   }
    365 
    366   void distinctFromOther(Test *b, const Wrapper &w) {
    367     use(a.weakProp); // no-warning
    368     use(b.weakProp); // no-warning
    369     use(w.a.weakProp); // no-warning
    370   }
    371 
    372   static void doubleLevelAccessField(const Wrapper &x, const Wrapper &y) {
    373     use(x.a.weakProp); // expected-warning{{weak property 'weakProp' may be accessed multiple times}}
    374     use(y.a.weakProp); // expected-note{{also accessed here}}
    375   }
    376 };
    377 
    378 
    379 // -----------------------
    380 // False positives
    381 // -----------------------
    382 
    383 // Most of these would require flow-sensitive analysis to silence correctly.
    384 
    385 void assignNil(Test *a) {
    386   if (condition())
    387     a.weakProp = nil; // expected-note{{also accessed here}}
    388 
    389   use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times}}
    390 }
    391 
    392 void branch(Test *a) {
    393   if (condition())
    394     use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times}}
    395   else
    396     use(a.weakProp); // expected-note{{also accessed here}}
    397 }
    398 
    399 void doubleLevelAccess(Test *a, Test *b) {
    400   use(a.strongProp.weakProp); // expected-warning{{weak property 'weakProp' may be accessed multiple times}}
    401   use(b.strongProp.weakProp); // expected-note{{also accessed here}}
    402 
    403   use(a.weakProp.weakProp); // no-warning
    404 }
    405 
    406 void doubleLevelAccessIvar(Test *a, Test *b) {
    407   use(a->ivar.weakProp); // expected-warning{{weak property 'weakProp' may be accessed multiple times}}
    408   use(b->ivar.weakProp); // expected-note{{also accessed here}}
    409 
    410   use(a.strongProp.weakProp); // no-warning
    411 }
    412 
    413 // rdar://13942025
    414 @interface X
    415 @end
    416 
    417 @implementation X
    418 - (int) warningAboutWeakVariableInsideTypeof {
    419     __typeof__(self) __weak weakSelf = self;
    420     ^(){
    421         __typeof__(weakSelf) blockSelf = weakSelf;
    422         use(blockSelf);
    423     }();
    424     return sizeof(weakSelf);
    425 }
    426 @end
    427 
    428