465 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
			
		
		
	
	
			465 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
| // 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
 | |
| 
 | |
| @interface Test {
 | |
| @public
 | |
|   Test *ivar;
 | |
|   __weak id weakIvar;
 | |
| }
 | |
| @property(weak) Test *weakProp;
 | |
| @property(strong) Test *strongProp;
 | |
| 
 | |
| - (__weak id)implicitProp;
 | |
| 
 | |
| + (__weak id)weakProp;
 | |
| @end
 | |
| 
 | |
| extern void use(id);
 | |
| extern id get();
 | |
| extern bool condition();
 | |
| #define nil ((id)0)
 | |
| 
 | |
| void sanity(Test *a) {
 | |
|   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}}
 | |
|   use(a.weakProp); // expected-note{{also accessed here}}
 | |
| 
 | |
|   use(a.strongProp);
 | |
|   use(a.strongProp); // no-warning
 | |
| 
 | |
|   use(a.weakProp); // expected-note{{also accessed here}}
 | |
| }
 | |
| 
 | |
| void singleUse(Test *a) {
 | |
|   use(a.weakProp); // no-warning
 | |
|   use(a.strongProp); // no-warning
 | |
| }
 | |
| 
 | |
| void assignsOnly(Test *a) {
 | |
|   a.weakProp = get(); // no-warning
 | |
| 
 | |
|   id next = get();
 | |
|   if (next)
 | |
|     a.weakProp = next; // no-warning
 | |
| 
 | |
|   a->weakIvar = get(); // no-warning
 | |
|   next = get();
 | |
|   if (next)
 | |
|     a->weakIvar = next; // no-warning
 | |
| 
 | |
|   extern __weak id x;
 | |
|   x = get(); // no-warning
 | |
|   next = get();
 | |
|   if (next)
 | |
|     x = next; // no-warning
 | |
| }
 | |
| 
 | |
| void assignThenRead(Test *a) {
 | |
|   a.weakProp = get(); // expected-note{{also accessed here}}
 | |
|   use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times}}
 | |
| }
 | |
| 
 | |
| void twoVariables(Test *a, Test *b) {
 | |
|   use(a.weakProp); // no-warning
 | |
|   use(b.weakProp); // no-warning
 | |
| }
 | |
| 
 | |
| void doubleLevelAccess(Test *a) {
 | |
|   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}}
 | |
|   use(a.strongProp.weakProp); // expected-note{{also accessed here}}
 | |
| }
 | |
| 
 | |
| void doubleLevelAccessIvar(Test *a) {
 | |
|   use(a.strongProp.weakProp); // expected-warning{{weak property 'weakProp' may be accessed multiple times}}
 | |
|   use(a.strongProp.weakProp); // expected-note{{also accessed here}}
 | |
| }
 | |
| 
 | |
| void implicitProperties(Test *a) {
 | |
|   use(a.implicitProp); // expected-warning{{weak implicit property 'implicitProp' is accessed multiple times}}
 | |
|   use(a.implicitProp); // expected-note{{also accessed here}}
 | |
| }
 | |
| 
 | |
| void classProperties() {
 | |
|   use(Test.weakProp); // expected-warning{{weak implicit property 'weakProp' is accessed multiple times}}
 | |
|   use(Test.weakProp); // expected-note{{also accessed here}}
 | |
| }
 | |
| 
 | |
| void classPropertiesAreDifferent(Test *a) {
 | |
|   use(Test.weakProp); // no-warning
 | |
|   use(a.weakProp); // no-warning
 | |
|   use(a.strongProp.weakProp); // no-warning
 | |
| }
 | |
| 
 | |
| void ivars(Test *a) {
 | |
|   use(a->weakIvar); // expected-warning{{weak instance variable 'weakIvar' is accessed multiple times}}
 | |
|   use(a->weakIvar); // expected-note{{also accessed here}}
 | |
| }
 | |
| 
 | |
| void globals() {
 | |
|   extern __weak id a;
 | |
|   use(a); // expected-warning{{weak variable 'a' is accessed multiple times}}
 | |
|   use(a); // expected-note{{also accessed here}}
 | |
| }
 | |
| 
 | |
| void messageGetter(Test *a) {
 | |
|   use([a weakProp]); // expected-warning{{weak property 'weakProp' is accessed multiple times}}
 | |
|   use([a weakProp]); // expected-note{{also accessed here}}
 | |
| }
 | |
| 
 | |
| void messageSetter(Test *a) {
 | |
|   [a setWeakProp:get()]; // no-warning
 | |
|   [a setWeakProp:get()]; // no-warning
 | |
| }
 | |
| 
 | |
| void messageSetterAndGetter(Test *a) {
 | |
|   [a setWeakProp:get()]; // expected-note{{also accessed here}}
 | |
|   use([a weakProp]); // expected-warning{{weak property 'weakProp' is accessed multiple times}}
 | |
| }
 | |
| 
 | |
| void mixDotAndMessageSend(Test *a, Test *b) {
 | |
|   use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times}}
 | |
|   use([a weakProp]); // expected-note{{also accessed here}}
 | |
| 
 | |
|   use([b weakProp]); // expected-warning{{weak property 'weakProp' is accessed multiple times}}
 | |
|   use(b.weakProp); // expected-note{{also accessed here}}
 | |
| }
 | |
| 
 | |
| 
 | |
| void assignToStrongWrongInit(Test *a) {
 | |
|   id val = a.weakProp; // expected-note{{also accessed here}}
 | |
|   use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times}}
 | |
| }
 | |
| 
 | |
| void assignToStrongWrong(Test *a) {
 | |
|   id val;
 | |
|   val = a.weakProp; // expected-note{{also accessed here}}
 | |
|   use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times}}
 | |
| }
 | |
| 
 | |
| void assignToIvarWrong(Test *a) {
 | |
|   a->weakIvar = get(); // expected-note{{also accessed here}}
 | |
|   use(a->weakIvar); // expected-warning{{weak instance variable 'weakIvar' is accessed multiple times}}
 | |
| }
 | |
| 
 | |
| void assignToGlobalWrong() {
 | |
|   extern __weak id a;
 | |
|   a = get(); // expected-note{{also accessed here}}
 | |
|   use(a); // expected-warning{{weak variable 'a' is accessed multiple times}}
 | |
| }
 | |
| 
 | |
| void assignToStrongOK(Test *a) {
 | |
|   if (condition()) {
 | |
|     id val = a.weakProp; // no-warning
 | |
|     (void)val;
 | |
|   } else {
 | |
|     id val;
 | |
|     val = a.weakProp; // no-warning
 | |
|     (void)val;
 | |
|   }
 | |
| }
 | |
| 
 | |
| void assignToStrongConditional(Test *a) {
 | |
|   id val = (condition() ? a.weakProp : a.weakProp); // no-warning
 | |
|   id val2 = a.implicitProp ?: a.implicitProp; // no-warning
 | |
| }
 | |
| 
 | |
| void testBlock(Test *a) {
 | |
|   use(a.weakProp); // no-warning
 | |
| 
 | |
|   use(^{
 | |
|     use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times in this block}}
 | |
|     use(a.weakProp); // expected-note{{also accessed here}}
 | |
|   });
 | |
| }
 | |
| 
 | |
| void assignToStrongWithCasts(Test *a) {
 | |
|   if (condition()) {
 | |
|     Test *val = (Test *)a.weakProp; // no-warning
 | |
|     (void)val;
 | |
|   } else {
 | |
|     id val;
 | |
|     val = (Test *)a.weakProp; // no-warning
 | |
|     (void)val;
 | |
|   }
 | |
| }
 | |
| 
 | |
| void assignToStrongWithMessages(Test *a) {
 | |
|   if (condition()) {
 | |
|     id val = [a weakProp]; // no-warning
 | |
|     (void)val;
 | |
|   } else {
 | |
|     id val;
 | |
|     val = [a weakProp]; // no-warning
 | |
|     (void)val;
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| void assignAfterRead(Test *a) {
 | |
|   // Special exception for a single read before any writes.
 | |
|   if (!a.weakProp) // no-warning
 | |
|     a.weakProp = get(); // no-warning
 | |
| }
 | |
| 
 | |
| void readOnceWriteMany(Test *a) {
 | |
|   if (!a.weakProp) { // no-warning
 | |
|     a.weakProp = get(); // no-warning
 | |
|     a.weakProp = get(); // no-warning
 | |
|   }
 | |
| }
 | |
| 
 | |
| void readOnceAfterWrite(Test *a) {
 | |
|   a.weakProp = get(); // expected-note{{also accessed here}}
 | |
|   if (!a.weakProp) { // expected-warning{{weak property 'weakProp' is accessed multiple times in this function}}
 | |
|     a.weakProp = get(); // expected-note{{also accessed here}}
 | |
|   }
 | |
| }
 | |
| 
 | |
| void readOnceWriteManyLoops(Test *a, Test *b, Test *c, Test *d, Test *e) {
 | |
|   while (condition()) {
 | |
|     if (!a.weakProp) { // expected-warning{{weak property 'weakProp' is accessed multiple times in this function}}
 | |
|       a.weakProp = get(); // expected-note{{also accessed here}}
 | |
|       a.weakProp = get(); // expected-note{{also accessed here}}
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   do {
 | |
|     if (!b.weakProp) { // expected-warning{{weak property 'weakProp' is accessed multiple times in this function}}
 | |
|       b.weakProp = get(); // expected-note{{also accessed here}}
 | |
|       b.weakProp = get(); // expected-note{{also accessed here}}
 | |
|     }
 | |
|   } while (condition());
 | |
| 
 | |
|   for (id x = get(); x; x = get()) {
 | |
|     if (!c.weakProp) { // expected-warning{{weak property 'weakProp' is accessed multiple times in this function}}
 | |
|       c.weakProp = get(); // expected-note{{also accessed here}}
 | |
|       c.weakProp = get(); // expected-note{{also accessed here}}
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   for (id x in get()) {
 | |
|     if (!d.weakProp) { // expected-warning{{weak property 'weakProp' is accessed multiple times in this function}}
 | |
|       d.weakProp = get(); // expected-note{{also accessed here}}
 | |
|       d.weakProp = get(); // expected-note{{also accessed here}}
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   int array[] = { 1, 2, 3 };
 | |
|   for (int i : array) {
 | |
|     if (!e.weakProp) { // expected-warning{{weak property 'weakProp' is accessed multiple times in this function}}
 | |
|       e.weakProp = get(); // expected-note{{also accessed here}}
 | |
|       e.weakProp = get(); // expected-note{{also accessed here}}
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| void readOnlyLoop(Test *a) {
 | |
|   while (condition()) {
 | |
|     use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times in this function}}
 | |
|   }
 | |
| }
 | |
| 
 | |
| void readInIterationLoop() {
 | |
|   for (Test *a in get())
 | |
|     use(a.weakProp); // no-warning
 | |
| }
 | |
| 
 | |
| void readDoubleLevelAccessInLoop() {
 | |
|   for (Test *a in get()) {
 | |
|     use(a.strongProp.weakProp); // no-warning
 | |
|   }
 | |
| }
 | |
| 
 | |
| void readParameterInLoop(Test *a) {
 | |
|   for (id unused in get()) {
 | |
|     use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times in this function}}
 | |
|     (void)unused;
 | |
|   }
 | |
| }
 | |
| 
 | |
| void readGlobalInLoop() {
 | |
|   static __weak id a;
 | |
|   for (id unused in get()) {
 | |
|     use(a); // expected-warning{{weak variable 'a' is accessed multiple times in this function}}
 | |
|     (void)unused;
 | |
|   }
 | |
| }
 | |
| 
 | |
| void doWhileLoop(Test *a) {
 | |
|   do {
 | |
|     use(a.weakProp); // no-warning
 | |
|   } while(0);
 | |
| }
 | |
| 
 | |
| 
 | |
| @interface Test (Methods)
 | |
| @end
 | |
| 
 | |
| @implementation Test (Methods)
 | |
| - (void)sanity {
 | |
|   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}}
 | |
|   use(self.weakProp); // expected-note{{also accessed here}}
 | |
| }
 | |
| 
 | |
| - (void)ivars {
 | |
|   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}}
 | |
|   use(weakIvar); // expected-note{{also accessed here}}
 | |
| }
 | |
| 
 | |
| - (void)doubleLevelAccessForSelf {
 | |
|   use(self.strongProp.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times}}
 | |
|   use(self.strongProp.weakProp); // expected-note{{also accessed here}}
 | |
| 
 | |
|   use(self->ivar.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times}}
 | |
|   use(self->ivar.weakProp); // expected-note{{also accessed here}}
 | |
| 
 | |
|   use(self->ivar->weakIvar); // expected-warning{{weak instance variable 'weakIvar' is accessed multiple times}}
 | |
|   use(self->ivar->weakIvar); // expected-note{{also accessed here}}
 | |
| }
 | |
| 
 | |
| - (void)distinctFromOther:(Test *)other {
 | |
|   use(self.strongProp.weakProp); // no-warning
 | |
|   use(other.strongProp.weakProp); // no-warning
 | |
| 
 | |
|   use(self->ivar.weakProp); // no-warning
 | |
|   use(other->ivar.weakProp); // no-warning
 | |
| 
 | |
|   use(self.strongProp->weakIvar); // no-warning
 | |
|   use(other.strongProp->weakIvar); // no-warning
 | |
| }
 | |
| @end
 | |
| 
 | |
| @interface Base1
 | |
| @end
 | |
| @interface Sub1 : Base1
 | |
| @end
 | |
| @interface Sub1(cat)
 | |
| -(id)prop;
 | |
| @end
 | |
| 
 | |
| void test1(Sub1 *s) {
 | |
|   use([s prop]);
 | |
|   use([s prop]);
 | |
| }
 | |
| 
 | |
| @interface Base1(cat)
 | |
| @property (weak) id prop;
 | |
| @end
 | |
| 
 | |
| void test2(Sub1 *s) {
 | |
|   // This does not warn because the "prop" in "Base1(cat)" was introduced
 | |
|   // after the method declaration and we don't find it as overridden.
 | |
|   // Always looking for overridden methods after the method declaration is expensive
 | |
|   // and it's not clear it is worth it currently.
 | |
|   use([s prop]);
 | |
|   use([s prop]);
 | |
| }
 | |
| 
 | |
| 
 | |
| class Wrapper {
 | |
|   Test *a;
 | |
| 
 | |
| public:
 | |
|   void fields() {
 | |
|     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}}
 | |
|     use(a.weakProp); // expected-note{{also accessed here}}
 | |
|   }
 | |
| 
 | |
|   void distinctFromOther(Test *b, const Wrapper &w) {
 | |
|     use(a.weakProp); // no-warning
 | |
|     use(b.weakProp); // no-warning
 | |
|     use(w.a.weakProp); // no-warning
 | |
|   }
 | |
| 
 | |
|   static void doubleLevelAccessField(const Wrapper &x, const Wrapper &y) {
 | |
|     use(x.a.weakProp); // expected-warning{{weak property 'weakProp' may be accessed multiple times}}
 | |
|     use(y.a.weakProp); // expected-note{{also accessed here}}
 | |
|   }
 | |
| };
 | |
| 
 | |
| 
 | |
| // -----------------------
 | |
| // False positives
 | |
| // -----------------------
 | |
| 
 | |
| // Most of these would require flow-sensitive analysis to silence correctly.
 | |
| 
 | |
| void assignNil(Test *a) {
 | |
|   if (condition())
 | |
|     a.weakProp = nil; // expected-note{{also accessed here}}
 | |
| 
 | |
|   use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times}}
 | |
| }
 | |
| 
 | |
| void branch(Test *a) {
 | |
|   if (condition())
 | |
|     use(a.weakProp); // expected-warning{{weak property 'weakProp' is accessed multiple times}}
 | |
|   else
 | |
|     use(a.weakProp); // expected-note{{also accessed here}}
 | |
| }
 | |
| 
 | |
| void doubleLevelAccess(Test *a, Test *b) {
 | |
|   use(a.strongProp.weakProp); // expected-warning{{weak property 'weakProp' may be accessed multiple times}}
 | |
|   use(b.strongProp.weakProp); // expected-note{{also accessed here}}
 | |
| 
 | |
|   use(a.weakProp.weakProp); // no-warning
 | |
| }
 | |
| 
 | |
| void doubleLevelAccessIvar(Test *a, Test *b) {
 | |
|   use(a->ivar.weakProp); // expected-warning{{weak property 'weakProp' may be accessed multiple times}}
 | |
|   use(b->ivar.weakProp); // expected-note{{also accessed here}}
 | |
| 
 | |
|   use(a.strongProp.weakProp); // no-warning
 | |
| }
 | |
| 
 | |
| // rdar://13942025
 | |
| @interface X
 | |
| @end
 | |
| 
 | |
| @implementation X
 | |
| - (int) warningAboutWeakVariableInsideTypeof {
 | |
|     __typeof__(self) __weak weakSelf = self;
 | |
|     ^(){
 | |
|         __typeof__(weakSelf) blockSelf = weakSelf;
 | |
|         use(blockSelf);
 | |
|     }();
 | |
|     return sizeof(weakSelf);
 | |
| }
 | |
| @end
 | |
| 
 | |
| // rdar://19053620
 | |
| @interface NSNull
 | |
| + (NSNull *)null;
 | |
| @end
 | |
| 
 | |
| @interface INTF @end
 | |
| 
 | |
| @implementation INTF
 | |
| - (void) Meth : (id) data
 | |
| {
 | |
|   data = data ?: NSNull.null;
 | |
| }
 | |
| @end
 | |
| 
 | |
| // This used to crash in WeakObjectProfileTy::getBaseInfo when getBase() was
 | |
| // called on an ObjCPropertyRefExpr object whose receiver was an interface.
 | |
| 
 | |
| @class NSString;
 | |
| @interface NSBundle
 | |
| +(NSBundle *)foo;
 | |
| @property (class) NSBundle *foo2;
 | |
| @property NSString *prop;
 | |
| @property(weak) NSString *weakProp;
 | |
| @end
 | |
| 
 | |
| @interface NSBundle2 : NSBundle
 | |
| @end
 | |
| 
 | |
| void foo() {
 | |
|   NSString * t = NSBundle.foo.prop;
 | |
|   use(NSBundle.foo.weakProp); // expected-warning{{weak property 'weakProp' may be accessed multiple times}}
 | |
|   use(NSBundle2.foo.weakProp); // expected-note{{also accessed here}}
 | |
| 
 | |
|   NSString * t2 = NSBundle.foo2.prop;
 | |
|   use(NSBundle.foo2.weakProp); // expected-warning{{weak property 'weakProp' may be accessed multiple times}}
 | |
|   use(NSBundle2.foo2.weakProp); // expected-note{{also accessed here}}
 | |
| }
 |