xref: /freebsd/contrib/llvm-project/clang/lib/APINotes/APINotesWriter.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 //===-- APINotesWriter.cpp - API Notes Writer -------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "clang/APINotes/APINotesWriter.h"
10 #include "APINotesFormat.h"
11 #include "clang/APINotes/Types.h"
12 #include "clang/Basic/FileManager.h"
13 #include "llvm/ADT/DenseMap.h"
14 #include "llvm/ADT/StringMap.h"
15 #include "llvm/Bitstream/BitstreamWriter.h"
16 #include "llvm/Support/DJB.h"
17 #include "llvm/Support/OnDiskHashTable.h"
18 #include "llvm/Support/VersionTuple.h"
19 
20 namespace clang {
21 namespace api_notes {
22 class APINotesWriter::Implementation {
23   friend class APINotesWriter;
24 
25   template <typename T>
26   using VersionedSmallVector =
27       llvm::SmallVector<std::pair<llvm::VersionTuple, T>, 1>;
28 
29   std::string ModuleName;
30   const FileEntry *SourceFile;
31 
32   /// Scratch space for bitstream writing.
33   llvm::SmallVector<uint64_t, 64> Scratch;
34 
35   /// Mapping from strings to identifier IDs.
36   llvm::StringMap<IdentifierID> IdentifierIDs;
37 
38   /// Information about contexts (Objective-C classes or protocols or C++
39   /// namespaces).
40   ///
41   /// Indexed by the parent context ID, context kind and the identifier ID of
42   /// this context and provides both the context ID and information describing
43   /// the context within that module.
44   llvm::DenseMap<ContextTableKey,
45                  std::pair<unsigned, VersionedSmallVector<ContextInfo>>>
46       Contexts;
47 
48   /// Information about parent contexts for each context.
49   ///
50   /// Indexed by context ID, provides the parent context ID.
51   llvm::DenseMap<uint32_t, uint32_t> ParentContexts;
52 
53   /// Mapping from context IDs to the identifier ID holding the name.
54   llvm::DenseMap<unsigned, unsigned> ContextNames;
55 
56   /// Information about Objective-C properties.
57   ///
58   /// Indexed by the context ID, property name, and whether this is an
59   /// instance property.
60   llvm::DenseMap<
61       std::tuple<unsigned, unsigned, char>,
62       llvm::SmallVector<std::pair<VersionTuple, ObjCPropertyInfo>, 1>>
63       ObjCProperties;
64 
65   /// Information about C record fields.
66   ///
67   /// Indexed by the context ID and name ID.
68   llvm::DenseMap<SingleDeclTableKey,
69                  llvm::SmallVector<std::pair<VersionTuple, FieldInfo>, 1>>
70       Fields;
71 
72   /// Information about Objective-C methods.
73   ///
74   /// Indexed by the context ID, selector ID, and Boolean (stored as a char)
75   /// indicating whether this is a class or instance method.
76   llvm::DenseMap<std::tuple<unsigned, unsigned, char>,
77                  llvm::SmallVector<std::pair<VersionTuple, ObjCMethodInfo>, 1>>
78       ObjCMethods;
79 
80   /// Information about C++ methods.
81   ///
82   /// Indexed by the context ID and name ID.
83   llvm::DenseMap<SingleDeclTableKey,
84                  llvm::SmallVector<std::pair<VersionTuple, CXXMethodInfo>, 1>>
85       CXXMethods;
86 
87   /// Mapping from selectors to selector ID.
88   llvm::DenseMap<StoredObjCSelector, SelectorID> SelectorIDs;
89 
90   /// Information about global variables.
91   ///
92   /// Indexed by the context ID, identifier ID.
93   llvm::DenseMap<
94       SingleDeclTableKey,
95       llvm::SmallVector<std::pair<VersionTuple, GlobalVariableInfo>, 1>>
96       GlobalVariables;
97 
98   /// Information about global functions.
99   ///
100   /// Indexed by the context ID, identifier ID.
101   llvm::DenseMap<
102       SingleDeclTableKey,
103       llvm::SmallVector<std::pair<VersionTuple, GlobalFunctionInfo>, 1>>
104       GlobalFunctions;
105 
106   /// Information about enumerators.
107   ///
108   /// Indexed by the identifier ID.
109   llvm::DenseMap<
110       unsigned, llvm::SmallVector<std::pair<VersionTuple, EnumConstantInfo>, 1>>
111       EnumConstants;
112 
113   /// Information about tags.
114   ///
115   /// Indexed by the context ID, identifier ID.
116   llvm::DenseMap<SingleDeclTableKey,
117                  llvm::SmallVector<std::pair<VersionTuple, TagInfo>, 1>>
118       Tags;
119 
120   /// Information about typedefs.
121   ///
122   /// Indexed by the context ID, identifier ID.
123   llvm::DenseMap<SingleDeclTableKey,
124                  llvm::SmallVector<std::pair<VersionTuple, TypedefInfo>, 1>>
125       Typedefs;
126 
127   /// Retrieve the ID for the given identifier.
getIdentifier(StringRef Identifier)128   IdentifierID getIdentifier(StringRef Identifier) {
129     if (Identifier.empty())
130       return 0;
131 
132     // Add to the identifier table if missing.
133     return IdentifierIDs.try_emplace(Identifier, IdentifierIDs.size() + 1)
134         .first->second;
135   }
136 
137   /// Retrieve the ID for the given selector.
getSelector(ObjCSelectorRef SelectorRef)138   SelectorID getSelector(ObjCSelectorRef SelectorRef) {
139     // Translate the selector reference into a stored selector.
140     StoredObjCSelector Selector;
141     Selector.NumArgs = SelectorRef.NumArgs;
142     Selector.Identifiers.reserve(SelectorRef.Identifiers.size());
143     for (auto piece : SelectorRef.Identifiers)
144       Selector.Identifiers.push_back(getIdentifier(piece));
145 
146     // Look for the stored selector.  Add to the selector table if missing.
147     return SelectorIDs.try_emplace(Selector, SelectorIDs.size()).first->second;
148   }
149 
150 private:
151   void writeBlockInfoBlock(llvm::BitstreamWriter &Stream);
152   void writeControlBlock(llvm::BitstreamWriter &Stream);
153   void writeIdentifierBlock(llvm::BitstreamWriter &Stream);
154   void writeContextBlock(llvm::BitstreamWriter &Stream);
155   void writeObjCPropertyBlock(llvm::BitstreamWriter &Stream);
156   void writeObjCMethodBlock(llvm::BitstreamWriter &Stream);
157   void writeCXXMethodBlock(llvm::BitstreamWriter &Stream);
158   void writeFieldBlock(llvm::BitstreamWriter &Stream);
159   void writeObjCSelectorBlock(llvm::BitstreamWriter &Stream);
160   void writeGlobalVariableBlock(llvm::BitstreamWriter &Stream);
161   void writeGlobalFunctionBlock(llvm::BitstreamWriter &Stream);
162   void writeEnumConstantBlock(llvm::BitstreamWriter &Stream);
163   void writeTagBlock(llvm::BitstreamWriter &Stream);
164   void writeTypedefBlock(llvm::BitstreamWriter &Stream);
165 
166 public:
Implementation(llvm::StringRef ModuleName,const FileEntry * SF)167   Implementation(llvm::StringRef ModuleName, const FileEntry *SF)
168       : ModuleName(std::string(ModuleName)), SourceFile(SF) {}
169 
170   void writeToStream(llvm::raw_ostream &OS);
171 };
172 
writeToStream(llvm::raw_ostream & OS)173 void APINotesWriter::Implementation::writeToStream(llvm::raw_ostream &OS) {
174   llvm::SmallVector<char, 0> Buffer;
175 
176   {
177     llvm::BitstreamWriter Stream(Buffer);
178 
179     // Emit the signature.
180     for (unsigned char Byte : API_NOTES_SIGNATURE)
181       Stream.Emit(Byte, 8);
182 
183     // Emit the blocks.
184     writeBlockInfoBlock(Stream);
185     writeControlBlock(Stream);
186     writeIdentifierBlock(Stream);
187     writeContextBlock(Stream);
188     writeObjCPropertyBlock(Stream);
189     writeObjCMethodBlock(Stream);
190     writeCXXMethodBlock(Stream);
191     writeFieldBlock(Stream);
192     writeObjCSelectorBlock(Stream);
193     writeGlobalVariableBlock(Stream);
194     writeGlobalFunctionBlock(Stream);
195     writeEnumConstantBlock(Stream);
196     writeTagBlock(Stream);
197     writeTypedefBlock(Stream);
198   }
199 
200   OS.write(Buffer.data(), Buffer.size());
201   OS.flush();
202 }
203 
204 namespace {
205 /// Record the name of a block.
emitBlockID(llvm::BitstreamWriter & Stream,unsigned ID,llvm::StringRef Name)206 void emitBlockID(llvm::BitstreamWriter &Stream, unsigned ID,
207                  llvm::StringRef Name) {
208   Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID,
209                     llvm::ArrayRef<unsigned>{ID});
210 
211   // Emit the block name if present.
212   if (Name.empty())
213     return;
214   Stream.EmitRecord(
215       llvm::bitc::BLOCKINFO_CODE_BLOCKNAME,
216       llvm::ArrayRef<unsigned char>(
217           const_cast<unsigned char *>(
218               reinterpret_cast<const unsigned char *>(Name.data())),
219           Name.size()));
220 }
221 
222 /// Record the name of a record within a block.
emitRecordID(llvm::BitstreamWriter & Stream,unsigned ID,llvm::StringRef Name)223 void emitRecordID(llvm::BitstreamWriter &Stream, unsigned ID,
224                   llvm::StringRef Name) {
225   assert(ID < 256 && "can't fit record ID in next to name");
226 
227   llvm::SmallVector<unsigned char, 64> Buffer;
228   Buffer.resize(Name.size() + 1);
229   Buffer[0] = ID;
230   memcpy(Buffer.data() + 1, Name.data(), Name.size());
231 
232   Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Buffer);
233 }
234 } // namespace
235 
writeBlockInfoBlock(llvm::BitstreamWriter & Stream)236 void APINotesWriter::Implementation::writeBlockInfoBlock(
237     llvm::BitstreamWriter &Stream) {
238   llvm::BCBlockRAII Scope(Stream, llvm::bitc::BLOCKINFO_BLOCK_ID, 2);
239 
240 #define BLOCK(Block) emitBlockID(Stream, Block##_ID, #Block)
241 #define BLOCK_RECORD(NameSpace, Block)                                         \
242   emitRecordID(Stream, NameSpace::Block, #Block)
243   BLOCK(CONTROL_BLOCK);
244   BLOCK_RECORD(control_block, METADATA);
245   BLOCK_RECORD(control_block, MODULE_NAME);
246 
247   BLOCK(IDENTIFIER_BLOCK);
248   BLOCK_RECORD(identifier_block, IDENTIFIER_DATA);
249 
250   BLOCK(OBJC_CONTEXT_BLOCK);
251   BLOCK_RECORD(context_block, CONTEXT_ID_DATA);
252 
253   BLOCK(OBJC_PROPERTY_BLOCK);
254   BLOCK_RECORD(objc_property_block, OBJC_PROPERTY_DATA);
255 
256   BLOCK(OBJC_METHOD_BLOCK);
257   BLOCK_RECORD(objc_method_block, OBJC_METHOD_DATA);
258 
259   BLOCK(OBJC_SELECTOR_BLOCK);
260   BLOCK_RECORD(objc_selector_block, OBJC_SELECTOR_DATA);
261 
262   BLOCK(GLOBAL_VARIABLE_BLOCK);
263   BLOCK_RECORD(global_variable_block, GLOBAL_VARIABLE_DATA);
264 
265   BLOCK(GLOBAL_FUNCTION_BLOCK);
266   BLOCK_RECORD(global_function_block, GLOBAL_FUNCTION_DATA);
267 #undef BLOCK_RECORD
268 #undef BLOCK
269 }
270 
writeControlBlock(llvm::BitstreamWriter & Stream)271 void APINotesWriter::Implementation::writeControlBlock(
272     llvm::BitstreamWriter &Stream) {
273   llvm::BCBlockRAII Scope(Stream, CONTROL_BLOCK_ID, 3);
274 
275   control_block::MetadataLayout Metadata(Stream);
276   Metadata.emit(Scratch, VERSION_MAJOR, VERSION_MINOR);
277 
278   control_block::ModuleNameLayout ModuleName(Stream);
279   ModuleName.emit(Scratch, this->ModuleName);
280 
281   if (SourceFile) {
282     control_block::SourceFileLayout SourceFile(Stream);
283     SourceFile.emit(Scratch, this->SourceFile->getSize(),
284                     this->SourceFile->getModificationTime());
285   }
286 }
287 
288 namespace {
289 /// Used to serialize the on-disk identifier table.
290 class IdentifierTableInfo {
291 public:
292   using key_type = StringRef;
293   using key_type_ref = key_type;
294   using data_type = IdentifierID;
295   using data_type_ref = const data_type &;
296   using hash_value_type = uint32_t;
297   using offset_type = unsigned;
298 
ComputeHash(key_type_ref Key)299   hash_value_type ComputeHash(key_type_ref Key) { return llvm::djbHash(Key); }
300 
301   std::pair<unsigned, unsigned>
EmitKeyDataLength(raw_ostream & OS,key_type_ref Key,data_type_ref)302   EmitKeyDataLength(raw_ostream &OS, key_type_ref Key, data_type_ref) {
303     uint32_t KeyLength = Key.size();
304     uint32_t DataLength = sizeof(uint32_t);
305 
306     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
307     writer.write<uint16_t>(KeyLength);
308     writer.write<uint16_t>(DataLength);
309     return {KeyLength, DataLength};
310   }
311 
EmitKey(raw_ostream & OS,key_type_ref Key,unsigned)312   void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) { OS << Key; }
313 
EmitData(raw_ostream & OS,key_type_ref,data_type_ref Data,unsigned)314   void EmitData(raw_ostream &OS, key_type_ref, data_type_ref Data, unsigned) {
315     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
316     writer.write<uint32_t>(Data);
317   }
318 };
319 } // namespace
320 
writeIdentifierBlock(llvm::BitstreamWriter & Stream)321 void APINotesWriter::Implementation::writeIdentifierBlock(
322     llvm::BitstreamWriter &Stream) {
323   llvm::BCBlockRAII restoreBlock(Stream, IDENTIFIER_BLOCK_ID, 3);
324 
325   if (IdentifierIDs.empty())
326     return;
327 
328   llvm::SmallString<4096> HashTableBlob;
329   uint32_t Offset;
330   {
331     llvm::OnDiskChainedHashTableGenerator<IdentifierTableInfo> Generator;
332     for (auto &II : IdentifierIDs)
333       Generator.insert(II.first(), II.second);
334 
335     llvm::raw_svector_ostream BlobStream(HashTableBlob);
336     // Make sure that no bucket is at offset 0
337     llvm::support::endian::write<uint32_t>(BlobStream, 0,
338                                            llvm::endianness::little);
339     Offset = Generator.Emit(BlobStream);
340   }
341 
342   identifier_block::IdentifierDataLayout IdentifierData(Stream);
343   IdentifierData.emit(Scratch, Offset, HashTableBlob);
344 }
345 
346 namespace {
347 /// Used to serialize the on-disk Objective-C context table.
348 class ContextIDTableInfo {
349 public:
350   using key_type = ContextTableKey;
351   using key_type_ref = key_type;
352   using data_type = unsigned;
353   using data_type_ref = const data_type &;
354   using hash_value_type = size_t;
355   using offset_type = unsigned;
356 
ComputeHash(key_type_ref Key)357   hash_value_type ComputeHash(key_type_ref Key) {
358     return static_cast<size_t>(Key.hashValue());
359   }
360 
EmitKeyDataLength(raw_ostream & OS,key_type_ref,data_type_ref)361   std::pair<unsigned, unsigned> EmitKeyDataLength(raw_ostream &OS, key_type_ref,
362                                                   data_type_ref) {
363     uint32_t KeyLength = sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint32_t);
364     uint32_t DataLength = sizeof(uint32_t);
365 
366     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
367     writer.write<uint16_t>(KeyLength);
368     writer.write<uint16_t>(DataLength);
369     return {KeyLength, DataLength};
370   }
371 
EmitKey(raw_ostream & OS,key_type_ref Key,unsigned)372   void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
373     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
374     writer.write<uint32_t>(Key.parentContextID);
375     writer.write<uint8_t>(Key.contextKind);
376     writer.write<uint32_t>(Key.contextID);
377   }
378 
EmitData(raw_ostream & OS,key_type_ref,data_type_ref Data,unsigned)379   void EmitData(raw_ostream &OS, key_type_ref, data_type_ref Data, unsigned) {
380     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
381     writer.write<uint32_t>(Data);
382   }
383 };
384 
385 /// Localized helper to make a type dependent, thwarting template argument
386 /// deduction.
387 template <typename T> struct MakeDependent { typedef T Type; };
388 
389 /// Retrieve the serialized size of the given VersionTuple, for use in
390 /// on-disk hash tables.
getVersionTupleSize(const VersionTuple & VT)391 unsigned getVersionTupleSize(const VersionTuple &VT) {
392   unsigned size = sizeof(uint8_t) + /*major*/ sizeof(uint32_t);
393   if (VT.getMinor())
394     size += sizeof(uint32_t);
395   if (VT.getSubminor())
396     size += sizeof(uint32_t);
397   if (VT.getBuild())
398     size += sizeof(uint32_t);
399   return size;
400 }
401 
402 /// Determine the size of an array of versioned information,
403 template <typename T>
getVersionedInfoSize(const llvm::SmallVectorImpl<std::pair<llvm::VersionTuple,T>> & VI,llvm::function_ref<unsigned (const typename MakeDependent<T>::Type &)> getInfoSize)404 unsigned getVersionedInfoSize(
405     const llvm::SmallVectorImpl<std::pair<llvm::VersionTuple, T>> &VI,
406     llvm::function_ref<unsigned(const typename MakeDependent<T>::Type &)>
407         getInfoSize) {
408   unsigned result = sizeof(uint16_t); // # of elements
409   for (const auto &E : VI) {
410     result += getVersionTupleSize(E.first);
411     result += getInfoSize(E.second);
412   }
413   return result;
414 }
415 
416 /// Emit a serialized representation of a version tuple.
emitVersionTuple(raw_ostream & OS,const VersionTuple & VT)417 void emitVersionTuple(raw_ostream &OS, const VersionTuple &VT) {
418   llvm::support::endian::Writer writer(OS, llvm::endianness::little);
419 
420   // First byte contains the number of components beyond the 'major' component.
421   uint8_t descriptor;
422   if (VT.getBuild())
423     descriptor = 3;
424   else if (VT.getSubminor())
425     descriptor = 2;
426   else if (VT.getMinor())
427     descriptor = 1;
428   else
429     descriptor = 0;
430   writer.write<uint8_t>(descriptor);
431 
432   // Write the components.
433   writer.write<uint32_t>(VT.getMajor());
434   if (auto minor = VT.getMinor())
435     writer.write<uint32_t>(*minor);
436   if (auto subminor = VT.getSubminor())
437     writer.write<uint32_t>(*subminor);
438   if (auto build = VT.getBuild())
439     writer.write<uint32_t>(*build);
440 }
441 
442 /// Emit versioned information.
443 template <typename T>
emitVersionedInfo(raw_ostream & OS,llvm::SmallVectorImpl<std::pair<VersionTuple,T>> & VI,llvm::function_ref<void (raw_ostream &,const typename MakeDependent<T>::Type &)> emitInfo)444 void emitVersionedInfo(
445     raw_ostream &OS, llvm::SmallVectorImpl<std::pair<VersionTuple, T>> &VI,
446     llvm::function_ref<void(raw_ostream &,
447                             const typename MakeDependent<T>::Type &)>
448         emitInfo) {
449   std::sort(VI.begin(), VI.end(),
450             [](const std::pair<VersionTuple, T> &LHS,
451                const std::pair<VersionTuple, T> &RHS) -> bool {
452               assert((&LHS == &RHS || LHS.first != RHS.first) &&
453                      "two entries for the same version");
454               return LHS.first < RHS.first;
455             });
456 
457   llvm::support::endian::Writer writer(OS, llvm::endianness::little);
458   writer.write<uint16_t>(VI.size());
459   for (const auto &E : VI) {
460     emitVersionTuple(OS, E.first);
461     emitInfo(OS, E.second);
462   }
463 }
464 
465 /// On-disk hash table info key base for handling versioned data.
466 template <typename Derived, typename KeyType, typename UnversionedDataType>
467 class VersionedTableInfo {
asDerived()468   Derived &asDerived() { return *static_cast<Derived *>(this); }
469 
asDerived() const470   const Derived &asDerived() const {
471     return *static_cast<const Derived *>(this);
472   }
473 
474 public:
475   using key_type = KeyType;
476   using key_type_ref = key_type;
477   using data_type =
478       llvm::SmallVector<std::pair<llvm::VersionTuple, UnversionedDataType>, 1>;
479   using data_type_ref = data_type &;
480   using hash_value_type = size_t;
481   using offset_type = unsigned;
482 
483   std::pair<unsigned, unsigned>
EmitKeyDataLength(raw_ostream & OS,key_type_ref Key,data_type_ref Data)484   EmitKeyDataLength(raw_ostream &OS, key_type_ref Key, data_type_ref Data) {
485     uint32_t KeyLength = asDerived().getKeyLength(Key);
486     uint32_t DataLength =
487         getVersionedInfoSize(Data, [this](const UnversionedDataType &UI) {
488           return asDerived().getUnversionedInfoSize(UI);
489         });
490 
491     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
492     writer.write<uint16_t>(KeyLength);
493     writer.write<uint16_t>(DataLength);
494     return {KeyLength, DataLength};
495   }
496 
EmitData(raw_ostream & OS,key_type_ref,data_type_ref Data,unsigned)497   void EmitData(raw_ostream &OS, key_type_ref, data_type_ref Data, unsigned) {
498     emitVersionedInfo(
499         OS, Data, [this](llvm::raw_ostream &OS, const UnversionedDataType &UI) {
500           asDerived().emitUnversionedInfo(OS, UI);
501         });
502   }
503 };
504 
505 /// Emit a serialized representation of the common entity information.
emitCommonEntityInfo(raw_ostream & OS,const CommonEntityInfo & CEI)506 void emitCommonEntityInfo(raw_ostream &OS, const CommonEntityInfo &CEI) {
507   llvm::support::endian::Writer writer(OS, llvm::endianness::little);
508 
509   uint8_t payload = 0;
510   if (auto swiftPrivate = CEI.isSwiftPrivate()) {
511     payload |= 0x01;
512     if (*swiftPrivate)
513       payload |= 0x02;
514   }
515   payload <<= 1;
516   payload |= CEI.Unavailable;
517   payload <<= 1;
518   payload |= CEI.UnavailableInSwift;
519 
520   writer.write<uint8_t>(payload);
521 
522   writer.write<uint16_t>(CEI.UnavailableMsg.size());
523   OS.write(CEI.UnavailableMsg.c_str(), CEI.UnavailableMsg.size());
524 
525   writer.write<uint16_t>(CEI.SwiftName.size());
526   OS.write(CEI.SwiftName.c_str(), CEI.SwiftName.size());
527 }
528 
529 /// Retrieve the serialized size of the given CommonEntityInfo, for use in
530 /// on-disk hash tables.
getCommonEntityInfoSize(const CommonEntityInfo & CEI)531 unsigned getCommonEntityInfoSize(const CommonEntityInfo &CEI) {
532   return 5 + CEI.UnavailableMsg.size() + CEI.SwiftName.size();
533 }
534 
535 // Retrieve the serialized size of the given CommonTypeInfo, for use
536 // in on-disk hash tables.
getCommonTypeInfoSize(const CommonTypeInfo & CTI)537 unsigned getCommonTypeInfoSize(const CommonTypeInfo &CTI) {
538   return 2 + (CTI.getSwiftBridge() ? CTI.getSwiftBridge()->size() : 0) + 2 +
539          (CTI.getNSErrorDomain() ? CTI.getNSErrorDomain()->size() : 0) +
540          getCommonEntityInfoSize(CTI);
541 }
542 
543 /// Emit a serialized representation of the common type information.
emitCommonTypeInfo(raw_ostream & OS,const CommonTypeInfo & CTI)544 void emitCommonTypeInfo(raw_ostream &OS, const CommonTypeInfo &CTI) {
545   emitCommonEntityInfo(OS, CTI);
546 
547   llvm::support::endian::Writer writer(OS, llvm::endianness::little);
548   if (auto swiftBridge = CTI.getSwiftBridge()) {
549     writer.write<uint16_t>(swiftBridge->size() + 1);
550     OS.write(swiftBridge->c_str(), swiftBridge->size());
551   } else {
552     writer.write<uint16_t>(0);
553   }
554   if (auto nsErrorDomain = CTI.getNSErrorDomain()) {
555     writer.write<uint16_t>(nsErrorDomain->size() + 1);
556     OS.write(nsErrorDomain->c_str(), CTI.getNSErrorDomain()->size());
557   } else {
558     writer.write<uint16_t>(0);
559   }
560 }
561 
562 /// Used to serialize the on-disk Objective-C property table.
563 class ContextInfoTableInfo
564     : public VersionedTableInfo<ContextInfoTableInfo, unsigned, ContextInfo> {
565 public:
getKeyLength(key_type_ref)566   unsigned getKeyLength(key_type_ref) { return sizeof(uint32_t); }
567 
EmitKey(raw_ostream & OS,key_type_ref Key,unsigned)568   void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
569     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
570     writer.write<uint32_t>(Key);
571   }
572 
ComputeHash(key_type_ref Key)573   hash_value_type ComputeHash(key_type_ref Key) {
574     return static_cast<size_t>(llvm::hash_value(Key));
575   }
576 
getUnversionedInfoSize(const ContextInfo & OCI)577   unsigned getUnversionedInfoSize(const ContextInfo &OCI) {
578     return getCommonTypeInfoSize(OCI) + 1;
579   }
580 
emitUnversionedInfo(raw_ostream & OS,const ContextInfo & OCI)581   void emitUnversionedInfo(raw_ostream &OS, const ContextInfo &OCI) {
582     emitCommonTypeInfo(OS, OCI);
583 
584     uint8_t payload = 0;
585     if (auto swiftImportAsNonGeneric = OCI.getSwiftImportAsNonGeneric())
586       payload |= (0x01 << 1) | (uint8_t)swiftImportAsNonGeneric.value();
587     payload <<= 2;
588     if (auto swiftObjCMembers = OCI.getSwiftObjCMembers())
589       payload |= (0x01 << 1) | (uint8_t)swiftObjCMembers.value();
590     payload <<= 3;
591     if (auto nullable = OCI.getDefaultNullability())
592       payload |= (0x01 << 2) | static_cast<uint8_t>(*nullable);
593     payload = (payload << 1) | (OCI.hasDesignatedInits() ? 1 : 0);
594 
595     OS << payload;
596   }
597 };
598 } // namespace
599 
writeContextBlock(llvm::BitstreamWriter & Stream)600 void APINotesWriter::Implementation::writeContextBlock(
601     llvm::BitstreamWriter &Stream) {
602   llvm::BCBlockRAII restoreBlock(Stream, OBJC_CONTEXT_BLOCK_ID, 3);
603 
604   if (Contexts.empty())
605     return;
606 
607   {
608     llvm::SmallString<4096> HashTableBlob;
609     uint32_t Offset;
610     {
611       llvm::OnDiskChainedHashTableGenerator<ContextIDTableInfo> Generator;
612       for (auto &OC : Contexts)
613         Generator.insert(OC.first, OC.second.first);
614 
615       llvm::raw_svector_ostream BlobStream(HashTableBlob);
616       // Make sure that no bucket is at offset 0
617       llvm::support::endian::write<uint32_t>(BlobStream, 0,
618                                              llvm::endianness::little);
619       Offset = Generator.Emit(BlobStream);
620     }
621 
622     context_block::ContextIDLayout ContextID(Stream);
623     ContextID.emit(Scratch, Offset, HashTableBlob);
624   }
625 
626   {
627     llvm::SmallString<4096> HashTableBlob;
628     uint32_t Offset;
629     {
630       llvm::OnDiskChainedHashTableGenerator<ContextInfoTableInfo> Generator;
631       for (auto &OC : Contexts)
632         Generator.insert(OC.second.first, OC.second.second);
633 
634       llvm::raw_svector_ostream BlobStream(HashTableBlob);
635       // Make sure that no bucket is at offset 0
636       llvm::support::endian::write<uint32_t>(BlobStream, 0,
637                                              llvm::endianness::little);
638       Offset = Generator.Emit(BlobStream);
639     }
640 
641     context_block::ContextInfoLayout ContextInfo(Stream);
642     ContextInfo.emit(Scratch, Offset, HashTableBlob);
643   }
644 }
645 
646 namespace {
647 /// Retrieve the serialized size of the given VariableInfo, for use in
648 /// on-disk hash tables.
getVariableInfoSize(const VariableInfo & VI)649 unsigned getVariableInfoSize(const VariableInfo &VI) {
650   return 2 + getCommonEntityInfoSize(VI) + 2 + VI.getType().size();
651 }
652 unsigned getParamInfoSize(const ParamInfo &PI);
653 
654 /// Emit a serialized representation of the variable information.
emitVariableInfo(raw_ostream & OS,const VariableInfo & VI)655 void emitVariableInfo(raw_ostream &OS, const VariableInfo &VI) {
656   emitCommonEntityInfo(OS, VI);
657 
658   uint8_t bytes[2] = {0, 0};
659   if (auto nullable = VI.getNullability()) {
660     bytes[0] = 1;
661     bytes[1] = static_cast<uint8_t>(*nullable);
662   } else {
663     // Nothing to do.
664   }
665 
666   OS.write(reinterpret_cast<const char *>(bytes), 2);
667 
668   llvm::support::endian::Writer writer(OS, llvm::endianness::little);
669   writer.write<uint16_t>(VI.getType().size());
670   OS.write(VI.getType().data(), VI.getType().size());
671 }
672 
673 /// Used to serialize the on-disk Objective-C property table.
674 class ObjCPropertyTableInfo
675     : public VersionedTableInfo<ObjCPropertyTableInfo,
676                                 std::tuple<unsigned, unsigned, char>,
677                                 ObjCPropertyInfo> {
678 public:
getKeyLength(key_type_ref)679   unsigned getKeyLength(key_type_ref) {
680     return sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint8_t);
681   }
682 
EmitKey(raw_ostream & OS,key_type_ref Key,unsigned)683   void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
684     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
685     writer.write<uint32_t>(std::get<0>(Key));
686     writer.write<uint32_t>(std::get<1>(Key));
687     writer.write<uint8_t>(std::get<2>(Key));
688   }
689 
ComputeHash(key_type_ref Key)690   hash_value_type ComputeHash(key_type_ref Key) {
691     return static_cast<size_t>(llvm::hash_value(Key));
692   }
693 
getUnversionedInfoSize(const ObjCPropertyInfo & OPI)694   unsigned getUnversionedInfoSize(const ObjCPropertyInfo &OPI) {
695     return getVariableInfoSize(OPI) + 1;
696   }
697 
emitUnversionedInfo(raw_ostream & OS,const ObjCPropertyInfo & OPI)698   void emitUnversionedInfo(raw_ostream &OS, const ObjCPropertyInfo &OPI) {
699     emitVariableInfo(OS, OPI);
700 
701     uint8_t flags = 0;
702     if (auto value = OPI.getSwiftImportAsAccessors()) {
703       flags |= 1 << 0;
704       flags |= value.value() << 1;
705     }
706     OS << flags;
707   }
708 };
709 } // namespace
710 
writeObjCPropertyBlock(llvm::BitstreamWriter & Stream)711 void APINotesWriter::Implementation::writeObjCPropertyBlock(
712     llvm::BitstreamWriter &Stream) {
713   llvm::BCBlockRAII Scope(Stream, OBJC_PROPERTY_BLOCK_ID, 3);
714 
715   if (ObjCProperties.empty())
716     return;
717 
718   {
719     llvm::SmallString<4096> HashTableBlob;
720     uint32_t Offset;
721     {
722       llvm::OnDiskChainedHashTableGenerator<ObjCPropertyTableInfo> Generator;
723       for (auto &OP : ObjCProperties)
724         Generator.insert(OP.first, OP.second);
725 
726       llvm::raw_svector_ostream BlobStream(HashTableBlob);
727       // Make sure that no bucket is at offset 0
728       llvm::support::endian::write<uint32_t>(BlobStream, 0,
729                                              llvm::endianness::little);
730       Offset = Generator.Emit(BlobStream);
731     }
732 
733     objc_property_block::ObjCPropertyDataLayout ObjCPropertyData(Stream);
734     ObjCPropertyData.emit(Scratch, Offset, HashTableBlob);
735   }
736 }
737 
738 namespace {
739 unsigned getFunctionInfoSize(const FunctionInfo &);
740 void emitFunctionInfo(llvm::raw_ostream &, const FunctionInfo &);
741 void emitParamInfo(raw_ostream &OS, const ParamInfo &PI);
742 
743 /// Used to serialize the on-disk Objective-C method table.
744 class ObjCMethodTableInfo
745     : public VersionedTableInfo<ObjCMethodTableInfo,
746                                 std::tuple<unsigned, unsigned, char>,
747                                 ObjCMethodInfo> {
748 public:
getKeyLength(key_type_ref)749   unsigned getKeyLength(key_type_ref) {
750     return sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint8_t);
751   }
752 
EmitKey(raw_ostream & OS,key_type_ref Key,unsigned)753   void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
754     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
755     writer.write<uint32_t>(std::get<0>(Key));
756     writer.write<uint32_t>(std::get<1>(Key));
757     writer.write<uint8_t>(std::get<2>(Key));
758   }
759 
ComputeHash(key_type_ref key)760   hash_value_type ComputeHash(key_type_ref key) {
761     return static_cast<size_t>(llvm::hash_value(key));
762   }
763 
getUnversionedInfoSize(const ObjCMethodInfo & OMI)764   unsigned getUnversionedInfoSize(const ObjCMethodInfo &OMI) {
765     auto size = getFunctionInfoSize(OMI) + 1;
766     if (OMI.Self)
767       size += getParamInfoSize(*OMI.Self);
768     return size;
769   }
770 
emitUnversionedInfo(raw_ostream & OS,const ObjCMethodInfo & OMI)771   void emitUnversionedInfo(raw_ostream &OS, const ObjCMethodInfo &OMI) {
772     uint8_t flags = 0;
773     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
774     flags = (flags << 1) | OMI.DesignatedInit;
775     flags = (flags << 1) | OMI.RequiredInit;
776     flags = (flags << 1) | static_cast<bool>(OMI.Self);
777     writer.write<uint8_t>(flags);
778 
779     emitFunctionInfo(OS, OMI);
780 
781     if (OMI.Self)
782       emitParamInfo(OS, *OMI.Self);
783   }
784 };
785 
786 /// Used to serialize the on-disk C++ method table.
787 class CXXMethodTableInfo
788     : public VersionedTableInfo<CXXMethodTableInfo, SingleDeclTableKey,
789                                 CXXMethodInfo> {
790 public:
getKeyLength(key_type_ref)791   unsigned getKeyLength(key_type_ref) {
792     return sizeof(uint32_t) + sizeof(uint32_t);
793   }
794 
EmitKey(raw_ostream & OS,key_type_ref Key,unsigned)795   void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
796     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
797     writer.write<uint32_t>(Key.parentContextID);
798     writer.write<uint32_t>(Key.nameID);
799   }
800 
ComputeHash(key_type_ref key)801   hash_value_type ComputeHash(key_type_ref key) {
802     return static_cast<size_t>(key.hashValue());
803   }
804 
getUnversionedInfoSize(const CXXMethodInfo & MI)805   unsigned getUnversionedInfoSize(const CXXMethodInfo &MI) {
806     auto size = getFunctionInfoSize(MI) + 1;
807     if (MI.This)
808       size += getParamInfoSize(*MI.This);
809     return size;
810   }
811 
emitUnversionedInfo(raw_ostream & OS,const CXXMethodInfo & MI)812   void emitUnversionedInfo(raw_ostream &OS, const CXXMethodInfo &MI) {
813     uint8_t flags = 0;
814     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
815     flags = (flags << 1) | static_cast<bool>(MI.This);
816     writer.write<uint8_t>(flags);
817 
818     emitFunctionInfo(OS, MI);
819     if (MI.This)
820       emitParamInfo(OS, *MI.This);
821   }
822 };
823 } // namespace
824 
writeObjCMethodBlock(llvm::BitstreamWriter & Stream)825 void APINotesWriter::Implementation::writeObjCMethodBlock(
826     llvm::BitstreamWriter &Stream) {
827   llvm::BCBlockRAII Scope(Stream, OBJC_METHOD_BLOCK_ID, 3);
828 
829   if (ObjCMethods.empty())
830     return;
831 
832   {
833     llvm::SmallString<4096> HashTableBlob;
834     uint32_t Offset;
835     {
836       llvm::OnDiskChainedHashTableGenerator<ObjCMethodTableInfo> Generator;
837       for (auto &OM : ObjCMethods)
838         Generator.insert(OM.first, OM.second);
839 
840       llvm::raw_svector_ostream BlobStream(HashTableBlob);
841       // Make sure that no bucket is at offset 0
842       llvm::support::endian::write<uint32_t>(BlobStream, 0,
843                                              llvm::endianness::little);
844       Offset = Generator.Emit(BlobStream);
845     }
846 
847     objc_method_block::ObjCMethodDataLayout ObjCMethodData(Stream);
848     ObjCMethodData.emit(Scratch, Offset, HashTableBlob);
849   }
850 }
851 
writeCXXMethodBlock(llvm::BitstreamWriter & Stream)852 void APINotesWriter::Implementation::writeCXXMethodBlock(
853     llvm::BitstreamWriter &Stream) {
854   llvm::BCBlockRAII Scope(Stream, CXX_METHOD_BLOCK_ID, 3);
855 
856   if (CXXMethods.empty())
857     return;
858 
859   {
860     llvm::SmallString<4096> HashTableBlob;
861     uint32_t Offset;
862     {
863       llvm::OnDiskChainedHashTableGenerator<CXXMethodTableInfo> Generator;
864       for (auto &MD : CXXMethods)
865         Generator.insert(MD.first, MD.second);
866 
867       llvm::raw_svector_ostream BlobStream(HashTableBlob);
868       // Make sure that no bucket is at offset 0
869       llvm::support::endian::write<uint32_t>(BlobStream, 0,
870                                              llvm::endianness::little);
871       Offset = Generator.Emit(BlobStream);
872     }
873 
874     cxx_method_block::CXXMethodDataLayout CXXMethodData(Stream);
875     CXXMethodData.emit(Scratch, Offset, HashTableBlob);
876   }
877 }
878 
879 namespace {
880 /// Used to serialize the on-disk C field table.
881 class FieldTableInfo
882     : public VersionedTableInfo<FieldTableInfo, SingleDeclTableKey, FieldInfo> {
883 public:
getKeyLength(key_type_ref)884   unsigned getKeyLength(key_type_ref) {
885     return sizeof(uint32_t) + sizeof(uint32_t);
886   }
887 
EmitKey(raw_ostream & OS,key_type_ref Key,unsigned)888   void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
889     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
890     writer.write<uint32_t>(Key.parentContextID);
891     writer.write<uint32_t>(Key.nameID);
892   }
893 
ComputeHash(key_type_ref key)894   hash_value_type ComputeHash(key_type_ref key) {
895     return static_cast<size_t>(key.hashValue());
896   }
897 
getUnversionedInfoSize(const FieldInfo & FI)898   unsigned getUnversionedInfoSize(const FieldInfo &FI) {
899     return getVariableInfoSize(FI);
900   }
901 
emitUnversionedInfo(raw_ostream & OS,const FieldInfo & FI)902   void emitUnversionedInfo(raw_ostream &OS, const FieldInfo &FI) {
903     emitVariableInfo(OS, FI);
904   }
905 };
906 } // namespace
907 
writeFieldBlock(llvm::BitstreamWriter & Stream)908 void APINotesWriter::Implementation::writeFieldBlock(
909     llvm::BitstreamWriter &Stream) {
910   llvm::BCBlockRAII Scope(Stream, FIELD_BLOCK_ID, 3);
911 
912   if (Fields.empty())
913     return;
914 
915   {
916     llvm::SmallString<4096> HashTableBlob;
917     uint32_t Offset;
918     {
919       llvm::OnDiskChainedHashTableGenerator<FieldTableInfo> Generator;
920       for (auto &FD : Fields)
921         Generator.insert(FD.first, FD.second);
922 
923       llvm::raw_svector_ostream BlobStream(HashTableBlob);
924       // Make sure that no bucket is at offset 0
925       llvm::support::endian::write<uint32_t>(BlobStream, 0,
926                                              llvm::endianness::little);
927       Offset = Generator.Emit(BlobStream);
928     }
929 
930     field_block::FieldDataLayout FieldData(Stream);
931     FieldData.emit(Scratch, Offset, HashTableBlob);
932   }
933 }
934 
935 namespace {
936 /// Used to serialize the on-disk Objective-C selector table.
937 class ObjCSelectorTableInfo {
938 public:
939   using key_type = StoredObjCSelector;
940   using key_type_ref = const key_type &;
941   using data_type = SelectorID;
942   using data_type_ref = data_type;
943   using hash_value_type = unsigned;
944   using offset_type = unsigned;
945 
ComputeHash(key_type_ref Key)946   hash_value_type ComputeHash(key_type_ref Key) {
947     return llvm::DenseMapInfo<StoredObjCSelector>::getHashValue(Key);
948   }
949 
950   std::pair<unsigned, unsigned>
EmitKeyDataLength(raw_ostream & OS,key_type_ref Key,data_type_ref)951   EmitKeyDataLength(raw_ostream &OS, key_type_ref Key, data_type_ref) {
952     uint32_t KeyLength =
953         sizeof(uint16_t) + sizeof(uint32_t) * Key.Identifiers.size();
954     uint32_t DataLength = sizeof(uint32_t);
955 
956     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
957     writer.write<uint16_t>(KeyLength);
958     writer.write<uint16_t>(DataLength);
959     return {KeyLength, DataLength};
960   }
961 
EmitKey(raw_ostream & OS,key_type_ref Key,unsigned)962   void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
963     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
964     writer.write<uint16_t>(Key.NumArgs);
965     for (auto Identifier : Key.Identifiers)
966       writer.write<uint32_t>(Identifier);
967   }
968 
EmitData(raw_ostream & OS,key_type_ref,data_type_ref Data,unsigned)969   void EmitData(raw_ostream &OS, key_type_ref, data_type_ref Data, unsigned) {
970     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
971     writer.write<uint32_t>(Data);
972   }
973 };
974 } // namespace
975 
writeObjCSelectorBlock(llvm::BitstreamWriter & Stream)976 void APINotesWriter::Implementation::writeObjCSelectorBlock(
977     llvm::BitstreamWriter &Stream) {
978   llvm::BCBlockRAII Scope(Stream, OBJC_SELECTOR_BLOCK_ID, 3);
979 
980   if (SelectorIDs.empty())
981     return;
982 
983   {
984     llvm::SmallString<4096> HashTableBlob;
985     uint32_t Offset;
986     {
987       llvm::OnDiskChainedHashTableGenerator<ObjCSelectorTableInfo> Generator;
988       for (auto &S : SelectorIDs)
989         Generator.insert(S.first, S.second);
990 
991       llvm::raw_svector_ostream BlobStream(HashTableBlob);
992       // Make sure that no bucket is at offset 0
993       llvm::support::endian::write<uint32_t>(BlobStream, 0,
994                                              llvm::endianness::little);
995       Offset = Generator.Emit(BlobStream);
996     }
997 
998     objc_selector_block::ObjCSelectorDataLayout ObjCSelectorData(Stream);
999     ObjCSelectorData.emit(Scratch, Offset, HashTableBlob);
1000   }
1001 }
1002 
1003 namespace {
1004 /// Used to serialize the on-disk global variable table.
1005 class GlobalVariableTableInfo
1006     : public VersionedTableInfo<GlobalVariableTableInfo, SingleDeclTableKey,
1007                                 GlobalVariableInfo> {
1008 public:
getKeyLength(key_type_ref)1009   unsigned getKeyLength(key_type_ref) {
1010     return sizeof(uint32_t) + sizeof(uint32_t);
1011   }
1012 
EmitKey(raw_ostream & OS,key_type_ref Key,unsigned)1013   void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
1014     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
1015     writer.write<uint32_t>(Key.parentContextID);
1016     writer.write<uint32_t>(Key.nameID);
1017   }
1018 
ComputeHash(key_type_ref Key)1019   hash_value_type ComputeHash(key_type_ref Key) {
1020     return static_cast<size_t>(Key.hashValue());
1021   }
1022 
getUnversionedInfoSize(const GlobalVariableInfo & GVI)1023   unsigned getUnversionedInfoSize(const GlobalVariableInfo &GVI) {
1024     return getVariableInfoSize(GVI);
1025   }
1026 
emitUnversionedInfo(raw_ostream & OS,const GlobalVariableInfo & GVI)1027   void emitUnversionedInfo(raw_ostream &OS, const GlobalVariableInfo &GVI) {
1028     emitVariableInfo(OS, GVI);
1029   }
1030 };
1031 } // namespace
1032 
writeGlobalVariableBlock(llvm::BitstreamWriter & Stream)1033 void APINotesWriter::Implementation::writeGlobalVariableBlock(
1034     llvm::BitstreamWriter &Stream) {
1035   llvm::BCBlockRAII Scope(Stream, GLOBAL_VARIABLE_BLOCK_ID, 3);
1036 
1037   if (GlobalVariables.empty())
1038     return;
1039 
1040   {
1041     llvm::SmallString<4096> HashTableBlob;
1042     uint32_t Offset;
1043     {
1044       llvm::OnDiskChainedHashTableGenerator<GlobalVariableTableInfo> Generator;
1045       for (auto &GV : GlobalVariables)
1046         Generator.insert(GV.first, GV.second);
1047 
1048       llvm::raw_svector_ostream BlobStream(HashTableBlob);
1049       // Make sure that no bucket is at offset 0
1050       llvm::support::endian::write<uint32_t>(BlobStream, 0,
1051                                              llvm::endianness::little);
1052       Offset = Generator.Emit(BlobStream);
1053     }
1054 
1055     global_variable_block::GlobalVariableDataLayout GlobalVariableData(Stream);
1056     GlobalVariableData.emit(Scratch, Offset, HashTableBlob);
1057   }
1058 }
1059 
1060 namespace {
getParamInfoSize(const ParamInfo & PI)1061 unsigned getParamInfoSize(const ParamInfo &PI) {
1062   return getVariableInfoSize(PI) + 1;
1063 }
1064 
emitParamInfo(raw_ostream & OS,const ParamInfo & PI)1065 void emitParamInfo(raw_ostream &OS, const ParamInfo &PI) {
1066   emitVariableInfo(OS, PI);
1067 
1068   uint8_t flags = 0;
1069   if (auto noescape = PI.isNoEscape()) {
1070     flags |= 0x01;
1071     if (*noescape)
1072       flags |= 0x02;
1073   }
1074   flags <<= 2;
1075   if (auto lifetimebound = PI.isLifetimebound()) {
1076     flags |= 0x01;
1077     if (*lifetimebound)
1078       flags |= 0x02;
1079   }
1080   flags <<= 3;
1081   if (auto RCC = PI.getRetainCountConvention())
1082     flags |= static_cast<uint8_t>(RCC.value()) + 1;
1083 
1084   llvm::support::endian::Writer writer(OS, llvm::endianness::little);
1085   writer.write<uint8_t>(flags);
1086 }
1087 
1088 /// Retrieve the serialized size of the given FunctionInfo, for use in on-disk
1089 /// hash tables.
getFunctionInfoSize(const FunctionInfo & FI)1090 unsigned getFunctionInfoSize(const FunctionInfo &FI) {
1091   unsigned size = getCommonEntityInfoSize(FI) + 2 + sizeof(uint64_t);
1092   size += sizeof(uint16_t);
1093   for (const auto &P : FI.Params)
1094     size += getParamInfoSize(P);
1095   size += sizeof(uint16_t) + FI.ResultType.size();
1096   size += sizeof(uint16_t) + FI.SwiftReturnOwnership.size();
1097   return size;
1098 }
1099 
1100 /// Emit a serialized representation of the function information.
emitFunctionInfo(raw_ostream & OS,const FunctionInfo & FI)1101 void emitFunctionInfo(raw_ostream &OS, const FunctionInfo &FI) {
1102   emitCommonEntityInfo(OS, FI);
1103 
1104   uint8_t flags = 0;
1105   flags |= FI.NullabilityAudited;
1106   flags <<= 3;
1107   if (auto RCC = FI.getRetainCountConvention())
1108     flags |= static_cast<uint8_t>(RCC.value()) + 1;
1109 
1110   llvm::support::endian::Writer writer(OS, llvm::endianness::little);
1111 
1112   writer.write<uint8_t>(flags);
1113   writer.write<uint8_t>(FI.NumAdjustedNullable);
1114   writer.write<uint64_t>(FI.NullabilityPayload);
1115 
1116   writer.write<uint16_t>(FI.Params.size());
1117   for (const auto &PI : FI.Params)
1118     emitParamInfo(OS, PI);
1119 
1120   writer.write<uint16_t>(FI.ResultType.size());
1121   writer.write(ArrayRef<char>{FI.ResultType});
1122   writer.write<uint16_t>(FI.SwiftReturnOwnership.size());
1123   writer.write(ArrayRef<char>{FI.SwiftReturnOwnership});
1124 }
1125 
1126 /// Used to serialize the on-disk global function table.
1127 class GlobalFunctionTableInfo
1128     : public VersionedTableInfo<GlobalFunctionTableInfo, SingleDeclTableKey,
1129                                 GlobalFunctionInfo> {
1130 public:
getKeyLength(key_type_ref)1131   unsigned getKeyLength(key_type_ref) {
1132     return sizeof(uint32_t) + sizeof(uint32_t);
1133   }
1134 
EmitKey(raw_ostream & OS,key_type_ref Key,unsigned)1135   void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
1136     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
1137     writer.write<uint32_t>(Key.parentContextID);
1138     writer.write<uint32_t>(Key.nameID);
1139   }
1140 
ComputeHash(key_type_ref Key)1141   hash_value_type ComputeHash(key_type_ref Key) {
1142     return static_cast<size_t>(Key.hashValue());
1143   }
1144 
getUnversionedInfoSize(const GlobalFunctionInfo & GFI)1145   unsigned getUnversionedInfoSize(const GlobalFunctionInfo &GFI) {
1146     return getFunctionInfoSize(GFI);
1147   }
1148 
emitUnversionedInfo(raw_ostream & OS,const GlobalFunctionInfo & GFI)1149   void emitUnversionedInfo(raw_ostream &OS, const GlobalFunctionInfo &GFI) {
1150     emitFunctionInfo(OS, GFI);
1151   }
1152 };
1153 } // namespace
1154 
writeGlobalFunctionBlock(llvm::BitstreamWriter & Stream)1155 void APINotesWriter::Implementation::writeGlobalFunctionBlock(
1156     llvm::BitstreamWriter &Stream) {
1157   llvm::BCBlockRAII Scope(Stream, GLOBAL_FUNCTION_BLOCK_ID, 3);
1158 
1159   if (GlobalFunctions.empty())
1160     return;
1161 
1162   {
1163     llvm::SmallString<4096> HashTableBlob;
1164     uint32_t Offset;
1165     {
1166       llvm::OnDiskChainedHashTableGenerator<GlobalFunctionTableInfo> Generator;
1167       for (auto &F : GlobalFunctions)
1168         Generator.insert(F.first, F.second);
1169 
1170       llvm::raw_svector_ostream BlobStream(HashTableBlob);
1171       // Make sure that no bucket is at offset 0
1172       llvm::support::endian::write<uint32_t>(BlobStream, 0,
1173                                              llvm::endianness::little);
1174       Offset = Generator.Emit(BlobStream);
1175     }
1176 
1177     global_function_block::GlobalFunctionDataLayout GlobalFunctionData(Stream);
1178     GlobalFunctionData.emit(Scratch, Offset, HashTableBlob);
1179   }
1180 }
1181 
1182 namespace {
1183 /// Used to serialize the on-disk global enum constant.
1184 class EnumConstantTableInfo
1185     : public VersionedTableInfo<EnumConstantTableInfo, unsigned,
1186                                 EnumConstantInfo> {
1187 public:
getKeyLength(key_type_ref)1188   unsigned getKeyLength(key_type_ref) { return sizeof(uint32_t); }
1189 
EmitKey(raw_ostream & OS,key_type_ref Key,unsigned)1190   void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
1191     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
1192     writer.write<uint32_t>(Key);
1193   }
1194 
ComputeHash(key_type_ref Key)1195   hash_value_type ComputeHash(key_type_ref Key) {
1196     return static_cast<size_t>(llvm::hash_value(Key));
1197   }
1198 
getUnversionedInfoSize(const EnumConstantInfo & ECI)1199   unsigned getUnversionedInfoSize(const EnumConstantInfo &ECI) {
1200     return getCommonEntityInfoSize(ECI);
1201   }
1202 
emitUnversionedInfo(raw_ostream & OS,const EnumConstantInfo & ECI)1203   void emitUnversionedInfo(raw_ostream &OS, const EnumConstantInfo &ECI) {
1204     emitCommonEntityInfo(OS, ECI);
1205   }
1206 };
1207 } // namespace
1208 
writeEnumConstantBlock(llvm::BitstreamWriter & Stream)1209 void APINotesWriter::Implementation::writeEnumConstantBlock(
1210     llvm::BitstreamWriter &Stream) {
1211   llvm::BCBlockRAII Scope(Stream, ENUM_CONSTANT_BLOCK_ID, 3);
1212 
1213   if (EnumConstants.empty())
1214     return;
1215 
1216   {
1217     llvm::SmallString<4096> HashTableBlob;
1218     uint32_t Offset;
1219     {
1220       llvm::OnDiskChainedHashTableGenerator<EnumConstantTableInfo> Generator;
1221       for (auto &EC : EnumConstants)
1222         Generator.insert(EC.first, EC.second);
1223 
1224       llvm::raw_svector_ostream BlobStream(HashTableBlob);
1225       // Make sure that no bucket is at offset 0
1226       llvm::support::endian::write<uint32_t>(BlobStream, 0,
1227                                              llvm::endianness::little);
1228       Offset = Generator.Emit(BlobStream);
1229     }
1230 
1231     enum_constant_block::EnumConstantDataLayout EnumConstantData(Stream);
1232     EnumConstantData.emit(Scratch, Offset, HashTableBlob);
1233   }
1234 }
1235 
1236 namespace {
1237 template <typename Derived, typename UnversionedDataType>
1238 class CommonTypeTableInfo
1239     : public VersionedTableInfo<Derived, SingleDeclTableKey,
1240                                 UnversionedDataType> {
1241 public:
1242   using key_type_ref = typename CommonTypeTableInfo::key_type_ref;
1243   using hash_value_type = typename CommonTypeTableInfo::hash_value_type;
1244 
getKeyLength(key_type_ref)1245   unsigned getKeyLength(key_type_ref) {
1246     return sizeof(uint32_t) + sizeof(IdentifierID);
1247   }
1248 
EmitKey(raw_ostream & OS,key_type_ref Key,unsigned)1249   void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
1250     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
1251     writer.write<uint32_t>(Key.parentContextID);
1252     writer.write<IdentifierID>(Key.nameID);
1253   }
1254 
ComputeHash(key_type_ref Key)1255   hash_value_type ComputeHash(key_type_ref Key) {
1256     return static_cast<size_t>(Key.hashValue());
1257   }
1258 
getUnversionedInfoSize(const UnversionedDataType & UDT)1259   unsigned getUnversionedInfoSize(const UnversionedDataType &UDT) {
1260     return getCommonTypeInfoSize(UDT);
1261   }
1262 
emitUnversionedInfo(raw_ostream & OS,const UnversionedDataType & UDT)1263   void emitUnversionedInfo(raw_ostream &OS, const UnversionedDataType &UDT) {
1264     emitCommonTypeInfo(OS, UDT);
1265   }
1266 };
1267 
1268 /// Used to serialize the on-disk tag table.
1269 class TagTableInfo : public CommonTypeTableInfo<TagTableInfo, TagInfo> {
1270 public:
getUnversionedInfoSize(const TagInfo & TI)1271   unsigned getUnversionedInfoSize(const TagInfo &TI) {
1272     // clang-format off
1273     return 2 + (TI.SwiftImportAs ? TI.SwiftImportAs->size() : 0) +
1274            2 + (TI.SwiftRetainOp ? TI.SwiftRetainOp->size() : 0) +
1275            2 + (TI.SwiftReleaseOp ? TI.SwiftReleaseOp->size() : 0) +
1276            2 + (TI.SwiftDefaultOwnership ? TI.SwiftDefaultOwnership->size() : 0) +
1277            2 + (TI.SwiftConformance ? TI.SwiftConformance->size() : 0) +
1278            3 + getCommonTypeInfoSize(TI);
1279     // clang-format on
1280   }
1281 
emitUnversionedInfo(raw_ostream & OS,const TagInfo & TI)1282   void emitUnversionedInfo(raw_ostream &OS, const TagInfo &TI) {
1283     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
1284 
1285     uint8_t Flags = 0;
1286     if (auto extensibility = TI.EnumExtensibility) {
1287       Flags |= static_cast<uint8_t>(extensibility.value()) + 1;
1288       assert((Flags < (1 << 2)) && "must fit in two bits");
1289     }
1290 
1291     Flags <<= 2;
1292     if (auto value = TI.isFlagEnum())
1293       Flags |= (value.value() << 1 | 1 << 0);
1294 
1295     writer.write<uint8_t>(Flags);
1296 
1297     if (auto Copyable = TI.isSwiftCopyable())
1298       writer.write<uint8_t>(*Copyable ? kSwiftConforms : kSwiftDoesNotConform);
1299     else
1300       writer.write<uint8_t>(0);
1301 
1302     if (auto Escapable = TI.isSwiftEscapable())
1303       writer.write<uint8_t>(*Escapable ? kSwiftConforms : kSwiftDoesNotConform);
1304     else
1305       writer.write<uint8_t>(0);
1306 
1307     if (auto ImportAs = TI.SwiftImportAs) {
1308       writer.write<uint16_t>(ImportAs->size() + 1);
1309       OS.write(ImportAs->c_str(), ImportAs->size());
1310     } else {
1311       writer.write<uint16_t>(0);
1312     }
1313     if (auto RetainOp = TI.SwiftRetainOp) {
1314       writer.write<uint16_t>(RetainOp->size() + 1);
1315       OS.write(RetainOp->c_str(), RetainOp->size());
1316     } else {
1317       writer.write<uint16_t>(0);
1318     }
1319     if (auto ReleaseOp = TI.SwiftReleaseOp) {
1320       writer.write<uint16_t>(ReleaseOp->size() + 1);
1321       OS.write(ReleaseOp->c_str(), ReleaseOp->size());
1322     } else {
1323       writer.write<uint16_t>(0);
1324     }
1325     if (auto DefaultOwnership = TI.SwiftDefaultOwnership) {
1326       writer.write<uint16_t>(DefaultOwnership->size() + 1);
1327       OS.write(DefaultOwnership->c_str(), DefaultOwnership->size());
1328     } else {
1329       writer.write<uint16_t>(0);
1330     }
1331     if (auto Conformance = TI.SwiftConformance) {
1332       writer.write<uint16_t>(Conformance->size() + 1);
1333       OS.write(Conformance->c_str(), Conformance->size());
1334     } else {
1335       writer.write<uint16_t>(0);
1336     }
1337 
1338     emitCommonTypeInfo(OS, TI);
1339   }
1340 };
1341 } // namespace
1342 
writeTagBlock(llvm::BitstreamWriter & Stream)1343 void APINotesWriter::Implementation::writeTagBlock(
1344     llvm::BitstreamWriter &Stream) {
1345   llvm::BCBlockRAII Scope(Stream, TAG_BLOCK_ID, 3);
1346 
1347   if (Tags.empty())
1348     return;
1349 
1350   {
1351     llvm::SmallString<4096> HashTableBlob;
1352     uint32_t Offset;
1353     {
1354       llvm::OnDiskChainedHashTableGenerator<TagTableInfo> Generator;
1355       for (auto &T : Tags)
1356         Generator.insert(T.first, T.second);
1357 
1358       llvm::raw_svector_ostream BlobStream(HashTableBlob);
1359       // Make sure that no bucket is at offset 0
1360       llvm::support::endian::write<uint32_t>(BlobStream, 0,
1361                                              llvm::endianness::little);
1362       Offset = Generator.Emit(BlobStream);
1363     }
1364 
1365     tag_block::TagDataLayout TagData(Stream);
1366     TagData.emit(Scratch, Offset, HashTableBlob);
1367   }
1368 }
1369 
1370 namespace {
1371 /// Used to serialize the on-disk typedef table.
1372 class TypedefTableInfo
1373     : public CommonTypeTableInfo<TypedefTableInfo, TypedefInfo> {
1374 public:
getUnversionedInfoSize(const TypedefInfo & TI)1375   unsigned getUnversionedInfoSize(const TypedefInfo &TI) {
1376     return 1 + getCommonTypeInfoSize(TI);
1377   }
1378 
emitUnversionedInfo(raw_ostream & OS,const TypedefInfo & TI)1379   void emitUnversionedInfo(raw_ostream &OS, const TypedefInfo &TI) {
1380     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
1381 
1382     uint8_t Flags = 0;
1383     if (auto swiftWrapper = TI.SwiftWrapper)
1384       Flags |= static_cast<uint8_t>(*swiftWrapper) + 1;
1385 
1386     writer.write<uint8_t>(Flags);
1387 
1388     emitCommonTypeInfo(OS, TI);
1389   }
1390 };
1391 } // namespace
1392 
writeTypedefBlock(llvm::BitstreamWriter & Stream)1393 void APINotesWriter::Implementation::writeTypedefBlock(
1394     llvm::BitstreamWriter &Stream) {
1395   llvm::BCBlockRAII Scope(Stream, TYPEDEF_BLOCK_ID, 3);
1396 
1397   if (Typedefs.empty())
1398     return;
1399 
1400   {
1401     llvm::SmallString<4096> HashTableBlob;
1402     uint32_t Offset;
1403     {
1404       llvm::OnDiskChainedHashTableGenerator<TypedefTableInfo> Generator;
1405       for (auto &T : Typedefs)
1406         Generator.insert(T.first, T.second);
1407 
1408       llvm::raw_svector_ostream BlobStream(HashTableBlob);
1409       // Make sure that no bucket is at offset 0
1410       llvm::support::endian::write<uint32_t>(BlobStream, 0,
1411                                              llvm::endianness::little);
1412       Offset = Generator.Emit(BlobStream);
1413     }
1414 
1415     typedef_block::TypedefDataLayout TypedefData(Stream);
1416     TypedefData.emit(Scratch, Offset, HashTableBlob);
1417   }
1418 }
1419 
1420 // APINotesWriter
1421 
APINotesWriter(llvm::StringRef ModuleName,const FileEntry * SF)1422 APINotesWriter::APINotesWriter(llvm::StringRef ModuleName, const FileEntry *SF)
1423     : Implementation(new class Implementation(ModuleName, SF)) {}
1424 
1425 APINotesWriter::~APINotesWriter() = default;
1426 
writeToStream(llvm::raw_ostream & OS)1427 void APINotesWriter::writeToStream(llvm::raw_ostream &OS) {
1428   Implementation->writeToStream(OS);
1429 }
1430 
addContext(std::optional<ContextID> ParentCtxID,llvm::StringRef Name,ContextKind Kind,const ContextInfo & Info,llvm::VersionTuple SwiftVersion)1431 ContextID APINotesWriter::addContext(std::optional<ContextID> ParentCtxID,
1432                                      llvm::StringRef Name, ContextKind Kind,
1433                                      const ContextInfo &Info,
1434                                      llvm::VersionTuple SwiftVersion) {
1435   IdentifierID NameID = Implementation->getIdentifier(Name);
1436 
1437   uint32_t RawParentCtxID = ParentCtxID ? ParentCtxID->Value : -1;
1438   ContextTableKey Key(RawParentCtxID, static_cast<uint8_t>(Kind), NameID);
1439   auto Known = Implementation->Contexts.find(Key);
1440   if (Known == Implementation->Contexts.end()) {
1441     unsigned NextID = Implementation->Contexts.size() + 1;
1442 
1443     Implementation::VersionedSmallVector<ContextInfo> EmptyVersionedInfo;
1444     Known = Implementation->Contexts
1445                 .insert(std::make_pair(
1446                     Key, std::make_pair(NextID, EmptyVersionedInfo)))
1447                 .first;
1448 
1449     Implementation->ContextNames[NextID] = NameID;
1450     Implementation->ParentContexts[NextID] = RawParentCtxID;
1451   }
1452 
1453   // Add this version information.
1454   auto &VersionedVec = Known->second.second;
1455   bool Found = false;
1456   for (auto &Versioned : VersionedVec) {
1457     if (Versioned.first == SwiftVersion) {
1458       Versioned.second |= Info;
1459       Found = true;
1460       break;
1461     }
1462   }
1463 
1464   if (!Found)
1465     VersionedVec.push_back({SwiftVersion, Info});
1466 
1467   return ContextID(Known->second.first);
1468 }
1469 
addObjCProperty(ContextID CtxID,StringRef Name,bool IsInstanceProperty,const ObjCPropertyInfo & Info,VersionTuple SwiftVersion)1470 void APINotesWriter::addObjCProperty(ContextID CtxID, StringRef Name,
1471                                      bool IsInstanceProperty,
1472                                      const ObjCPropertyInfo &Info,
1473                                      VersionTuple SwiftVersion) {
1474   IdentifierID NameID = Implementation->getIdentifier(Name);
1475   Implementation
1476       ->ObjCProperties[std::make_tuple(CtxID.Value, NameID, IsInstanceProperty)]
1477       .push_back({SwiftVersion, Info});
1478 }
1479 
addObjCMethod(ContextID CtxID,ObjCSelectorRef Selector,bool IsInstanceMethod,const ObjCMethodInfo & Info,VersionTuple SwiftVersion)1480 void APINotesWriter::addObjCMethod(ContextID CtxID, ObjCSelectorRef Selector,
1481                                    bool IsInstanceMethod,
1482                                    const ObjCMethodInfo &Info,
1483                                    VersionTuple SwiftVersion) {
1484   SelectorID SelID = Implementation->getSelector(Selector);
1485   auto Key = std::tuple<unsigned, unsigned, char>{CtxID.Value, SelID,
1486                                                   IsInstanceMethod};
1487   Implementation->ObjCMethods[Key].push_back({SwiftVersion, Info});
1488 
1489   // If this method is a designated initializer, update the class to note that
1490   // it has designated initializers.
1491   if (Info.DesignatedInit) {
1492     assert(Implementation->ParentContexts.contains(CtxID.Value));
1493     uint32_t ParentCtxID = Implementation->ParentContexts[CtxID.Value];
1494     ContextTableKey CtxKey(ParentCtxID,
1495                            static_cast<uint8_t>(ContextKind::ObjCClass),
1496                            Implementation->ContextNames[CtxID.Value]);
1497     assert(Implementation->Contexts.contains(CtxKey));
1498     auto &VersionedVec = Implementation->Contexts[CtxKey].second;
1499     bool Found = false;
1500     for (auto &Versioned : VersionedVec) {
1501       if (Versioned.first == SwiftVersion) {
1502         Versioned.second.setHasDesignatedInits(true);
1503         Found = true;
1504         break;
1505       }
1506     }
1507 
1508     if (!Found) {
1509       VersionedVec.push_back({SwiftVersion, ContextInfo()});
1510       VersionedVec.back().second.setHasDesignatedInits(true);
1511     }
1512   }
1513 }
1514 
addCXXMethod(ContextID CtxID,llvm::StringRef Name,const CXXMethodInfo & Info,VersionTuple SwiftVersion)1515 void APINotesWriter::addCXXMethod(ContextID CtxID, llvm::StringRef Name,
1516                                   const CXXMethodInfo &Info,
1517                                   VersionTuple SwiftVersion) {
1518   IdentifierID NameID = Implementation->getIdentifier(Name);
1519   SingleDeclTableKey Key(CtxID.Value, NameID);
1520   Implementation->CXXMethods[Key].push_back({SwiftVersion, Info});
1521 }
1522 
addField(ContextID CtxID,llvm::StringRef Name,const FieldInfo & Info,VersionTuple SwiftVersion)1523 void APINotesWriter::addField(ContextID CtxID, llvm::StringRef Name,
1524                               const FieldInfo &Info,
1525                               VersionTuple SwiftVersion) {
1526   IdentifierID NameID = Implementation->getIdentifier(Name);
1527   SingleDeclTableKey Key(CtxID.Value, NameID);
1528   Implementation->Fields[Key].push_back({SwiftVersion, Info});
1529 }
1530 
addGlobalVariable(std::optional<Context> Ctx,llvm::StringRef Name,const GlobalVariableInfo & Info,VersionTuple SwiftVersion)1531 void APINotesWriter::addGlobalVariable(std::optional<Context> Ctx,
1532                                        llvm::StringRef Name,
1533                                        const GlobalVariableInfo &Info,
1534                                        VersionTuple SwiftVersion) {
1535   IdentifierID VariableID = Implementation->getIdentifier(Name);
1536   SingleDeclTableKey Key(Ctx, VariableID);
1537   Implementation->GlobalVariables[Key].push_back({SwiftVersion, Info});
1538 }
1539 
addGlobalFunction(std::optional<Context> Ctx,llvm::StringRef Name,const GlobalFunctionInfo & Info,VersionTuple SwiftVersion)1540 void APINotesWriter::addGlobalFunction(std::optional<Context> Ctx,
1541                                        llvm::StringRef Name,
1542                                        const GlobalFunctionInfo &Info,
1543                                        VersionTuple SwiftVersion) {
1544   IdentifierID NameID = Implementation->getIdentifier(Name);
1545   SingleDeclTableKey Key(Ctx, NameID);
1546   Implementation->GlobalFunctions[Key].push_back({SwiftVersion, Info});
1547 }
1548 
addEnumConstant(llvm::StringRef Name,const EnumConstantInfo & Info,VersionTuple SwiftVersion)1549 void APINotesWriter::addEnumConstant(llvm::StringRef Name,
1550                                      const EnumConstantInfo &Info,
1551                                      VersionTuple SwiftVersion) {
1552   IdentifierID EnumConstantID = Implementation->getIdentifier(Name);
1553   Implementation->EnumConstants[EnumConstantID].push_back({SwiftVersion, Info});
1554 }
1555 
addTag(std::optional<Context> Ctx,llvm::StringRef Name,const TagInfo & Info,VersionTuple SwiftVersion)1556 void APINotesWriter::addTag(std::optional<Context> Ctx, llvm::StringRef Name,
1557                             const TagInfo &Info, VersionTuple SwiftVersion) {
1558   IdentifierID TagID = Implementation->getIdentifier(Name);
1559   SingleDeclTableKey Key(Ctx, TagID);
1560   Implementation->Tags[Key].push_back({SwiftVersion, Info});
1561 }
1562 
addTypedef(std::optional<Context> Ctx,llvm::StringRef Name,const TypedefInfo & Info,VersionTuple SwiftVersion)1563 void APINotesWriter::addTypedef(std::optional<Context> Ctx,
1564                                 llvm::StringRef Name, const TypedefInfo &Info,
1565                                 VersionTuple SwiftVersion) {
1566   IdentifierID TypedefID = Implementation->getIdentifier(Name);
1567   SingleDeclTableKey Key(Ctx, TypedefID);
1568   Implementation->Typedefs[Key].push_back({SwiftVersion, Info});
1569 }
1570 } // namespace api_notes
1571 } // namespace clang
1572