that became supported after r297019
The commit r297019 expanded the performSelector ObjC method family heuristic
to ensure that -Wobjc-unsafe-perform-selector covers all performSelector
variations. However, this made the -Warc-performSelector-leaks too noisy, as
that warning produces mostly false positives since the selector is unknown.
This commit reverts the ObjC method family heuristics introduced in r297019.
This ensures that -Warc-performSelector-leaks isn't too noisy. The commit still
preserves the coverage of -Wobjc-unsafe-perform-selector.
rdar://
31124629
llvm-svn: 298587
break;
case OMF_performSelector:
- if (!isInstanceMethod() ||
- !(getReturnType()->isObjCIdType() || getReturnType()->isVoidType()))
+ if (!isInstanceMethod() || !getReturnType()->isObjCIdType())
family = OMF_None;
else {
unsigned noParams = param_size();
- if (noParams < 1 || noParams > 5)
+ if (noParams < 1 || noParams > 3)
family = OMF_None;
else {
ObjCMethodDecl::param_type_iterator it = param_type_begin();
family = OMF_None;
break;
}
- // The first type should generally always be 'id' or 'Thread *', the
- // other types can vary.
- if (noParams > 1) {
- ArgT = *(it + 1);
- if (!ArgT->isObjCObjectPointerType()) {
+ while (--noParams) {
+ it++;
+ ArgT = (*it);
+ if (!ArgT->isObjCIdType()) {
family = OMF_None;
break;
}
bool IsClassObjectCall) {
// Check if this is a performSelector method that uses a selector that returns
// a record or a vector type.
- if (Method->getMethodFamily() != OMF_performSelector || Args.empty())
+ if (Method->getSelector().getMethodFamily() != OMF_performSelector ||
+ Args.empty())
return;
const auto *SE = dyn_cast<ObjCSelectorExpr>(Args[0]->IgnoreParens());
if (!SE)
- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
+
+- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(double)delay inModes:(I *)modes;
+
@end
@implementation I
return [self performSelector : @selector(PlusZero)];
return [self performSelector : @selector(PlusOne)]; // expected-error {{performSelector names a selector which retains the object}}
+ // Avoid the unkown selector warning for more complicated performSelector
+ // variations because it produces too many false positives.
+ [self performSelector: sel1 withObject:0 afterDelay:0 inModes:0];
+
return [self performSelector: @selector(self)]; // No error, -self is not +1!
}
- (id)performSelector:(SEL)aSelector { return 0; }
- (id)performSelector:(SEL)aSelector withObject:(id)object { return 0; }
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2 { return 0; }
+- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(double)delay inModes:(I *)modes { }
@end