[Swift] Add swift_bridge attribute for bridging Objective-C types to Swift.
diff --git a/include/clang/APINotes/Types.h b/include/clang/APINotes/Types.h
index 79f34cc..decb137 100644
--- a/include/clang/APINotes/Types.h
+++ b/include/clang/APINotes/Types.h
@@ -127,6 +127,11 @@
/// Whether this class has designated initializers recorded.
unsigned HasDesignatedInits : 1;
+ /// The Swift type to which a given Objective-C class is bridged.
+ ///
+ /// Reflects the swift_bridge attribute.
+ std::string SwiftBridge;
+
public:
ObjCContextInfo()
: CommonEntityInfo(),
@@ -162,11 +167,15 @@
DefaultNullability = 0;
}
+ const std::string &getSwiftBridge() const { return SwiftBridge; }
+ void setSwiftBridge(const std::string &swiftType) { SwiftBridge = swiftType; }
+
friend bool operator==(const ObjCContextInfo &lhs, const ObjCContextInfo &rhs) {
return static_cast<const CommonEntityInfo &>(lhs) == rhs &&
lhs.HasDefaultNullability == rhs.HasDefaultNullability &&
lhs.DefaultNullability == rhs.DefaultNullability &&
- lhs.HasDesignatedInits == rhs.HasDesignatedInits;
+ lhs.HasDesignatedInits == rhs.HasDesignatedInits &&
+ lhs.SwiftBridge == rhs.SwiftBridge;
}
friend bool operator!=(const ObjCContextInfo &lhs, const ObjCContextInfo &rhs) {
@@ -186,6 +195,10 @@
}
lhs.HasDesignatedInits |= rhs.HasDesignatedInits;
+
+ if (lhs.SwiftBridge.empty() && !rhs.SwiftBridge.empty())
+ lhs.SwiftBridge = rhs.SwiftBridge;
+
return lhs;
}
diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td
index 99be3af..63748c3 100644
--- a/include/clang/Basic/Attr.td
+++ b/include/clang/Basic/Attr.td
@@ -1309,6 +1309,14 @@
let Documentation = [RegparmDocs];
}
+def SwiftBridge : Attr {
+ let Spellings = [GNU<"swift_bridge">];
+ let Subjects = SubjectList<[Tag, TypedefName, ObjCProtocol], ErrorDiag,
+ "ExpectedType">;
+ let Args = [StringArgument<"SwiftType">];
+ let Documentation = [SwiftBridgeDocs];
+}
+
def SwiftError : InheritableAttr {
let Spellings = [GCC<"swift_error">];
let Args = [EnumArgument<"Convention", "ConventionKind",
diff --git a/include/clang/Basic/AttrDocs.td b/include/clang/Basic/AttrDocs.td
index 08cd99b..d27cdd9 100644
--- a/include/clang/Basic/AttrDocs.td
+++ b/include/clang/Basic/AttrDocs.td
@@ -1758,6 +1758,12 @@
}];
}
+def SwiftDocs : DocumentationCategory<"Controlling Swift Import"> {
+ let Content = [{
+Clang supports additional attributes for controlling how APIs are imported into Swift.
+ }];
+}
+
def NSErrorDomainDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
@@ -1765,9 +1771,11 @@
}];
}
-def SwiftDocs : DocumentationCategory<"Controlling Swift Import"> {
+
+def SwiftBridgeDocs : Documentation {
+ let Category = SwiftDocs;
let Content = [{
-Clang supports additional attributes for controlling how APIs are imported into Swift.
+The ``swift_bridge`` attribute indicates that the type to which the attribute appertains is bridged to the named Swift type.
}];
}
diff --git a/lib/APINotes/APINotesReader.cpp b/lib/APINotes/APINotesReader.cpp
index 2583128..2d8fcb7 100644
--- a/lib/APINotes/APINotesReader.cpp
+++ b/lib/APINotes/APINotesReader.cpp
@@ -140,6 +140,14 @@
}
++data;
result.second.setHasDesignatedInits(*data++);
+
+ // swift bridge.
+ unsigned swiftBridgeLength =
+ endian::readNext<uint16_t, little, unaligned>(data);
+ result.second.setSwiftBridge(
+ StringRef(reinterpret_cast<const char *>(data), swiftBridgeLength));
+ data += swiftBridgeLength;
+
return result;
}
};
diff --git a/lib/APINotes/APINotesWriter.cpp b/lib/APINotes/APINotesWriter.cpp
index a9d83d9..102932f 100644
--- a/lib/APINotes/APINotesWriter.cpp
+++ b/lib/APINotes/APINotesWriter.cpp
@@ -302,7 +302,8 @@
uint32_t keyLength = sizeof(IdentifierID) + 1;
uint32_t dataLength = sizeof(ContextID)
+ getCommonEntityInfoSize(data.second)
- + dataBytes;
+ + dataBytes
+ + 2 + data.second.getSwiftBridge().size();
endian::Writer<little> writer(out);
writer.write<uint16_t>(keyLength);
writer.write<uint16_t>(dataLength);
@@ -333,6 +334,10 @@
bytes[2] = data.second.hasDesignatedInits();
out.write(reinterpret_cast<const char *>(bytes), dataBytes);
+
+ writer.write<uint16_t>(data.second.getSwiftBridge().size());
+ out.write(data.second.getSwiftBridge().data(),
+ data.second.getSwiftBridge().size());
}
};
} // end anonymous namespace
diff --git a/lib/APINotes/APINotesYAMLCompiler.cpp b/lib/APINotes/APINotesYAMLCompiler.cpp
index 8896c40..17d8fab 100644
--- a/lib/APINotes/APINotesYAMLCompiler.cpp
+++ b/lib/APINotes/APINotesYAMLCompiler.cpp
@@ -189,6 +189,7 @@
bool AuditedForNullability = false;
AvailabilityItem Availability;
StringRef SwiftName;
+ StringRef SwiftBridge;
MethodsSeq Methods;
PropertiesSeq Properties;
};
@@ -313,6 +314,7 @@
io.mapOptional("Availability", c.Availability.Mode);
io.mapOptional("AvailabilityMsg", c.Availability.Msg);
io.mapOptional("SwiftName", c.SwiftName);
+ io.mapOptional("SwiftBridge", c.SwiftBridge);
io.mapOptional("Methods", c.Methods);
io.mapOptional("Properties", c.Properties);
}
@@ -521,6 +523,9 @@
if (cl.AuditedForNullability)
cInfo.setDefaultNullability(*DefaultNullability);
+ if (isClass)
+ cInfo.setSwiftBridge(cl.SwiftBridge);
+
ContextID clID = isClass ? Writer->addObjCClass(cl.Name, cInfo) :
Writer->addObjCProtocol(cl.Name, cInfo);
@@ -727,6 +732,8 @@
if (info.getDefaultNullability()) {
record.AuditedForNullability = true;
}
+
+ record.SwiftBridge = copyString(info.getSwiftBridge());
}
/// Map availability information, if present.
diff --git a/lib/Sema/SemaAPINotes.cpp b/lib/Sema/SemaAPINotes.cpp
index 4faabd0..22b29f4 100644
--- a/lib/Sema/SemaAPINotes.cpp
+++ b/lib/Sema/SemaAPINotes.cpp
@@ -238,6 +238,22 @@
ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(Info));
}
+/// Process API notes for an Objective-C class.
+static void ProcessAPINotes(Sema &S, ObjCInterfaceDecl *D,
+ const api_notes::ObjCContextInfo &Info) {
+ // swift_bridge
+ if (!Info.getSwiftBridge().empty() &&
+ !D->getAttr<SwiftBridgeAttr>()) {
+ D->addAttr(
+ SwiftBridgeAttr::CreateImplicit(S.Context,
+ CopyString(S.Context,
+ Info.getSwiftBridge())));
+ }
+
+ // Handle information common to Objective-C classes and protocols.
+ ProcessAPINotes(S, static_cast<clang::ObjCContainerDecl *>(D), Info);
+}
+
/// Process API notes that are associated with this declaration, mapping them
/// to attributes as appropriate.
void Sema::ProcessAPINotes(Decl *D) {
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index b8bfc61..85fbc1f 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -4715,6 +4715,24 @@
attr.getAttributeSpellingListIndex()));
}
+static void handleSwiftBridgeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ // Make sure that there is a string literal as the annotation's single
+ // argument.
+ StringRef Str;
+ if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str))
+ return;
+
+ // Don't duplicate annotations that are already set.
+ if (D->hasAttr<SwiftBridgeAttr>()) {
+ S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute) << Attr.getName();
+ return;
+ }
+
+ D->addAttr(::new (S.Context)
+ SwiftBridgeAttr(Attr.getRange(), S.Context, Str,
+ Attr.getAttributeSpellingListIndex()));
+}
+
//===----------------------------------------------------------------------===//
// Microsoft specific attribute handlers.
//===----------------------------------------------------------------------===//
@@ -5914,6 +5932,9 @@
case AttributeList::AT_SwiftError:
handleSwiftError(S, D, Attr);
break;
+ case AttributeList::AT_SwiftBridge:
+ handleSwiftBridgeAttr(S, D, Attr);
+ break;
}
}
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index 3f957af..e5db79f 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -1687,7 +1687,8 @@
= ObjCProtocolDecl::Create(Context, CurContext, Ident,
IdentPair.second, AtProtocolLoc,
PrevDecl);
-
+ ProcessAPINotes(PDecl);
+
PushOnScopeChains(PDecl, TUScope);
CheckObjCDeclScope(PDecl);
@@ -3009,7 +3010,8 @@
ClassName, TypeParams, PrevIDecl,
IdentLocs[i]);
IDecl->setAtEndRange(IdentLocs[i]);
-
+ ProcessAPINotes(IDecl);
+
PushOnScopeChains(IDecl, TUScope);
CheckObjCDeclScope(IDecl);
DeclsInGroup.push_back(IDecl);
diff --git a/test/APINotes/Inputs/roundtrip.apinotes b/test/APINotes/Inputs/roundtrip.apinotes
index a1b60e5..18bf2de 100644
--- a/test/APINotes/Inputs/roundtrip.apinotes
+++ b/test/APINotes/Inputs/roundtrip.apinotes
@@ -7,6 +7,7 @@
Availability: available
AvailabilityMsg: ''
SwiftName: ''
+ SwiftBridge: ''
Methods:
- Selector: init
MethodKind: Instance
@@ -45,6 +46,7 @@
Availability: available
AvailabilityMsg: ''
SwiftName: ''
+ SwiftBridge: View
Methods:
- Selector: 'addSubview:'
MethodKind: Instance