// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime-has-weak -fobjc-arc -fblocks -Wno-objc-root-class -Wreceiver-is-weak -verify %s
// rdar://10225276

@interface Test0
- (void) setBlock: (void(^)(void)) block;
- (void) addBlock: (void(^)(void)) block;
- (void) actNow;
@end

void test0(Test0 *x) {
  __weak Test0 *weakx = x;
  [x addBlock: ^{ [weakx actNow]; }]; // expected-warning {{weak receiver may be unpredictably set to nil}} expected-note {{assign the value to a strong variable to keep the object alive during use}}
  [x setBlock: ^{ [weakx actNow]; }]; // expected-warning {{weak receiver may be unpredictably set to nil}} expected-note {{assign the value to a strong variable to keep the object alive during use}}
  x.block = ^{ [weakx actNow]; }; // expected-warning {{weak receiver may be unpredictably set to nil}} expected-note {{assign the value to a strong variable to keep the object alive during use}}

  [weakx addBlock: ^{ [x actNow]; }]; // expected-warning {{weak receiver may be unpredictably set to nil}} expected-note {{assign the value to a strong variable to keep the object alive during use}}
  [weakx setBlock: ^{ [x actNow]; }]; // expected-warning {{weak receiver may be unpredictably set to nil}} expected-note {{assign the value to a strong variable to keep the object alive during use}}
  weakx.block = ^{ [x actNow]; };     // expected-warning {{weak receiver may be unpredictably set to nil}} expected-note {{assign the value to a strong variable to keep the object alive during use}}
}

@interface Test
{
  __weak Test* weak_prop;
}
- (void) Meth;
@property  __weak Test* weak_prop; // expected-note {{property declared here}}
@property (weak, atomic) id weak_atomic_prop; // expected-note {{property declared here}}
- (__weak id) P; // expected-note {{method 'P' declared here}}
@end

@implementation Test
- (void) Meth {
    if (self.weak_prop) {
      self.weak_prop = 0;
    }
    if (self.weak_atomic_prop) {
      self.weak_atomic_prop = 0;
    }
    [self.weak_prop Meth]; // expected-warning {{weak property may be unpredictably set to nil}} expected-note {{assign the value to a strong variable to keep the object alive during use}}
    id pi = self.P;

    [self.weak_atomic_prop Meth];  // expected-warning {{weak property may be unpredictably set to nil}} expected-note {{assign the value to a strong variable to keep the object alive during use}}

    [self.P Meth];		   // expected-warning {{weak implicit property may be unpredictably set to nil}} expected-note {{assign the value to a strong variable to keep the object alive during use}}
}

- (__weak id) P { return 0; }
@dynamic weak_prop, weak_atomic_prop;
@end


@interface MyClass {
    __weak MyClass *_parent;
}
@property (weak) MyClass *parent; // expected-note 4 {{property declared here}}
@end

@implementation MyClass
@synthesize parent = _parent;

- (void)doSomething
{
    [[self parent] doSomething]; // expected-warning {{weak property may be unpredictably set to nil}} expected-note {{assign the value to a strong variable to keep the object alive during use}}

    (void)self.parent.doSomething; // expected-warning {{weak property may be unpredictably set to nil}} expected-note {{assign the value to a strong variable to keep the object alive during use}}
}

@end


// Weak properties on protocols can be synthesized by an adopting class.
@protocol MyProtocol
@property (weak) id object; // expected-note 2 {{property declared here}}
@end

void testProtocol(id <MyProtocol> input) {
  [[input object] Meth]; // expected-warning {{weak property may be unpredictably set to nil}} expected-note {{assign the value to a strong variable to keep the object alive during use}}
  [input.object Meth]; // expected-warning {{weak property may be unpredictably set to nil}} expected-note {{assign the value to a strong variable to keep the object alive during use}}
}


@interface Subclass : MyClass
// Unnecessarily redeclare -parent.
- (id)parent;
@end

@implementation Subclass

- (id)parent {
  return [super parent];
}

- (void)doSomethingElse {
  [[self parent] doSomething]; // expected-warning {{weak property may be unpredictably set to nil}} expected-note {{assign the value to a strong variable to keep the object alive during use}}

  (void)self.parent.doSomething; // expected-warning {{weak property may be unpredictably set to nil}} expected-note {{assign the value to a strong variable to keep the object alive during use}}
}

@end