[clang] 20d704a - [objc_direct] also go through implementations when looking for clashes
Pierre Habouzit via cfe-commits
cfe-commits at lists.llvm.org
Mon Mar 23 20:49:34 PDT 2020
Author: Pierre Habouzit
Date: 2020-03-23T20:49:09-07:00
New Revision: 20d704a75ed51c7a9a155aa3978d0c02671c3f69
URL: https://github.com/llvm/llvm-project/commit/20d704a75ed51c7a9a155aa3978d0c02671c3f69
DIFF: https://github.com/llvm/llvm-project/commit/20d704a75ed51c7a9a155aa3978d0c02671c3f69.diff
LOG: [objc_direct] also go through implementations when looking for clashes
Some methods are sometimes declared in the @implementation blocks which
can cause undiagnosed clashes.
Just write a checkObjCDirectMethodClashes() for this purpose.
Also make sure that "unavailable" selectors do not inherit
objc_direct_members.
Differential Revision: https://reviews.llvm.org/D76643
Signed-off-by: Pierre Habouzit <phabouzit at apple.com>
Radar-ID: rdar://problem/59332804, rdar://problem/59782963
Added:
Modified:
clang/lib/Sema/SemaDeclObjC.cpp
clang/test/SemaObjC/method-direct-one-definition.m
clang/test/SemaObjC/method-direct.m
Removed:
################################################################################
diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp
index 369b04ed8e25..934e1a23141c 100644
--- a/clang/lib/Sema/SemaDeclObjC.cpp
+++ b/clang/lib/Sema/SemaDeclObjC.cpp
@@ -4581,6 +4581,62 @@ static void checkObjCMethodX86VectorTypes(Sema &SemaRef,
<< (Triple.isMacOSX() ? "macOS 10.11" : "iOS 9");
}
+static void mergeObjCDirectMembers(Sema &S, Decl *CD, ObjCMethodDecl *Method) {
+ if (!Method->isDirectMethod() && !Method->hasAttr<UnavailableAttr>() &&
+ CD->hasAttr<ObjCDirectMembersAttr>()) {
+ Method->addAttr(
+ ObjCDirectAttr::CreateImplicit(S.Context, Method->getLocation()));
+ }
+}
+
+static void checkObjCDirectMethodClashes(Sema &S, ObjCInterfaceDecl *IDecl,
+ ObjCMethodDecl *Method,
+ ObjCImplDecl *ImpDecl = nullptr) {
+ auto Sel = Method->getSelector();
+ bool isInstance = Method->isInstanceMethod();
+ bool diagnosed = false;
+
+ auto diagClash = [&](const ObjCMethodDecl *IMD) {
+ if (diagnosed || IMD->isImplicit())
+ return;
+ if (Method->isDirectMethod() || IMD->isDirectMethod()) {
+ S.Diag(Method->getLocation(), diag::err_objc_direct_duplicate_decl)
+ << Method->isDirectMethod() << /* method */ 0 << IMD->isDirectMethod()
+ << Method->getDeclName();
+ S.Diag(IMD->getLocation(), diag::note_previous_declaration);
+ diagnosed = true;
+ }
+ };
+
+ // Look for any other declaration of this method anywhere we can see in this
+ // compilation unit.
+ //
+ // We do not use IDecl->lookupMethod() because we have specific needs:
+ //
+ // - we absolutely do not need to walk protocols, because
+ // diag::err_objc_direct_on_protocol has already been emitted
+ // during parsing if there's a conflict,
+ //
+ // - when we do not find a match in a given @interface container,
+ // we need to attempt looking it up in the @implementation block if the
+ // translation unit sees it to find more clashes.
+
+ if (auto *IMD = IDecl->getMethod(Sel, isInstance))
+ diagClash(IMD);
+ else if (auto *Impl = IDecl->getImplementation())
+ if (Impl != ImpDecl)
+ if (auto *IMD = IDecl->getImplementation()->getMethod(Sel, isInstance))
+ diagClash(IMD);
+
+ for (const auto *Cat : IDecl->visible_categories())
+ if (auto *IMD = Cat->getMethod(Sel, isInstance))
+ diagClash(IMD);
+ else if (auto CatImpl = Cat->getImplementation())
+ if (CatImpl != ImpDecl)
+ if (auto *IMD = Cat->getMethod(Sel, isInstance))
+ diagClash(IMD);
+}
+
Decl *Sema::ActOnMethodDeclaration(
Scope *S, SourceLocation MethodLoc, SourceLocation EndLoc,
tok::TokenKind MethodType, ObjCDeclSpec &ReturnQT, ParsedType ReturnType,
@@ -4809,9 +4865,9 @@ Decl *Sema::ActOnMethodDeclaration(
Diag(ObjCMethod->getLocation(), diag::warn_dealloc_in_category)
<< ObjCMethod->getDeclName();
}
- } else if (ImpDecl->hasAttr<ObjCDirectMembersAttr>()) {
- ObjCMethod->addAttr(
- ObjCDirectAttr::CreateImplicit(Context, ObjCMethod->getLocation()));
+ } else {
+ mergeObjCDirectMembers(*this, ClassDecl, ObjCMethod);
+ checkObjCDirectMethodClashes(*this, IDecl, ObjCMethod, ImpDecl);
}
// Warn if a method declared in a protocol to which a category or
@@ -4832,39 +4888,16 @@ Decl *Sema::ActOnMethodDeclaration(
}
} else {
if (!isa<ObjCProtocolDecl>(ClassDecl)) {
- if (!ObjCMethod->isDirectMethod() &&
- ClassDecl->hasAttr<ObjCDirectMembersAttr>()) {
- ObjCMethod->addAttr(
- ObjCDirectAttr::CreateImplicit(Context, ObjCMethod->getLocation()));
- }
+ mergeObjCDirectMembers(*this, ClassDecl, ObjCMethod);
- // There can be a single declaration in any @interface container
- // for a given direct method, look for clashes as we add them.
- //
- // For valid code, we should always know the primary interface
- // declaration by now, however for invalid code we'll keep parsing
- // but we won't find the primary interface and IDecl will be nil.
ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(ClassDecl);
if (!IDecl)
IDecl = cast<ObjCCategoryDecl>(ClassDecl)->getClassInterface();
-
+ // For valid code, we should always know the primary interface
+ // declaration by now, however for invalid code we'll keep parsing
+ // but we won't find the primary interface and IDecl will be nil.
if (IDecl)
- if (auto *IMD = IDecl->lookupMethod(ObjCMethod->getSelector(),
- ObjCMethod->isInstanceMethod(),
- /*shallowCategoryLookup=*/false,
- /*followSuper=*/false)) {
- if (isa<ObjCProtocolDecl>(IMD->getDeclContext())) {
- // Do not emit a diagnostic for the Protocol case:
- // diag::err_objc_direct_on_protocol has already been emitted
- // during parsing for these with a nicer diagnostic.
- } else if (ObjCMethod->isDirectMethod() || IMD->isDirectMethod()) {
- Diag(ObjCMethod->getLocation(),
- diag::err_objc_direct_duplicate_decl)
- << ObjCMethod->isDirectMethod() << /* method */ 0
- << IMD->isDirectMethod() << ObjCMethod->getDeclName();
- Diag(IMD->getLocation(), diag::note_previous_declaration);
- }
- }
+ checkObjCDirectMethodClashes(*this, IDecl, ObjCMethod);
}
cast<DeclContext>(ClassDecl)->addDecl(ObjCMethod);
diff --git a/clang/test/SemaObjC/method-direct-one-definition.m b/clang/test/SemaObjC/method-direct-one-definition.m
index e6355d2cb7ba..3dcf89d784cf 100644
--- a/clang/test/SemaObjC/method-direct-one-definition.m
+++ b/clang/test/SemaObjC/method-direct-one-definition.m
@@ -30,6 +30,15 @@ @interface B (OtherCat)
- (void)B_OtherCat __attribute__((objc_direct)); // expected-note {{previous declaration is here}}
@end
+ at implementation B
+- (void)B_primary {
+}
+- (void)B_extension {
+}
+- (void)B_implOnly __attribute__((objc_direct)) { // expected-note {{previous declaration is here}}
+}
+ at end
+
@implementation B (Cat)
- (void)B_primary { // expected-error {{direct method was declared in the primary interface but is implemented in a category}}
}
@@ -39,6 +48,8 @@ - (void)B_Cat {
}
- (void)B_OtherCat { // expected-error {{direct method was declared in a category but is implemented in a
diff erent category}}
}
+- (void)B_implOnly __attribute__((objc_direct)) { // expected-error {{direct method declaration conflicts with previous direct declaration of method 'B_implOnly'}}
+}
@end
__attribute__((objc_root_class))
diff --git a/clang/test/SemaObjC/method-direct.m b/clang/test/SemaObjC/method-direct.m
index 9aef9808abbd..80ca5b2e6ebe 100644
--- a/clang/test/SemaObjC/method-direct.m
+++ b/clang/test/SemaObjC/method-direct.m
@@ -12,6 +12,7 @@ + (void)classProtoMethod __attribute__((objc_direct)); // expected-error {{'objc
__attribute__((objc_root_class))
@interface Root
+- (void)unavailableInChild;
- (void)rootRegular; // expected-note {{previous declaration is here}}
+ (void)classRootRegular; // expected-note {{previous declaration is here}}
- (void)rootDirect __attribute__((objc_direct)); // expected-note {{previous declaration is here}};
@@ -52,6 +53,7 @@ + (void)classRootCategoryDirect2 __attribute__((objc_direct)); // expected-note
__attribute__((objc_direct_members))
@interface SubDirectMembers : Root
@property int foo; // expected-note {{previous declaration is here}}
+- (void)unavailableInChild __attribute__((unavailable)); // should not warn
- (instancetype)init;
@end
@@ -81,6 +83,8 @@ + (void)classRootCategoryDirect2; // expected-error {{cannot override a method
__attribute__((objc_direct_members))
@implementation Root
+- (void)unavailableInChild {
+}
- (void)rootRegular {
}
+ (void)classRootRegular {
More information about the cfe-commits
mailing list