clang 19.0.0git
APINotesWriter.cpp
Go to the documentation of this file.
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
10#include "APINotesFormat.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
20namespace clang {
21namespace api_notes {
23 friend class APINotesWriter;
24
25 template <typename T>
28
29 std::string ModuleName;
30 const FileEntry *SourceFile;
31
32 /// Scratch space for bitstream writing.
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>,
63 ObjCProperties;
64
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>,
71 ObjCMethods;
72
73 /// Mapping from selectors to selector ID.
74 llvm::DenseMap<StoredObjCSelector, SelectorID> SelectorIDs;
75
76 /// Information about global variables.
77 ///
78 /// Indexed by the context ID, contextKind, identifier ID.
79 llvm::DenseMap<
82 GlobalVariables;
83
84 /// Information about global functions.
85 ///
86 /// Indexed by the context ID, contextKind, identifier ID.
87 llvm::DenseMap<
90 GlobalFunctions;
91
92 /// Information about enumerators.
93 ///
94 /// Indexed by the identifier ID.
95 llvm::DenseMap<
97 EnumConstants;
98
99 /// Information about tags.
100 ///
101 /// Indexed by the context ID, contextKind, identifier ID.
102 llvm::DenseMap<ContextTableKey,
104 Tags;
105
106 /// Information about typedefs.
107 ///
108 /// Indexed by the context ID, contextKind, identifier ID.
109 llvm::DenseMap<ContextTableKey,
111 Typedefs;
112
113 /// Retrieve the ID for the given identifier.
115 if (Identifier.empty())
116 return 0;
117
118 auto Known = IdentifierIDs.find(Identifier);
119 if (Known != IdentifierIDs.end())
120 return Known->second;
121
122 // Add to the identifier table.
123 Known = IdentifierIDs.insert({Identifier, IdentifierIDs.size() + 1}).first;
124 return Known->second;
125 }
126
127 /// Retrieve the ID for the given selector.
128 SelectorID getSelector(ObjCSelectorRef SelectorRef) {
129 // Translate the selector reference into a stored selector.
131 Selector.NumArgs = SelectorRef.NumArgs;
132 Selector.Identifiers.reserve(SelectorRef.Identifiers.size());
133 for (auto piece : SelectorRef.Identifiers)
134 Selector.Identifiers.push_back(getIdentifier(piece));
135
136 // Look for the stored selector.
137 auto Known = SelectorIDs.find(Selector);
138 if (Known != SelectorIDs.end())
139 return Known->second;
140
141 // Add to the selector table.
142 Known = SelectorIDs.insert({Selector, SelectorIDs.size()}).first;
143 return Known->second;
144 }
145
146private:
147 void writeBlockInfoBlock(llvm::BitstreamWriter &Stream);
148 void writeControlBlock(llvm::BitstreamWriter &Stream);
149 void writeIdentifierBlock(llvm::BitstreamWriter &Stream);
150 void writeContextBlock(llvm::BitstreamWriter &Stream);
151 void writeObjCPropertyBlock(llvm::BitstreamWriter &Stream);
152 void writeObjCMethodBlock(llvm::BitstreamWriter &Stream);
153 void writeObjCSelectorBlock(llvm::BitstreamWriter &Stream);
154 void writeGlobalVariableBlock(llvm::BitstreamWriter &Stream);
155 void writeGlobalFunctionBlock(llvm::BitstreamWriter &Stream);
156 void writeEnumConstantBlock(llvm::BitstreamWriter &Stream);
157 void writeTagBlock(llvm::BitstreamWriter &Stream);
158 void writeTypedefBlock(llvm::BitstreamWriter &Stream);
159
160public:
161 Implementation(llvm::StringRef ModuleName, const FileEntry *SF)
162 : ModuleName(std::string(ModuleName)), SourceFile(SF) {}
163
164 void writeToStream(llvm::raw_ostream &OS);
165};
166
169
170 {
171 llvm::BitstreamWriter Stream(Buffer);
172
173 // Emit the signature.
174 for (unsigned char Byte : API_NOTES_SIGNATURE)
175 Stream.Emit(Byte, 8);
176
177 // Emit the blocks.
178 writeBlockInfoBlock(Stream);
179 writeControlBlock(Stream);
180 writeIdentifierBlock(Stream);
181 writeContextBlock(Stream);
182 writeObjCPropertyBlock(Stream);
183 writeObjCMethodBlock(Stream);
184 writeObjCSelectorBlock(Stream);
185 writeGlobalVariableBlock(Stream);
186 writeGlobalFunctionBlock(Stream);
187 writeEnumConstantBlock(Stream);
188 writeTagBlock(Stream);
189 writeTypedefBlock(Stream);
190 }
191
192 OS.write(Buffer.data(), Buffer.size());
193 OS.flush();
194}
195
196namespace {
197/// Record the name of a block.
198void emitBlockID(llvm::BitstreamWriter &Stream, unsigned ID,
199 llvm::StringRef Name) {
200 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID,
202
203 // Emit the block name if present.
204 if (Name.empty())
205 return;
206 Stream.EmitRecord(
207 llvm::bitc::BLOCKINFO_CODE_BLOCKNAME,
209 const_cast<unsigned char *>(
210 reinterpret_cast<const unsigned char *>(Name.data())),
211 Name.size()));
212}
213
214/// Record the name of a record within a block.
215void emitRecordID(llvm::BitstreamWriter &Stream, unsigned ID,
216 llvm::StringRef Name) {
217 assert(ID < 256 && "can't fit record ID in next to name");
218
220 Buffer.resize(Name.size() + 1);
221 Buffer[0] = ID;
222 memcpy(Buffer.data() + 1, Name.data(), Name.size());
223
224 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Buffer);
225}
226} // namespace
227
228void APINotesWriter::Implementation::writeBlockInfoBlock(
229 llvm::BitstreamWriter &Stream) {
230 llvm::BCBlockRAII Scope(Stream, llvm::bitc::BLOCKINFO_BLOCK_ID, 2);
231
232#define BLOCK(Block) emitBlockID(Stream, Block##_ID, #Block)
233#define BLOCK_RECORD(NameSpace, Block) \
234 emitRecordID(Stream, NameSpace::Block, #Block)
235 BLOCK(CONTROL_BLOCK);
236 BLOCK_RECORD(control_block, METADATA);
237 BLOCK_RECORD(control_block, MODULE_NAME);
238
239 BLOCK(IDENTIFIER_BLOCK);
240 BLOCK_RECORD(identifier_block, IDENTIFIER_DATA);
241
242 BLOCK(OBJC_CONTEXT_BLOCK);
243 BLOCK_RECORD(context_block, CONTEXT_ID_DATA);
244
245 BLOCK(OBJC_PROPERTY_BLOCK);
246 BLOCK_RECORD(objc_property_block, OBJC_PROPERTY_DATA);
247
248 BLOCK(OBJC_METHOD_BLOCK);
249 BLOCK_RECORD(objc_method_block, OBJC_METHOD_DATA);
250
251 BLOCK(OBJC_SELECTOR_BLOCK);
252 BLOCK_RECORD(objc_selector_block, OBJC_SELECTOR_DATA);
253
254 BLOCK(GLOBAL_VARIABLE_BLOCK);
255 BLOCK_RECORD(global_variable_block, GLOBAL_VARIABLE_DATA);
256
257 BLOCK(GLOBAL_FUNCTION_BLOCK);
258 BLOCK_RECORD(global_function_block, GLOBAL_FUNCTION_DATA);
259#undef BLOCK_RECORD
260#undef BLOCK
261}
262
263void APINotesWriter::Implementation::writeControlBlock(
264 llvm::BitstreamWriter &Stream) {
265 llvm::BCBlockRAII Scope(Stream, CONTROL_BLOCK_ID, 3);
266
267 control_block::MetadataLayout Metadata(Stream);
268 Metadata.emit(Scratch, VERSION_MAJOR, VERSION_MINOR);
269
270 control_block::ModuleNameLayout ModuleName(Stream);
271 ModuleName.emit(Scratch, this->ModuleName);
272
273 if (SourceFile) {
274 control_block::SourceFileLayout SourceFile(Stream);
275 SourceFile.emit(Scratch, this->SourceFile->getSize(),
276 this->SourceFile->getModificationTime());
277 }
278}
279
280namespace {
281/// Used to serialize the on-disk identifier table.
282class IdentifierTableInfo {
283public:
284 using key_type = StringRef;
285 using key_type_ref = key_type;
286 using data_type = IdentifierID;
287 using data_type_ref = const data_type &;
288 using hash_value_type = uint32_t;
289 using offset_type = unsigned;
290
291 hash_value_type ComputeHash(key_type_ref Key) { return llvm::djbHash(Key); }
292
293 std::pair<unsigned, unsigned>
294 EmitKeyDataLength(raw_ostream &OS, key_type_ref Key, data_type_ref) {
295 uint32_t KeyLength = Key.size();
296 uint32_t DataLength = sizeof(uint32_t);
297
298 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
299 writer.write<uint16_t>(KeyLength);
300 writer.write<uint16_t>(DataLength);
301 return {KeyLength, DataLength};
302 }
303
304 void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) { OS << Key; }
305
306 void EmitData(raw_ostream &OS, key_type_ref, data_type_ref Data, unsigned) {
307 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
308 writer.write<uint32_t>(Data);
309 }
310};
311} // namespace
312
313void APINotesWriter::Implementation::writeIdentifierBlock(
314 llvm::BitstreamWriter &Stream) {
315 llvm::BCBlockRAII restoreBlock(Stream, IDENTIFIER_BLOCK_ID, 3);
316
317 if (IdentifierIDs.empty())
318 return;
319
320 llvm::SmallString<4096> HashTableBlob;
321 uint32_t Offset;
322 {
323 llvm::OnDiskChainedHashTableGenerator<IdentifierTableInfo> Generator;
324 for (auto &II : IdentifierIDs)
325 Generator.insert(II.first(), II.second);
326
327 llvm::raw_svector_ostream BlobStream(HashTableBlob);
328 // Make sure that no bucket is at offset 0
329 llvm::support::endian::write<uint32_t>(BlobStream, 0,
330 llvm::endianness::little);
331 Offset = Generator.Emit(BlobStream);
332 }
333
334 identifier_block::IdentifierDataLayout IdentifierData(Stream);
335 IdentifierData.emit(Scratch, Offset, HashTableBlob);
336}
337
338namespace {
339/// Used to serialize the on-disk Objective-C context table.
340class ContextIDTableInfo {
341public:
342 using key_type = ContextTableKey;
343 using key_type_ref = key_type;
344 using data_type = unsigned;
345 using data_type_ref = const data_type &;
346 using hash_value_type = size_t;
347 using offset_type = unsigned;
348
349 hash_value_type ComputeHash(key_type_ref Key) {
350 return static_cast<size_t>(Key.hashValue());
351 }
352
353 std::pair<unsigned, unsigned> EmitKeyDataLength(raw_ostream &OS, key_type_ref,
354 data_type_ref) {
355 uint32_t KeyLength = sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint32_t);
356 uint32_t DataLength = sizeof(uint32_t);
357
358 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
359 writer.write<uint16_t>(KeyLength);
360 writer.write<uint16_t>(DataLength);
361 return {KeyLength, DataLength};
362 }
363
364 void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
365 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
366 writer.write<uint32_t>(Key.parentContextID);
367 writer.write<uint8_t>(Key.contextKind);
368 writer.write<uint32_t>(Key.contextID);
369 }
370
371 void EmitData(raw_ostream &OS, key_type_ref, data_type_ref Data, unsigned) {
372 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
373 writer.write<uint32_t>(Data);
374 }
375};
376
377/// Localized helper to make a type dependent, thwarting template argument
378/// deduction.
379template <typename T> struct MakeDependent { typedef T Type; };
380
381/// Retrieve the serialized size of the given VersionTuple, for use in
382/// on-disk hash tables.
383unsigned getVersionTupleSize(const VersionTuple &VT) {
384 unsigned size = sizeof(uint8_t) + /*major*/ sizeof(uint32_t);
385 if (VT.getMinor())
386 size += sizeof(uint32_t);
387 if (VT.getSubminor())
388 size += sizeof(uint32_t);
389 if (VT.getBuild())
390 size += sizeof(uint32_t);
391 return size;
392}
393
394/// Determine the size of an array of versioned information,
395template <typename T>
396unsigned getVersionedInfoSize(
397 const llvm::SmallVectorImpl<std::pair<llvm::VersionTuple, T>> &VI,
398 llvm::function_ref<unsigned(const typename MakeDependent<T>::Type &)>
399 getInfoSize) {
400 unsigned result = sizeof(uint16_t); // # of elements
401 for (const auto &E : VI) {
402 result += getVersionTupleSize(E.first);
403 result += getInfoSize(E.second);
404 }
405 return result;
406}
407
408/// Emit a serialized representation of a version tuple.
409void emitVersionTuple(raw_ostream &OS, const VersionTuple &VT) {
410 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
411
412 // First byte contains the number of components beyond the 'major' component.
413 uint8_t descriptor;
414 if (VT.getBuild())
415 descriptor = 3;
416 else if (VT.getSubminor())
417 descriptor = 2;
418 else if (VT.getMinor())
419 descriptor = 1;
420 else
421 descriptor = 0;
422 writer.write<uint8_t>(descriptor);
423
424 // Write the components.
425 writer.write<uint32_t>(VT.getMajor());
426 if (auto minor = VT.getMinor())
427 writer.write<uint32_t>(*minor);
428 if (auto subminor = VT.getSubminor())
429 writer.write<uint32_t>(*subminor);
430 if (auto build = VT.getBuild())
431 writer.write<uint32_t>(*build);
432}
433
434/// Emit versioned information.
435template <typename T>
436void emitVersionedInfo(
437 raw_ostream &OS, llvm::SmallVectorImpl<std::pair<VersionTuple, T>> &VI,
438 llvm::function_ref<void(raw_ostream &,
439 const typename MakeDependent<T>::Type &)>
440 emitInfo) {
441 std::sort(VI.begin(), VI.end(),
442 [](const std::pair<VersionTuple, T> &LHS,
443 const std::pair<VersionTuple, T> &RHS) -> bool {
444 assert((&LHS == &RHS || LHS.first != RHS.first) &&
445 "two entries for the same version");
446 return LHS.first < RHS.first;
447 });
448
449 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
450 writer.write<uint16_t>(VI.size());
451 for (const auto &E : VI) {
452 emitVersionTuple(OS, E.first);
453 emitInfo(OS, E.second);
454 }
455}
456
457/// On-disk hash table info key base for handling versioned data.
458template <typename Derived, typename KeyType, typename UnversionedDataType>
459class VersionedTableInfo {
460 Derived &asDerived() { return *static_cast<Derived *>(this); }
461
462 const Derived &asDerived() const {
463 return *static_cast<const Derived *>(this);
464 }
465
466public:
467 using key_type = KeyType;
468 using key_type_ref = key_type;
469 using data_type =
471 using data_type_ref = data_type &;
472 using hash_value_type = size_t;
473 using offset_type = unsigned;
474
475 std::pair<unsigned, unsigned>
476 EmitKeyDataLength(raw_ostream &OS, key_type_ref Key, data_type_ref Data) {
477 uint32_t KeyLength = asDerived().getKeyLength(Key);
478 uint32_t DataLength =
479 getVersionedInfoSize(Data, [this](const UnversionedDataType &UI) {
480 return asDerived().getUnversionedInfoSize(UI);
481 });
482
483 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
484 writer.write<uint16_t>(KeyLength);
485 writer.write<uint16_t>(DataLength);
486 return {KeyLength, DataLength};
487 }
488
489 void EmitData(raw_ostream &OS, key_type_ref, data_type_ref Data, unsigned) {
490 emitVersionedInfo(
491 OS, Data, [this](llvm::raw_ostream &OS, const UnversionedDataType &UI) {
492 asDerived().emitUnversionedInfo(OS, UI);
493 });
494 }
495};
496
497/// Emit a serialized representation of the common entity information.
498void emitCommonEntityInfo(raw_ostream &OS, const CommonEntityInfo &CEI) {
499 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
500
501 uint8_t payload = 0;
502 if (auto swiftPrivate = CEI.isSwiftPrivate()) {
503 payload |= 0x01;
504 if (*swiftPrivate)
505 payload |= 0x02;
506 }
507 payload <<= 1;
508 payload |= CEI.Unavailable;
509 payload <<= 1;
510 payload |= CEI.UnavailableInSwift;
511
512 writer.write<uint8_t>(payload);
513
514 writer.write<uint16_t>(CEI.UnavailableMsg.size());
515 OS.write(CEI.UnavailableMsg.c_str(), CEI.UnavailableMsg.size());
516
517 writer.write<uint16_t>(CEI.SwiftName.size());
518 OS.write(CEI.SwiftName.c_str(), CEI.SwiftName.size());
519}
520
521/// Retrieve the serialized size of the given CommonEntityInfo, for use in
522/// on-disk hash tables.
523unsigned getCommonEntityInfoSize(const CommonEntityInfo &CEI) {
524 return 5 + CEI.UnavailableMsg.size() + CEI.SwiftName.size();
525}
526
527// Retrieve the serialized size of the given CommonTypeInfo, for use
528// in on-disk hash tables.
529unsigned getCommonTypeInfoSize(const CommonTypeInfo &CTI) {
530 return 2 + (CTI.getSwiftBridge() ? CTI.getSwiftBridge()->size() : 0) + 2 +
531 (CTI.getNSErrorDomain() ? CTI.getNSErrorDomain()->size() : 0) +
532 getCommonEntityInfoSize(CTI);
533}
534
535/// Emit a serialized representation of the common type information.
536void emitCommonTypeInfo(raw_ostream &OS, const CommonTypeInfo &CTI) {
537 emitCommonEntityInfo(OS, CTI);
538
539 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
540 if (auto swiftBridge = CTI.getSwiftBridge()) {
541 writer.write<uint16_t>(swiftBridge->size() + 1);
542 OS.write(swiftBridge->c_str(), swiftBridge->size());
543 } else {
544 writer.write<uint16_t>(0);
545 }
546 if (auto nsErrorDomain = CTI.getNSErrorDomain()) {
547 writer.write<uint16_t>(nsErrorDomain->size() + 1);
548 OS.write(nsErrorDomain->c_str(), CTI.getNSErrorDomain()->size());
549 } else {
550 writer.write<uint16_t>(0);
551 }
552}
553
554/// Used to serialize the on-disk Objective-C property table.
555class ContextInfoTableInfo
556 : public VersionedTableInfo<ContextInfoTableInfo, unsigned, ContextInfo> {
557public:
558 unsigned getKeyLength(key_type_ref) { return sizeof(uint32_t); }
559
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);
563 }
564
565 hash_value_type ComputeHash(key_type_ref Key) {
566 return static_cast<size_t>(llvm::hash_value(Key));
567 }
568
569 unsigned getUnversionedInfoSize(const ContextInfo &OCI) {
570 return getCommonTypeInfoSize(OCI) + 1;
571 }
572
573 void emitUnversionedInfo(raw_ostream &OS, const ContextInfo &OCI) {
574 emitCommonTypeInfo(OS, OCI);
575
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);
586
587 OS << payload;
588 }
589};
590} // namespace
591
592void APINotesWriter::Implementation::writeContextBlock(
593 llvm::BitstreamWriter &Stream) {
594 llvm::BCBlockRAII restoreBlock(Stream, OBJC_CONTEXT_BLOCK_ID, 3);
595
596 if (Contexts.empty())
597 return;
598
599 {
600 llvm::SmallString<4096> HashTableBlob;
601 uint32_t Offset;
602 {
603 llvm::OnDiskChainedHashTableGenerator<ContextIDTableInfo> Generator;
604 for (auto &OC : Contexts)
605 Generator.insert(OC.first, OC.second.first);
606
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);
612 }
613
614 context_block::ContextIDLayout ContextID(Stream);
615 ContextID.emit(Scratch, Offset, HashTableBlob);
616 }
617
618 {
619 llvm::SmallString<4096> HashTableBlob;
620 uint32_t Offset;
621 {
622 llvm::OnDiskChainedHashTableGenerator<ContextInfoTableInfo> Generator;
623 for (auto &OC : Contexts)
624 Generator.insert(OC.second.first, OC.second.second);
625
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);
631 }
632
633 context_block::ContextInfoLayout ContextInfo(Stream);
634 ContextInfo.emit(Scratch, Offset, HashTableBlob);
635 }
636}
637
638namespace {
639/// Retrieve the serialized size of the given VariableInfo, for use in
640/// on-disk hash tables.
641unsigned getVariableInfoSize(const VariableInfo &VI) {
642 return 2 + getCommonEntityInfoSize(VI) + 2 + VI.getType().size();
643}
644
645/// Emit a serialized representation of the variable information.
646void emitVariableInfo(raw_ostream &OS, const VariableInfo &VI) {
647 emitCommonEntityInfo(OS, VI);
648
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.
655 }
656
657 OS.write(reinterpret_cast<const char *>(bytes), 2);
658
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());
662}
663
664/// Used to serialize the on-disk Objective-C property table.
665class ObjCPropertyTableInfo
666 : public VersionedTableInfo<ObjCPropertyTableInfo,
667 std::tuple<unsigned, unsigned, char>,
668 ObjCPropertyInfo> {
669public:
670 unsigned getKeyLength(key_type_ref) {
671 return sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint8_t);
672 }
673
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));
679 }
680
681 hash_value_type ComputeHash(key_type_ref Key) {
682 return static_cast<size_t>(llvm::hash_value(Key));
683 }
684
685 unsigned getUnversionedInfoSize(const ObjCPropertyInfo &OPI) {
686 return getVariableInfoSize(OPI) + 1;
687 }
688
689 void emitUnversionedInfo(raw_ostream &OS, const ObjCPropertyInfo &OPI) {
690 emitVariableInfo(OS, OPI);
691
692 uint8_t flags = 0;
693 if (auto value = OPI.getSwiftImportAsAccessors()) {
694 flags |= 1 << 0;
695 flags |= value.value() << 1;
696 }
697 OS << flags;
698 }
699};
700} // namespace
701
702void APINotesWriter::Implementation::writeObjCPropertyBlock(
703 llvm::BitstreamWriter &Stream) {
704 llvm::BCBlockRAII Scope(Stream, OBJC_PROPERTY_BLOCK_ID, 3);
705
706 if (ObjCProperties.empty())
707 return;
708
709 {
710 llvm::SmallString<4096> HashTableBlob;
711 uint32_t Offset;
712 {
713 llvm::OnDiskChainedHashTableGenerator<ObjCPropertyTableInfo> Generator;
714 for (auto &OP : ObjCProperties)
715 Generator.insert(OP.first, OP.second);
716
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);
722 }
723
724 objc_property_block::ObjCPropertyDataLayout ObjCPropertyData(Stream);
725 ObjCPropertyData.emit(Scratch, Offset, HashTableBlob);
726 }
727}
728
729namespace {
730unsigned getFunctionInfoSize(const FunctionInfo &);
731void emitFunctionInfo(llvm::raw_ostream &, const FunctionInfo &);
732
733/// Used to serialize the on-disk Objective-C method table.
734class ObjCMethodTableInfo
735 : public VersionedTableInfo<ObjCMethodTableInfo,
736 std::tuple<unsigned, unsigned, char>,
737 ObjCMethodInfo> {
738public:
739 unsigned getKeyLength(key_type_ref) {
740 return sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint8_t);
741 }
742
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));
748 }
749
750 hash_value_type ComputeHash(key_type_ref key) {
751 return static_cast<size_t>(llvm::hash_value(key));
752 }
753
754 unsigned getUnversionedInfoSize(const ObjCMethodInfo &OMI) {
755 return getFunctionInfoSize(OMI) + 1;
756 }
757
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);
764
765 emitFunctionInfo(OS, OMI);
766 }
767};
768} // namespace
769
770void APINotesWriter::Implementation::writeObjCMethodBlock(
771 llvm::BitstreamWriter &Stream) {
772 llvm::BCBlockRAII Scope(Stream, OBJC_METHOD_BLOCK_ID, 3);
773
774 if (ObjCMethods.empty())
775 return;
776
777 {
778 llvm::SmallString<4096> HashTableBlob;
779 uint32_t Offset;
780 {
781 llvm::OnDiskChainedHashTableGenerator<ObjCMethodTableInfo> Generator;
782 for (auto &OM : ObjCMethods)
783 Generator.insert(OM.first, OM.second);
784
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);
790 }
791
792 objc_method_block::ObjCMethodDataLayout ObjCMethodData(Stream);
793 ObjCMethodData.emit(Scratch, Offset, HashTableBlob);
794 }
795}
796
797namespace {
798/// Used to serialize the on-disk Objective-C selector table.
799class ObjCSelectorTableInfo {
800public:
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;
807
808 hash_value_type ComputeHash(key_type_ref Key) {
809 return llvm::DenseMapInfo<StoredObjCSelector>::getHashValue(Key);
810 }
811
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);
817
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};
822 }
823
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.NumArgs);
827 for (auto Identifier : Key.Identifiers)
828 writer.write<uint32_t>(Identifier);
829 }
830
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);
834 }
835};
836} // namespace
837
838void APINotesWriter::Implementation::writeObjCSelectorBlock(
839 llvm::BitstreamWriter &Stream) {
840 llvm::BCBlockRAII Scope(Stream, OBJC_SELECTOR_BLOCK_ID, 3);
841
842 if (SelectorIDs.empty())
843 return;
844
845 {
846 llvm::SmallString<4096> HashTableBlob;
847 uint32_t Offset;
848 {
849 llvm::OnDiskChainedHashTableGenerator<ObjCSelectorTableInfo> Generator;
850 for (auto &S : SelectorIDs)
851 Generator.insert(S.first, S.second);
852
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);
858 }
859
860 objc_selector_block::ObjCSelectorDataLayout ObjCSelectorData(Stream);
861 ObjCSelectorData.emit(Scratch, Offset, HashTableBlob);
862 }
863}
864
865namespace {
866/// Used to serialize the on-disk global variable table.
867class GlobalVariableTableInfo
868 : public VersionedTableInfo<GlobalVariableTableInfo, ContextTableKey,
869 GlobalVariableInfo> {
870public:
871 unsigned getKeyLength(key_type_ref) {
872 return sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint32_t);
873 }
874
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);
880 }
881
882 hash_value_type ComputeHash(key_type_ref Key) {
883 return static_cast<size_t>(Key.hashValue());
884 }
885
886 unsigned getUnversionedInfoSize(const GlobalVariableInfo &GVI) {
887 return getVariableInfoSize(GVI);
888 }
889
890 void emitUnversionedInfo(raw_ostream &OS, const GlobalVariableInfo &GVI) {
891 emitVariableInfo(OS, GVI);
892 }
893};
894} // namespace
895
896void APINotesWriter::Implementation::writeGlobalVariableBlock(
897 llvm::BitstreamWriter &Stream) {
898 llvm::BCBlockRAII Scope(Stream, GLOBAL_VARIABLE_BLOCK_ID, 3);
899
900 if (GlobalVariables.empty())
901 return;
902
903 {
904 llvm::SmallString<4096> HashTableBlob;
905 uint32_t Offset;
906 {
907 llvm::OnDiskChainedHashTableGenerator<GlobalVariableTableInfo> Generator;
908 for (auto &GV : GlobalVariables)
909 Generator.insert(GV.first, GV.second);
910
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);
916 }
917
918 global_variable_block::GlobalVariableDataLayout GlobalVariableData(Stream);
919 GlobalVariableData.emit(Scratch, Offset, HashTableBlob);
920 }
921}
922
923namespace {
924unsigned getParamInfoSize(const ParamInfo &PI) {
925 return getVariableInfoSize(PI) + 1;
926}
927
928void emitParamInfo(raw_ostream &OS, const ParamInfo &PI) {
929 emitVariableInfo(OS, PI);
930
931 uint8_t flags = 0;
932 if (auto noescape = PI.isNoEscape()) {
933 flags |= 0x01;
934 if (*noescape)
935 flags |= 0x02;
936 }
937 flags <<= 3;
938 if (auto RCC = PI.getRetainCountConvention())
939 flags |= static_cast<uint8_t>(RCC.value()) + 1;
940
941 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
942 writer.write<uint8_t>(flags);
943}
944
945/// Retrieve the serialized size of the given FunctionInfo, for use in on-disk
946/// hash tables.
947unsigned 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;
954}
955
956/// Emit a serialized representation of the function information.
957void emitFunctionInfo(raw_ostream &OS, const FunctionInfo &FI) {
958 emitCommonEntityInfo(OS, FI);
959
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;
965
966 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
967
968 writer.write<uint8_t>(flags);
969 writer.write<uint8_t>(FI.NumAdjustedNullable);
970 writer.write<uint64_t>(FI.NullabilityPayload);
971
972 writer.write<uint16_t>(FI.Params.size());
973 for (const auto &PI : FI.Params)
974 emitParamInfo(OS, PI);
975
976 writer.write<uint16_t>(FI.ResultType.size());
977 writer.write(ArrayRef<char>{FI.ResultType.data(), FI.ResultType.size()});
978}
979
980/// Used to serialize the on-disk global function table.
981class GlobalFunctionTableInfo
982 : public VersionedTableInfo<GlobalFunctionTableInfo, ContextTableKey,
983 GlobalFunctionInfo> {
984public:
985 unsigned getKeyLength(key_type_ref) {
986 return sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint32_t);
987 }
988
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);
994 }
995
996 hash_value_type ComputeHash(key_type_ref Key) {
997 return static_cast<size_t>(Key.hashValue());
998 }
999
1000 unsigned getUnversionedInfoSize(const GlobalFunctionInfo &GFI) {
1001 return getFunctionInfoSize(GFI);
1002 }
1003
1004 void emitUnversionedInfo(raw_ostream &OS, const GlobalFunctionInfo &GFI) {
1005 emitFunctionInfo(OS, GFI);
1006 }
1007};
1008} // namespace
1009
1010void APINotesWriter::Implementation::writeGlobalFunctionBlock(
1011 llvm::BitstreamWriter &Stream) {
1012 llvm::BCBlockRAII Scope(Stream, GLOBAL_FUNCTION_BLOCK_ID, 3);
1013
1014 if (GlobalFunctions.empty())
1015 return;
1016
1017 {
1018 llvm::SmallString<4096> HashTableBlob;
1019 uint32_t Offset;
1020 {
1021 llvm::OnDiskChainedHashTableGenerator<GlobalFunctionTableInfo> Generator;
1022 for (auto &F : GlobalFunctions)
1023 Generator.insert(F.first, F.second);
1024
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);
1030 }
1031
1032 global_function_block::GlobalFunctionDataLayout GlobalFunctionData(Stream);
1033 GlobalFunctionData.emit(Scratch, Offset, HashTableBlob);
1034 }
1035}
1036
1037namespace {
1038/// Used to serialize the on-disk global enum constant.
1039class EnumConstantTableInfo
1040 : public VersionedTableInfo<EnumConstantTableInfo, unsigned,
1041 EnumConstantInfo> {
1042public:
1043 unsigned getKeyLength(key_type_ref) { return sizeof(uint32_t); }
1044
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);
1048 }
1049
1050 hash_value_type ComputeHash(key_type_ref Key) {
1051 return static_cast<size_t>(llvm::hash_value(Key));
1052 }
1053
1054 unsigned getUnversionedInfoSize(const EnumConstantInfo &ECI) {
1055 return getCommonEntityInfoSize(ECI);
1056 }
1057
1058 void emitUnversionedInfo(raw_ostream &OS, const EnumConstantInfo &ECI) {
1059 emitCommonEntityInfo(OS, ECI);
1060 }
1061};
1062} // namespace
1063
1064void APINotesWriter::Implementation::writeEnumConstantBlock(
1065 llvm::BitstreamWriter &Stream) {
1066 llvm::BCBlockRAII Scope(Stream, ENUM_CONSTANT_BLOCK_ID, 3);
1067
1068 if (EnumConstants.empty())
1069 return;
1070
1071 {
1072 llvm::SmallString<4096> HashTableBlob;
1073 uint32_t Offset;
1074 {
1075 llvm::OnDiskChainedHashTableGenerator<EnumConstantTableInfo> Generator;
1076 for (auto &EC : EnumConstants)
1077 Generator.insert(EC.first, EC.second);
1078
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);
1084 }
1085
1086 enum_constant_block::EnumConstantDataLayout EnumConstantData(Stream);
1087 EnumConstantData.emit(Scratch, Offset, HashTableBlob);
1088 }
1089}
1090
1091namespace {
1092template <typename Derived, typename UnversionedDataType>
1093class CommonTypeTableInfo
1094 : public VersionedTableInfo<Derived, ContextTableKey, UnversionedDataType> {
1095public:
1096 using key_type_ref = typename CommonTypeTableInfo::key_type_ref;
1097 using hash_value_type = typename CommonTypeTableInfo::hash_value_type;
1098
1099 unsigned getKeyLength(key_type_ref) {
1100 return sizeof(uint32_t) + sizeof(uint8_t) + sizeof(IdentifierID);
1101 }
1102
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);
1108 }
1109
1110 hash_value_type ComputeHash(key_type_ref Key) {
1111 return static_cast<size_t>(Key.hashValue());
1112 }
1113
1114 unsigned getUnversionedInfoSize(const UnversionedDataType &UDT) {
1115 return getCommonTypeInfoSize(UDT);
1116 }
1117
1118 void emitUnversionedInfo(raw_ostream &OS, const UnversionedDataType &UDT) {
1119 emitCommonTypeInfo(OS, UDT);
1120 }
1121};
1122
1123/// Used to serialize the on-disk tag table.
1124class TagTableInfo : public CommonTypeTableInfo<TagTableInfo, TagInfo> {
1125public:
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 2 + getCommonTypeInfoSize(TI);
1131 }
1132
1133 void emitUnversionedInfo(raw_ostream &OS, const TagInfo &TI) {
1134 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
1135
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");
1140 }
1141
1142 Flags <<= 2;
1143 if (auto value = TI.isFlagEnum())
1144 Flags |= (value.value() << 1 | 1 << 0);
1145
1146 writer.write<uint8_t>(Flags);
1147
1148 if (auto Copyable = TI.isSwiftCopyable())
1149 writer.write<uint8_t>(*Copyable ? kSwiftCopyable : kSwiftNonCopyable);
1150 else
1151 writer.write<uint8_t>(0);
1152
1153 if (auto ImportAs = TI.SwiftImportAs) {
1154 writer.write<uint16_t>(ImportAs->size() + 1);
1155 OS.write(ImportAs->c_str(), ImportAs->size());
1156 } else {
1157 writer.write<uint16_t>(0);
1158 }
1159 if (auto RetainOp = TI.SwiftRetainOp) {
1160 writer.write<uint16_t>(RetainOp->size() + 1);
1161 OS.write(RetainOp->c_str(), RetainOp->size());
1162 } else {
1163 writer.write<uint16_t>(0);
1164 }
1165 if (auto ReleaseOp = TI.SwiftReleaseOp) {
1166 writer.write<uint16_t>(ReleaseOp->size() + 1);
1167 OS.write(ReleaseOp->c_str(), ReleaseOp->size());
1168 } else {
1169 writer.write<uint16_t>(0);
1170 }
1171
1172 emitCommonTypeInfo(OS, TI);
1173 }
1174};
1175} // namespace
1176
1177void APINotesWriter::Implementation::writeTagBlock(
1178 llvm::BitstreamWriter &Stream) {
1179 llvm::BCBlockRAII Scope(Stream, TAG_BLOCK_ID, 3);
1180
1181 if (Tags.empty())
1182 return;
1183
1184 {
1185 llvm::SmallString<4096> HashTableBlob;
1186 uint32_t Offset;
1187 {
1188 llvm::OnDiskChainedHashTableGenerator<TagTableInfo> Generator;
1189 for (auto &T : Tags)
1190 Generator.insert(T.first, T.second);
1191
1192 llvm::raw_svector_ostream BlobStream(HashTableBlob);
1193 // Make sure that no bucket is at offset 0
1194 llvm::support::endian::write<uint32_t>(BlobStream, 0,
1195 llvm::endianness::little);
1196 Offset = Generator.Emit(BlobStream);
1197 }
1198
1199 tag_block::TagDataLayout TagData(Stream);
1200 TagData.emit(Scratch, Offset, HashTableBlob);
1201 }
1202}
1203
1204namespace {
1205/// Used to serialize the on-disk typedef table.
1206class TypedefTableInfo
1207 : public CommonTypeTableInfo<TypedefTableInfo, TypedefInfo> {
1208public:
1209 unsigned getUnversionedInfoSize(const TypedefInfo &TI) {
1210 return 1 + getCommonTypeInfoSize(TI);
1211 }
1212
1213 void emitUnversionedInfo(raw_ostream &OS, const TypedefInfo &TI) {
1214 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
1215
1216 uint8_t Flags = 0;
1217 if (auto swiftWrapper = TI.SwiftWrapper)
1218 Flags |= static_cast<uint8_t>(*swiftWrapper) + 1;
1219
1220 writer.write<uint8_t>(Flags);
1221
1222 emitCommonTypeInfo(OS, TI);
1223 }
1224};
1225} // namespace
1226
1227void APINotesWriter::Implementation::writeTypedefBlock(
1228 llvm::BitstreamWriter &Stream) {
1229 llvm::BCBlockRAII Scope(Stream, TYPEDEF_BLOCK_ID, 3);
1230
1231 if (Typedefs.empty())
1232 return;
1233
1234 {
1235 llvm::SmallString<4096> HashTableBlob;
1236 uint32_t Offset;
1237 {
1238 llvm::OnDiskChainedHashTableGenerator<TypedefTableInfo> Generator;
1239 for (auto &T : Typedefs)
1240 Generator.insert(T.first, T.second);
1241
1242 llvm::raw_svector_ostream BlobStream(HashTableBlob);
1243 // Make sure that no bucket is at offset 0
1244 llvm::support::endian::write<uint32_t>(BlobStream, 0,
1245 llvm::endianness::little);
1246 Offset = Generator.Emit(BlobStream);
1247 }
1248
1249 typedef_block::TypedefDataLayout TypedefData(Stream);
1250 TypedefData.emit(Scratch, Offset, HashTableBlob);
1251 }
1252}
1253
1254// APINotesWriter
1255
1256APINotesWriter::APINotesWriter(llvm::StringRef ModuleName, const FileEntry *SF)
1257 : Implementation(new class Implementation(ModuleName, SF)) {}
1258
1260
1261void APINotesWriter::writeToStream(llvm::raw_ostream &OS) {
1263}
1264
1265ContextID APINotesWriter::addContext(std::optional<ContextID> ParentCtxID,
1266 llvm::StringRef Name, ContextKind Kind,
1267 const ContextInfo &Info,
1268 llvm::VersionTuple SwiftVersion) {
1269 IdentifierID NameID = Implementation->getIdentifier(Name);
1270
1271 uint32_t RawParentCtxID = ParentCtxID ? ParentCtxID->Value : -1;
1272 ContextTableKey Key(RawParentCtxID, static_cast<uint8_t>(Kind), NameID);
1273 auto Known = Implementation->Contexts.find(Key);
1274 if (Known == Implementation->Contexts.end()) {
1275 unsigned NextID = Implementation->Contexts.size() + 1;
1276
1278 Known = Implementation->Contexts
1279 .insert(std::make_pair(
1280 Key, std::make_pair(NextID, EmptyVersionedInfo)))
1281 .first;
1282
1283 Implementation->ContextNames[NextID] = NameID;
1284 Implementation->ParentContexts[NextID] = RawParentCtxID;
1285 }
1286
1287 // Add this version information.
1288 auto &VersionedVec = Known->second.second;
1289 bool Found = false;
1290 for (auto &Versioned : VersionedVec) {
1291 if (Versioned.first == SwiftVersion) {
1292 Versioned.second |= Info;
1293 Found = true;
1294 break;
1295 }
1296 }
1297
1298 if (!Found)
1299 VersionedVec.push_back({SwiftVersion, Info});
1300
1301 return ContextID(Known->second.first);
1302}
1303
1305 bool IsInstanceProperty,
1306 const ObjCPropertyInfo &Info,
1307 VersionTuple SwiftVersion) {
1308 IdentifierID NameID = Implementation->getIdentifier(Name);
1310 ->ObjCProperties[std::make_tuple(CtxID.Value, NameID, IsInstanceProperty)]
1311 .push_back({SwiftVersion, Info});
1312}
1313
1315 bool IsInstanceMethod,
1316 const ObjCMethodInfo &Info,
1317 VersionTuple SwiftVersion) {
1318 SelectorID SelID = Implementation->getSelector(Selector);
1319 auto Key = std::tuple<unsigned, unsigned, char>{CtxID.Value, SelID,
1320 IsInstanceMethod};
1321 Implementation->ObjCMethods[Key].push_back({SwiftVersion, Info});
1322
1323 // If this method is a designated initializer, update the class to note that
1324 // it has designated initializers.
1325 if (Info.DesignatedInit) {
1326 assert(Implementation->ParentContexts.contains(CtxID.Value));
1327 uint32_t ParentCtxID = Implementation->ParentContexts[CtxID.Value];
1328 ContextTableKey CtxKey(ParentCtxID,
1329 static_cast<uint8_t>(ContextKind::ObjCClass),
1330 Implementation->ContextNames[CtxID.Value]);
1331 assert(Implementation->Contexts.contains(CtxKey));
1332 auto &VersionedVec = Implementation->Contexts[CtxKey].second;
1333 bool Found = false;
1334 for (auto &Versioned : VersionedVec) {
1335 if (Versioned.first == SwiftVersion) {
1336 Versioned.second.setHasDesignatedInits(true);
1337 Found = true;
1338 break;
1339 }
1340 }
1341
1342 if (!Found) {
1343 VersionedVec.push_back({SwiftVersion, ContextInfo()});
1344 VersionedVec.back().second.setHasDesignatedInits(true);
1345 }
1346 }
1347}
1348
1349void APINotesWriter::addGlobalVariable(std::optional<Context> Ctx,
1350 llvm::StringRef Name,
1351 const GlobalVariableInfo &Info,
1352 VersionTuple SwiftVersion) {
1353 IdentifierID VariableID = Implementation->getIdentifier(Name);
1354 ContextTableKey Key(Ctx, VariableID);
1355 Implementation->GlobalVariables[Key].push_back({SwiftVersion, Info});
1356}
1357
1358void APINotesWriter::addGlobalFunction(std::optional<Context> Ctx,
1359 llvm::StringRef Name,
1360 const GlobalFunctionInfo &Info,
1361 VersionTuple SwiftVersion) {
1362 IdentifierID NameID = Implementation->getIdentifier(Name);
1363 ContextTableKey Key(Ctx, NameID);
1364 Implementation->GlobalFunctions[Key].push_back({SwiftVersion, Info});
1365}
1366
1367void APINotesWriter::addEnumConstant(llvm::StringRef Name,
1368 const EnumConstantInfo &Info,
1369 VersionTuple SwiftVersion) {
1370 IdentifierID EnumConstantID = Implementation->getIdentifier(Name);
1371 Implementation->EnumConstants[EnumConstantID].push_back({SwiftVersion, Info});
1372}
1373
1374void APINotesWriter::addTag(std::optional<Context> Ctx, llvm::StringRef Name,
1375 const TagInfo &Info, VersionTuple SwiftVersion) {
1376 IdentifierID TagID = Implementation->getIdentifier(Name);
1377 ContextTableKey Key(Ctx, TagID);
1378 Implementation->Tags[Key].push_back({SwiftVersion, Info});
1379}
1380
1381void APINotesWriter::addTypedef(std::optional<Context> Ctx,
1382 llvm::StringRef Name, const TypedefInfo &Info,
1383 VersionTuple SwiftVersion) {
1384 IdentifierID TypedefID = Implementation->getIdentifier(Name);
1385 ContextTableKey Key(Ctx, TypedefID);
1386 Implementation->Typedefs[Key].push_back({SwiftVersion, Info});
1387}
1388} // namespace api_notes
1389} // namespace clang
#define BLOCK_RECORD(NameSpace, Block)
MatchType Type
StringRef P
static StringRef bytes(const std::vector< T, Allocator > &v)
Definition: ASTWriter.cpp:127
static char ID
Definition: Arena.cpp:183
enum clang::sema::@1646::IndirectLocalPathEntry::EntryKind Kind
Expr * E
Defines the clang::FileManager interface and associated types.
StringRef Identifier
Definition: Format.cpp:2997
static void emitRecordID(unsigned ID, const char *Name, llvm::BitstreamWriter &Stream, SmallVectorImpl< uint64_t > &Record)
static void emitBlockID(unsigned ID, const char *Name, llvm::BitstreamWriter &Stream, SmallVectorImpl< uint64_t > &Record)
static StringRef getIdentifier(const Token &Tok)
const char * Data
#define BLOCK(DERIVED, BASE)
Definition: Template.h:621
__DEVICE__ void * memcpy(void *__a, const void *__b, size_t __c)
__SIZE_TYPE__ size_t
Cached information about one file (either on disk or in the virtual file system).
Definition: FileEntry.h:300
off_t getSize() const
Definition: FileEntry.h:325
Smart pointer class that efficiently represents Objective-C method names.
Implementation(llvm::StringRef ModuleName, const FileEntry *SF)
A class that writes API notes data to a binary representation that can be read by the APINotesReader.
void addObjCMethod(ContextID CtxID, ObjCSelectorRef Selector, bool IsInstanceMethod, const ObjCMethodInfo &Info, llvm::VersionTuple SwiftVersion)
Add information about a specific Objective-C method.
void addEnumConstant(llvm::StringRef Name, const EnumConstantInfo &Info, llvm::VersionTuple SwiftVersion)
Add information about an enumerator.
ContextID addContext(std::optional< ContextID > ParentCtxID, llvm::StringRef Name, ContextKind Kind, const ContextInfo &Info, llvm::VersionTuple SwiftVersion)
Add information about a specific Objective-C class or protocol or a C++ namespace.
void addGlobalFunction(std::optional< Context > Ctx, llvm::StringRef Name, const GlobalFunctionInfo &Info, llvm::VersionTuple SwiftVersion)
Add information about a global function.
void addObjCProperty(ContextID CtxID, llvm::StringRef Name, bool IsInstanceProperty, const ObjCPropertyInfo &Info, llvm::VersionTuple SwiftVersion)
Add information about a specific Objective-C property.
void addGlobalVariable(std::optional< Context > Ctx, llvm::StringRef Name, const GlobalVariableInfo &Info, llvm::VersionTuple SwiftVersion)
Add information about a global variable.
void addTypedef(std::optional< Context > Ctx, llvm::StringRef Name, const TypedefInfo &Info, llvm::VersionTuple SwiftVersion)
Add information about a typedef.
void writeToStream(llvm::raw_ostream &OS)
void addTag(std::optional< Context > Ctx, llvm::StringRef Name, const TagInfo &Info, llvm::VersionTuple SwiftVersion)
Add information about a tag (struct/union/enum/C++ class).
APINotesWriter(llvm::StringRef ModuleName, const FileEntry *SF)
Create a new API notes writer with the given module name and (optional) source file.
Opaque context ID used to refer to an Objective-C class or protocol or a C++ namespace.
Definition: Types.h:788
Describes API notes data for an Objective-C class or protocol or a C++ namespace.
Definition: Types.h:197
Describes API notes data for an enumerator.
Definition: Types.h:667
Describes API notes data for a global function.
Definition: Types.h:661
Describes API notes data for a global variable.
Definition: Types.h:655
Describes API notes data for an Objective-C method.
Definition: Types.h:616
unsigned DesignatedInit
Whether this is a designated initializer of its class.
Definition: Types.h:620
Describes API notes data for an Objective-C property.
Definition: Types.h:368
Describes API notes data for a tag.
Definition: Types.h:673
Describes API notes data for a typedef.
Definition: Types.h:756
llvm::BCRecordLayout< CONTEXT_ID_DATA, llvm::BCVBR< 16 >, llvm::BCBlob > ContextIDLayout
llvm::BCRecordLayout< CONTEXT_INFO_DATA, llvm::BCVBR< 16 >, llvm::BCBlob > ContextInfoLayout
llvm::BCRecordLayout< SOURCE_FILE, llvm::BCVBR< 16 >, llvm::BCVBR< 16 > > SourceFileLayout
llvm::BCRecordLayout< MODULE_NAME, llvm::BCBlob > ModuleNameLayout
llvm::BCRecordLayout< METADATA, llvm::BCFixed< 16 >, llvm::BCFixed< 16 > > MetadataLayout
llvm::BCRecordLayout< ENUM_CONSTANT_DATA, llvm::BCVBR< 16 >, llvm::BCBlob > EnumConstantDataLayout
llvm::BCRecordLayout< GLOBAL_FUNCTION_DATA, llvm::BCVBR< 16 >, llvm::BCBlob > GlobalFunctionDataLayout
llvm::BCRecordLayout< GLOBAL_VARIABLE_DATA, llvm::BCVBR< 16 >, llvm::BCBlob > GlobalVariableDataLayout
llvm::BCRecordLayout< IDENTIFIER_DATA, llvm::BCVBR< 16 >, llvm::BCBlob > IdentifierDataLayout
llvm::BCRecordLayout< OBJC_METHOD_DATA, llvm::BCVBR< 16 >, llvm::BCBlob > ObjCMethodDataLayout
llvm::BCRecordLayout< OBJC_PROPERTY_DATA, llvm::BCVBR< 16 >, llvm::BCBlob > ObjCPropertyDataLayout
llvm::BCRecordLayout< OBJC_SELECTOR_DATA, llvm::BCVBR< 16 >, llvm::BCBlob > ObjCSelectorDataLayout
llvm::BCRecordLayout< TAG_DATA, llvm::BCVBR< 16 >, llvm::BCBlob > TagDataLayout
llvm::BCRecordLayout< TYPEDEF_DATA, llvm::BCVBR< 16 >, llvm::BCBlob > TypedefDataLayout
llvm::PointerEmbeddedInt< unsigned, 31 > SelectorID
llvm::PointerEmbeddedInt< unsigned, 31 > IdentifierID
const uint16_t VERSION_MAJOR
API notes file major version number.
const unsigned char API_NOTES_SIGNATURE[]
Magic number for API notes files.
const uint16_t VERSION_MINOR
API notes file minor version number.
@ OBJC_CONTEXT_BLOCK_ID
The Objective-C context data block, which contains information about Objective-C classes and protocol...
@ TYPEDEF_BLOCK_ID
The typedef data block, which maps typedef names to information about the typedefs.
@ OBJC_PROPERTY_BLOCK_ID
The Objective-C property data block, which maps Objective-C (class name, property name) pairs to info...
@ ENUM_CONSTANT_BLOCK_ID
The enum constant data block, which maps enumerator names to information about the enumerators.
@ TAG_BLOCK_ID
The tag data block, which maps tag names to information about the tags.
@ OBJC_METHOD_BLOCK_ID
The Objective-C property data block, which maps Objective-C (class name, selector,...
@ OBJC_SELECTOR_BLOCK_ID
The Objective-C selector data block, which maps Objective-C selector names (# of pieces,...
@ GLOBAL_FUNCTION_BLOCK_ID
The (global) functions data block, which maps global function names to information about the global f...
@ CONTROL_BLOCK_ID
The control block, which contains all of the information that needs to be validated prior to committi...
@ IDENTIFIER_BLOCK_ID
The identifier data block, which maps identifier strings to IDs.
@ GLOBAL_VARIABLE_BLOCK_ID
The global variables data block, which maps global variable names to information about the global var...
uint32_t SelectorID
An ID number that refers to an ObjC selector in an AST file.
Definition: ASTBitCodes.h:167
uint64_t IdentifierID
An ID number that refers to an identifier in an AST file.
Definition: ASTBitCodes.h:63
unsigned ComputeHash(Selector Sel)
Definition: ASTCommon.cpp:289
std::shared_ptr< MatchComputation< T > > Generator
Definition: RewriteRule.h:65
The JSON file list parser is used to communicate input to InstallAPI.
const FunctionProtoType * T
unsigned long uint64_t
hash_code hash_value(const clang::tooling::dependencies::ModuleID &ID)
A stored Objective-C or C++ context, represented by the ID of its parent context, the kind of this co...
A temporary reference to an Objective-C selector, suitable for referencing selector data on the stack...
Definition: Types.h:814
llvm::ArrayRef< llvm::StringRef > Identifiers
Definition: Types.h:816
A stored Objective-C selector.