Skip to content

Commit d0205d8

Browse files
authored
Merge pull request #26975 from slavapestov/nlml-fixes
Implement lazy member loading for mirrored protocol members in imported types
2 parents 956b9f2 + d76a8ce commit d0205d8

File tree

9 files changed

+230
-170
lines changed

9 files changed

+230
-170
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 34 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -3031,33 +3031,25 @@ void ClangImporter::loadObjCMethods(
30313031

30323032
// Collect the set of visible Objective-C methods with this selector.
30333033
clang::Selector clangSelector = Impl.exportSelector(selector);
3034-
SmallVector<clang::ObjCMethodDecl *, 4> objcMethods;
3035-
auto &sema = Impl.Instance->getSema();
3036-
sema.CollectMultipleMethodsInGlobalPool(clangSelector, objcMethods,
3037-
isInstanceMethod,
3038-
/*CheckTheOther=*/false);
30393034

3040-
// Check whether this method is in the class we care about.
3041-
SmallVector<AbstractFunctionDecl *, 4> foundMethods;
3042-
for (auto objcMethod : objcMethods) {
3043-
// Find the owner of this method and determine whether it is the class
3044-
// we're looking for.
3045-
if (objcMethod->getClassInterface() != objcClass)
3046-
continue;
3035+
AbstractFunctionDecl *method = nullptr;
3036+
auto *objcMethod = objcClass->lookupMethod(
3037+
clangSelector, isInstanceMethod,
3038+
/*shallowCategoryLookup=*/false,
3039+
/*followSuper=*/false);
30473040

3041+
if (objcMethod) {
30483042
// If we found a property accessor, import the property.
30493043
if (objcMethod->isPropertyAccessor())
30503044
(void)Impl.importDecl(objcMethod->findPropertyDecl(true),
30513045
Impl.CurrentVersion);
30523046

3053-
if (auto method = dyn_cast_or_null<AbstractFunctionDecl>(
3054-
Impl.importDecl(objcMethod, Impl.CurrentVersion))) {
3055-
foundMethods.push_back(method);
3056-
}
3047+
method = dyn_cast_or_null<AbstractFunctionDecl>(
3048+
Impl.importDecl(objcMethod, Impl.CurrentVersion));
30573049
}
30583050

30593051
// If we didn't find anything, we're done.
3060-
if (foundMethods.empty())
3052+
if (method == nullptr)
30613053
return;
30623054

30633055
// If we did find something, it might be a duplicate of something we found
@@ -3066,10 +3058,9 @@ void ClangImporter::loadObjCMethods(
30663058
// FIXME: We shouldn't need to do this.
30673059
llvm::SmallPtrSet<AbstractFunctionDecl *, 4> known;
30683060
known.insert(methods.begin(), methods.end());
3069-
for (auto method : foundMethods) {
3070-
if (known.insert(method).second)
3071-
methods.push_back(method);
3072-
}
3061+
3062+
if (known.insert(method).second)
3063+
methods.push_back(method);
30733064
}
30743065

30753066
void
@@ -3730,52 +3721,19 @@ void ClangImporter::Implementation::lookupAllObjCMembers(
37303721
}
37313722
}
37323723

3733-
// Force the members of the entire inheritance hierarchy to be loaded and
3734-
// deserialized before loading the named member of this class. This allows the
3735-
// decl members table to be warmed up and enables the correct identification of
3736-
// overrides.
3737-
//
3738-
// FIXME: Very low hanging fruit: Loading everything is extremely wasteful. We
3739-
// should be able to just load the name lazy member loading is asking for.
3740-
static void ensureSuperclassMembersAreLoaded(const ClassDecl *CD) {
3741-
if (!CD)
3742-
return;
3743-
3744-
CD = CD->getSuperclassDecl();
3745-
if (!CD || !CD->hasClangNode())
3746-
return;
3747-
3748-
CD->loadAllMembers();
3749-
3750-
for (auto *ED : const_cast<ClassDecl *>(CD)->getExtensions())
3751-
ED->loadAllMembers();
3752-
}
3753-
37543724
Optional<TinyPtrVector<ValueDecl *>>
37553725
ClangImporter::Implementation::loadNamedMembers(
37563726
const IterableDeclContext *IDC, DeclBaseName N, uint64_t contextData) {
37573727

37583728
auto *D = IDC->getDecl();
3759-
auto *DC = cast<DeclContext>(D);
3729+
auto *DC = D->getInnermostDeclContext();
37603730
auto *CD = D->getClangDecl();
37613731
auto *CDC = cast<clang::DeclContext>(CD);
37623732
assert(CD && "loadNamedMembers on a Decl without a clangDecl");
37633733

37643734
auto *nominal = DC->getSelfNominalTypeDecl();
37653735
auto effectiveClangContext = getEffectiveClangContext(nominal);
37663736

3767-
// FIXME: The legacy of mirroring protocol members rears its ugly head,
3768-
// and as a result we have to bail on any @interface or @category that
3769-
// has a declared protocol conformance.
3770-
if (auto *ID = dyn_cast<clang::ObjCInterfaceDecl>(CD)) {
3771-
if (ID->protocol_begin() != ID->protocol_end())
3772-
return None;
3773-
}
3774-
if (auto *CCD = dyn_cast<clang::ObjCCategoryDecl>(CD)) {
3775-
if (CCD->protocol_begin() != CCD->protocol_end())
3776-
return None;
3777-
}
3778-
37793737
// There are 3 cases:
37803738
//
37813739
// - The decl is from a bridging header, CMO is Some(nullptr)
@@ -3799,7 +3757,16 @@ ClangImporter::Implementation::loadNamedMembers(
37993757

38003758
assert(isa<clang::ObjCContainerDecl>(CD) || isa<clang::NamespaceDecl>(CD));
38013759

3802-
ensureSuperclassMembersAreLoaded(dyn_cast<ClassDecl>(D));
3760+
// Force the members of the entire inheritance hierarchy to be loaded and
3761+
// deserialized before loading the named member of a class. This warms up
3762+
// ClangImporter::Implementation::MembersForNominal, used for computing
3763+
// property overrides.
3764+
//
3765+
// FIXME: If getOverriddenDecl() kicked off a request for imported decls,
3766+
// we could postpone this until overrides are actually requested.
3767+
if (auto *classDecl = dyn_cast<ClassDecl>(D))
3768+
if (auto *superclassDecl = classDecl->getSuperclassDecl())
3769+
(void) const_cast<ClassDecl *>(superclassDecl)->lookupDirect(N);
38033770

38043771
TinyPtrVector<ValueDecl *> Members;
38053772
for (auto entry : table->lookup(SerializedSwiftName(N),
@@ -3829,7 +3796,7 @@ ClangImporter::Implementation::loadNamedMembers(
38293796
auto member = entry.get<clang::NamedDecl *>();
38303797
if (!isVisibleClangEntry(member)) continue;
38313798

3832-
// Skip Decls from different clang::DeclContexts
3799+
// Skip Decls from different clang::DeclContexts
38333800
if (member->getDeclContext() != CDC) continue;
38343801

38353802
SmallVector<Decl*, 4> tmp;
@@ -3853,6 +3820,16 @@ ClangImporter::Implementation::loadNamedMembers(
38533820
Members.push_back(cast<ValueDecl>(ctor));
38543821
}
38553822
}
3823+
3824+
if (!isa<ProtocolDecl>(D)) {
3825+
if (auto *OCD = dyn_cast<clang::ObjCContainerDecl>(CD)) {
3826+
SmallVector<Decl *, 1> newMembers;
3827+
importMirroredProtocolMembers(OCD, DC, N, newMembers);
3828+
for (auto member : newMembers)
3829+
Members.push_back(cast<ValueDecl>(member));
3830+
}
3831+
}
3832+
38563833
return Members;
38573834
}
38583835

0 commit comments

Comments
 (0)