[Clang importer] Generalize name lookup tables for globals-as-members.

A swift_name attribute on a global declaration can specify a dotted
name (e.g., SomeStruct.member) to map that global into a member of the
(Swift-)named type. Handle this mapping in DeclName parsing, plumb it
through importFullName, and cope with it in the Swift name lookup
tables (tested via the dump) and importing into a Swift DeclContext
(as-yet-untested). Part of SE-0033.
This commit is contained in:
Doug Gregor
2016-02-29 23:23:10 -08:00
parent 1d9da2e803
commit 7265328e07
8 changed files with 370 additions and 83 deletions

View File

@@ -48,6 +48,7 @@ bool SwiftLookupTable::contextRequiresName(ContextKind kind) {
case ContextKind::ObjCClass:
case ContextKind::ObjCProtocol:
case ContextKind::Tag:
case ContextKind::Typedef:
return true;
case ContextKind::TranslationUnit:
@@ -55,13 +56,54 @@ bool SwiftLookupTable::contextRequiresName(ContextKind kind) {
}
}
/// Try to translate the given Clang declaration into a context.
static Optional<std::pair<SwiftLookupTable::ContextKind, StringRef>>
translateDeclToContext(clang::NamedDecl *decl) {
// Tag declaration.
if (auto tag = dyn_cast<clang::TagDecl>(decl)) {
if (tag->getIdentifier())
return std::make_pair(SwiftLookupTable::ContextKind::Tag, tag->getName());
if (auto typedefDecl = tag->getTypedefNameForAnonDecl())
return std::make_pair(SwiftLookupTable::ContextKind::Tag,
typedefDecl->getName());
return None;
}
// Objective-C class context.
if (auto objcClass = dyn_cast<clang::ObjCInterfaceDecl>(decl))
return std::make_pair(SwiftLookupTable::ContextKind::ObjCClass,
objcClass->getName());
// Objective-C protocol context.
if (auto objcProtocol = dyn_cast<clang::ObjCProtocolDecl>(decl))
return std::make_pair(SwiftLookupTable::ContextKind::ObjCProtocol,
objcProtocol->getName());
// Typedefs.
if (auto typedefName = dyn_cast<clang::TypedefNameDecl>(decl)) {
// If this typedef is merely a restatement of a tag declaration's type,
// return the result for that tag.
if (auto tag = typedefName->getUnderlyingType()->getAsTagDecl())
return translateDeclToContext(tag);
// Otherwise, this must be a typedef mapped to a strong type.
return std::make_pair(SwiftLookupTable::ContextKind::Typedef,
typedefName->getName());
}
return None;
}
Optional<std::pair<SwiftLookupTable::ContextKind, StringRef>>
SwiftLookupTable::translateContext(EffectiveClangContext context) {
if (auto dc = context.dyn_cast<clang::DeclContext *>()) {
switch (context.getKind()) {
case EffectiveClangContext::DeclContext: {
auto dc = context.getAsDeclContext();
// Translation unit context.
if (dc->isTranslationUnit())
return std::make_pair(ContextKind::TranslationUnit, StringRef());
// Tag declaration context.
if (auto tag = dyn_cast<clang::TagDecl>(dc)) {
if (tag->getIdentifier())
@@ -82,7 +124,40 @@ SwiftLookupTable::translateContext(EffectiveClangContext context) {
return None;
}
llvm_unreachable("Non-Clang-DeclContexts are not yet handled");
case EffectiveClangContext::TypedefContext:
return std::make_pair(ContextKind::Typedef,
context.getTypedefName()->getName());
case EffectiveClangContext::UnresolvedContext:
// Resolve the context.
if (auto decl = resolveContext(context.getUnresolvedName())) {
if (auto context = translateDeclToContext(decl))
return context;
}
return None;
}
}
/// Lookup an unresolved context name and resolve it to a Clang
/// declaration context or typedef name.
clang::NamedDecl *SwiftLookupTable::resolveContext(StringRef unresolvedName) {
// Look for a context with the given Swift name.
for (auto entry : lookup(unresolvedName,
std::make_pair(ContextKind::TranslationUnit,
StringRef()))) {
if (auto decl = entry.dyn_cast<clang::NamedDecl *>()) {
if (isa<clang::TagDecl>(decl) ||
isa<clang::ObjCInterfaceDecl>(decl) ||
isa<clang::ObjCProtocolDecl>(decl) ||
isa<clang::TypedefNameDecl>(decl))
return decl;
}
}
// FIXME: Search imported modules to resolve the context.
return nullptr;
}
void SwiftLookupTable::addCategory(clang::ObjCCategoryDecl *category) {
@@ -168,26 +243,22 @@ auto SwiftLookupTable::findOrCreate(StringRef baseName)
}
SmallVector<SwiftLookupTable::SingleEntry, 4>
SwiftLookupTable::lookup(StringRef baseName,
clang::DeclContext *searchContext) {
SwiftLookupTable::lookup(
StringRef baseName,
llvm::Optional<std::pair<ContextKind, StringRef>> searchContext) {
SmallVector<SwiftLookupTable::SingleEntry, 4> result;
// Find the lookup table entry for this base name.
auto known = findOrCreate(baseName);
if (known == LookupTable.end()) return result;
// Translate context.
Optional<std::pair<SwiftLookupTable::ContextKind, StringRef>> context;
if (searchContext) {
context = translateContext(searchContext);
if (!context) return result;
}
// Walk each of the entries.
for (auto &entry : known->second) {
// If we're looking in a particular context and it doesn't match the
// entry context, we're done.
if (context && *context != entry.Context) continue;
if (searchContext && entry.Context != *searchContext)
continue;
// Map each of the declarations.
for (auto &stored : entry.DeclsOrMacros)
@@ -197,6 +268,19 @@ SwiftLookupTable::lookup(StringRef baseName,
return result;
}
SmallVector<SwiftLookupTable::SingleEntry, 4>
SwiftLookupTable::lookup(StringRef baseName,
EffectiveClangContext searchContext) {
// Translate context.
Optional<std::pair<SwiftLookupTable::ContextKind, StringRef>> context;
if (searchContext) {
context = translateContext(searchContext);
if (!context) return { };
}
return lookup(baseName, context);
}
SmallVector<StringRef, 4> SwiftLookupTable::allBaseNames() {
// If we have a reader, enumerate its base names.
if (Reader) return Reader->getBaseNames();
@@ -228,6 +312,7 @@ SwiftLookupTable::lookupObjCMembers(StringRef baseName) {
case ContextKind::ObjCClass:
case ContextKind::ObjCProtocol:
case ContextKind::Typedef:
break;
}
@@ -312,7 +397,7 @@ void SwiftLookupTable::deserializeAll() {
if (!Reader) return;
for (auto baseName : Reader->getBaseNames()) {
(void)lookup(baseName, nullptr);
(void)lookup(baseName, None);
}
(void)categories();
@@ -339,6 +424,7 @@ void SwiftLookupTable::dump() const {
case ContextKind::Tag:
case ContextKind::ObjCClass:
case ContextKind::ObjCProtocol:
case ContextKind::Typedef:
llvm::errs() << entry.Context.second;
}
llvm::errs() << ": ";