Skip to content

Commit 87da04e

Browse files
committed
ClangImporter: Lazily load mirrored protocol members in classes
1 parent 45e5848 commit 87da04e

File tree

4 files changed

+58
-32
lines changed

4 files changed

+58
-32
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3605,26 +3605,14 @@ ClangImporter::Implementation::loadNamedMembers(
36053605
const IterableDeclContext *IDC, DeclBaseName N, uint64_t contextData) {
36063606

36073607
auto *D = IDC->getDecl();
3608-
auto *DC = cast<DeclContext>(D);
3608+
auto *DC = D->getInnermostDeclContext();
36093609
auto *CD = D->getClangDecl();
36103610
auto *CDC = cast<clang::DeclContext>(CD);
36113611
assert(CD && "loadNamedMembers on a Decl without a clangDecl");
36123612

36133613
auto *nominal = DC->getSelfNominalTypeDecl();
36143614
auto effectiveClangContext = getEffectiveClangContext(nominal);
36153615

3616-
// FIXME: The legacy of mirroring protocol members rears its ugly head,
3617-
// and as a result we have to bail on any @interface or @category that
3618-
// has a declared protocol conformance.
3619-
if (auto *ID = dyn_cast<clang::ObjCInterfaceDecl>(CD)) {
3620-
if (ID->protocol_begin() != ID->protocol_end())
3621-
return None;
3622-
}
3623-
if (auto *CCD = dyn_cast<clang::ObjCCategoryDecl>(CD)) {
3624-
if (CCD->protocol_begin() != CCD->protocol_end())
3625-
return None;
3626-
}
3627-
36283616
// Also bail out if there are any global-as-member mappings for this type; we
36293617
// can support some of them lazily but the full set of idioms seems
36303618
// prohibitively complex (also they're not stored in by-name lookup, for
@@ -3687,6 +3675,15 @@ ClangImporter::Implementation::loadNamedMembers(
36873675
}
36883676
}
36893677

3678+
if (!isa<ProtocolDecl>(D)) {
3679+
if (auto *OCD = dyn_cast<clang::ObjCContainerDecl>(CD)) {
3680+
SmallVector<Decl *, 1> newMembers;
3681+
importMirroredProtocolMembers(OCD, DC, N, newMembers);
3682+
for (auto member : newMembers)
3683+
Members.push_back(cast<ValueDecl>(member));
3684+
}
3685+
}
3686+
36903687
return Members;
36913688
}
36923689

lib/ClangImporter/ImportDecl.cpp

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4511,7 +4511,8 @@ namespace {
45114511
/// methods become class methods on NSObject).
45124512
void importMirroredProtocolMembers(const clang::ObjCContainerDecl *decl,
45134513
DeclContext *dc,
4514-
SmallVectorImpl<Decl *> &members);
4514+
Optional<DeclBaseName> name,
4515+
SmallVectorImpl<Decl *> &newMembers);
45154516

45164517
void importNonOverriddenMirroredMethods(DeclContext *dc,
45174518
MutableArrayRef<MirroredMethodEntry> entries,
@@ -6927,9 +6928,16 @@ Optional<GenericParamList *> SwiftDeclConverter::importObjCGenericParams(
69276928
genericParams, Impl.importSourceLoc(typeParamList->getRAngleLoc()));
69286929
}
69296930

6931+
void ClangImporter::Implementation::importMirroredProtocolMembers(
6932+
const clang::ObjCContainerDecl *decl, DeclContext *dc,
6933+
Optional<DeclBaseName> name, SmallVectorImpl<Decl *> &members) {
6934+
SwiftDeclConverter converter(*this, CurrentVersion);
6935+
converter.importMirroredProtocolMembers(decl, dc, name, members);
6936+
}
6937+
69306938
void SwiftDeclConverter::importMirroredProtocolMembers(
69316939
const clang::ObjCContainerDecl *decl, DeclContext *dc,
6932-
SmallVectorImpl<Decl *> &members) {
6940+
Optional<DeclBaseName> name, SmallVectorImpl<Decl *> &members) {
69336941
assert(dc);
69346942
const clang::ObjCInterfaceDecl *interfaceDecl = nullptr;
69356943
const ClangModuleUnit *declModule;
@@ -6975,24 +6983,24 @@ void SwiftDeclConverter::importMirroredProtocolMembers(
69756983

69766984
const auto &languageVersion =
69776985
Impl.SwiftContext.LangOpts.EffectiveLanguageVersion;
6978-
for (auto member : proto->getMembers()) {
6986+
auto importProtocolRequirement = [&](Decl *member) {
69796987
// Skip compatibility stubs; there's no reason to mirror them.
69806988
if (member->getAttrs().isUnavailableInSwiftVersion(languageVersion))
6981-
continue;
6989+
return;
69826990

69836991
if (auto prop = dyn_cast<VarDecl>(member)) {
69846992
auto objcProp =
69856993
dyn_cast_or_null<clang::ObjCPropertyDecl>(prop->getClangDecl());
69866994
if (!objcProp)
6987-
continue;
6995+
return;
69886996

69896997
// We can't import a property if there's already a method with this
69906998
// name. (This also covers other properties with that same name.)
69916999
// FIXME: We should still mirror the setter as a method if it's
69927000
// not already there.
69937001
clang::Selector sel = objcProp->getGetterName();
69947002
if (interfaceDecl->getInstanceMethod(sel))
6995-
continue;
7003+
return;
69967004

69977005
bool inNearbyCategory =
69987006
std::any_of(interfaceDecl->visible_categories_begin(),
@@ -7009,7 +7017,7 @@ void SwiftDeclConverter::importMirroredProtocolMembers(
70097017
return category->getInstanceMethod(sel);
70107018
});
70117019
if (inNearbyCategory)
7012-
continue;
7020+
return;
70137021

70147022
if (auto imported =
70157023
Impl.importMirroredDecl(objcProp, dc, getVersion(), proto)) {
@@ -7018,24 +7026,38 @@ void SwiftDeclConverter::importMirroredProtocolMembers(
70187026
// metatype.
70197027
}
70207028

7021-
continue;
7029+
return;
70227030
}
70237031

70247032
auto afd = dyn_cast<AbstractFunctionDecl>(member);
70257033
if (!afd)
7026-
continue;
7034+
return;
70277035

70287036
if (isa<AccessorDecl>(afd))
7029-
continue;
7037+
return;
70307038

70317039
auto objcMethod =
70327040
dyn_cast_or_null<clang::ObjCMethodDecl>(member->getClangDecl());
70337041
if (!objcMethod)
7034-
continue;
7042+
return;
70357043

70367044
// For now, just remember that we saw this method.
70377045
methodsByName[objcMethod->getSelector()]
70387046
.push_back(MirroredMethodEntry{objcMethod, proto});
7047+
};
7048+
7049+
if (name) {
7050+
// If we're asked to import a specific name only, look for that in the
7051+
// protocol.
7052+
auto results = proto->lookupDirect(*name);
7053+
for (auto *member : results)
7054+
if (member->getDeclContext() == proto)
7055+
importProtocolRequirement(member);
7056+
7057+
} else {
7058+
// Otherwise, import all mirrored members.
7059+
for (auto *member : proto->getMembers())
7060+
importProtocolRequirement(member);
70397061
}
70407062
}
70417063

@@ -8676,20 +8698,22 @@ void ClangImporter::Implementation::collectMembersToAdd(
86768698
insertMembersAndAlternates(nd, members);
86778699
}
86788700

8701+
// Objective-C protocols don't require any special handling.
8702+
if (isa<clang::ObjCProtocolDecl>(objcContainer))
8703+
return;
8704+
8705+
// Objective-C interfaces can inherit constructors from their superclass,
8706+
// which we must model explicitly.
86798707
if (auto clangClass = dyn_cast<clang::ObjCInterfaceDecl>(objcContainer)) {
86808708
importInheritedConstructors(cast<ClassDecl>(D), members);
8681-
86828709
objcContainer = clangClass->getDefinition();
8683-
} else if (auto clangProto
8684-
= dyn_cast<clang::ObjCProtocolDecl>(objcContainer)) {
8685-
objcContainer = clangProto->getDefinition();
86868710
}
86878711

8688-
// Import mirrored declarations for protocols to which this category
8689-
// or extension conforms.
8712+
// Interfaces and categories can declare protocol conformances, and
8713+
// members of those protocols are mirrored into the interface or
8714+
// category.
86908715
// FIXME: This is supposed to be a short-term hack.
8691-
SwiftDeclConverter converter(*this, CurrentVersion);
8692-
converter.importMirroredProtocolMembers(objcContainer, DC, members);
8716+
importMirroredProtocolMembers(objcContainer, DC, None, members);
86938717
}
86948718

86958719
void ClangImporter::Implementation::loadAllConformances(

lib/ClangImporter/ImporterImpl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -797,6 +797,10 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
797797
void importInheritedConstructors(ClassDecl *classDecl,
798798
SmallVectorImpl<Decl *> &newMembers);
799799

800+
void importMirroredProtocolMembers(const clang::ObjCContainerDecl *decl,
801+
DeclContext *dc, Optional<DeclBaseName> name,
802+
SmallVectorImpl<Decl *> &members);
803+
800804
/// Utility function for building simple generic signatures.
801805
GenericSignature *buildGenericSignature(GenericParamList *genericParams,
802806
DeclContext *dc);

test/NameBinding/named_lazy_member_loading_protocol_mirroring.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
// Check that named-lazy-member-loading reduces the number of Decls deserialized
99
// RUN: %target-swift-frontend -typecheck -I %S/Inputs/NamedLazyMembers -disable-named-lazy-member-loading -stats-output-dir %t/stats-pre %s
1010
// RUN: %target-swift-frontend -typecheck -I %S/Inputs/NamedLazyMembers -stats-output-dir %t/stats-post %s
11+
// RUN: %{python} %utils/process-stats-dir.py --evaluate-delta 'NumTotalClangImportedEntities < -10' %t/stats-pre %t/stats-post
1112

1213
import NamedLazyMembers
1314

0 commit comments

Comments
 (0)