public:
/// \brief - Returns instance or factory methods in global method pool for
- /// given selector. If no such method or only one method found, function returns
- /// false; otherwise, it returns true
- bool CollectMultipleMethodsInGlobalPool(Selector Sel,
- SmallVectorImpl<ObjCMethodDecl*>& Methods,
- bool instance);
+ /// given selector. It checks the desired kind first, if none is found, and
+ /// parameter checkTheOther is set, it then checks the other kind. If no such
+ /// method or only one method is found, function returns false; otherwise, it
+ /// returns true.
+ bool
+ CollectMultipleMethodsInGlobalPool(Selector Sel,
+ SmallVectorImpl<ObjCMethodDecl*>& Methods,
+ bool InstanceFirst, bool CheckTheOther);
- bool AreMultipleMethodsInGlobalPool(Selector Sel, ObjCMethodDecl *BestMethod,
- SourceRange R,
- bool receiverIdOrClass);
+ bool
+ AreMultipleMethodsInGlobalPool(Selector Sel, ObjCMethodDecl *BestMethod,
+ SourceRange R, bool receiverIdOrClass,
+ SmallVectorImpl<ObjCMethodDecl*>& Methods);
- void DiagnoseMultipleMethodInGlobalPool(SmallVectorImpl<ObjCMethodDecl*> &Methods,
- Selector Sel, SourceRange R,
- bool receiverIdOrClass);
+ void
+ DiagnoseMultipleMethodInGlobalPool(SmallVectorImpl<ObjCMethodDecl*> &Methods,
+ Selector Sel, SourceRange R,
+ bool receiverIdOrClass);
private:
/// \brief - Returns a selector which best matches given argument list or
/// nullptr if none could be found
ObjCMethodDecl *SelectBestMethod(Selector Sel, MultiExprArg Args,
- bool IsInstance);
+ bool IsInstance,
+ SmallVectorImpl<ObjCMethodDecl*>& Methods);
/// \brief Record the typo correction failure and return an empty correction.
return (chosen->getReturnType()->isIntegerType());
}
+/// We first select the type of the method: Instance or Factory, then collect
+/// all methods with that type.
bool Sema::CollectMultipleMethodsInGlobalPool(
- Selector Sel, SmallVectorImpl<ObjCMethodDecl *> &Methods, bool instance) {
+ Selector Sel, SmallVectorImpl<ObjCMethodDecl *> &Methods,
+ bool InstanceFirst, bool CheckTheOther) {
if (ExternalSource)
ReadMethodPool(Sel);
GlobalMethodPool::iterator Pos = MethodPool.find(Sel);
if (Pos == MethodPool.end())
return false;
+
// Gather the non-hidden methods.
- ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second;
+ ObjCMethodList &MethList = InstanceFirst ? Pos->second.first :
+ Pos->second.second;
for (ObjCMethodList *M = &MethList; M; M = M->getNext())
if (M->getMethod() && !M->getMethod()->isHidden())
Methods.push_back(M->getMethod());
+
+ // Return if we find any method with the desired kind.
+ if (!Methods.empty())
+ return Methods.size() > 1;
+
+ if (!CheckTheOther)
+ return false;
+
+ // Gather the other kind.
+ ObjCMethodList &MethList2 = InstanceFirst ? Pos->second.second :
+ Pos->second.first;
+ for (ObjCMethodList *M = &MethList2; M; M = M->getNext())
+ if (M->getMethod() && !M->getMethod()->isHidden())
+ Methods.push_back(M->getMethod());
+
return Methods.size() > 1;
}
-bool Sema::AreMultipleMethodsInGlobalPool(Selector Sel, ObjCMethodDecl *BestMethod,
- SourceRange R,
- bool receiverIdOrClass) {
+bool Sema::AreMultipleMethodsInGlobalPool(
+ Selector Sel, ObjCMethodDecl *BestMethod, SourceRange R,
+ bool receiverIdOrClass, SmallVectorImpl<ObjCMethodDecl *> &Methods) {
+ // Diagnose finding more than one method in global pool.
+ SmallVector<ObjCMethodDecl *, 4> FilteredMethods;
+ FilteredMethods.push_back(BestMethod);
+
+ for (auto *M : Methods)
+ if (M != BestMethod && !M->hasAttr<UnavailableAttr>())
+ FilteredMethods.push_back(M);
+
+ if (FilteredMethods.size() > 1)
+ DiagnoseMultipleMethodInGlobalPool(FilteredMethods, Sel, R,
+ receiverIdOrClass);
+
GlobalMethodPool::iterator Pos = MethodPool.find(Sel);
// Test for no method in the pool which should not trigger any warning by
// caller.
return true;
ObjCMethodList &MethList =
BestMethod->isInstanceMethod() ? Pos->second.first : Pos->second.second;
-
- // Diagnose finding more than one method in global pool
- SmallVector<ObjCMethodDecl *, 4> Methods;
- Methods.push_back(BestMethod);
- for (ObjCMethodList *ML = &MethList; ML; ML = ML->getNext())
- if (ObjCMethodDecl *M = ML->getMethod())
- if (!M->isHidden() && M != BestMethod && !M->hasAttr<UnavailableAttr>())
- Methods.push_back(M);
- if (Methods.size() > 1)
- DiagnoseMultipleMethodInGlobalPool(Methods, Sel, R, receiverIdOrClass);
-
return MethList.hasMoreThanOneDecl();
}
typeBound);
if (receiverIsIdLike || ReceiverType->isBlockPointerType() ||
(Receiver && Context.isObjCNSObjectType(Receiver->getType()))) {
- Method = LookupInstanceMethodInGlobalPool(Sel,
- SourceRange(LBracLoc, RBracLoc),
- receiverIsIdLike);
- if (!Method)
- Method = LookupFactoryMethodInGlobalPool(Sel,
- SourceRange(LBracLoc,RBracLoc),
- receiverIsIdLike);
- if (Method) {
+ SmallVector<ObjCMethodDecl*, 4> Methods;
+ CollectMultipleMethodsInGlobalPool(Sel, Methods, true/*InstanceFirst*/,
+ true/*CheckTheOther*/);
+ if (!Methods.empty()) {
+ // We chose the first method as the initial condidate, then try to
+ // select a better one.
+ Method = Methods[0];
+
if (ObjCMethodDecl *BestMethod =
- SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod()))
+ SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod(), Methods))
Method = BestMethod;
+
if (!AreMultipleMethodsInGlobalPool(Sel, Method,
SourceRange(LBracLoc, RBracLoc),
- receiverIsIdLike)) {
- DiagnoseUseOfDecl(Method, SelLoc);
- }
+ receiverIsIdLike, Methods))
+ DiagnoseUseOfDecl(Method, SelLoc);
}
} else if (ReceiverType->isObjCClassOrClassKindOfType() ||
ReceiverType->isObjCQualifiedClassType()) {
if (!Method) {
// If not messaging 'self', look for any factory method named 'Sel'.
if (!Receiver || !isSelfExpr(Receiver)) {
- Method = LookupFactoryMethodInGlobalPool(Sel,
- SourceRange(LBracLoc, RBracLoc));
- if (!Method) {
- // If no class (factory) method was found, check if an _instance_
- // method of the same name exists in the root class only.
- Method = LookupInstanceMethodInGlobalPool(Sel,
- SourceRange(LBracLoc, RBracLoc));
- if (Method)
- if (const ObjCInterfaceDecl *ID =
- dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext())) {
- if (ID->getSuperClass())
- Diag(SelLoc, diag::warn_root_inst_method_not_found)
- << Sel << SourceRange(LBracLoc, RBracLoc);
- }
+ // If no class (factory) method was found, check if an _instance_
+ // method of the same name exists in the root class only.
+ SmallVector<ObjCMethodDecl*, 4> Methods;
+ CollectMultipleMethodsInGlobalPool(Sel, Methods,
+ false/*InstanceFirst*/,
+ true/*CheckTheOther*/);
+ if (!Methods.empty()) {
+ // We chose the first method as the initial condidate, then try
+ // to select a better one.
+ Method = Methods[0];
+
+ // If we find an instance method, emit waring.
+ if (Method->isInstanceMethod()) {
+ if (const ObjCInterfaceDecl *ID =
+ dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext())) {
+ if (ID->getSuperClass())
+ Diag(SelLoc, diag::warn_root_inst_method_not_found)
+ << Sel << SourceRange(LBracLoc, RBracLoc);
+ }
+ }
+
+ if (ObjCMethodDecl *BestMethod =
+ SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod(),
+ Methods))
+ Method = BestMethod;
}
- if (Method)
- if (ObjCMethodDecl *BestMethod =
- SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod()))
- Method = BestMethod;
}
}
}
// behavior isn't very desirable, however we need it for GCC
// compatibility. FIXME: should we deviate??
if (OCIType->qual_empty()) {
- Method = LookupInstanceMethodInGlobalPool(Sel,
- SourceRange(LBracLoc, RBracLoc));
- if (Method) {
- if (auto BestMethod =
- SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod()))
+ SmallVector<ObjCMethodDecl*, 4> Methods;
+ CollectMultipleMethodsInGlobalPool(Sel, Methods,
+ true/*InstanceFirst*/,
+ false/*CheckTheOther*/);
+ if (!Methods.empty()) {
+ // We chose the first method as the initial condidate, then try
+ // to select a better one.
+ Method = Methods[0];
+
+ if (ObjCMethodDecl *BestMethod =
+ SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod(),
+ Methods))
Method = BestMethod;
+
AreMultipleMethodsInGlobalPool(Sel, Method,
SourceRange(LBracLoc, RBracLoc),
- true);
+ true/*receiverIdOrClass*/,
+ Methods);
}
if (Method && !forwardClass)
Diag(SelLoc, diag::warn_maynot_respond)
}
}
-ObjCMethodDecl *Sema::SelectBestMethod(Selector Sel, MultiExprArg Args,
- bool IsInstance) {
- SmallVector<ObjCMethodDecl*, 4> Methods;
- if (!CollectMultipleMethodsInGlobalPool(Sel, Methods, IsInstance))
+ObjCMethodDecl *
+Sema::SelectBestMethod(Selector Sel, MultiExprArg Args, bool IsInstance,
+ SmallVectorImpl<ObjCMethodDecl *> &Methods) {
+ if (Methods.size() <= 1)
return nullptr;
-
+
for (unsigned b = 0, e = Methods.size(); b < e; b++) {
bool Match = true;
ObjCMethodDecl *Method = Methods[b];