@@ -4636,6 +4636,62 @@ static void checkObjCMethodX86VectorTypes(Sema &SemaRef,
46364636 << (Triple.isMacOSX () ? " macOS 10.11" : " iOS 9" );
46374637}
46384638
4639+ static void mergeObjCDirectMembers (Sema &S, Decl *CD, ObjCMethodDecl *Method) {
4640+ if (!Method->isDirectMethod () && !Method->hasAttr <UnavailableAttr>() &&
4641+ CD->hasAttr <ObjCDirectMembersAttr>()) {
4642+ Method->addAttr (
4643+ ObjCDirectAttr::CreateImplicit (S.Context , Method->getLocation ()));
4644+ }
4645+ }
4646+
4647+ static void checkObjCDirectMethodClashes (Sema &S, ObjCInterfaceDecl *IDecl,
4648+ ObjCMethodDecl *Method,
4649+ ObjCImplDecl *ImpDecl = nullptr ) {
4650+ auto Sel = Method->getSelector ();
4651+ bool isInstance = Method->isInstanceMethod ();
4652+ bool diagnosed = false ;
4653+
4654+ auto diagClash = [&](const ObjCMethodDecl *IMD) {
4655+ if (diagnosed || IMD->isImplicit ())
4656+ return ;
4657+ if (Method->isDirectMethod () || IMD->isDirectMethod ()) {
4658+ S.Diag (Method->getLocation (), diag::err_objc_direct_duplicate_decl)
4659+ << Method->isDirectMethod () << /* method */ 0 << IMD->isDirectMethod ()
4660+ << Method->getDeclName ();
4661+ S.Diag (IMD->getLocation (), diag::note_previous_declaration);
4662+ diagnosed = true ;
4663+ }
4664+ };
4665+
4666+ // Look for any other declaration of this method anywhere we can see in this
4667+ // compilation unit.
4668+ //
4669+ // We do not use IDecl->lookupMethod() because we have specific needs:
4670+ //
4671+ // - we absolutely do not need to walk protocols, because
4672+ // diag::err_objc_direct_on_protocol has already been emitted
4673+ // during parsing if there's a conflict,
4674+ //
4675+ // - when we do not find a match in a given @interface container,
4676+ // we need to attempt looking it up in the @implementation block if the
4677+ // translation unit sees it to find more clashes.
4678+
4679+ if (auto *IMD = IDecl->getMethod (Sel, isInstance))
4680+ diagClash (IMD);
4681+ else if (auto *Impl = IDecl->getImplementation ())
4682+ if (Impl != ImpDecl)
4683+ if (auto *IMD = IDecl->getImplementation ()->getMethod (Sel, isInstance))
4684+ diagClash (IMD);
4685+
4686+ for (const auto *Cat : IDecl->visible_categories ())
4687+ if (auto *IMD = Cat->getMethod (Sel, isInstance))
4688+ diagClash (IMD);
4689+ else if (auto CatImpl = Cat->getImplementation ())
4690+ if (CatImpl != ImpDecl)
4691+ if (auto *IMD = Cat->getMethod (Sel, isInstance))
4692+ diagClash (IMD);
4693+ }
4694+
46394695Decl *Sema::ActOnMethodDeclaration (
46404696 Scope *S, SourceLocation MethodLoc, SourceLocation EndLoc,
46414697 tok::TokenKind MethodType, ObjCDeclSpec &ReturnQT, ParsedType ReturnType,
@@ -4866,9 +4922,9 @@ Decl *Sema::ActOnMethodDeclaration(
48664922 Diag (ObjCMethod->getLocation (), diag::warn_dealloc_in_category)
48674923 << ObjCMethod->getDeclName ();
48684924 }
4869- } else if (ImpDecl-> hasAttr <ObjCDirectMembersAttr>()) {
4870- ObjCMethod-> addAttr (
4871- ObjCDirectAttr::CreateImplicit (Context, ObjCMethod-> getLocation ()) );
4925+ } else {
4926+ mergeObjCDirectMembers (* this , ClassDecl, ObjCMethod);
4927+ checkObjCDirectMethodClashes (* this , IDecl, ObjCMethod, ImpDecl );
48724928 }
48734929
48744930 // Warn if a method declared in a protocol to which a category or
@@ -4889,39 +4945,16 @@ Decl *Sema::ActOnMethodDeclaration(
48894945 }
48904946 } else {
48914947 if (!isa<ObjCProtocolDecl>(ClassDecl)) {
4892- if (!ObjCMethod->isDirectMethod () &&
4893- ClassDecl->hasAttr <ObjCDirectMembersAttr>()) {
4894- ObjCMethod->addAttr (
4895- ObjCDirectAttr::CreateImplicit (Context, ObjCMethod->getLocation ()));
4896- }
4948+ mergeObjCDirectMembers (*this , ClassDecl, ObjCMethod);
48974949
4898- // There can be a single declaration in any @interface container
4899- // for a given direct method, look for clashes as we add them.
4900- //
4901- // For valid code, we should always know the primary interface
4902- // declaration by now, however for invalid code we'll keep parsing
4903- // but we won't find the primary interface and IDecl will be nil.
49044950 ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(ClassDecl);
49054951 if (!IDecl)
49064952 IDecl = cast<ObjCCategoryDecl>(ClassDecl)->getClassInterface ();
4907-
4953+ // For valid code, we should always know the primary interface
4954+ // declaration by now, however for invalid code we'll keep parsing
4955+ // but we won't find the primary interface and IDecl will be nil.
49084956 if (IDecl)
4909- if (auto *IMD = IDecl->lookupMethod (ObjCMethod->getSelector (),
4910- ObjCMethod->isInstanceMethod (),
4911- /* shallowCategoryLookup=*/ false ,
4912- /* followSuper=*/ false )) {
4913- if (isa<ObjCProtocolDecl>(IMD->getDeclContext ())) {
4914- // Do not emit a diagnostic for the Protocol case:
4915- // diag::err_objc_direct_on_protocol has already been emitted
4916- // during parsing for these with a nicer diagnostic.
4917- } else if (ObjCMethod->isDirectMethod () || IMD->isDirectMethod ()) {
4918- Diag (ObjCMethod->getLocation (),
4919- diag::err_objc_direct_duplicate_decl)
4920- << ObjCMethod->isDirectMethod () << /* method */ 0
4921- << IMD->isDirectMethod () << ObjCMethod->getDeclName ();
4922- Diag (IMD->getLocation (), diag::note_previous_declaration);
4923- }
4924- }
4957+ checkObjCDirectMethodClashes (*this , IDecl, ObjCMethod);
49254958 }
49264959
49274960 cast<DeclContext>(ClassDecl)->addDecl (ObjCMethod);
0 commit comments