diff options
Diffstat (limited to 'clang/lib/Sema/SemaDeclObjC.cpp')
-rw-r--r-- | clang/lib/Sema/SemaDeclObjC.cpp | 48 |
1 files changed, 43 insertions, 5 deletions
diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index 8ba3e7acec2..32244e9e195 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -3281,11 +3281,45 @@ static bool isAcceptableMethodMismatch(ObjCMethodDecl *chosen, return (chosen->getReturnType()->isIntegerType()); } +/// Return true if the given method is wthin the type bound. +static bool FilterMethodsByTypeBound(ObjCMethodDecl *Method, + const ObjCObjectType *TypeBound) { + if (!TypeBound) + return true; + + if (TypeBound->isObjCId()) + // FIXME: should we handle the case of bounding to id<A, B> differently? + return true; + + auto *BoundInterface = TypeBound->getInterface(); + assert(BoundInterface && "unexpected object type!"); + + // Check if the Method belongs to a protocol. We should allow any method + // defined in any protocol, because any subclass could adopt the protocol. + auto *MethodProtocol = dyn_cast<ObjCProtocolDecl>(Method->getDeclContext()); + if (MethodProtocol) { + return true; + } + + // If the Method belongs to a class, check if it belongs to the class + // hierarchy of the class bound. + if (ObjCInterfaceDecl *MethodInterface = Method->getClassInterface()) { + // We allow methods declared within classes that are part of the hierarchy + // of the class bound (superclass of, subclass of, or the same as the class + // bound). + return MethodInterface == BoundInterface || + MethodInterface->isSuperClassOf(BoundInterface) || + BoundInterface->isSuperClassOf(MethodInterface); + } + llvm_unreachable("unknow method context"); +} + /// 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 InstanceFirst, bool CheckTheOther) { + bool InstanceFirst, bool CheckTheOther, + const ObjCObjectType *TypeBound) { if (ExternalSource) ReadMethodPool(Sel); @@ -3297,8 +3331,10 @@ bool Sema::CollectMultipleMethodsInGlobalPool( 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()); + if (M->getMethod() && !M->getMethod()->isHidden()) { + if (FilterMethodsByTypeBound(M->getMethod(), TypeBound)) + Methods.push_back(M->getMethod()); + } // Return if we find any method with the desired kind. if (!Methods.empty()) @@ -3311,8 +3347,10 @@ bool Sema::CollectMultipleMethodsInGlobalPool( 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()); + if (M->getMethod() && !M->getMethod()->isHidden()) { + if (FilterMethodsByTypeBound(M->getMethod(), TypeBound)) + Methods.push_back(M->getMethod()); + } return Methods.size() > 1; } |