Skip to content

Commit e210684

Browse files
committed
Support class extensions in objcImpl
Their requirements are now included when typechecking the main body extension. Fixes rdar://118535473.
1 parent 5edd379 commit e210684

File tree

4 files changed

+37
-3
lines changed

4 files changed

+37
-3
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5885,6 +5885,10 @@ Identifier ExtensionDecl::getObjCCategoryName() const {
58855885

58865886
// We'll look for an implementation with this category name.
58875887
auto clangCategoryName = category->getName();
5888+
if (clangCategoryName.empty())
5889+
// Class extension (has an empty name).
5890+
return Identifier();
5891+
58885892
return getASTContext().getIdentifier(clangCategoryName);
58895893
}
58905894

@@ -6109,6 +6113,13 @@ Decl *Decl::getObjCImplementationDecl() const {
61096113
// This *is* the implementation, if it has one.
61106114
return nullptr;
61116115

6116+
// If this is an imported class extension, it's implemented by the main body's
6117+
// implementation. (But the relationship is not reciprocal, and hence not
6118+
// modeled by `ObjCInterfaceAndImplementationRequest`.)
6119+
if (auto ext = dyn_cast<ExtensionDecl>(this))
6120+
if (ext->getObjCCategoryName().empty())
6121+
return ext->getSelfNominalTypeDecl()->getObjCImplementationDecl();
6122+
61126123
ObjCInterfaceAndImplementationRequest req{const_cast<Decl *>(this)};
61136124
return evaluateOrDefault(getASTContext().evaluator, req, {})
61146125
.implementationDecl;

lib/Sema/TypeCheckDeclObjC.cpp

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3068,6 +3068,17 @@ class ObjCImplementationChecker {
30683068

30693069
addRequirement(member);
30703070
}
3071+
3072+
if (auto classDecl = dyn_cast<ClassDecl>(idc)) {
3073+
// The extension for the main class body should also implement the
3074+
// contents of class extensions. Find all class extensions (imported
3075+
// categories with no name) and add their requirements too.
3076+
for (auto ext : classDecl->getExtensions()) {
3077+
if (ext->hasClangNode() && ext->getObjCCategoryName().empty()) {
3078+
addRequirements(ext);
3079+
}
3080+
}
3081+
}
30713082
}
30723083

30733084
void addCandidates(ExtensionDecl *ext) {
@@ -3422,9 +3433,9 @@ class ObjCImplementationChecker {
34223433

34233434
// Check only applies to members of implementations, not implementations in
34243435
// their own right.
3425-
if (!cand->isObjCImplementation()
3426-
&& cand->getDeclContext()->getImplementedObjCContext()
3427-
!= req->getDeclContext())
3436+
if (!cand->isObjCImplementation() &&
3437+
getCategoryName(cand->getDeclContext()->getImplementedObjCContext())
3438+
!= getCategoryName(req->getDeclContext()))
34283439
return MatchOutcome::WrongCategory;
34293440

34303441
if (cand->getKind() != req->getKind())

test/decl/ext/Inputs/objc_implementation.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,13 @@
5959

6060
@end
6161

62+
@interface ObjCClass ()
63+
64+
- (void)extensionMethodFromHeader1:(int)param;
65+
- (void)extensionMethodFromHeader2:(int)param;
66+
67+
@end
68+
6269
@interface ObjCClass (PresentAdditions)
6370

6471
- (void)categoryMethodFromHeader1:(int)param;

test/decl/ext/objc_implementation.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ protocol EmptySwiftProto {}
1212
// FIXME: give better diagnostic expected-warning@-6 {{extension for main class interface should provide implementation for instance method 'method(fromHeader3:)'}}
1313
// expected-warning@-7 {{'@_objcImplementation' extension cannot add conformance to 'EmptySwiftProto'; add this conformance with an ordinary extension}}
1414
// expected-warning@-8 {{'@_objcImplementation' extension cannot add conformance to 'EmptyObjCProto'; add this conformance in the Objective-C header}}
15+
// expected-warning@-9 {{extension for main class interface should provide implementation for instance method 'extensionMethod(fromHeader2:)'}}
1516

1617
func method(fromHeader1: CInt) {
1718
// OK, provides an implementation for the header's method.
@@ -215,6 +216,10 @@ protocol EmptySwiftProto {}
215216
@nonobjc public convenience init(notFromHeader6: CInt) {
216217
// OK
217218
}
219+
220+
@objc func extensionMethod(fromHeader1: CInt) {
221+
// OK
222+
}
218223
}
219224

220225
@_objcImplementation(PresentAdditions) extension ObjCClass {

0 commit comments

Comments
 (0)