blob: 264c598942aec4ed62971aa0a57f4c7933c6f18c [file] [log] [blame]
// 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