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