Skip to content

Commit 0e40128

Browse files
committed
[Clang importer] Use Clang swift_bridge attribute for bridging.
When an Objective-C class type is annotated with the swift_bridge value type, bridge it to the named type. Use API notes on Foundation rather than special cases. For Objective-C classes where bridging was baked into the Clang importer (NSString, NSArray, NSDictionary, NSSet), add API notes to put the appropriate swift_bridge attribute on these Objective-C classes. Note: requires Clang update.
1 parent 32db894 commit 0e40128

File tree

5 files changed

+89
-29
lines changed

5 files changed

+89
-29
lines changed

apinotes/Foundation.apinotes

+8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
---
22
Name: Foundation
33
Classes:
4+
- Name: NSArray
5+
SwiftBridge: 'Swift.Array'
6+
- Name: NSDictionary
7+
SwiftBridge: 'Swift.Dictionary'
8+
- Name: NSSet
9+
SwiftBridge: 'Swift.Set'
10+
- Name: NSString
11+
SwiftBridge: 'Swift.String'
412
- Name: NSDistributedNotificationCenter
513
Methods:
614
- Selector: 'notificationCenterForType:'

apinotes/ObjectiveC.apinotes

+8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
---
22
Name: ObjectiveC
33
Classes:
4+
- Name: NSArray
5+
SwiftBridge: 'Swift.Array'
6+
- Name: NSDictionary
7+
SwiftBridge: 'Swift.Dictionary'
8+
- Name: NSSet
9+
SwiftBridge: 'Swift.Set'
10+
- Name: NSString
11+
SwiftBridge: 'Swift.String'
412
- Name: List
513
Methods:
614
- Selector: init

lib/ClangImporter/ImportType.cpp

+60-26
Original file line numberDiff line numberDiff line change
@@ -646,6 +646,31 @@ namespace {
646646
return nullptr;
647647
}
648648

649+
/// Map the Clang swift_bridge attribute to a specific type.
650+
Type mapSwiftBridgeAttr(const clang::NamedDecl *clangDecl) {
651+
// Check whether there is a swift_bridge attribute.
652+
auto bridgeAttr = clangDecl->getAttr<clang::SwiftBridgeAttr>();
653+
if (!bridgeAttr) return Type();
654+
655+
// Determine the module and Swift declaration names.
656+
StringRef moduleName;
657+
StringRef name = bridgeAttr->getSwiftType();
658+
auto dotPos = name.find('.');
659+
if (dotPos == StringRef::npos) {
660+
// Determine the module name from the Clang declaration.
661+
if (auto module = clangDecl->getImportedOwningModule())
662+
moduleName = module->getTopLevelModuleName();
663+
else
664+
moduleName = clangDecl->getASTContext().getLangOpts().CurrentModule;
665+
} else {
666+
// The string is ModuleName.TypeName.
667+
moduleName = name.substr(0, dotPos);
668+
name = name.substr(dotPos + 1);
669+
}
670+
671+
return Impl.getNamedSwiftType(moduleName, name);
672+
}
673+
649674
ImportResult
650675
VisitObjCObjectPointerType(const clang::ObjCObjectPointerType *type) {
651676
// If this object pointer refers to an Objective-C class (possibly
@@ -684,20 +709,11 @@ namespace {
684709

685710
// Determine whether this Objective-C class type is bridged to
686711
// a Swift type.
687-
NominalTypeDecl *bridgedTypeDecl = nullptr;
688-
StringRef objcClassName = objcClass->getName();
689-
if (objcClassName == "NSString")
690-
bridgedTypeDecl = Impl.SwiftContext.getStringDecl();
691-
else if (objcClassName == "NSArray")
692-
bridgedTypeDecl = Impl.SwiftContext.getArrayDecl();
693-
else if (objcClassName == "NSDictionary")
694-
bridgedTypeDecl = Impl.SwiftContext.getDictionaryDecl();
695-
else if (objcClassName == "NSSet")
696-
bridgedTypeDecl = Impl.SwiftContext.getSetDecl();
697-
698712
Type bridgedType;
699-
if (bridgedTypeDecl)
700-
bridgedType = bridgedTypeDecl->getDeclaredType();
713+
if (auto objcClassDef = objcClass->getDefinition())
714+
bridgedType = mapSwiftBridgeAttr(objcClassDef);
715+
else
716+
bridgedType = mapSwiftBridgeAttr(objcClass);
701717

702718
if (bridgedType) {
703719
// Gather the type arguments.
@@ -2214,29 +2230,36 @@ Module *ClangImporter::Implementation::getNamedModule(StringRef name) {
22142230
}
22152231

22162232
static Module *tryLoadModule(ASTContext &C,
2217-
Identifier name,
2233+
Identifier moduleName,
22182234
bool importForwardDeclarations,
2219-
Optional<Module *> &cache) {
2220-
if (!cache.hasValue()) {
2221-
// If we're synthesizing forward declarations, we don't want to pull in
2222-
// the module too eagerly.
2223-
if (importForwardDeclarations)
2224-
cache = C.getLoadedModule(name);
2225-
else
2226-
cache = C.getModule({ {name, SourceLoc()} });
2227-
}
2235+
llvm::DenseMap<Identifier, Module *>
2236+
&checkedModules) {
2237+
// If we've already done this check, return the cached result.
2238+
auto known = checkedModules.find(moduleName);
2239+
if (known != checkedModules.end())
2240+
return known->second;
2241+
2242+
Module *module;
2243+
2244+
// If we're synthesizing forward declarations, we don't want to pull in
2245+
// the module too eagerly.
2246+
if (importForwardDeclarations)
2247+
module = C.getLoadedModule(moduleName);
2248+
else
2249+
module = C.getModule({ {moduleName, SourceLoc()} });
22282250

2229-
return cache.getValue();
2251+
checkedModules[moduleName] = module;
2252+
return module;
22302253
}
22312254

22322255
Module *ClangImporter::Implementation::tryLoadFoundationModule() {
22332256
return tryLoadModule(SwiftContext, SwiftContext.Id_Foundation,
2234-
ImportForwardDeclarations, checkedFoundationModule);
2257+
ImportForwardDeclarations, checkedModules);
22352258
}
22362259

22372260
Module *ClangImporter::Implementation::tryLoadSIMDModule() {
22382261
return tryLoadModule(SwiftContext, SwiftContext.Id_simd,
2239-
ImportForwardDeclarations, checkedSIMDModule);
2262+
ImportForwardDeclarations, checkedModules);
22402263
}
22412264

22422265
Type ClangImporter::Implementation::getNamedSwiftType(Module *module,
@@ -2277,6 +2300,17 @@ Type ClangImporter::Implementation::getNamedSwiftType(Module *module,
22772300
return type->getDeclaredType();
22782301
}
22792302

2303+
Type ClangImporter::Implementation::getNamedSwiftType(StringRef moduleName,
2304+
StringRef name) {
2305+
// Try to load the module.
2306+
auto module = tryLoadModule(SwiftContext,
2307+
SwiftContext.getIdentifier(moduleName),
2308+
ImportForwardDeclarations, checkedModules);
2309+
if (!module) return Type();
2310+
2311+
return getNamedSwiftType(module, name);
2312+
}
2313+
22802314
Type
22812315
ClangImporter::Implementation::
22822316
getNamedSwiftTypeSpecialization(Module *module, StringRef name,

lib/ClangImporter/ImporterImpl.h

+12-2
Original file line numberDiff line numberDiff line change
@@ -605,7 +605,8 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
605605
clang::Selector setObjectForKeyedSubscript;
606606

607607
private:
608-
Optional<Module *> checkedFoundationModule, checkedSIMDModule;
608+
/// Records those modules that we have looked up.
609+
llvm::DenseMap<Identifier, Module *> checkedModules;
609610

610611
/// External Decls that we have imported but not passed to the ASTContext yet.
611612
SmallVector<Decl *, 4> RegisteredExternalDecls;
@@ -1098,7 +1099,16 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
10981099

10991100
/// \brief Retrieve the named Swift type, e.g., Int32.
11001101
///
1101-
/// \param module The name of the module in which the type should occur.
1102+
/// \param moduleName The name of the module in which the type should occur.
1103+
///
1104+
/// \param name The name of the type to find.
1105+
///
1106+
/// \returns The named type, or null if the type could not be found.
1107+
Type getNamedSwiftType(StringRef moduleName, StringRef name);
1108+
1109+
/// \brief Retrieve the named Swift type, e.g., Int32.
1110+
///
1111+
/// \param module The module in which the type should occur.
11021112
///
11031113
/// \param name The name of the type to find.
11041114
///

lib/ClangImporter/SwiftLookupTable.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ const uint16_t SWIFT_LOOKUP_TABLE_VERSION_MAJOR = 1;
128128
/// Lookup table minor version number.
129129
///
130130
/// When the format changes IN ANY WAY, this number should be incremented.
131-
const uint16_t SWIFT_LOOKUP_TABLE_VERSION_MINOR = 9; // typedef context kind
131+
const uint16_t SWIFT_LOOKUP_TABLE_VERSION_MINOR = 10; // swift bridge
132132

133133
/// A lookup table that maps Swift names to the set of Clang
134134
/// declarations with that particular name.

0 commit comments

Comments
 (0)