[API Notes] Add support for SwiftName on anything, which maps to the swift_name attribute.
This allows API notes to be used to override the Swift names of
Objective-C entities.
diff --git a/include/clang/APINotes/Types.h b/include/clang/APINotes/Types.h
index 3cf1493..79f34cc 100644
--- a/include/clang/APINotes/Types.h
+++ b/include/clang/APINotes/Types.h
@@ -58,7 +58,7 @@
/// Describes API notes data for any entity.
///
-/// This is used as the base of
+/// This is used as the base of all API notes.
class CommonEntityInfo {
public:
/// Message to use when this entity is unavailable.
@@ -70,13 +70,17 @@
/// Whether this entity is marked unavailable in Swift.
unsigned UnavailableInSwift : 1;
+ /// Swift name of this entity.
+ std::string SwiftName;
+
CommonEntityInfo() : Unavailable(0), UnavailableInSwift(0) { }
friend bool operator==(const CommonEntityInfo &lhs,
const CommonEntityInfo &rhs) {
return lhs.UnavailableMsg == rhs.UnavailableMsg &&
lhs.Unavailable == rhs.Unavailable &&
- lhs.UnavailableInSwift == rhs.UnavailableInSwift;
+ lhs.UnavailableInSwift == rhs.UnavailableInSwift &&
+ lhs.SwiftName == rhs.SwiftName;
}
friend bool operator!=(const CommonEntityInfo &lhs,
@@ -103,6 +107,10 @@
}
}
+ if (rhs.SwiftName.length() != 0 &&
+ lhs.SwiftName.length() == 0)
+ lhs.SwiftName = rhs.SwiftName;
+
return lhs;
}
diff --git a/lib/APINotes/APINotesFormat.h b/lib/APINotes/APINotesFormat.h
index 0801d2c..7924104 100644
--- a/lib/APINotes/APINotesFormat.h
+++ b/lib/APINotes/APINotesFormat.h
@@ -35,7 +35,7 @@
/// API notes file minor version number.
///
/// When the format changes IN ANY WAY, this number should be incremented.
-const uint16_t VERSION_MINOR = 7;
+const uint16_t VERSION_MINOR = 8;
using IdentifierID = Fixnum<31>;
using IdentifierIDField = BCVBR<16>;
diff --git a/lib/APINotes/APINotesReader.cpp b/lib/APINotes/APINotesReader.cpp
index c768f3a..2583128 100644
--- a/lib/APINotes/APINotesReader.cpp
+++ b/lib/APINotes/APINotesReader.cpp
@@ -39,6 +39,13 @@
= std::string(reinterpret_cast<const char *>(data),
reinterpret_cast<const char *>(data) + msgLength);
data += msgLength;
+
+ unsigned swiftNameLength
+ = endian::readNext<uint16_t, little, unaligned>(data);
+ info.SwiftName
+ = std::string(reinterpret_cast<const char *>(data),
+ reinterpret_cast<const char *>(data) + swiftNameLength);
+ data += swiftNameLength;
}
/// Used to deserialize the on-disk identifier table.
diff --git a/lib/APINotes/APINotesWriter.cpp b/lib/APINotes/APINotesWriter.cpp
index 0e498a7..a9d83d9 100644
--- a/lib/APINotes/APINotesWriter.cpp
+++ b/lib/APINotes/APINotesWriter.cpp
@@ -265,7 +265,7 @@
/// Retrieve the serialized size of the given CommonEntityInfo, for use in
/// on-disk hash tables.
static unsigned getCommonEntityInfoSize(const CommonEntityInfo &info) {
- return 3 + info.UnavailableMsg.size();
+ return 5 + info.UnavailableMsg.size() + info.SwiftName.size();
}
/// Emit a serialized representation of the common entity information.
@@ -275,6 +275,8 @@
writer.write<uint8_t>(info.Unavailable << 1 | info.UnavailableInSwift);
writer.write<uint16_t>(info.UnavailableMsg.size());
out.write(info.UnavailableMsg.c_str(), info.UnavailableMsg.size());
+ writer.write<uint16_t>(info.SwiftName.size());
+ out.write(info.SwiftName.c_str(), info.SwiftName.size());
}
/// Used to serialize the on-disk Objective-C context table.
diff --git a/lib/APINotes/APINotesYAMLCompiler.cpp b/lib/APINotes/APINotesYAMLCompiler.cpp
index 8c27a01..8896c40 100644
--- a/lib/APINotes/APINotesYAMLCompiler.cpp
+++ b/lib/APINotes/APINotesYAMLCompiler.cpp
@@ -168,6 +168,7 @@
NullabilitySeq Nullability;
llvm::Optional<NullabilityKind> NullabilityOfRet;
AvailabilityItem Availability;
+ StringRef SwiftName;
api_notes::FactoryAsInitKind FactoryAsInit
= api_notes::FactoryAsInitKind::Infer;
bool DesignatedInit = false;
@@ -179,6 +180,7 @@
StringRef Name;
llvm::Optional<NullabilityKind> Nullability;
AvailabilityItem Availability;
+ StringRef SwiftName;
};
typedef std::vector<Property> PropertiesSeq;
@@ -186,6 +188,7 @@
StringRef Name;
bool AuditedForNullability = false;
AvailabilityItem Availability;
+ StringRef SwiftName;
MethodsSeq Methods;
PropertiesSeq Properties;
};
@@ -196,6 +199,7 @@
NullabilitySeq Nullability;
llvm::Optional<NullabilityKind> NullabilityOfRet;
AvailabilityItem Availability;
+ StringRef SwiftName;
};
typedef std::vector<Function> FunctionsSeq;
@@ -203,6 +207,7 @@
StringRef Name;
llvm::Optional<NullabilityKind> Nullability;
AvailabilityItem Availability;
+ StringRef SwiftName;
};
typedef std::vector<GlobalVariable> GlobalVariablesSeq;
@@ -278,6 +283,7 @@
AbsentNullability);
io.mapOptional("Availability", p.Availability.Mode);
io.mapOptional("AvailabilityMsg", p.Availability.Msg);
+ io.mapOptional("SwiftName", p.SwiftName);
}
};
@@ -291,6 +297,7 @@
AbsentNullability);
io.mapOptional("Availability", m.Availability.Mode);
io.mapOptional("AvailabilityMsg", m.Availability.Msg);
+ io.mapOptional("SwiftName", m.SwiftName);
io.mapOptional("FactoryAsInit", m.FactoryAsInit,
api_notes::FactoryAsInitKind::Infer);
io.mapOptional("DesignatedInit", m.DesignatedInit, false);
@@ -305,6 +312,7 @@
io.mapOptional("AuditedForNullability", c.AuditedForNullability, false);
io.mapOptional("Availability", c.Availability.Mode);
io.mapOptional("AvailabilityMsg", c.Availability.Msg);
+ io.mapOptional("SwiftName", c.SwiftName);
io.mapOptional("Methods", c.Methods);
io.mapOptional("Properties", c.Properties);
}
@@ -319,6 +327,7 @@
AbsentNullability);
io.mapOptional("Availability", f.Availability.Mode);
io.mapOptional("AvailabilityMsg", f.Availability.Msg);
+ io.mapOptional("SwiftName", f.SwiftName);
}
};
@@ -330,6 +339,7 @@
AbsentNullability);
io.mapOptional("Availability", v.Availability.Mode);
io.mapOptional("AvailabilityMsg", v.Availability.Msg);
+ io.mapOptional("SwiftName", v.SwiftName);
}
};
@@ -463,6 +473,7 @@
return;
convertAvailability(meth.Availability, mInfo, meth.Selector);
+ mInfo.SwiftName = meth.SwiftName;
// Check if the selector ends with ':' to determine if it takes arguments.
bool takesArguments = meth.Selector.endswith(":");
@@ -505,6 +516,7 @@
return;
convertAvailability(cl.Availability, cInfo, cl.Name);
+ cInfo.SwiftName = cl.SwiftName;
if (cl.AuditedForNullability)
cInfo.setDefaultNullability(*DefaultNullability);
@@ -545,6 +557,7 @@
if (!isAvailable(prop.Availability))
continue;
convertAvailability(prop.Availability, pInfo, prop.Name);
+ pInfo.SwiftName = prop.SwiftName;
if (prop.Nullability)
pInfo.setNullabilityAudited(*prop.Nullability);
Writer->addObjCProperty(clID, prop.Name, pInfo);
@@ -598,6 +611,7 @@
if (!isAvailable(global.Availability))
continue;
convertAvailability(global.Availability, info, global.Name);
+ info.SwiftName = global.SwiftName;
if (global.Nullability)
info.setNullabilityAudited(*global.Nullability);
Writer->addGlobalVariable(global.Name, info);
@@ -617,6 +631,7 @@
if (!isAvailable(function.Availability))
continue;
convertAvailability(function.Availability, info, function.Name);
+ info.SwiftName = function.SwiftName;
convertNullability(function.Nullability,
function.NullabilityOfRet,
info, function.Name);
@@ -707,6 +722,8 @@
// Handle class information.
handleAvailability(record.Availability, info);
+ record.SwiftName = copyString(info.SwiftName);
+
if (info.getDefaultNullability()) {
record.AuditedForNullability = true;
}
@@ -771,6 +788,7 @@
handleNullability(method.Nullability, method.NullabilityOfRet, info,
selector.count(':'));
handleAvailability(method.Availability, info);
+ method.SwiftName = copyString(info.SwiftName);
method.FactoryAsInit = info.getFactoryAsInitKind();
method.DesignatedInit = info.DesignatedInit;
method.Required = info.Required;
@@ -787,6 +805,7 @@
Property property;
property.Name = name;
handleAvailability(property.Availability, info);
+ property.SwiftName = copyString(info.SwiftName);
// FIXME: No way to represent "not audited for nullability".
if (auto nullability = info.getNullability()) {
@@ -805,6 +824,7 @@
Function function;
function.Name = name;
handleAvailability(function.Availability, info);
+ function.SwiftName = copyString(info.SwiftName);
if (info.NumAdjustedNullable > 0)
handleNullability(function.Nullability, function.NullabilityOfRet,
info, info.NumAdjustedNullable-1);
@@ -817,6 +837,7 @@
GlobalVariable global;
global.Name = name;
handleAvailability(global.Availability, info);
+ global.SwiftName = copyString(info.SwiftName);
// FIXME: No way to represent "not audited for nullability".
if (auto nullability = info.getNullability()) {
diff --git a/lib/Sema/SemaAPINotes.cpp b/lib/Sema/SemaAPINotes.cpp
index 6f08fd4..4faabd0 100644
--- a/lib/Sema/SemaAPINotes.cpp
+++ b/lib/Sema/SemaAPINotes.cpp
@@ -93,21 +93,38 @@
}
}
+/// Copy a string into ASTContext-allocated memory.
+static StringRef CopyString(ASTContext &ctx, StringRef string) {
+ void *mem = ctx.Allocate(string.size(), alignof(char));
+ memcpy(mem, string.data(), string.size());
+ return StringRef(static_cast<char *>(mem), string.size());
+}
+
static void ProcessAPINotes(Sema &S, Decl *D,
const api_notes::CommonEntityInfo &Info) {
// Availability
if (Info.Unavailable && !D->hasAttr<UnavailableAttr>()) {
- D->addAttr(UnavailableAttr::CreateImplicit(S.Context, Info.UnavailableMsg));
+ D->addAttr(UnavailableAttr::CreateImplicit(S.Context,
+ CopyString(S.Context,
+ Info.UnavailableMsg)));
}
if (Info.UnavailableInSwift) {
- D->addAttr(AvailabilityAttr::CreateImplicit(S.Context,
- &S.Context.Idents.get("swift"),
- VersionTuple(),
- VersionTuple(),
- VersionTuple(),
- /*Unavailable=*/true,
- Info.UnavailableMsg));
+ D->addAttr(AvailabilityAttr::CreateImplicit(
+ S.Context,
+ &S.Context.Idents.get("swift"),
+ VersionTuple(),
+ VersionTuple(),
+ VersionTuple(),
+ /*Unavailable=*/true,
+ CopyString(S.Context, Info.UnavailableMsg)));
+ }
+
+ // swift_name
+ if (!Info.SwiftName.empty() && !D->hasAttr<SwiftNameAttr>()) {
+ D->addAttr(SwiftNameAttr::CreateImplicit(S.Context,
+ CopyString(S.Context,
+ Info.SwiftName)));
}
}
diff --git a/test/APINotes/Inputs/roundtrip.apinotes b/test/APINotes/Inputs/roundtrip.apinotes
index b172240..a1b60e5 100644
--- a/test/APINotes/Inputs/roundtrip.apinotes
+++ b/test/APINotes/Inputs/roundtrip.apinotes
@@ -6,12 +6,14 @@
- Name: NSCell
Availability: available
AvailabilityMsg: ''
+ SwiftName: ''
Methods:
- Selector: init
MethodKind: Instance
NullabilityOfRet: U
Availability: available
AvailabilityMsg: ''
+ SwiftName: ''
DesignatedInit: true
- Selector: 'initImageCell:'
MethodKind: Instance
@@ -19,6 +21,7 @@
NullabilityOfRet: U
Availability: available
AvailabilityMsg: ''
+ SwiftName: ''
DesignatedInit: true
- Selector: 'initTextCell:'
MethodKind: Instance
@@ -26,6 +29,7 @@
NullabilityOfRet: U
Availability: available
AvailabilityMsg: ''
+ SwiftName: ''
DesignatedInit: true
- Selector: 'initWithCoder:'
MethodKind: Instance
@@ -33,12 +37,14 @@
NullabilityOfRet: U
Availability: available
AvailabilityMsg: ''
+ SwiftName: ''
DesignatedInit: true
Required: true
- Name: NSView
AuditedForNullability: true
Availability: available
AvailabilityMsg: ''
+ SwiftName: ''
Methods:
- Selector: 'addSubview:'
MethodKind: Instance
@@ -46,34 +52,41 @@
NullabilityOfRet: N
Availability: available
AvailabilityMsg: ''
+ SwiftName: ''
- Selector: 'addSubview:positioned:relativeTo:'
MethodKind: Instance
Nullability: [ N, N, O ]
NullabilityOfRet: N
Availability: available
AvailabilityMsg: ''
+ SwiftName: ''
- Selector: 'beginDraggingSessionWithItems:event:source:'
MethodKind: Instance
Nullability: [ U, U, N ]
NullabilityOfRet: N
Availability: available
AvailabilityMsg: ''
+ SwiftName: 'beginDragginSession(_:event:source:)'
Properties:
- Name: enclosingScrollView
Nullability: O
Availability: available
AvailabilityMsg: ''
+ SwiftName: enclosing
- Name: makeBackingLayer
Nullability: N
Availability: available
AvailabilityMsg: ''
+ SwiftName: ''
Functions:
- Name: NSAvailableWindowDepths
NullabilityOfRet: N
Availability: available
AvailabilityMsg: ''
+ SwiftName: 'availableWindowDepths()'
Globals:
- Name: NSCalibratedWhiteColorSpace
Nullability: N
Availability: available
AvailabilityMsg: ''
+ SwiftName: calibratedWhite