@@ -4581,6 +4581,62 @@ static void checkObjCMethodX86VectorTypes(Sema &SemaRef,
4581
4581
<< (Triple.isMacOSX () ? " macOS 10.11" : " iOS 9" );
4582
4582
}
4583
4583
4584
+ static void mergeObjCDirectMembers (Sema &S, Decl *CD, ObjCMethodDecl *Method) {
4585
+ if (!Method->isDirectMethod () && !Method->hasAttr <UnavailableAttr>() &&
4586
+ CD->hasAttr <ObjCDirectMembersAttr>()) {
4587
+ Method->addAttr (
4588
+ ObjCDirectAttr::CreateImplicit (S.Context , Method->getLocation ()));
4589
+ }
4590
+ }
4591
+
4592
+ static void checkObjCDirectMethodClashes (Sema &S, ObjCInterfaceDecl *IDecl,
4593
+ ObjCMethodDecl *Method,
4594
+ ObjCImplDecl *ImpDecl = nullptr ) {
4595
+ auto Sel = Method->getSelector ();
4596
+ bool isInstance = Method->isInstanceMethod ();
4597
+ bool diagnosed = false ;
4598
+
4599
+ auto diagClash = [&](const ObjCMethodDecl *IMD) {
4600
+ if (diagnosed || IMD->isImplicit ())
4601
+ return ;
4602
+ if (Method->isDirectMethod () || IMD->isDirectMethod ()) {
4603
+ S.Diag (Method->getLocation (), diag::err_objc_direct_duplicate_decl)
4604
+ << Method->isDirectMethod () << /* method */ 0 << IMD->isDirectMethod ()
4605
+ << Method->getDeclName ();
4606
+ S.Diag (IMD->getLocation (), diag::note_previous_declaration);
4607
+ diagnosed = true ;
4608
+ }
4609
+ };
4610
+
4611
+ // Look for any other declaration of this method anywhere we can see in this
4612
+ // compilation unit.
4613
+ //
4614
+ // We do not use IDecl->lookupMethod() because we have specific needs:
4615
+ //
4616
+ // - we absolutely do not need to walk protocols, because
4617
+ // diag::err_objc_direct_on_protocol has already been emitted
4618
+ // during parsing if there's a conflict,
4619
+ //
4620
+ // - when we do not find a match in a given @interface container,
4621
+ // we need to attempt looking it up in the @implementation block if the
4622
+ // translation unit sees it to find more clashes.
4623
+
4624
+ if (auto *IMD = IDecl->getMethod (Sel, isInstance))
4625
+ diagClash (IMD);
4626
+ else if (auto *Impl = IDecl->getImplementation ())
4627
+ if (Impl != ImpDecl)
4628
+ if (auto *IMD = IDecl->getImplementation ()->getMethod (Sel, isInstance))
4629
+ diagClash (IMD);
4630
+
4631
+ for (const auto *Cat : IDecl->visible_categories ())
4632
+ if (auto *IMD = Cat->getMethod (Sel, isInstance))
4633
+ diagClash (IMD);
4634
+ else if (auto CatImpl = Cat->getImplementation ())
4635
+ if (CatImpl != ImpDecl)
4636
+ if (auto *IMD = Cat->getMethod (Sel, isInstance))
4637
+ diagClash (IMD);
4638
+ }
4639
+
4584
4640
Decl *Sema::ActOnMethodDeclaration (
4585
4641
Scope *S, SourceLocation MethodLoc, SourceLocation EndLoc,
4586
4642
tok::TokenKind MethodType, ObjCDeclSpec &ReturnQT, ParsedType ReturnType,
@@ -4809,9 +4865,9 @@ Decl *Sema::ActOnMethodDeclaration(
4809
4865
Diag (ObjCMethod->getLocation (), diag::warn_dealloc_in_category)
4810
4866
<< ObjCMethod->getDeclName ();
4811
4867
}
4812
- } else if (ImpDecl-> hasAttr <ObjCDirectMembersAttr>()) {
4813
- ObjCMethod-> addAttr (
4814
- ObjCDirectAttr::CreateImplicit (Context, ObjCMethod-> getLocation ()) );
4868
+ } else {
4869
+ mergeObjCDirectMembers (* this , ClassDecl, ObjCMethod);
4870
+ checkObjCDirectMethodClashes (* this , IDecl, ObjCMethod, ImpDecl );
4815
4871
}
4816
4872
4817
4873
// Warn if a method declared in a protocol to which a category or
@@ -4832,39 +4888,16 @@ Decl *Sema::ActOnMethodDeclaration(
4832
4888
}
4833
4889
} else {
4834
4890
if (!isa<ObjCProtocolDecl>(ClassDecl)) {
4835
- if (!ObjCMethod->isDirectMethod () &&
4836
- ClassDecl->hasAttr <ObjCDirectMembersAttr>()) {
4837
- ObjCMethod->addAttr (
4838
- ObjCDirectAttr::CreateImplicit (Context, ObjCMethod->getLocation ()));
4839
- }
4891
+ mergeObjCDirectMembers (*this , ClassDecl, ObjCMethod);
4840
4892
4841
- // There can be a single declaration in any @interface container
4842
- // for a given direct method, look for clashes as we add them.
4843
- //
4844
- // For valid code, we should always know the primary interface
4845
- // declaration by now, however for invalid code we'll keep parsing
4846
- // but we won't find the primary interface and IDecl will be nil.
4847
4893
ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(ClassDecl);
4848
4894
if (!IDecl)
4849
4895
IDecl = cast<ObjCCategoryDecl>(ClassDecl)->getClassInterface ();
4850
-
4896
+ // For valid code, we should always know the primary interface
4897
+ // declaration by now, however for invalid code we'll keep parsing
4898
+ // but we won't find the primary interface and IDecl will be nil.
4851
4899
if (IDecl)
4852
- if (auto *IMD = IDecl->lookupMethod (ObjCMethod->getSelector (),
4853
- ObjCMethod->isInstanceMethod (),
4854
- /* shallowCategoryLookup=*/ false ,
4855
- /* followSuper=*/ false )) {
4856
- if (isa<ObjCProtocolDecl>(IMD->getDeclContext ())) {
4857
- // Do not emit a diagnostic for the Protocol case:
4858
- // diag::err_objc_direct_on_protocol has already been emitted
4859
- // during parsing for these with a nicer diagnostic.
4860
- } else if (ObjCMethod->isDirectMethod () || IMD->isDirectMethod ()) {
4861
- Diag (ObjCMethod->getLocation (),
4862
- diag::err_objc_direct_duplicate_decl)
4863
- << ObjCMethod->isDirectMethod () << /* method */ 0
4864
- << IMD->isDirectMethod () << ObjCMethod->getDeclName ();
4865
- Diag (IMD->getLocation (), diag::note_previous_declaration);
4866
- }
4867
- }
4900
+ checkObjCDirectMethodClashes (*this , IDecl, ObjCMethod);
4868
4901
}
4869
4902
4870
4903
cast<DeclContext>(ClassDecl)->addDecl (ObjCMethod);
0 commit comments