@@ -4636,6 +4636,62 @@ static void checkObjCMethodX86VectorTypes(Sema &SemaRef,
4636
4636
<< (Triple.isMacOSX () ? " macOS 10.11" : " iOS 9" );
4637
4637
}
4638
4638
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
+
4639
4695
Decl *Sema::ActOnMethodDeclaration (
4640
4696
Scope *S, SourceLocation MethodLoc, SourceLocation EndLoc,
4641
4697
tok::TokenKind MethodType, ObjCDeclSpec &ReturnQT, ParsedType ReturnType,
@@ -4866,9 +4922,9 @@ Decl *Sema::ActOnMethodDeclaration(
4866
4922
Diag (ObjCMethod->getLocation (), diag::warn_dealloc_in_category)
4867
4923
<< ObjCMethod->getDeclName ();
4868
4924
}
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 );
4872
4928
}
4873
4929
4874
4930
// Warn if a method declared in a protocol to which a category or
@@ -4889,39 +4945,16 @@ Decl *Sema::ActOnMethodDeclaration(
4889
4945
}
4890
4946
} else {
4891
4947
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);
4897
4949
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.
4904
4950
ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(ClassDecl);
4905
4951
if (!IDecl)
4906
4952
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.
4908
4956
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);
4925
4958
}
4926
4959
4927
4960
cast<DeclContext>(ClassDecl)->addDecl (ObjCMethod);
0 commit comments