[clang][modules] Don't prevent translation of FW_Private includes when explicitly...
[llvm-project.git] / clang / lib / APINotes / APINotesWriter.cpp
blob770d78e22050c01d3d09c27fa86fdb085a293227
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 //===----------------------------------------------------------------------===//
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"
20 namespace clang {
21 namespace api_notes {
22 class APINotesWriter::Implementation {
23 friend class APINotesWriter;
25 template <typename T>
26 using VersionedSmallVector =
27 llvm::SmallVector<std::pair<llvm::VersionTuple, T>, 1>;
29 std::string ModuleName;
30 const FileEntry *SourceFile;
32 /// Scratch space for bitstream writing.
33 llvm::SmallVector<uint64_t, 64> Scratch;
35 /// Mapping from strings to identifier IDs.
36 llvm::StringMap<IdentifierID> IdentifierIDs;
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<ObjCContextInfo>>>
46 ObjCContexts;
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;
53 /// Mapping from context IDs to the identifier ID holding the name.
54 llvm::DenseMap<unsigned, unsigned> ObjCContextNames;
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;
65 /// Information about Objective-C methods.
66 ///
67 /// Indexed by the context ID, selector ID, and Boolean (stored as a char)
68 /// indicating whether this is a class or instance method.
69 llvm::DenseMap<std::tuple<unsigned, unsigned, char>,
70 llvm::SmallVector<std::pair<VersionTuple, ObjCMethodInfo>, 1>>
71 ObjCMethods;
73 /// Mapping from selectors to selector ID.
74 llvm::DenseMap<StoredObjCSelector, SelectorID> SelectorIDs;
76 /// Information about global variables.
77 ///
78 /// Indexed by the context ID, contextKind, identifier ID.
79 llvm::DenseMap<
80 ContextTableKey,
81 llvm::SmallVector<std::pair<VersionTuple, GlobalVariableInfo>, 1>>
82 GlobalVariables;
84 /// Information about global functions.
85 ///
86 /// Indexed by the context ID, contextKind, identifier ID.
87 llvm::DenseMap<
88 ContextTableKey,
89 llvm::SmallVector<std::pair<VersionTuple, GlobalFunctionInfo>, 1>>
90 GlobalFunctions;
92 /// Information about enumerators.
93 ///
94 /// Indexed by the identifier ID.
95 llvm::DenseMap<
96 unsigned, llvm::SmallVector<std::pair<VersionTuple, EnumConstantInfo>, 1>>
97 EnumConstants;
99 /// Information about tags.
101 /// Indexed by the context ID, contextKind, identifier ID.
102 llvm::DenseMap<ContextTableKey,
103 llvm::SmallVector<std::pair<VersionTuple, TagInfo>, 1>>
104 Tags;
106 /// Information about typedefs.
108 /// Indexed by the context ID, contextKind, identifier ID.
109 llvm::DenseMap<ContextTableKey,
110 llvm::SmallVector<std::pair<VersionTuple, TypedefInfo>, 1>>
111 Typedefs;
113 /// Retrieve the ID for the given identifier.
114 IdentifierID getIdentifier(StringRef Identifier) {
115 if (Identifier.empty())
116 return 0;
118 auto Known = IdentifierIDs.find(Identifier);
119 if (Known != IdentifierIDs.end())
120 return Known->second;
122 // Add to the identifier table.
123 Known = IdentifierIDs.insert({Identifier, IdentifierIDs.size() + 1}).first;
124 return Known->second;
127 /// Retrieve the ID for the given selector.
128 SelectorID getSelector(ObjCSelectorRef SelectorRef) {
129 // Translate the selector reference into a stored selector.
130 StoredObjCSelector Selector;
131 Selector.Identifiers.reserve(SelectorRef.Identifiers.size());
132 for (auto piece : SelectorRef.Identifiers)
133 Selector.Identifiers.push_back(getIdentifier(piece));
135 // Look for the stored selector.
136 auto Known = SelectorIDs.find(Selector);
137 if (Known != SelectorIDs.end())
138 return Known->second;
140 // Add to the selector table.
141 Known = SelectorIDs.insert({Selector, SelectorIDs.size()}).first;
142 return Known->second;
145 private:
146 void writeBlockInfoBlock(llvm::BitstreamWriter &Stream);
147 void writeControlBlock(llvm::BitstreamWriter &Stream);
148 void writeIdentifierBlock(llvm::BitstreamWriter &Stream);
149 void writeObjCContextBlock(llvm::BitstreamWriter &Stream);
150 void writeObjCPropertyBlock(llvm::BitstreamWriter &Stream);
151 void writeObjCMethodBlock(llvm::BitstreamWriter &Stream);
152 void writeObjCSelectorBlock(llvm::BitstreamWriter &Stream);
153 void writeGlobalVariableBlock(llvm::BitstreamWriter &Stream);
154 void writeGlobalFunctionBlock(llvm::BitstreamWriter &Stream);
155 void writeEnumConstantBlock(llvm::BitstreamWriter &Stream);
156 void writeTagBlock(llvm::BitstreamWriter &Stream);
157 void writeTypedefBlock(llvm::BitstreamWriter &Stream);
159 public:
160 Implementation(llvm::StringRef ModuleName, const FileEntry *SF)
161 : ModuleName(std::string(ModuleName)), SourceFile(SF) {}
163 void writeToStream(llvm::raw_ostream &OS);
166 void APINotesWriter::Implementation::writeToStream(llvm::raw_ostream &OS) {
167 llvm::SmallVector<char, 0> Buffer;
170 llvm::BitstreamWriter Stream(Buffer);
172 // Emit the signature.
173 for (unsigned char Byte : API_NOTES_SIGNATURE)
174 Stream.Emit(Byte, 8);
176 // Emit the blocks.
177 writeBlockInfoBlock(Stream);
178 writeControlBlock(Stream);
179 writeIdentifierBlock(Stream);
180 writeObjCContextBlock(Stream);
181 writeObjCPropertyBlock(Stream);
182 writeObjCMethodBlock(Stream);
183 writeObjCSelectorBlock(Stream);
184 writeGlobalVariableBlock(Stream);
185 writeGlobalFunctionBlock(Stream);
186 writeEnumConstantBlock(Stream);
187 writeTagBlock(Stream);
188 writeTypedefBlock(Stream);
191 OS.write(Buffer.data(), Buffer.size());
192 OS.flush();
195 namespace {
196 /// Record the name of a block.
197 void emitBlockID(llvm::BitstreamWriter &Stream, unsigned ID,
198 llvm::StringRef Name) {
199 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID,
200 llvm::ArrayRef<unsigned>{ID});
202 // Emit the block name if present.
203 if (Name.empty())
204 return;
205 Stream.EmitRecord(
206 llvm::bitc::BLOCKINFO_CODE_BLOCKNAME,
207 llvm::ArrayRef<unsigned char>(
208 const_cast<unsigned char *>(
209 reinterpret_cast<const unsigned char *>(Name.data())),
210 Name.size()));
213 /// Record the name of a record within a block.
214 void emitRecordID(llvm::BitstreamWriter &Stream, unsigned ID,
215 llvm::StringRef Name) {
216 assert(ID < 256 && "can't fit record ID in next to name");
218 llvm::SmallVector<unsigned char, 64> Buffer;
219 Buffer.resize(Name.size() + 1);
220 Buffer[0] = ID;
221 memcpy(Buffer.data() + 1, Name.data(), Name.size());
223 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Buffer);
225 } // namespace
227 void APINotesWriter::Implementation::writeBlockInfoBlock(
228 llvm::BitstreamWriter &Stream) {
229 llvm::BCBlockRAII Scope(Stream, llvm::bitc::BLOCKINFO_BLOCK_ID, 2);
231 #define BLOCK(Block) emitBlockID(Stream, Block##_ID, #Block)
232 #define BLOCK_RECORD(NameSpace, Block) \
233 emitRecordID(Stream, NameSpace::Block, #Block)
234 BLOCK(CONTROL_BLOCK);
235 BLOCK_RECORD(control_block, METADATA);
236 BLOCK_RECORD(control_block, MODULE_NAME);
238 BLOCK(IDENTIFIER_BLOCK);
239 BLOCK_RECORD(identifier_block, IDENTIFIER_DATA);
241 BLOCK(OBJC_CONTEXT_BLOCK);
242 BLOCK_RECORD(objc_context_block, OBJC_CONTEXT_ID_DATA);
244 BLOCK(OBJC_PROPERTY_BLOCK);
245 BLOCK_RECORD(objc_property_block, OBJC_PROPERTY_DATA);
247 BLOCK(OBJC_METHOD_BLOCK);
248 BLOCK_RECORD(objc_method_block, OBJC_METHOD_DATA);
250 BLOCK(OBJC_SELECTOR_BLOCK);
251 BLOCK_RECORD(objc_selector_block, OBJC_SELECTOR_DATA);
253 BLOCK(GLOBAL_VARIABLE_BLOCK);
254 BLOCK_RECORD(global_variable_block, GLOBAL_VARIABLE_DATA);
256 BLOCK(GLOBAL_FUNCTION_BLOCK);
257 BLOCK_RECORD(global_function_block, GLOBAL_FUNCTION_DATA);
258 #undef BLOCK_RECORD
259 #undef BLOCK
262 void APINotesWriter::Implementation::writeControlBlock(
263 llvm::BitstreamWriter &Stream) {
264 llvm::BCBlockRAII Scope(Stream, CONTROL_BLOCK_ID, 3);
266 control_block::MetadataLayout Metadata(Stream);
267 Metadata.emit(Scratch, VERSION_MAJOR, VERSION_MINOR);
269 control_block::ModuleNameLayout ModuleName(Stream);
270 ModuleName.emit(Scratch, this->ModuleName);
272 if (SourceFile) {
273 control_block::SourceFileLayout SourceFile(Stream);
274 SourceFile.emit(Scratch, this->SourceFile->getSize(),
275 this->SourceFile->getModificationTime());
279 namespace {
280 /// Used to serialize the on-disk identifier table.
281 class IdentifierTableInfo {
282 public:
283 using key_type = StringRef;
284 using key_type_ref = key_type;
285 using data_type = IdentifierID;
286 using data_type_ref = const data_type &;
287 using hash_value_type = uint32_t;
288 using offset_type = unsigned;
290 hash_value_type ComputeHash(key_type_ref Key) { return llvm::djbHash(Key); }
292 std::pair<unsigned, unsigned>
293 EmitKeyDataLength(raw_ostream &OS, key_type_ref Key, data_type_ref) {
294 uint32_t KeyLength = Key.size();
295 uint32_t DataLength = sizeof(uint32_t);
297 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
298 writer.write<uint16_t>(KeyLength);
299 writer.write<uint16_t>(DataLength);
300 return {KeyLength, DataLength};
303 void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) { OS << Key; }
305 void EmitData(raw_ostream &OS, key_type_ref, data_type_ref Data, unsigned) {
306 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
307 writer.write<uint32_t>(Data);
310 } // namespace
312 void APINotesWriter::Implementation::writeIdentifierBlock(
313 llvm::BitstreamWriter &Stream) {
314 llvm::BCBlockRAII restoreBlock(Stream, IDENTIFIER_BLOCK_ID, 3);
316 if (IdentifierIDs.empty())
317 return;
319 llvm::SmallString<4096> HashTableBlob;
320 uint32_t Offset;
322 llvm::OnDiskChainedHashTableGenerator<IdentifierTableInfo> Generator;
323 for (auto &II : IdentifierIDs)
324 Generator.insert(II.first(), II.second);
326 llvm::raw_svector_ostream BlobStream(HashTableBlob);
327 // Make sure that no bucket is at offset 0
328 llvm::support::endian::write<uint32_t>(BlobStream, 0,
329 llvm::endianness::little);
330 Offset = Generator.Emit(BlobStream);
333 identifier_block::IdentifierDataLayout IdentifierData(Stream);
334 IdentifierData.emit(Scratch, Offset, HashTableBlob);
337 namespace {
338 /// Used to serialize the on-disk Objective-C context table.
339 class ObjCContextIDTableInfo {
340 public:
341 using key_type = ContextTableKey;
342 using key_type_ref = key_type;
343 using data_type = unsigned;
344 using data_type_ref = const data_type &;
345 using hash_value_type = size_t;
346 using offset_type = unsigned;
348 hash_value_type ComputeHash(key_type_ref Key) {
349 return static_cast<size_t>(Key.hashValue());
352 std::pair<unsigned, unsigned> EmitKeyDataLength(raw_ostream &OS, key_type_ref,
353 data_type_ref) {
354 uint32_t KeyLength = sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint32_t);
355 uint32_t DataLength = sizeof(uint32_t);
357 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
358 writer.write<uint16_t>(KeyLength);
359 writer.write<uint16_t>(DataLength);
360 return {KeyLength, DataLength};
363 void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
364 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
365 writer.write<uint32_t>(Key.parentContextID);
366 writer.write<uint8_t>(Key.contextKind);
367 writer.write<uint32_t>(Key.contextID);
370 void EmitData(raw_ostream &OS, key_type_ref, data_type_ref Data, unsigned) {
371 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
372 writer.write<uint32_t>(Data);
376 /// Localized helper to make a type dependent, thwarting template argument
377 /// deduction.
378 template <typename T> struct MakeDependent { typedef T Type; };
380 /// Retrieve the serialized size of the given VersionTuple, for use in
381 /// on-disk hash tables.
382 unsigned getVersionTupleSize(const VersionTuple &VT) {
383 unsigned size = sizeof(uint8_t) + /*major*/ sizeof(uint32_t);
384 if (VT.getMinor())
385 size += sizeof(uint32_t);
386 if (VT.getSubminor())
387 size += sizeof(uint32_t);
388 if (VT.getBuild())
389 size += sizeof(uint32_t);
390 return size;
393 /// Determine the size of an array of versioned information,
394 template <typename T>
395 unsigned getVersionedInfoSize(
396 const llvm::SmallVectorImpl<std::pair<llvm::VersionTuple, T>> &VI,
397 llvm::function_ref<unsigned(const typename MakeDependent<T>::Type &)>
398 getInfoSize) {
399 unsigned result = sizeof(uint16_t); // # of elements
400 for (const auto &E : VI) {
401 result += getVersionTupleSize(E.first);
402 result += getInfoSize(E.second);
404 return result;
407 /// Emit a serialized representation of a version tuple.
408 void emitVersionTuple(raw_ostream &OS, const VersionTuple &VT) {
409 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
411 // First byte contains the number of components beyond the 'major' component.
412 uint8_t descriptor;
413 if (VT.getBuild())
414 descriptor = 3;
415 else if (VT.getSubminor())
416 descriptor = 2;
417 else if (VT.getMinor())
418 descriptor = 1;
419 else
420 descriptor = 0;
421 writer.write<uint8_t>(descriptor);
423 // Write the components.
424 writer.write<uint32_t>(VT.getMajor());
425 if (auto minor = VT.getMinor())
426 writer.write<uint32_t>(*minor);
427 if (auto subminor = VT.getSubminor())
428 writer.write<uint32_t>(*subminor);
429 if (auto build = VT.getBuild())
430 writer.write<uint32_t>(*build);
433 /// Emit versioned information.
434 template <typename T>
435 void emitVersionedInfo(
436 raw_ostream &OS, llvm::SmallVectorImpl<std::pair<VersionTuple, T>> &VI,
437 llvm::function_ref<void(raw_ostream &,
438 const typename MakeDependent<T>::Type &)>
439 emitInfo) {
440 std::sort(VI.begin(), VI.end(),
441 [](const std::pair<VersionTuple, T> &LHS,
442 const std::pair<VersionTuple, T> &RHS) -> bool {
443 assert(LHS.first != RHS.first &&
444 "two entries for the same version");
445 return LHS.first < RHS.first;
448 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
449 writer.write<uint16_t>(VI.size());
450 for (const auto &E : VI) {
451 emitVersionTuple(OS, E.first);
452 emitInfo(OS, E.second);
456 /// On-disk hash table info key base for handling versioned data.
457 template <typename Derived, typename KeyType, typename UnversionedDataType>
458 class VersionedTableInfo {
459 Derived &asDerived() { return *static_cast<Derived *>(this); }
461 const Derived &asDerived() const {
462 return *static_cast<const Derived *>(this);
465 public:
466 using key_type = KeyType;
467 using key_type_ref = key_type;
468 using data_type =
469 llvm::SmallVector<std::pair<llvm::VersionTuple, UnversionedDataType>, 1>;
470 using data_type_ref = data_type &;
471 using hash_value_type = size_t;
472 using offset_type = unsigned;
474 std::pair<unsigned, unsigned>
475 EmitKeyDataLength(raw_ostream &OS, key_type_ref Key, data_type_ref Data) {
476 uint32_t KeyLength = asDerived().getKeyLength(Key);
477 uint32_t DataLength =
478 getVersionedInfoSize(Data, [this](const UnversionedDataType &UI) {
479 return asDerived().getUnversionedInfoSize(UI);
482 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
483 writer.write<uint16_t>(KeyLength);
484 writer.write<uint16_t>(DataLength);
485 return {KeyLength, DataLength};
488 void EmitData(raw_ostream &OS, key_type_ref, data_type_ref Data, unsigned) {
489 emitVersionedInfo(
490 OS, Data, [this](llvm::raw_ostream &OS, const UnversionedDataType &UI) {
491 asDerived().emitUnversionedInfo(OS, UI);
496 /// Emit a serialized representation of the common entity information.
497 void emitCommonEntityInfo(raw_ostream &OS, const CommonEntityInfo &CEI) {
498 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
500 uint8_t payload = 0;
501 if (auto swiftPrivate = CEI.isSwiftPrivate()) {
502 payload |= 0x01;
503 if (*swiftPrivate)
504 payload |= 0x02;
506 payload <<= 1;
507 payload |= CEI.Unavailable;
508 payload <<= 1;
509 payload |= CEI.UnavailableInSwift;
511 writer.write<uint8_t>(payload);
513 writer.write<uint16_t>(CEI.UnavailableMsg.size());
514 OS.write(CEI.UnavailableMsg.c_str(), CEI.UnavailableMsg.size());
516 writer.write<uint16_t>(CEI.SwiftName.size());
517 OS.write(CEI.SwiftName.c_str(), CEI.SwiftName.size());
520 /// Retrieve the serialized size of the given CommonEntityInfo, for use in
521 /// on-disk hash tables.
522 unsigned getCommonEntityInfoSize(const CommonEntityInfo &CEI) {
523 return 5 + CEI.UnavailableMsg.size() + CEI.SwiftName.size();
526 // Retrieve the serialized size of the given CommonTypeInfo, for use
527 // in on-disk hash tables.
528 unsigned getCommonTypeInfoSize(const CommonTypeInfo &CTI) {
529 return 2 + (CTI.getSwiftBridge() ? CTI.getSwiftBridge()->size() : 0) + 2 +
530 (CTI.getNSErrorDomain() ? CTI.getNSErrorDomain()->size() : 0) +
531 getCommonEntityInfoSize(CTI);
534 /// Emit a serialized representation of the common type information.
535 void emitCommonTypeInfo(raw_ostream &OS, const CommonTypeInfo &CTI) {
536 emitCommonEntityInfo(OS, CTI);
538 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
539 if (auto swiftBridge = CTI.getSwiftBridge()) {
540 writer.write<uint16_t>(swiftBridge->size() + 1);
541 OS.write(swiftBridge->c_str(), swiftBridge->size());
542 } else {
543 writer.write<uint16_t>(0);
545 if (auto nsErrorDomain = CTI.getNSErrorDomain()) {
546 writer.write<uint16_t>(nsErrorDomain->size() + 1);
547 OS.write(nsErrorDomain->c_str(), CTI.getNSErrorDomain()->size());
548 } else {
549 writer.write<uint16_t>(0);
553 /// Used to serialize the on-disk Objective-C property table.
554 class ObjCContextInfoTableInfo
555 : public VersionedTableInfo<ObjCContextInfoTableInfo, unsigned,
556 ObjCContextInfo> {
557 public:
558 unsigned getKeyLength(key_type_ref) { return sizeof(uint32_t); }
560 void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
561 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
562 writer.write<uint32_t>(Key);
565 hash_value_type ComputeHash(key_type_ref Key) {
566 return static_cast<size_t>(llvm::hash_value(Key));
569 unsigned getUnversionedInfoSize(const ObjCContextInfo &OCI) {
570 return getCommonTypeInfoSize(OCI) + 1;
573 void emitUnversionedInfo(raw_ostream &OS, const ObjCContextInfo &OCI) {
574 emitCommonTypeInfo(OS, OCI);
576 uint8_t payload = 0;
577 if (auto swiftImportAsNonGeneric = OCI.getSwiftImportAsNonGeneric())
578 payload |= (0x01 << 1) | (uint8_t)swiftImportAsNonGeneric.value();
579 payload <<= 2;
580 if (auto swiftObjCMembers = OCI.getSwiftObjCMembers())
581 payload |= (0x01 << 1) | (uint8_t)swiftObjCMembers.value();
582 payload <<= 3;
583 if (auto nullable = OCI.getDefaultNullability())
584 payload |= (0x01 << 2) | static_cast<uint8_t>(*nullable);
585 payload = (payload << 1) | (OCI.hasDesignatedInits() ? 1 : 0);
587 OS << payload;
590 } // namespace
592 void APINotesWriter::Implementation::writeObjCContextBlock(
593 llvm::BitstreamWriter &Stream) {
594 llvm::BCBlockRAII restoreBlock(Stream, OBJC_CONTEXT_BLOCK_ID, 3);
596 if (ObjCContexts.empty())
597 return;
600 llvm::SmallString<4096> HashTableBlob;
601 uint32_t Offset;
603 llvm::OnDiskChainedHashTableGenerator<ObjCContextIDTableInfo> Generator;
604 for (auto &OC : ObjCContexts)
605 Generator.insert(OC.first, OC.second.first);
607 llvm::raw_svector_ostream BlobStream(HashTableBlob);
608 // Make sure that no bucket is at offset 0
609 llvm::support::endian::write<uint32_t>(BlobStream, 0,
610 llvm::endianness::little);
611 Offset = Generator.Emit(BlobStream);
614 objc_context_block::ObjCContextIDLayout ObjCContextID(Stream);
615 ObjCContextID.emit(Scratch, Offset, HashTableBlob);
619 llvm::SmallString<4096> HashTableBlob;
620 uint32_t Offset;
622 llvm::OnDiskChainedHashTableGenerator<ObjCContextInfoTableInfo> Generator;
623 for (auto &OC : ObjCContexts)
624 Generator.insert(OC.second.first, OC.second.second);
626 llvm::raw_svector_ostream BlobStream(HashTableBlob);
627 // Make sure that no bucket is at offset 0
628 llvm::support::endian::write<uint32_t>(BlobStream, 0,
629 llvm::endianness::little);
630 Offset = Generator.Emit(BlobStream);
633 objc_context_block::ObjCContextInfoLayout ObjCContextInfo(Stream);
634 ObjCContextInfo.emit(Scratch, Offset, HashTableBlob);
638 namespace {
639 /// Retrieve the serialized size of the given VariableInfo, for use in
640 /// on-disk hash tables.
641 unsigned getVariableInfoSize(const VariableInfo &VI) {
642 return 2 + getCommonEntityInfoSize(VI) + 2 + VI.getType().size();
645 /// Emit a serialized representation of the variable information.
646 void emitVariableInfo(raw_ostream &OS, const VariableInfo &VI) {
647 emitCommonEntityInfo(OS, VI);
649 uint8_t bytes[2] = {0, 0};
650 if (auto nullable = VI.getNullability()) {
651 bytes[0] = 1;
652 bytes[1] = static_cast<uint8_t>(*nullable);
653 } else {
654 // Nothing to do.
657 OS.write(reinterpret_cast<const char *>(bytes), 2);
659 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
660 writer.write<uint16_t>(VI.getType().size());
661 OS.write(VI.getType().data(), VI.getType().size());
664 /// Used to serialize the on-disk Objective-C property table.
665 class ObjCPropertyTableInfo
666 : public VersionedTableInfo<ObjCPropertyTableInfo,
667 std::tuple<unsigned, unsigned, char>,
668 ObjCPropertyInfo> {
669 public:
670 unsigned getKeyLength(key_type_ref) {
671 return sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint8_t);
674 void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
675 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
676 writer.write<uint32_t>(std::get<0>(Key));
677 writer.write<uint32_t>(std::get<1>(Key));
678 writer.write<uint8_t>(std::get<2>(Key));
681 hash_value_type ComputeHash(key_type_ref Key) {
682 return static_cast<size_t>(llvm::hash_value(Key));
685 unsigned getUnversionedInfoSize(const ObjCPropertyInfo &OPI) {
686 return getVariableInfoSize(OPI) + 1;
689 void emitUnversionedInfo(raw_ostream &OS, const ObjCPropertyInfo &OPI) {
690 emitVariableInfo(OS, OPI);
692 uint8_t flags = 0;
693 if (auto value = OPI.getSwiftImportAsAccessors()) {
694 flags |= 1 << 0;
695 flags |= value.value() << 1;
697 OS << flags;
700 } // namespace
702 void APINotesWriter::Implementation::writeObjCPropertyBlock(
703 llvm::BitstreamWriter &Stream) {
704 llvm::BCBlockRAII Scope(Stream, OBJC_PROPERTY_BLOCK_ID, 3);
706 if (ObjCProperties.empty())
707 return;
710 llvm::SmallString<4096> HashTableBlob;
711 uint32_t Offset;
713 llvm::OnDiskChainedHashTableGenerator<ObjCPropertyTableInfo> Generator;
714 for (auto &OP : ObjCProperties)
715 Generator.insert(OP.first, OP.second);
717 llvm::raw_svector_ostream BlobStream(HashTableBlob);
718 // Make sure that no bucket is at offset 0
719 llvm::support::endian::write<uint32_t>(BlobStream, 0,
720 llvm::endianness::little);
721 Offset = Generator.Emit(BlobStream);
724 objc_property_block::ObjCPropertyDataLayout ObjCPropertyData(Stream);
725 ObjCPropertyData.emit(Scratch, Offset, HashTableBlob);
729 namespace {
730 unsigned getFunctionInfoSize(const FunctionInfo &);
731 void emitFunctionInfo(llvm::raw_ostream &, const FunctionInfo &);
733 /// Used to serialize the on-disk Objective-C method table.
734 class ObjCMethodTableInfo
735 : public VersionedTableInfo<ObjCMethodTableInfo,
736 std::tuple<unsigned, unsigned, char>,
737 ObjCMethodInfo> {
738 public:
739 unsigned getKeyLength(key_type_ref) {
740 return sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint8_t);
743 void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
744 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
745 writer.write<uint32_t>(std::get<0>(Key));
746 writer.write<uint32_t>(std::get<1>(Key));
747 writer.write<uint8_t>(std::get<2>(Key));
750 hash_value_type ComputeHash(key_type_ref key) {
751 return static_cast<size_t>(llvm::hash_value(key));
754 unsigned getUnversionedInfoSize(const ObjCMethodInfo &OMI) {
755 return getFunctionInfoSize(OMI) + 1;
758 void emitUnversionedInfo(raw_ostream &OS, const ObjCMethodInfo &OMI) {
759 uint8_t flags = 0;
760 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
761 flags = (flags << 1) | OMI.DesignatedInit;
762 flags = (flags << 1) | OMI.RequiredInit;
763 writer.write<uint8_t>(flags);
765 emitFunctionInfo(OS, OMI);
768 } // namespace
770 void APINotesWriter::Implementation::writeObjCMethodBlock(
771 llvm::BitstreamWriter &Stream) {
772 llvm::BCBlockRAII Scope(Stream, OBJC_METHOD_BLOCK_ID, 3);
774 if (ObjCMethods.empty())
775 return;
778 llvm::SmallString<4096> HashTableBlob;
779 uint32_t Offset;
781 llvm::OnDiskChainedHashTableGenerator<ObjCMethodTableInfo> Generator;
782 for (auto &OM : ObjCMethods)
783 Generator.insert(OM.first, OM.second);
785 llvm::raw_svector_ostream BlobStream(HashTableBlob);
786 // Make sure that no bucket is at offset 0
787 llvm::support::endian::write<uint32_t>(BlobStream, 0,
788 llvm::endianness::little);
789 Offset = Generator.Emit(BlobStream);
792 objc_method_block::ObjCMethodDataLayout ObjCMethodData(Stream);
793 ObjCMethodData.emit(Scratch, Offset, HashTableBlob);
797 namespace {
798 /// Used to serialize the on-disk Objective-C selector table.
799 class ObjCSelectorTableInfo {
800 public:
801 using key_type = StoredObjCSelector;
802 using key_type_ref = const key_type &;
803 using data_type = SelectorID;
804 using data_type_ref = data_type;
805 using hash_value_type = unsigned;
806 using offset_type = unsigned;
808 hash_value_type ComputeHash(key_type_ref Key) {
809 return llvm::DenseMapInfo<StoredObjCSelector>::getHashValue(Key);
812 std::pair<unsigned, unsigned>
813 EmitKeyDataLength(raw_ostream &OS, key_type_ref Key, data_type_ref) {
814 uint32_t KeyLength =
815 sizeof(uint16_t) + sizeof(uint32_t) * Key.Identifiers.size();
816 uint32_t DataLength = sizeof(uint32_t);
818 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
819 writer.write<uint16_t>(KeyLength);
820 writer.write<uint16_t>(DataLength);
821 return {KeyLength, DataLength};
824 void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
825 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
826 writer.write<uint16_t>(Key.NumPieces);
827 for (auto Identifier : Key.Identifiers)
828 writer.write<uint32_t>(Identifier);
831 void EmitData(raw_ostream &OS, key_type_ref, data_type_ref Data, unsigned) {
832 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
833 writer.write<uint32_t>(Data);
836 } // namespace
838 void APINotesWriter::Implementation::writeObjCSelectorBlock(
839 llvm::BitstreamWriter &Stream) {
840 llvm::BCBlockRAII Scope(Stream, OBJC_SELECTOR_BLOCK_ID, 3);
842 if (SelectorIDs.empty())
843 return;
846 llvm::SmallString<4096> HashTableBlob;
847 uint32_t Offset;
849 llvm::OnDiskChainedHashTableGenerator<ObjCSelectorTableInfo> Generator;
850 for (auto &S : SelectorIDs)
851 Generator.insert(S.first, S.second);
853 llvm::raw_svector_ostream BlobStream(HashTableBlob);
854 // Make sure that no bucket is at offset 0
855 llvm::support::endian::write<uint32_t>(BlobStream, 0,
856 llvm::endianness::little);
857 Offset = Generator.Emit(BlobStream);
860 objc_selector_block::ObjCSelectorDataLayout ObjCSelectorData(Stream);
861 ObjCSelectorData.emit(Scratch, Offset, HashTableBlob);
865 namespace {
866 /// Used to serialize the on-disk global variable table.
867 class GlobalVariableTableInfo
868 : public VersionedTableInfo<GlobalVariableTableInfo, ContextTableKey,
869 GlobalVariableInfo> {
870 public:
871 unsigned getKeyLength(key_type_ref) {
872 return sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint32_t);
875 void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
876 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
877 writer.write<uint32_t>(Key.parentContextID);
878 writer.write<uint8_t>(Key.contextKind);
879 writer.write<uint32_t>(Key.contextID);
882 hash_value_type ComputeHash(key_type_ref Key) {
883 return static_cast<size_t>(Key.hashValue());
886 unsigned getUnversionedInfoSize(const GlobalVariableInfo &GVI) {
887 return getVariableInfoSize(GVI);
890 void emitUnversionedInfo(raw_ostream &OS, const GlobalVariableInfo &GVI) {
891 emitVariableInfo(OS, GVI);
894 } // namespace
896 void APINotesWriter::Implementation::writeGlobalVariableBlock(
897 llvm::BitstreamWriter &Stream) {
898 llvm::BCBlockRAII Scope(Stream, GLOBAL_VARIABLE_BLOCK_ID, 3);
900 if (GlobalVariables.empty())
901 return;
904 llvm::SmallString<4096> HashTableBlob;
905 uint32_t Offset;
907 llvm::OnDiskChainedHashTableGenerator<GlobalVariableTableInfo> Generator;
908 for (auto &GV : GlobalVariables)
909 Generator.insert(GV.first, GV.second);
911 llvm::raw_svector_ostream BlobStream(HashTableBlob);
912 // Make sure that no bucket is at offset 0
913 llvm::support::endian::write<uint32_t>(BlobStream, 0,
914 llvm::endianness::little);
915 Offset = Generator.Emit(BlobStream);
918 global_variable_block::GlobalVariableDataLayout GlobalVariableData(Stream);
919 GlobalVariableData.emit(Scratch, Offset, HashTableBlob);
923 namespace {
924 unsigned getParamInfoSize(const ParamInfo &PI) {
925 return getVariableInfoSize(PI) + 1;
928 void emitParamInfo(raw_ostream &OS, const ParamInfo &PI) {
929 emitVariableInfo(OS, PI);
931 uint8_t flags = 0;
932 if (auto noescape = PI.isNoEscape()) {
933 flags |= 0x01;
934 if (*noescape)
935 flags |= 0x02;
937 flags <<= 3;
938 if (auto RCC = PI.getRetainCountConvention())
939 flags |= static_cast<uint8_t>(RCC.value()) + 1;
941 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
942 writer.write<uint8_t>(flags);
945 /// Retrieve the serialized size of the given FunctionInfo, for use in on-disk
946 /// hash tables.
947 unsigned getFunctionInfoSize(const FunctionInfo &FI) {
948 unsigned size = getCommonEntityInfoSize(FI) + 2 + sizeof(uint64_t);
949 size += sizeof(uint16_t);
950 for (const auto &P : FI.Params)
951 size += getParamInfoSize(P);
952 size += sizeof(uint16_t) + FI.ResultType.size();
953 return size;
956 /// Emit a serialized representation of the function information.
957 void emitFunctionInfo(raw_ostream &OS, const FunctionInfo &FI) {
958 emitCommonEntityInfo(OS, FI);
960 uint8_t flags = 0;
961 flags |= FI.NullabilityAudited;
962 flags <<= 3;
963 if (auto RCC = FI.getRetainCountConvention())
964 flags |= static_cast<uint8_t>(RCC.value()) + 1;
966 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
968 writer.write<uint8_t>(flags);
969 writer.write<uint8_t>(FI.NumAdjustedNullable);
970 writer.write<uint64_t>(FI.NullabilityPayload);
972 writer.write<uint16_t>(FI.Params.size());
973 for (const auto &PI : FI.Params)
974 emitParamInfo(OS, PI);
976 writer.write<uint16_t>(FI.ResultType.size());
977 writer.write(ArrayRef<char>{FI.ResultType.data(), FI.ResultType.size()});
980 /// Used to serialize the on-disk global function table.
981 class GlobalFunctionTableInfo
982 : public VersionedTableInfo<GlobalFunctionTableInfo, ContextTableKey,
983 GlobalFunctionInfo> {
984 public:
985 unsigned getKeyLength(key_type_ref) {
986 return sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint32_t);
989 void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
990 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
991 writer.write<uint32_t>(Key.parentContextID);
992 writer.write<uint8_t>(Key.contextKind);
993 writer.write<uint32_t>(Key.contextID);
996 hash_value_type ComputeHash(key_type_ref Key) {
997 return static_cast<size_t>(Key.hashValue());
1000 unsigned getUnversionedInfoSize(const GlobalFunctionInfo &GFI) {
1001 return getFunctionInfoSize(GFI);
1004 void emitUnversionedInfo(raw_ostream &OS, const GlobalFunctionInfo &GFI) {
1005 emitFunctionInfo(OS, GFI);
1008 } // namespace
1010 void APINotesWriter::Implementation::writeGlobalFunctionBlock(
1011 llvm::BitstreamWriter &Stream) {
1012 llvm::BCBlockRAII Scope(Stream, GLOBAL_FUNCTION_BLOCK_ID, 3);
1014 if (GlobalFunctions.empty())
1015 return;
1018 llvm::SmallString<4096> HashTableBlob;
1019 uint32_t Offset;
1021 llvm::OnDiskChainedHashTableGenerator<GlobalFunctionTableInfo> Generator;
1022 for (auto &F : GlobalFunctions)
1023 Generator.insert(F.first, F.second);
1025 llvm::raw_svector_ostream BlobStream(HashTableBlob);
1026 // Make sure that no bucket is at offset 0
1027 llvm::support::endian::write<uint32_t>(BlobStream, 0,
1028 llvm::endianness::little);
1029 Offset = Generator.Emit(BlobStream);
1032 global_function_block::GlobalFunctionDataLayout GlobalFunctionData(Stream);
1033 GlobalFunctionData.emit(Scratch, Offset, HashTableBlob);
1037 namespace {
1038 /// Used to serialize the on-disk global enum constant.
1039 class EnumConstantTableInfo
1040 : public VersionedTableInfo<EnumConstantTableInfo, unsigned,
1041 EnumConstantInfo> {
1042 public:
1043 unsigned getKeyLength(key_type_ref) { return sizeof(uint32_t); }
1045 void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
1046 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
1047 writer.write<uint32_t>(Key);
1050 hash_value_type ComputeHash(key_type_ref Key) {
1051 return static_cast<size_t>(llvm::hash_value(Key));
1054 unsigned getUnversionedInfoSize(const EnumConstantInfo &ECI) {
1055 return getCommonEntityInfoSize(ECI);
1058 void emitUnversionedInfo(raw_ostream &OS, const EnumConstantInfo &ECI) {
1059 emitCommonEntityInfo(OS, ECI);
1062 } // namespace
1064 void APINotesWriter::Implementation::writeEnumConstantBlock(
1065 llvm::BitstreamWriter &Stream) {
1066 llvm::BCBlockRAII Scope(Stream, ENUM_CONSTANT_BLOCK_ID, 3);
1068 if (EnumConstants.empty())
1069 return;
1072 llvm::SmallString<4096> HashTableBlob;
1073 uint32_t Offset;
1075 llvm::OnDiskChainedHashTableGenerator<EnumConstantTableInfo> Generator;
1076 for (auto &EC : EnumConstants)
1077 Generator.insert(EC.first, EC.second);
1079 llvm::raw_svector_ostream BlobStream(HashTableBlob);
1080 // Make sure that no bucket is at offset 0
1081 llvm::support::endian::write<uint32_t>(BlobStream, 0,
1082 llvm::endianness::little);
1083 Offset = Generator.Emit(BlobStream);
1086 enum_constant_block::EnumConstantDataLayout EnumConstantData(Stream);
1087 EnumConstantData.emit(Scratch, Offset, HashTableBlob);
1091 namespace {
1092 template <typename Derived, typename UnversionedDataType>
1093 class CommonTypeTableInfo
1094 : public VersionedTableInfo<Derived, ContextTableKey, UnversionedDataType> {
1095 public:
1096 using key_type_ref = typename CommonTypeTableInfo::key_type_ref;
1097 using hash_value_type = typename CommonTypeTableInfo::hash_value_type;
1099 unsigned getKeyLength(key_type_ref) {
1100 return sizeof(uint32_t) + sizeof(uint8_t) + sizeof(IdentifierID);
1103 void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
1104 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
1105 writer.write<uint32_t>(Key.parentContextID);
1106 writer.write<uint8_t>(Key.contextKind);
1107 writer.write<IdentifierID>(Key.contextID);
1110 hash_value_type ComputeHash(key_type_ref Key) {
1111 return static_cast<size_t>(Key.hashValue());
1114 unsigned getUnversionedInfoSize(const UnversionedDataType &UDT) {
1115 return getCommonTypeInfoSize(UDT);
1118 void emitUnversionedInfo(raw_ostream &OS, const UnversionedDataType &UDT) {
1119 emitCommonTypeInfo(OS, UDT);
1123 /// Used to serialize the on-disk tag table.
1124 class TagTableInfo : public CommonTypeTableInfo<TagTableInfo, TagInfo> {
1125 public:
1126 unsigned getUnversionedInfoSize(const TagInfo &TI) {
1127 return 2 + (TI.SwiftImportAs ? TI.SwiftImportAs->size() : 0) +
1128 2 + (TI.SwiftRetainOp ? TI.SwiftRetainOp->size() : 0) +
1129 2 + (TI.SwiftReleaseOp ? TI.SwiftReleaseOp->size() : 0) +
1130 1 + getCommonTypeInfoSize(TI);
1133 void emitUnversionedInfo(raw_ostream &OS, const TagInfo &TI) {
1134 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
1136 uint8_t Flags = 0;
1137 if (auto extensibility = TI.EnumExtensibility) {
1138 Flags |= static_cast<uint8_t>(extensibility.value()) + 1;
1139 assert((Flags < (1 << 2)) && "must fit in two bits");
1142 Flags <<= 2;
1143 if (auto value = TI.isFlagEnum())
1144 Flags |= (value.value() << 1 | 1 << 0);
1146 writer.write<uint8_t>(Flags);
1148 if (auto ImportAs = TI.SwiftImportAs) {
1149 writer.write<uint16_t>(ImportAs->size() + 1);
1150 OS.write(ImportAs->c_str(), ImportAs->size());
1151 } else {
1152 writer.write<uint16_t>(0);
1154 if (auto RetainOp = TI.SwiftRetainOp) {
1155 writer.write<uint16_t>(RetainOp->size() + 1);
1156 OS.write(RetainOp->c_str(), RetainOp->size());
1157 } else {
1158 writer.write<uint16_t>(0);
1160 if (auto ReleaseOp = TI.SwiftReleaseOp) {
1161 writer.write<uint16_t>(ReleaseOp->size() + 1);
1162 OS.write(ReleaseOp->c_str(), ReleaseOp->size());
1163 } else {
1164 writer.write<uint16_t>(0);
1167 emitCommonTypeInfo(OS, TI);
1170 } // namespace
1172 void APINotesWriter::Implementation::writeTagBlock(
1173 llvm::BitstreamWriter &Stream) {
1174 llvm::BCBlockRAII Scope(Stream, TAG_BLOCK_ID, 3);
1176 if (Tags.empty())
1177 return;
1180 llvm::SmallString<4096> HashTableBlob;
1181 uint32_t Offset;
1183 llvm::OnDiskChainedHashTableGenerator<TagTableInfo> Generator;
1184 for (auto &T : Tags)
1185 Generator.insert(T.first, T.second);
1187 llvm::raw_svector_ostream BlobStream(HashTableBlob);
1188 // Make sure that no bucket is at offset 0
1189 llvm::support::endian::write<uint32_t>(BlobStream, 0,
1190 llvm::endianness::little);
1191 Offset = Generator.Emit(BlobStream);
1194 tag_block::TagDataLayout TagData(Stream);
1195 TagData.emit(Scratch, Offset, HashTableBlob);
1199 namespace {
1200 /// Used to serialize the on-disk typedef table.
1201 class TypedefTableInfo
1202 : public CommonTypeTableInfo<TypedefTableInfo, TypedefInfo> {
1203 public:
1204 unsigned getUnversionedInfoSize(const TypedefInfo &TI) {
1205 return 1 + getCommonTypeInfoSize(TI);
1208 void emitUnversionedInfo(raw_ostream &OS, const TypedefInfo &TI) {
1209 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
1211 uint8_t Flags = 0;
1212 if (auto swiftWrapper = TI.SwiftWrapper)
1213 Flags |= static_cast<uint8_t>(*swiftWrapper) + 1;
1215 writer.write<uint8_t>(Flags);
1217 emitCommonTypeInfo(OS, TI);
1220 } // namespace
1222 void APINotesWriter::Implementation::writeTypedefBlock(
1223 llvm::BitstreamWriter &Stream) {
1224 llvm::BCBlockRAII Scope(Stream, TYPEDEF_BLOCK_ID, 3);
1226 if (Typedefs.empty())
1227 return;
1230 llvm::SmallString<4096> HashTableBlob;
1231 uint32_t Offset;
1233 llvm::OnDiskChainedHashTableGenerator<TypedefTableInfo> Generator;
1234 for (auto &T : Typedefs)
1235 Generator.insert(T.first, T.second);
1237 llvm::raw_svector_ostream BlobStream(HashTableBlob);
1238 // Make sure that no bucket is at offset 0
1239 llvm::support::endian::write<uint32_t>(BlobStream, 0,
1240 llvm::endianness::little);
1241 Offset = Generator.Emit(BlobStream);
1244 typedef_block::TypedefDataLayout TypedefData(Stream);
1245 TypedefData.emit(Scratch, Offset, HashTableBlob);
1249 // APINotesWriter
1251 APINotesWriter::APINotesWriter(llvm::StringRef ModuleName, const FileEntry *SF)
1252 : Implementation(new class Implementation(ModuleName, SF)) {}
1254 APINotesWriter::~APINotesWriter() = default;
1256 void APINotesWriter::writeToStream(llvm::raw_ostream &OS) {
1257 Implementation->writeToStream(OS);
1260 ContextID APINotesWriter::addObjCContext(std::optional<ContextID> ParentCtxID,
1261 StringRef Name, ContextKind Kind,
1262 const ObjCContextInfo &Info,
1263 VersionTuple SwiftVersion) {
1264 IdentifierID NameID = Implementation->getIdentifier(Name);
1266 uint32_t RawParentCtxID = ParentCtxID ? ParentCtxID->Value : -1;
1267 ContextTableKey Key(RawParentCtxID, static_cast<uint8_t>(Kind), NameID);
1268 auto Known = Implementation->ObjCContexts.find(Key);
1269 if (Known == Implementation->ObjCContexts.end()) {
1270 unsigned NextID = Implementation->ObjCContexts.size() + 1;
1272 Implementation::VersionedSmallVector<ObjCContextInfo> EmptyVersionedInfo;
1273 Known = Implementation->ObjCContexts
1274 .insert(std::make_pair(
1275 Key, std::make_pair(NextID, EmptyVersionedInfo)))
1276 .first;
1278 Implementation->ObjCContextNames[NextID] = NameID;
1279 Implementation->ParentContexts[NextID] = RawParentCtxID;
1282 // Add this version information.
1283 auto &VersionedVec = Known->second.second;
1284 bool Found = false;
1285 for (auto &Versioned : VersionedVec) {
1286 if (Versioned.first == SwiftVersion) {
1287 Versioned.second |= Info;
1288 Found = true;
1289 break;
1293 if (!Found)
1294 VersionedVec.push_back({SwiftVersion, Info});
1296 return ContextID(Known->second.first);
1299 void APINotesWriter::addObjCProperty(ContextID CtxID, StringRef Name,
1300 bool IsInstanceProperty,
1301 const ObjCPropertyInfo &Info,
1302 VersionTuple SwiftVersion) {
1303 IdentifierID NameID = Implementation->getIdentifier(Name);
1304 Implementation
1305 ->ObjCProperties[std::make_tuple(CtxID.Value, NameID, IsInstanceProperty)]
1306 .push_back({SwiftVersion, Info});
1309 void APINotesWriter::addObjCMethod(ContextID CtxID, ObjCSelectorRef Selector,
1310 bool IsInstanceMethod,
1311 const ObjCMethodInfo &Info,
1312 VersionTuple SwiftVersion) {
1313 SelectorID SelID = Implementation->getSelector(Selector);
1314 auto Key = std::tuple<unsigned, unsigned, char>{CtxID.Value, SelID,
1315 IsInstanceMethod};
1316 Implementation->ObjCMethods[Key].push_back({SwiftVersion, Info});
1318 // If this method is a designated initializer, update the class to note that
1319 // it has designated initializers.
1320 if (Info.DesignatedInit) {
1321 assert(Implementation->ParentContexts.contains(CtxID.Value));
1322 uint32_t ParentCtxID = Implementation->ParentContexts[CtxID.Value];
1323 ContextTableKey CtxKey(ParentCtxID,
1324 static_cast<uint8_t>(ContextKind::ObjCClass),
1325 Implementation->ObjCContextNames[CtxID.Value]);
1326 assert(Implementation->ObjCContexts.contains(CtxKey));
1327 auto &VersionedVec = Implementation->ObjCContexts[CtxKey].second;
1328 bool Found = false;
1329 for (auto &Versioned : VersionedVec) {
1330 if (Versioned.first == SwiftVersion) {
1331 Versioned.second.setHasDesignatedInits(true);
1332 Found = true;
1333 break;
1337 if (!Found) {
1338 VersionedVec.push_back({SwiftVersion, ObjCContextInfo()});
1339 VersionedVec.back().second.setHasDesignatedInits(true);
1344 void APINotesWriter::addGlobalVariable(std::optional<Context> Ctx,
1345 llvm::StringRef Name,
1346 const GlobalVariableInfo &Info,
1347 VersionTuple SwiftVersion) {
1348 IdentifierID VariableID = Implementation->getIdentifier(Name);
1349 ContextTableKey Key(Ctx, VariableID);
1350 Implementation->GlobalVariables[Key].push_back({SwiftVersion, Info});
1353 void APINotesWriter::addGlobalFunction(std::optional<Context> Ctx,
1354 llvm::StringRef Name,
1355 const GlobalFunctionInfo &Info,
1356 VersionTuple SwiftVersion) {
1357 IdentifierID NameID = Implementation->getIdentifier(Name);
1358 ContextTableKey Key(Ctx, NameID);
1359 Implementation->GlobalFunctions[Key].push_back({SwiftVersion, Info});
1362 void APINotesWriter::addEnumConstant(llvm::StringRef Name,
1363 const EnumConstantInfo &Info,
1364 VersionTuple SwiftVersion) {
1365 IdentifierID EnumConstantID = Implementation->getIdentifier(Name);
1366 Implementation->EnumConstants[EnumConstantID].push_back({SwiftVersion, Info});
1369 void APINotesWriter::addTag(std::optional<Context> Ctx, llvm::StringRef Name,
1370 const TagInfo &Info, VersionTuple SwiftVersion) {
1371 IdentifierID TagID = Implementation->getIdentifier(Name);
1372 ContextTableKey Key(Ctx, TagID);
1373 Implementation->Tags[Key].push_back({SwiftVersion, Info});
1376 void APINotesWriter::addTypedef(std::optional<Context> Ctx,
1377 llvm::StringRef Name, const TypedefInfo &Info,
1378 VersionTuple SwiftVersion) {
1379 IdentifierID TypedefID = Implementation->getIdentifier(Name);
1380 ContextTableKey Key(Ctx, TypedefID);
1381 Implementation->Typedefs[Key].push_back({SwiftVersion, Info});
1383 } // namespace api_notes
1384 } // namespace clang