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