mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Implement importing of forward declared objc protocols and interfaces
This modifies the ClangImporter to introduce an opaque placeholder representation for forward declared Objective-C interfaces and protocols when imported into Swift. In the compiler, the new functionality is hidden behind a frontend flag -enable-import-objc-forward-declarations, and is on by default for language mode >6. The feature is disabled entirely in LLDB expression evaluation / Swift REPL, regardless of language version.
This commit is contained in:
@@ -597,6 +597,7 @@ ModuleDecl::ModuleDecl(Identifier name, ASTContext &ctx,
|
||||
Bits.ModuleDecl.HasIncrementalInfo = 0;
|
||||
Bits.ModuleDecl.HasHermeticSealAtLink = 0;
|
||||
Bits.ModuleDecl.IsConcurrencyChecked = 0;
|
||||
Bits.ModuleDecl.ObjCNameLookupCachePopulated = 0;
|
||||
}
|
||||
|
||||
ImplicitImportList ModuleDecl::getImplicitImports() const {
|
||||
@@ -1176,6 +1177,60 @@ void ModuleDecl::getTopLevelDeclsWhereAttributesMatch(
|
||||
FORWARD(getTopLevelDeclsWhereAttributesMatch, (Results, matchAttributes));
|
||||
}
|
||||
|
||||
void ModuleDecl::lookupTopLevelDeclsByObjCName(SmallVectorImpl<Decl *> &Results,
|
||||
DeclName name) {
|
||||
if (!isObjCNameLookupCachePopulated())
|
||||
populateObjCNameLookupCache();
|
||||
|
||||
// A top level decl can't be special anyways
|
||||
if (name.isSpecial())
|
||||
return;
|
||||
|
||||
auto resultsForFileUnit = ObjCNameLookupCache.find(name.getBaseIdentifier());
|
||||
if (resultsForFileUnit == ObjCNameLookupCache.end())
|
||||
return;
|
||||
|
||||
Results.append(resultsForFileUnit->second.begin(),
|
||||
resultsForFileUnit->second.end());
|
||||
}
|
||||
|
||||
void ModuleDecl::populateObjCNameLookupCache() {
|
||||
SmallVector<Decl *> topLevelObjCExposedDeclsInFileUnit;
|
||||
auto hasObjCAttrNamePredicate = [](const DeclAttributes &attrs) -> bool {
|
||||
return attrs.hasAttribute<ObjCAttr>();
|
||||
};
|
||||
|
||||
for (FileUnit *file : getFiles()) {
|
||||
file->getTopLevelDeclsWhereAttributesMatch(
|
||||
topLevelObjCExposedDeclsInFileUnit, hasObjCAttrNamePredicate);
|
||||
if (auto *synth = file->getSynthesizedFile()) {
|
||||
synth->getTopLevelDeclsWhereAttributesMatch(
|
||||
topLevelObjCExposedDeclsInFileUnit, hasObjCAttrNamePredicate);
|
||||
}
|
||||
}
|
||||
|
||||
for (Decl *decl : topLevelObjCExposedDeclsInFileUnit) {
|
||||
if (ValueDecl *VD = dyn_cast<ValueDecl>(decl); VD && VD->hasName()) {
|
||||
const auto &declObjCAttribute = VD->getAttrs().getAttribute<ObjCAttr>();
|
||||
// No top level decl (class, protocol, extension etc.) is allowed to have a
|
||||
// compound name, @objc provided or otherwise. Global functions are allowed to
|
||||
// have compound names, but not allowed to have @objc attributes. Thus we
|
||||
// are sure to not hit asserts getting the simple name.
|
||||
//
|
||||
// Similarly, init, dealloc and subscript (the special names) can't be top
|
||||
// level decls, so we won't hit asserts getting the base identifier out of the
|
||||
// value decl.
|
||||
const Identifier &declObjCName =
|
||||
declObjCAttribute->hasName()
|
||||
? declObjCAttribute->getName()->getSimpleName()
|
||||
: VD->getName().getBaseIdentifier();
|
||||
ObjCNameLookupCache[declObjCName].push_back(decl);
|
||||
}
|
||||
}
|
||||
|
||||
setIsObjCNameLookupCachePopulated(true);
|
||||
}
|
||||
|
||||
void SourceFile::getTopLevelDecls(SmallVectorImpl<Decl*> &Results) const {
|
||||
auto decls = getTopLevelDecls();
|
||||
Results.append(decls.begin(), decls.end());
|
||||
@@ -3347,6 +3402,9 @@ bool SourceFile::shouldCrossImport() const {
|
||||
void ModuleDecl::clearLookupCache() {
|
||||
getASTContext().getImportCache().clear();
|
||||
|
||||
setIsObjCNameLookupCachePopulated(false);
|
||||
ObjCNameLookupCache.clear();
|
||||
|
||||
if (!Cache)
|
||||
return;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user