Path: blob/main/contrib/llvm-project/clang/lib/APINotes/APINotesWriter.cpp
35259 views
//===-- APINotesWriter.cpp - API Notes Writer -------------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "clang/APINotes/APINotesWriter.h"9#include "APINotesFormat.h"10#include "clang/APINotes/Types.h"11#include "clang/Basic/FileManager.h"12#include "llvm/ADT/DenseMap.h"13#include "llvm/ADT/StringMap.h"14#include "llvm/Bitstream/BitstreamWriter.h"15#include "llvm/Support/DJB.h"16#include "llvm/Support/OnDiskHashTable.h"17#include "llvm/Support/VersionTuple.h"1819namespace clang {20namespace api_notes {21class APINotesWriter::Implementation {22friend class APINotesWriter;2324template <typename T>25using VersionedSmallVector =26llvm::SmallVector<std::pair<llvm::VersionTuple, T>, 1>;2728std::string ModuleName;29const FileEntry *SourceFile;3031/// Scratch space for bitstream writing.32llvm::SmallVector<uint64_t, 64> Scratch;3334/// Mapping from strings to identifier IDs.35llvm::StringMap<IdentifierID> IdentifierIDs;3637/// Information about contexts (Objective-C classes or protocols or C++38/// namespaces).39///40/// Indexed by the parent context ID, context kind and the identifier ID of41/// this context and provides both the context ID and information describing42/// the context within that module.43llvm::DenseMap<ContextTableKey,44std::pair<unsigned, VersionedSmallVector<ContextInfo>>>45Contexts;4647/// Information about parent contexts for each context.48///49/// Indexed by context ID, provides the parent context ID.50llvm::DenseMap<uint32_t, uint32_t> ParentContexts;5152/// Mapping from context IDs to the identifier ID holding the name.53llvm::DenseMap<unsigned, unsigned> ContextNames;5455/// Information about Objective-C properties.56///57/// Indexed by the context ID, property name, and whether this is an58/// instance property.59llvm::DenseMap<60std::tuple<unsigned, unsigned, char>,61llvm::SmallVector<std::pair<VersionTuple, ObjCPropertyInfo>, 1>>62ObjCProperties;6364/// Information about Objective-C methods.65///66/// Indexed by the context ID, selector ID, and Boolean (stored as a char)67/// indicating whether this is a class or instance method.68llvm::DenseMap<std::tuple<unsigned, unsigned, char>,69llvm::SmallVector<std::pair<VersionTuple, ObjCMethodInfo>, 1>>70ObjCMethods;7172/// Information about C++ methods.73///74/// Indexed by the context ID and name ID.75llvm::DenseMap<SingleDeclTableKey,76llvm::SmallVector<std::pair<VersionTuple, CXXMethodInfo>, 1>>77CXXMethods;7879/// Mapping from selectors to selector ID.80llvm::DenseMap<StoredObjCSelector, SelectorID> SelectorIDs;8182/// Information about global variables.83///84/// Indexed by the context ID, identifier ID.85llvm::DenseMap<86SingleDeclTableKey,87llvm::SmallVector<std::pair<VersionTuple, GlobalVariableInfo>, 1>>88GlobalVariables;8990/// Information about global functions.91///92/// Indexed by the context ID, identifier ID.93llvm::DenseMap<94SingleDeclTableKey,95llvm::SmallVector<std::pair<VersionTuple, GlobalFunctionInfo>, 1>>96GlobalFunctions;9798/// Information about enumerators.99///100/// Indexed by the identifier ID.101llvm::DenseMap<102unsigned, llvm::SmallVector<std::pair<VersionTuple, EnumConstantInfo>, 1>>103EnumConstants;104105/// Information about tags.106///107/// Indexed by the context ID, identifier ID.108llvm::DenseMap<SingleDeclTableKey,109llvm::SmallVector<std::pair<VersionTuple, TagInfo>, 1>>110Tags;111112/// Information about typedefs.113///114/// Indexed by the context ID, identifier ID.115llvm::DenseMap<SingleDeclTableKey,116llvm::SmallVector<std::pair<VersionTuple, TypedefInfo>, 1>>117Typedefs;118119/// Retrieve the ID for the given identifier.120IdentifierID getIdentifier(StringRef Identifier) {121if (Identifier.empty())122return 0;123124auto Known = IdentifierIDs.find(Identifier);125if (Known != IdentifierIDs.end())126return Known->second;127128// Add to the identifier table.129Known = IdentifierIDs.insert({Identifier, IdentifierIDs.size() + 1}).first;130return Known->second;131}132133/// Retrieve the ID for the given selector.134SelectorID getSelector(ObjCSelectorRef SelectorRef) {135// Translate the selector reference into a stored selector.136StoredObjCSelector Selector;137Selector.NumArgs = SelectorRef.NumArgs;138Selector.Identifiers.reserve(SelectorRef.Identifiers.size());139for (auto piece : SelectorRef.Identifiers)140Selector.Identifiers.push_back(getIdentifier(piece));141142// Look for the stored selector.143auto Known = SelectorIDs.find(Selector);144if (Known != SelectorIDs.end())145return Known->second;146147// Add to the selector table.148Known = SelectorIDs.insert({Selector, SelectorIDs.size()}).first;149return Known->second;150}151152private:153void writeBlockInfoBlock(llvm::BitstreamWriter &Stream);154void writeControlBlock(llvm::BitstreamWriter &Stream);155void writeIdentifierBlock(llvm::BitstreamWriter &Stream);156void writeContextBlock(llvm::BitstreamWriter &Stream);157void writeObjCPropertyBlock(llvm::BitstreamWriter &Stream);158void writeObjCMethodBlock(llvm::BitstreamWriter &Stream);159void writeCXXMethodBlock(llvm::BitstreamWriter &Stream);160void writeObjCSelectorBlock(llvm::BitstreamWriter &Stream);161void writeGlobalVariableBlock(llvm::BitstreamWriter &Stream);162void writeGlobalFunctionBlock(llvm::BitstreamWriter &Stream);163void writeEnumConstantBlock(llvm::BitstreamWriter &Stream);164void writeTagBlock(llvm::BitstreamWriter &Stream);165void writeTypedefBlock(llvm::BitstreamWriter &Stream);166167public:168Implementation(llvm::StringRef ModuleName, const FileEntry *SF)169: ModuleName(std::string(ModuleName)), SourceFile(SF) {}170171void writeToStream(llvm::raw_ostream &OS);172};173174void APINotesWriter::Implementation::writeToStream(llvm::raw_ostream &OS) {175llvm::SmallVector<char, 0> Buffer;176177{178llvm::BitstreamWriter Stream(Buffer);179180// Emit the signature.181for (unsigned char Byte : API_NOTES_SIGNATURE)182Stream.Emit(Byte, 8);183184// Emit the blocks.185writeBlockInfoBlock(Stream);186writeControlBlock(Stream);187writeIdentifierBlock(Stream);188writeContextBlock(Stream);189writeObjCPropertyBlock(Stream);190writeObjCMethodBlock(Stream);191writeCXXMethodBlock(Stream);192writeObjCSelectorBlock(Stream);193writeGlobalVariableBlock(Stream);194writeGlobalFunctionBlock(Stream);195writeEnumConstantBlock(Stream);196writeTagBlock(Stream);197writeTypedefBlock(Stream);198}199200OS.write(Buffer.data(), Buffer.size());201OS.flush();202}203204namespace {205/// Record the name of a block.206void emitBlockID(llvm::BitstreamWriter &Stream, unsigned ID,207llvm::StringRef Name) {208Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID,209llvm::ArrayRef<unsigned>{ID});210211// Emit the block name if present.212if (Name.empty())213return;214Stream.EmitRecord(215llvm::bitc::BLOCKINFO_CODE_BLOCKNAME,216llvm::ArrayRef<unsigned char>(217const_cast<unsigned char *>(218reinterpret_cast<const unsigned char *>(Name.data())),219Name.size()));220}221222/// Record the name of a record within a block.223void emitRecordID(llvm::BitstreamWriter &Stream, unsigned ID,224llvm::StringRef Name) {225assert(ID < 256 && "can't fit record ID in next to name");226227llvm::SmallVector<unsigned char, 64> Buffer;228Buffer.resize(Name.size() + 1);229Buffer[0] = ID;230memcpy(Buffer.data() + 1, Name.data(), Name.size());231232Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Buffer);233}234} // namespace235236void APINotesWriter::Implementation::writeBlockInfoBlock(237llvm::BitstreamWriter &Stream) {238llvm::BCBlockRAII Scope(Stream, llvm::bitc::BLOCKINFO_BLOCK_ID, 2);239240#define BLOCK(Block) emitBlockID(Stream, Block##_ID, #Block)241#define BLOCK_RECORD(NameSpace, Block) \242emitRecordID(Stream, NameSpace::Block, #Block)243BLOCK(CONTROL_BLOCK);244BLOCK_RECORD(control_block, METADATA);245BLOCK_RECORD(control_block, MODULE_NAME);246247BLOCK(IDENTIFIER_BLOCK);248BLOCK_RECORD(identifier_block, IDENTIFIER_DATA);249250BLOCK(OBJC_CONTEXT_BLOCK);251BLOCK_RECORD(context_block, CONTEXT_ID_DATA);252253BLOCK(OBJC_PROPERTY_BLOCK);254BLOCK_RECORD(objc_property_block, OBJC_PROPERTY_DATA);255256BLOCK(OBJC_METHOD_BLOCK);257BLOCK_RECORD(objc_method_block, OBJC_METHOD_DATA);258259BLOCK(OBJC_SELECTOR_BLOCK);260BLOCK_RECORD(objc_selector_block, OBJC_SELECTOR_DATA);261262BLOCK(GLOBAL_VARIABLE_BLOCK);263BLOCK_RECORD(global_variable_block, GLOBAL_VARIABLE_DATA);264265BLOCK(GLOBAL_FUNCTION_BLOCK);266BLOCK_RECORD(global_function_block, GLOBAL_FUNCTION_DATA);267#undef BLOCK_RECORD268#undef BLOCK269}270271void APINotesWriter::Implementation::writeControlBlock(272llvm::BitstreamWriter &Stream) {273llvm::BCBlockRAII Scope(Stream, CONTROL_BLOCK_ID, 3);274275control_block::MetadataLayout Metadata(Stream);276Metadata.emit(Scratch, VERSION_MAJOR, VERSION_MINOR);277278control_block::ModuleNameLayout ModuleName(Stream);279ModuleName.emit(Scratch, this->ModuleName);280281if (SourceFile) {282control_block::SourceFileLayout SourceFile(Stream);283SourceFile.emit(Scratch, this->SourceFile->getSize(),284this->SourceFile->getModificationTime());285}286}287288namespace {289/// Used to serialize the on-disk identifier table.290class IdentifierTableInfo {291public:292using key_type = StringRef;293using key_type_ref = key_type;294using data_type = IdentifierID;295using data_type_ref = const data_type &;296using hash_value_type = uint32_t;297using offset_type = unsigned;298299hash_value_type ComputeHash(key_type_ref Key) { return llvm::djbHash(Key); }300301std::pair<unsigned, unsigned>302EmitKeyDataLength(raw_ostream &OS, key_type_ref Key, data_type_ref) {303uint32_t KeyLength = Key.size();304uint32_t DataLength = sizeof(uint32_t);305306llvm::support::endian::Writer writer(OS, llvm::endianness::little);307writer.write<uint16_t>(KeyLength);308writer.write<uint16_t>(DataLength);309return {KeyLength, DataLength};310}311312void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) { OS << Key; }313314void EmitData(raw_ostream &OS, key_type_ref, data_type_ref Data, unsigned) {315llvm::support::endian::Writer writer(OS, llvm::endianness::little);316writer.write<uint32_t>(Data);317}318};319} // namespace320321void APINotesWriter::Implementation::writeIdentifierBlock(322llvm::BitstreamWriter &Stream) {323llvm::BCBlockRAII restoreBlock(Stream, IDENTIFIER_BLOCK_ID, 3);324325if (IdentifierIDs.empty())326return;327328llvm::SmallString<4096> HashTableBlob;329uint32_t Offset;330{331llvm::OnDiskChainedHashTableGenerator<IdentifierTableInfo> Generator;332for (auto &II : IdentifierIDs)333Generator.insert(II.first(), II.second);334335llvm::raw_svector_ostream BlobStream(HashTableBlob);336// Make sure that no bucket is at offset 0337llvm::support::endian::write<uint32_t>(BlobStream, 0,338llvm::endianness::little);339Offset = Generator.Emit(BlobStream);340}341342identifier_block::IdentifierDataLayout IdentifierData(Stream);343IdentifierData.emit(Scratch, Offset, HashTableBlob);344}345346namespace {347/// Used to serialize the on-disk Objective-C context table.348class ContextIDTableInfo {349public:350using key_type = ContextTableKey;351using key_type_ref = key_type;352using data_type = unsigned;353using data_type_ref = const data_type &;354using hash_value_type = size_t;355using offset_type = unsigned;356357hash_value_type ComputeHash(key_type_ref Key) {358return static_cast<size_t>(Key.hashValue());359}360361std::pair<unsigned, unsigned> EmitKeyDataLength(raw_ostream &OS, key_type_ref,362data_type_ref) {363uint32_t KeyLength = sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint32_t);364uint32_t DataLength = sizeof(uint32_t);365366llvm::support::endian::Writer writer(OS, llvm::endianness::little);367writer.write<uint16_t>(KeyLength);368writer.write<uint16_t>(DataLength);369return {KeyLength, DataLength};370}371372void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {373llvm::support::endian::Writer writer(OS, llvm::endianness::little);374writer.write<uint32_t>(Key.parentContextID);375writer.write<uint8_t>(Key.contextKind);376writer.write<uint32_t>(Key.contextID);377}378379void EmitData(raw_ostream &OS, key_type_ref, data_type_ref Data, unsigned) {380llvm::support::endian::Writer writer(OS, llvm::endianness::little);381writer.write<uint32_t>(Data);382}383};384385/// Localized helper to make a type dependent, thwarting template argument386/// deduction.387template <typename T> struct MakeDependent { typedef T Type; };388389/// Retrieve the serialized size of the given VersionTuple, for use in390/// on-disk hash tables.391unsigned getVersionTupleSize(const VersionTuple &VT) {392unsigned size = sizeof(uint8_t) + /*major*/ sizeof(uint32_t);393if (VT.getMinor())394size += sizeof(uint32_t);395if (VT.getSubminor())396size += sizeof(uint32_t);397if (VT.getBuild())398size += sizeof(uint32_t);399return size;400}401402/// Determine the size of an array of versioned information,403template <typename T>404unsigned getVersionedInfoSize(405const llvm::SmallVectorImpl<std::pair<llvm::VersionTuple, T>> &VI,406llvm::function_ref<unsigned(const typename MakeDependent<T>::Type &)>407getInfoSize) {408unsigned result = sizeof(uint16_t); // # of elements409for (const auto &E : VI) {410result += getVersionTupleSize(E.first);411result += getInfoSize(E.second);412}413return result;414}415416/// Emit a serialized representation of a version tuple.417void emitVersionTuple(raw_ostream &OS, const VersionTuple &VT) {418llvm::support::endian::Writer writer(OS, llvm::endianness::little);419420// First byte contains the number of components beyond the 'major' component.421uint8_t descriptor;422if (VT.getBuild())423descriptor = 3;424else if (VT.getSubminor())425descriptor = 2;426else if (VT.getMinor())427descriptor = 1;428else429descriptor = 0;430writer.write<uint8_t>(descriptor);431432// Write the components.433writer.write<uint32_t>(VT.getMajor());434if (auto minor = VT.getMinor())435writer.write<uint32_t>(*minor);436if (auto subminor = VT.getSubminor())437writer.write<uint32_t>(*subminor);438if (auto build = VT.getBuild())439writer.write<uint32_t>(*build);440}441442/// Emit versioned information.443template <typename T>444void emitVersionedInfo(445raw_ostream &OS, llvm::SmallVectorImpl<std::pair<VersionTuple, T>> &VI,446llvm::function_ref<void(raw_ostream &,447const typename MakeDependent<T>::Type &)>448emitInfo) {449std::sort(VI.begin(), VI.end(),450[](const std::pair<VersionTuple, T> &LHS,451const std::pair<VersionTuple, T> &RHS) -> bool {452assert((&LHS == &RHS || LHS.first != RHS.first) &&453"two entries for the same version");454return LHS.first < RHS.first;455});456457llvm::support::endian::Writer writer(OS, llvm::endianness::little);458writer.write<uint16_t>(VI.size());459for (const auto &E : VI) {460emitVersionTuple(OS, E.first);461emitInfo(OS, E.second);462}463}464465/// On-disk hash table info key base for handling versioned data.466template <typename Derived, typename KeyType, typename UnversionedDataType>467class VersionedTableInfo {468Derived &asDerived() { return *static_cast<Derived *>(this); }469470const Derived &asDerived() const {471return *static_cast<const Derived *>(this);472}473474public:475using key_type = KeyType;476using key_type_ref = key_type;477using data_type =478llvm::SmallVector<std::pair<llvm::VersionTuple, UnversionedDataType>, 1>;479using data_type_ref = data_type &;480using hash_value_type = size_t;481using offset_type = unsigned;482483std::pair<unsigned, unsigned>484EmitKeyDataLength(raw_ostream &OS, key_type_ref Key, data_type_ref Data) {485uint32_t KeyLength = asDerived().getKeyLength(Key);486uint32_t DataLength =487getVersionedInfoSize(Data, [this](const UnversionedDataType &UI) {488return asDerived().getUnversionedInfoSize(UI);489});490491llvm::support::endian::Writer writer(OS, llvm::endianness::little);492writer.write<uint16_t>(KeyLength);493writer.write<uint16_t>(DataLength);494return {KeyLength, DataLength};495}496497void EmitData(raw_ostream &OS, key_type_ref, data_type_ref Data, unsigned) {498emitVersionedInfo(499OS, Data, [this](llvm::raw_ostream &OS, const UnversionedDataType &UI) {500asDerived().emitUnversionedInfo(OS, UI);501});502}503};504505/// Emit a serialized representation of the common entity information.506void emitCommonEntityInfo(raw_ostream &OS, const CommonEntityInfo &CEI) {507llvm::support::endian::Writer writer(OS, llvm::endianness::little);508509uint8_t payload = 0;510if (auto swiftPrivate = CEI.isSwiftPrivate()) {511payload |= 0x01;512if (*swiftPrivate)513payload |= 0x02;514}515payload <<= 1;516payload |= CEI.Unavailable;517payload <<= 1;518payload |= CEI.UnavailableInSwift;519520writer.write<uint8_t>(payload);521522writer.write<uint16_t>(CEI.UnavailableMsg.size());523OS.write(CEI.UnavailableMsg.c_str(), CEI.UnavailableMsg.size());524525writer.write<uint16_t>(CEI.SwiftName.size());526OS.write(CEI.SwiftName.c_str(), CEI.SwiftName.size());527}528529/// Retrieve the serialized size of the given CommonEntityInfo, for use in530/// on-disk hash tables.531unsigned getCommonEntityInfoSize(const CommonEntityInfo &CEI) {532return 5 + CEI.UnavailableMsg.size() + CEI.SwiftName.size();533}534535// Retrieve the serialized size of the given CommonTypeInfo, for use536// in on-disk hash tables.537unsigned getCommonTypeInfoSize(const CommonTypeInfo &CTI) {538return 2 + (CTI.getSwiftBridge() ? CTI.getSwiftBridge()->size() : 0) + 2 +539(CTI.getNSErrorDomain() ? CTI.getNSErrorDomain()->size() : 0) +540getCommonEntityInfoSize(CTI);541}542543/// Emit a serialized representation of the common type information.544void emitCommonTypeInfo(raw_ostream &OS, const CommonTypeInfo &CTI) {545emitCommonEntityInfo(OS, CTI);546547llvm::support::endian::Writer writer(OS, llvm::endianness::little);548if (auto swiftBridge = CTI.getSwiftBridge()) {549writer.write<uint16_t>(swiftBridge->size() + 1);550OS.write(swiftBridge->c_str(), swiftBridge->size());551} else {552writer.write<uint16_t>(0);553}554if (auto nsErrorDomain = CTI.getNSErrorDomain()) {555writer.write<uint16_t>(nsErrorDomain->size() + 1);556OS.write(nsErrorDomain->c_str(), CTI.getNSErrorDomain()->size());557} else {558writer.write<uint16_t>(0);559}560}561562/// Used to serialize the on-disk Objective-C property table.563class ContextInfoTableInfo564: public VersionedTableInfo<ContextInfoTableInfo, unsigned, ContextInfo> {565public:566unsigned getKeyLength(key_type_ref) { return sizeof(uint32_t); }567568void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {569llvm::support::endian::Writer writer(OS, llvm::endianness::little);570writer.write<uint32_t>(Key);571}572573hash_value_type ComputeHash(key_type_ref Key) {574return static_cast<size_t>(llvm::hash_value(Key));575}576577unsigned getUnversionedInfoSize(const ContextInfo &OCI) {578return getCommonTypeInfoSize(OCI) + 1;579}580581void emitUnversionedInfo(raw_ostream &OS, const ContextInfo &OCI) {582emitCommonTypeInfo(OS, OCI);583584uint8_t payload = 0;585if (auto swiftImportAsNonGeneric = OCI.getSwiftImportAsNonGeneric())586payload |= (0x01 << 1) | (uint8_t)swiftImportAsNonGeneric.value();587payload <<= 2;588if (auto swiftObjCMembers = OCI.getSwiftObjCMembers())589payload |= (0x01 << 1) | (uint8_t)swiftObjCMembers.value();590payload <<= 3;591if (auto nullable = OCI.getDefaultNullability())592payload |= (0x01 << 2) | static_cast<uint8_t>(*nullable);593payload = (payload << 1) | (OCI.hasDesignatedInits() ? 1 : 0);594595OS << payload;596}597};598} // namespace599600void APINotesWriter::Implementation::writeContextBlock(601llvm::BitstreamWriter &Stream) {602llvm::BCBlockRAII restoreBlock(Stream, OBJC_CONTEXT_BLOCK_ID, 3);603604if (Contexts.empty())605return;606607{608llvm::SmallString<4096> HashTableBlob;609uint32_t Offset;610{611llvm::OnDiskChainedHashTableGenerator<ContextIDTableInfo> Generator;612for (auto &OC : Contexts)613Generator.insert(OC.first, OC.second.first);614615llvm::raw_svector_ostream BlobStream(HashTableBlob);616// Make sure that no bucket is at offset 0617llvm::support::endian::write<uint32_t>(BlobStream, 0,618llvm::endianness::little);619Offset = Generator.Emit(BlobStream);620}621622context_block::ContextIDLayout ContextID(Stream);623ContextID.emit(Scratch, Offset, HashTableBlob);624}625626{627llvm::SmallString<4096> HashTableBlob;628uint32_t Offset;629{630llvm::OnDiskChainedHashTableGenerator<ContextInfoTableInfo> Generator;631for (auto &OC : Contexts)632Generator.insert(OC.second.first, OC.second.second);633634llvm::raw_svector_ostream BlobStream(HashTableBlob);635// Make sure that no bucket is at offset 0636llvm::support::endian::write<uint32_t>(BlobStream, 0,637llvm::endianness::little);638Offset = Generator.Emit(BlobStream);639}640641context_block::ContextInfoLayout ContextInfo(Stream);642ContextInfo.emit(Scratch, Offset, HashTableBlob);643}644}645646namespace {647/// Retrieve the serialized size of the given VariableInfo, for use in648/// on-disk hash tables.649unsigned getVariableInfoSize(const VariableInfo &VI) {650return 2 + getCommonEntityInfoSize(VI) + 2 + VI.getType().size();651}652653/// Emit a serialized representation of the variable information.654void emitVariableInfo(raw_ostream &OS, const VariableInfo &VI) {655emitCommonEntityInfo(OS, VI);656657uint8_t bytes[2] = {0, 0};658if (auto nullable = VI.getNullability()) {659bytes[0] = 1;660bytes[1] = static_cast<uint8_t>(*nullable);661} else {662// Nothing to do.663}664665OS.write(reinterpret_cast<const char *>(bytes), 2);666667llvm::support::endian::Writer writer(OS, llvm::endianness::little);668writer.write<uint16_t>(VI.getType().size());669OS.write(VI.getType().data(), VI.getType().size());670}671672/// Used to serialize the on-disk Objective-C property table.673class ObjCPropertyTableInfo674: public VersionedTableInfo<ObjCPropertyTableInfo,675std::tuple<unsigned, unsigned, char>,676ObjCPropertyInfo> {677public:678unsigned getKeyLength(key_type_ref) {679return sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint8_t);680}681682void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {683llvm::support::endian::Writer writer(OS, llvm::endianness::little);684writer.write<uint32_t>(std::get<0>(Key));685writer.write<uint32_t>(std::get<1>(Key));686writer.write<uint8_t>(std::get<2>(Key));687}688689hash_value_type ComputeHash(key_type_ref Key) {690return static_cast<size_t>(llvm::hash_value(Key));691}692693unsigned getUnversionedInfoSize(const ObjCPropertyInfo &OPI) {694return getVariableInfoSize(OPI) + 1;695}696697void emitUnversionedInfo(raw_ostream &OS, const ObjCPropertyInfo &OPI) {698emitVariableInfo(OS, OPI);699700uint8_t flags = 0;701if (auto value = OPI.getSwiftImportAsAccessors()) {702flags |= 1 << 0;703flags |= value.value() << 1;704}705OS << flags;706}707};708} // namespace709710void APINotesWriter::Implementation::writeObjCPropertyBlock(711llvm::BitstreamWriter &Stream) {712llvm::BCBlockRAII Scope(Stream, OBJC_PROPERTY_BLOCK_ID, 3);713714if (ObjCProperties.empty())715return;716717{718llvm::SmallString<4096> HashTableBlob;719uint32_t Offset;720{721llvm::OnDiskChainedHashTableGenerator<ObjCPropertyTableInfo> Generator;722for (auto &OP : ObjCProperties)723Generator.insert(OP.first, OP.second);724725llvm::raw_svector_ostream BlobStream(HashTableBlob);726// Make sure that no bucket is at offset 0727llvm::support::endian::write<uint32_t>(BlobStream, 0,728llvm::endianness::little);729Offset = Generator.Emit(BlobStream);730}731732objc_property_block::ObjCPropertyDataLayout ObjCPropertyData(Stream);733ObjCPropertyData.emit(Scratch, Offset, HashTableBlob);734}735}736737namespace {738unsigned getFunctionInfoSize(const FunctionInfo &);739void emitFunctionInfo(llvm::raw_ostream &, const FunctionInfo &);740741/// Used to serialize the on-disk Objective-C method table.742class ObjCMethodTableInfo743: public VersionedTableInfo<ObjCMethodTableInfo,744std::tuple<unsigned, unsigned, char>,745ObjCMethodInfo> {746public:747unsigned getKeyLength(key_type_ref) {748return sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint8_t);749}750751void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {752llvm::support::endian::Writer writer(OS, llvm::endianness::little);753writer.write<uint32_t>(std::get<0>(Key));754writer.write<uint32_t>(std::get<1>(Key));755writer.write<uint8_t>(std::get<2>(Key));756}757758hash_value_type ComputeHash(key_type_ref key) {759return static_cast<size_t>(llvm::hash_value(key));760}761762unsigned getUnversionedInfoSize(const ObjCMethodInfo &OMI) {763return getFunctionInfoSize(OMI) + 1;764}765766void emitUnversionedInfo(raw_ostream &OS, const ObjCMethodInfo &OMI) {767uint8_t flags = 0;768llvm::support::endian::Writer writer(OS, llvm::endianness::little);769flags = (flags << 1) | OMI.DesignatedInit;770flags = (flags << 1) | OMI.RequiredInit;771writer.write<uint8_t>(flags);772773emitFunctionInfo(OS, OMI);774}775};776777/// Used to serialize the on-disk C++ method table.778class CXXMethodTableInfo779: public VersionedTableInfo<CXXMethodTableInfo, SingleDeclTableKey,780CXXMethodInfo> {781public:782unsigned getKeyLength(key_type_ref) {783return sizeof(uint32_t) + sizeof(uint32_t);784}785786void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {787llvm::support::endian::Writer writer(OS, llvm::endianness::little);788writer.write<uint32_t>(Key.parentContextID);789writer.write<uint32_t>(Key.nameID);790}791792hash_value_type ComputeHash(key_type_ref key) {793return static_cast<size_t>(key.hashValue());794}795796unsigned getUnversionedInfoSize(const CXXMethodInfo &OMI) {797return getFunctionInfoSize(OMI);798}799800void emitUnversionedInfo(raw_ostream &OS, const CXXMethodInfo &OMI) {801emitFunctionInfo(OS, OMI);802}803};804} // namespace805806void APINotesWriter::Implementation::writeObjCMethodBlock(807llvm::BitstreamWriter &Stream) {808llvm::BCBlockRAII Scope(Stream, OBJC_METHOD_BLOCK_ID, 3);809810if (ObjCMethods.empty())811return;812813{814llvm::SmallString<4096> HashTableBlob;815uint32_t Offset;816{817llvm::OnDiskChainedHashTableGenerator<ObjCMethodTableInfo> Generator;818for (auto &OM : ObjCMethods)819Generator.insert(OM.first, OM.second);820821llvm::raw_svector_ostream BlobStream(HashTableBlob);822// Make sure that no bucket is at offset 0823llvm::support::endian::write<uint32_t>(BlobStream, 0,824llvm::endianness::little);825Offset = Generator.Emit(BlobStream);826}827828objc_method_block::ObjCMethodDataLayout ObjCMethodData(Stream);829ObjCMethodData.emit(Scratch, Offset, HashTableBlob);830}831}832833void APINotesWriter::Implementation::writeCXXMethodBlock(834llvm::BitstreamWriter &Stream) {835llvm::BCBlockRAII Scope(Stream, CXX_METHOD_BLOCK_ID, 3);836837if (CXXMethods.empty())838return;839840{841llvm::SmallString<4096> HashTableBlob;842uint32_t Offset;843{844llvm::OnDiskChainedHashTableGenerator<CXXMethodTableInfo> Generator;845for (auto &MD : CXXMethods)846Generator.insert(MD.first, MD.second);847848llvm::raw_svector_ostream BlobStream(HashTableBlob);849// Make sure that no bucket is at offset 0850llvm::support::endian::write<uint32_t>(BlobStream, 0,851llvm::endianness::little);852Offset = Generator.Emit(BlobStream);853}854855cxx_method_block::CXXMethodDataLayout CXXMethodData(Stream);856CXXMethodData.emit(Scratch, Offset, HashTableBlob);857}858}859860namespace {861/// Used to serialize the on-disk Objective-C selector table.862class ObjCSelectorTableInfo {863public:864using key_type = StoredObjCSelector;865using key_type_ref = const key_type &;866using data_type = SelectorID;867using data_type_ref = data_type;868using hash_value_type = unsigned;869using offset_type = unsigned;870871hash_value_type ComputeHash(key_type_ref Key) {872return llvm::DenseMapInfo<StoredObjCSelector>::getHashValue(Key);873}874875std::pair<unsigned, unsigned>876EmitKeyDataLength(raw_ostream &OS, key_type_ref Key, data_type_ref) {877uint32_t KeyLength =878sizeof(uint16_t) + sizeof(uint32_t) * Key.Identifiers.size();879uint32_t DataLength = sizeof(uint32_t);880881llvm::support::endian::Writer writer(OS, llvm::endianness::little);882writer.write<uint16_t>(KeyLength);883writer.write<uint16_t>(DataLength);884return {KeyLength, DataLength};885}886887void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {888llvm::support::endian::Writer writer(OS, llvm::endianness::little);889writer.write<uint16_t>(Key.NumArgs);890for (auto Identifier : Key.Identifiers)891writer.write<uint32_t>(Identifier);892}893894void EmitData(raw_ostream &OS, key_type_ref, data_type_ref Data, unsigned) {895llvm::support::endian::Writer writer(OS, llvm::endianness::little);896writer.write<uint32_t>(Data);897}898};899} // namespace900901void APINotesWriter::Implementation::writeObjCSelectorBlock(902llvm::BitstreamWriter &Stream) {903llvm::BCBlockRAII Scope(Stream, OBJC_SELECTOR_BLOCK_ID, 3);904905if (SelectorIDs.empty())906return;907908{909llvm::SmallString<4096> HashTableBlob;910uint32_t Offset;911{912llvm::OnDiskChainedHashTableGenerator<ObjCSelectorTableInfo> Generator;913for (auto &S : SelectorIDs)914Generator.insert(S.first, S.second);915916llvm::raw_svector_ostream BlobStream(HashTableBlob);917// Make sure that no bucket is at offset 0918llvm::support::endian::write<uint32_t>(BlobStream, 0,919llvm::endianness::little);920Offset = Generator.Emit(BlobStream);921}922923objc_selector_block::ObjCSelectorDataLayout ObjCSelectorData(Stream);924ObjCSelectorData.emit(Scratch, Offset, HashTableBlob);925}926}927928namespace {929/// Used to serialize the on-disk global variable table.930class GlobalVariableTableInfo931: public VersionedTableInfo<GlobalVariableTableInfo, SingleDeclTableKey,932GlobalVariableInfo> {933public:934unsigned getKeyLength(key_type_ref) {935return sizeof(uint32_t) + sizeof(uint32_t);936}937938void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {939llvm::support::endian::Writer writer(OS, llvm::endianness::little);940writer.write<uint32_t>(Key.parentContextID);941writer.write<uint32_t>(Key.nameID);942}943944hash_value_type ComputeHash(key_type_ref Key) {945return static_cast<size_t>(Key.hashValue());946}947948unsigned getUnversionedInfoSize(const GlobalVariableInfo &GVI) {949return getVariableInfoSize(GVI);950}951952void emitUnversionedInfo(raw_ostream &OS, const GlobalVariableInfo &GVI) {953emitVariableInfo(OS, GVI);954}955};956} // namespace957958void APINotesWriter::Implementation::writeGlobalVariableBlock(959llvm::BitstreamWriter &Stream) {960llvm::BCBlockRAII Scope(Stream, GLOBAL_VARIABLE_BLOCK_ID, 3);961962if (GlobalVariables.empty())963return;964965{966llvm::SmallString<4096> HashTableBlob;967uint32_t Offset;968{969llvm::OnDiskChainedHashTableGenerator<GlobalVariableTableInfo> Generator;970for (auto &GV : GlobalVariables)971Generator.insert(GV.first, GV.second);972973llvm::raw_svector_ostream BlobStream(HashTableBlob);974// Make sure that no bucket is at offset 0975llvm::support::endian::write<uint32_t>(BlobStream, 0,976llvm::endianness::little);977Offset = Generator.Emit(BlobStream);978}979980global_variable_block::GlobalVariableDataLayout GlobalVariableData(Stream);981GlobalVariableData.emit(Scratch, Offset, HashTableBlob);982}983}984985namespace {986unsigned getParamInfoSize(const ParamInfo &PI) {987return getVariableInfoSize(PI) + 1;988}989990void emitParamInfo(raw_ostream &OS, const ParamInfo &PI) {991emitVariableInfo(OS, PI);992993uint8_t flags = 0;994if (auto noescape = PI.isNoEscape()) {995flags |= 0x01;996if (*noescape)997flags |= 0x02;998}999flags <<= 3;1000if (auto RCC = PI.getRetainCountConvention())1001flags |= static_cast<uint8_t>(RCC.value()) + 1;10021003llvm::support::endian::Writer writer(OS, llvm::endianness::little);1004writer.write<uint8_t>(flags);1005}10061007/// Retrieve the serialized size of the given FunctionInfo, for use in on-disk1008/// hash tables.1009unsigned getFunctionInfoSize(const FunctionInfo &FI) {1010unsigned size = getCommonEntityInfoSize(FI) + 2 + sizeof(uint64_t);1011size += sizeof(uint16_t);1012for (const auto &P : FI.Params)1013size += getParamInfoSize(P);1014size += sizeof(uint16_t) + FI.ResultType.size();1015return size;1016}10171018/// Emit a serialized representation of the function information.1019void emitFunctionInfo(raw_ostream &OS, const FunctionInfo &FI) {1020emitCommonEntityInfo(OS, FI);10211022uint8_t flags = 0;1023flags |= FI.NullabilityAudited;1024flags <<= 3;1025if (auto RCC = FI.getRetainCountConvention())1026flags |= static_cast<uint8_t>(RCC.value()) + 1;10271028llvm::support::endian::Writer writer(OS, llvm::endianness::little);10291030writer.write<uint8_t>(flags);1031writer.write<uint8_t>(FI.NumAdjustedNullable);1032writer.write<uint64_t>(FI.NullabilityPayload);10331034writer.write<uint16_t>(FI.Params.size());1035for (const auto &PI : FI.Params)1036emitParamInfo(OS, PI);10371038writer.write<uint16_t>(FI.ResultType.size());1039writer.write(ArrayRef<char>{FI.ResultType.data(), FI.ResultType.size()});1040}10411042/// Used to serialize the on-disk global function table.1043class GlobalFunctionTableInfo1044: public VersionedTableInfo<GlobalFunctionTableInfo, SingleDeclTableKey,1045GlobalFunctionInfo> {1046public:1047unsigned getKeyLength(key_type_ref) {1048return sizeof(uint32_t) + sizeof(uint32_t);1049}10501051void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {1052llvm::support::endian::Writer writer(OS, llvm::endianness::little);1053writer.write<uint32_t>(Key.parentContextID);1054writer.write<uint32_t>(Key.nameID);1055}10561057hash_value_type ComputeHash(key_type_ref Key) {1058return static_cast<size_t>(Key.hashValue());1059}10601061unsigned getUnversionedInfoSize(const GlobalFunctionInfo &GFI) {1062return getFunctionInfoSize(GFI);1063}10641065void emitUnversionedInfo(raw_ostream &OS, const GlobalFunctionInfo &GFI) {1066emitFunctionInfo(OS, GFI);1067}1068};1069} // namespace10701071void APINotesWriter::Implementation::writeGlobalFunctionBlock(1072llvm::BitstreamWriter &Stream) {1073llvm::BCBlockRAII Scope(Stream, GLOBAL_FUNCTION_BLOCK_ID, 3);10741075if (GlobalFunctions.empty())1076return;10771078{1079llvm::SmallString<4096> HashTableBlob;1080uint32_t Offset;1081{1082llvm::OnDiskChainedHashTableGenerator<GlobalFunctionTableInfo> Generator;1083for (auto &F : GlobalFunctions)1084Generator.insert(F.first, F.second);10851086llvm::raw_svector_ostream BlobStream(HashTableBlob);1087// Make sure that no bucket is at offset 01088llvm::support::endian::write<uint32_t>(BlobStream, 0,1089llvm::endianness::little);1090Offset = Generator.Emit(BlobStream);1091}10921093global_function_block::GlobalFunctionDataLayout GlobalFunctionData(Stream);1094GlobalFunctionData.emit(Scratch, Offset, HashTableBlob);1095}1096}10971098namespace {1099/// Used to serialize the on-disk global enum constant.1100class EnumConstantTableInfo1101: public VersionedTableInfo<EnumConstantTableInfo, unsigned,1102EnumConstantInfo> {1103public:1104unsigned getKeyLength(key_type_ref) { return sizeof(uint32_t); }11051106void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {1107llvm::support::endian::Writer writer(OS, llvm::endianness::little);1108writer.write<uint32_t>(Key);1109}11101111hash_value_type ComputeHash(key_type_ref Key) {1112return static_cast<size_t>(llvm::hash_value(Key));1113}11141115unsigned getUnversionedInfoSize(const EnumConstantInfo &ECI) {1116return getCommonEntityInfoSize(ECI);1117}11181119void emitUnversionedInfo(raw_ostream &OS, const EnumConstantInfo &ECI) {1120emitCommonEntityInfo(OS, ECI);1121}1122};1123} // namespace11241125void APINotesWriter::Implementation::writeEnumConstantBlock(1126llvm::BitstreamWriter &Stream) {1127llvm::BCBlockRAII Scope(Stream, ENUM_CONSTANT_BLOCK_ID, 3);11281129if (EnumConstants.empty())1130return;11311132{1133llvm::SmallString<4096> HashTableBlob;1134uint32_t Offset;1135{1136llvm::OnDiskChainedHashTableGenerator<EnumConstantTableInfo> Generator;1137for (auto &EC : EnumConstants)1138Generator.insert(EC.first, EC.second);11391140llvm::raw_svector_ostream BlobStream(HashTableBlob);1141// Make sure that no bucket is at offset 01142llvm::support::endian::write<uint32_t>(BlobStream, 0,1143llvm::endianness::little);1144Offset = Generator.Emit(BlobStream);1145}11461147enum_constant_block::EnumConstantDataLayout EnumConstantData(Stream);1148EnumConstantData.emit(Scratch, Offset, HashTableBlob);1149}1150}11511152namespace {1153template <typename Derived, typename UnversionedDataType>1154class CommonTypeTableInfo1155: public VersionedTableInfo<Derived, SingleDeclTableKey,1156UnversionedDataType> {1157public:1158using key_type_ref = typename CommonTypeTableInfo::key_type_ref;1159using hash_value_type = typename CommonTypeTableInfo::hash_value_type;11601161unsigned getKeyLength(key_type_ref) {1162return sizeof(uint32_t) + sizeof(IdentifierID);1163}11641165void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {1166llvm::support::endian::Writer writer(OS, llvm::endianness::little);1167writer.write<uint32_t>(Key.parentContextID);1168writer.write<IdentifierID>(Key.nameID);1169}11701171hash_value_type ComputeHash(key_type_ref Key) {1172return static_cast<size_t>(Key.hashValue());1173}11741175unsigned getUnversionedInfoSize(const UnversionedDataType &UDT) {1176return getCommonTypeInfoSize(UDT);1177}11781179void emitUnversionedInfo(raw_ostream &OS, const UnversionedDataType &UDT) {1180emitCommonTypeInfo(OS, UDT);1181}1182};11831184/// Used to serialize the on-disk tag table.1185class TagTableInfo : public CommonTypeTableInfo<TagTableInfo, TagInfo> {1186public:1187unsigned getUnversionedInfoSize(const TagInfo &TI) {1188return 2 + (TI.SwiftImportAs ? TI.SwiftImportAs->size() : 0) +11892 + (TI.SwiftRetainOp ? TI.SwiftRetainOp->size() : 0) +11902 + (TI.SwiftReleaseOp ? TI.SwiftReleaseOp->size() : 0) +11912 + getCommonTypeInfoSize(TI);1192}11931194void emitUnversionedInfo(raw_ostream &OS, const TagInfo &TI) {1195llvm::support::endian::Writer writer(OS, llvm::endianness::little);11961197uint8_t Flags = 0;1198if (auto extensibility = TI.EnumExtensibility) {1199Flags |= static_cast<uint8_t>(extensibility.value()) + 1;1200assert((Flags < (1 << 2)) && "must fit in two bits");1201}12021203Flags <<= 2;1204if (auto value = TI.isFlagEnum())1205Flags |= (value.value() << 1 | 1 << 0);12061207writer.write<uint8_t>(Flags);12081209if (auto Copyable = TI.isSwiftCopyable())1210writer.write<uint8_t>(*Copyable ? kSwiftCopyable : kSwiftNonCopyable);1211else1212writer.write<uint8_t>(0);12131214if (auto ImportAs = TI.SwiftImportAs) {1215writer.write<uint16_t>(ImportAs->size() + 1);1216OS.write(ImportAs->c_str(), ImportAs->size());1217} else {1218writer.write<uint16_t>(0);1219}1220if (auto RetainOp = TI.SwiftRetainOp) {1221writer.write<uint16_t>(RetainOp->size() + 1);1222OS.write(RetainOp->c_str(), RetainOp->size());1223} else {1224writer.write<uint16_t>(0);1225}1226if (auto ReleaseOp = TI.SwiftReleaseOp) {1227writer.write<uint16_t>(ReleaseOp->size() + 1);1228OS.write(ReleaseOp->c_str(), ReleaseOp->size());1229} else {1230writer.write<uint16_t>(0);1231}12321233emitCommonTypeInfo(OS, TI);1234}1235};1236} // namespace12371238void APINotesWriter::Implementation::writeTagBlock(1239llvm::BitstreamWriter &Stream) {1240llvm::BCBlockRAII Scope(Stream, TAG_BLOCK_ID, 3);12411242if (Tags.empty())1243return;12441245{1246llvm::SmallString<4096> HashTableBlob;1247uint32_t Offset;1248{1249llvm::OnDiskChainedHashTableGenerator<TagTableInfo> Generator;1250for (auto &T : Tags)1251Generator.insert(T.first, T.second);12521253llvm::raw_svector_ostream BlobStream(HashTableBlob);1254// Make sure that no bucket is at offset 01255llvm::support::endian::write<uint32_t>(BlobStream, 0,1256llvm::endianness::little);1257Offset = Generator.Emit(BlobStream);1258}12591260tag_block::TagDataLayout TagData(Stream);1261TagData.emit(Scratch, Offset, HashTableBlob);1262}1263}12641265namespace {1266/// Used to serialize the on-disk typedef table.1267class TypedefTableInfo1268: public CommonTypeTableInfo<TypedefTableInfo, TypedefInfo> {1269public:1270unsigned getUnversionedInfoSize(const TypedefInfo &TI) {1271return 1 + getCommonTypeInfoSize(TI);1272}12731274void emitUnversionedInfo(raw_ostream &OS, const TypedefInfo &TI) {1275llvm::support::endian::Writer writer(OS, llvm::endianness::little);12761277uint8_t Flags = 0;1278if (auto swiftWrapper = TI.SwiftWrapper)1279Flags |= static_cast<uint8_t>(*swiftWrapper) + 1;12801281writer.write<uint8_t>(Flags);12821283emitCommonTypeInfo(OS, TI);1284}1285};1286} // namespace12871288void APINotesWriter::Implementation::writeTypedefBlock(1289llvm::BitstreamWriter &Stream) {1290llvm::BCBlockRAII Scope(Stream, TYPEDEF_BLOCK_ID, 3);12911292if (Typedefs.empty())1293return;12941295{1296llvm::SmallString<4096> HashTableBlob;1297uint32_t Offset;1298{1299llvm::OnDiskChainedHashTableGenerator<TypedefTableInfo> Generator;1300for (auto &T : Typedefs)1301Generator.insert(T.first, T.second);13021303llvm::raw_svector_ostream BlobStream(HashTableBlob);1304// Make sure that no bucket is at offset 01305llvm::support::endian::write<uint32_t>(BlobStream, 0,1306llvm::endianness::little);1307Offset = Generator.Emit(BlobStream);1308}13091310typedef_block::TypedefDataLayout TypedefData(Stream);1311TypedefData.emit(Scratch, Offset, HashTableBlob);1312}1313}13141315// APINotesWriter13161317APINotesWriter::APINotesWriter(llvm::StringRef ModuleName, const FileEntry *SF)1318: Implementation(new class Implementation(ModuleName, SF)) {}13191320APINotesWriter::~APINotesWriter() = default;13211322void APINotesWriter::writeToStream(llvm::raw_ostream &OS) {1323Implementation->writeToStream(OS);1324}13251326ContextID APINotesWriter::addContext(std::optional<ContextID> ParentCtxID,1327llvm::StringRef Name, ContextKind Kind,1328const ContextInfo &Info,1329llvm::VersionTuple SwiftVersion) {1330IdentifierID NameID = Implementation->getIdentifier(Name);13311332uint32_t RawParentCtxID = ParentCtxID ? ParentCtxID->Value : -1;1333ContextTableKey Key(RawParentCtxID, static_cast<uint8_t>(Kind), NameID);1334auto Known = Implementation->Contexts.find(Key);1335if (Known == Implementation->Contexts.end()) {1336unsigned NextID = Implementation->Contexts.size() + 1;13371338Implementation::VersionedSmallVector<ContextInfo> EmptyVersionedInfo;1339Known = Implementation->Contexts1340.insert(std::make_pair(1341Key, std::make_pair(NextID, EmptyVersionedInfo)))1342.first;13431344Implementation->ContextNames[NextID] = NameID;1345Implementation->ParentContexts[NextID] = RawParentCtxID;1346}13471348// Add this version information.1349auto &VersionedVec = Known->second.second;1350bool Found = false;1351for (auto &Versioned : VersionedVec) {1352if (Versioned.first == SwiftVersion) {1353Versioned.second |= Info;1354Found = true;1355break;1356}1357}13581359if (!Found)1360VersionedVec.push_back({SwiftVersion, Info});13611362return ContextID(Known->second.first);1363}13641365void APINotesWriter::addObjCProperty(ContextID CtxID, StringRef Name,1366bool IsInstanceProperty,1367const ObjCPropertyInfo &Info,1368VersionTuple SwiftVersion) {1369IdentifierID NameID = Implementation->getIdentifier(Name);1370Implementation1371->ObjCProperties[std::make_tuple(CtxID.Value, NameID, IsInstanceProperty)]1372.push_back({SwiftVersion, Info});1373}13741375void APINotesWriter::addObjCMethod(ContextID CtxID, ObjCSelectorRef Selector,1376bool IsInstanceMethod,1377const ObjCMethodInfo &Info,1378VersionTuple SwiftVersion) {1379SelectorID SelID = Implementation->getSelector(Selector);1380auto Key = std::tuple<unsigned, unsigned, char>{CtxID.Value, SelID,1381IsInstanceMethod};1382Implementation->ObjCMethods[Key].push_back({SwiftVersion, Info});13831384// If this method is a designated initializer, update the class to note that1385// it has designated initializers.1386if (Info.DesignatedInit) {1387assert(Implementation->ParentContexts.contains(CtxID.Value));1388uint32_t ParentCtxID = Implementation->ParentContexts[CtxID.Value];1389ContextTableKey CtxKey(ParentCtxID,1390static_cast<uint8_t>(ContextKind::ObjCClass),1391Implementation->ContextNames[CtxID.Value]);1392assert(Implementation->Contexts.contains(CtxKey));1393auto &VersionedVec = Implementation->Contexts[CtxKey].second;1394bool Found = false;1395for (auto &Versioned : VersionedVec) {1396if (Versioned.first == SwiftVersion) {1397Versioned.second.setHasDesignatedInits(true);1398Found = true;1399break;1400}1401}14021403if (!Found) {1404VersionedVec.push_back({SwiftVersion, ContextInfo()});1405VersionedVec.back().second.setHasDesignatedInits(true);1406}1407}1408}14091410void APINotesWriter::addCXXMethod(ContextID CtxID, llvm::StringRef Name,1411const CXXMethodInfo &Info,1412VersionTuple SwiftVersion) {1413IdentifierID NameID = Implementation->getIdentifier(Name);1414SingleDeclTableKey Key(CtxID.Value, NameID);1415Implementation->CXXMethods[Key].push_back({SwiftVersion, Info});1416}14171418void APINotesWriter::addGlobalVariable(std::optional<Context> Ctx,1419llvm::StringRef Name,1420const GlobalVariableInfo &Info,1421VersionTuple SwiftVersion) {1422IdentifierID VariableID = Implementation->getIdentifier(Name);1423SingleDeclTableKey Key(Ctx, VariableID);1424Implementation->GlobalVariables[Key].push_back({SwiftVersion, Info});1425}14261427void APINotesWriter::addGlobalFunction(std::optional<Context> Ctx,1428llvm::StringRef Name,1429const GlobalFunctionInfo &Info,1430VersionTuple SwiftVersion) {1431IdentifierID NameID = Implementation->getIdentifier(Name);1432SingleDeclTableKey Key(Ctx, NameID);1433Implementation->GlobalFunctions[Key].push_back({SwiftVersion, Info});1434}14351436void APINotesWriter::addEnumConstant(llvm::StringRef Name,1437const EnumConstantInfo &Info,1438VersionTuple SwiftVersion) {1439IdentifierID EnumConstantID = Implementation->getIdentifier(Name);1440Implementation->EnumConstants[EnumConstantID].push_back({SwiftVersion, Info});1441}14421443void APINotesWriter::addTag(std::optional<Context> Ctx, llvm::StringRef Name,1444const TagInfo &Info, VersionTuple SwiftVersion) {1445IdentifierID TagID = Implementation->getIdentifier(Name);1446SingleDeclTableKey Key(Ctx, TagID);1447Implementation->Tags[Key].push_back({SwiftVersion, Info});1448}14491450void APINotesWriter::addTypedef(std::optional<Context> Ctx,1451llvm::StringRef Name, const TypedefInfo &Info,1452VersionTuple SwiftVersion) {1453IdentifierID TypedefID = Implementation->getIdentifier(Name);1454SingleDeclTableKey Key(Ctx, TypedefID);1455Implementation->Typedefs[Key].push_back({SwiftVersion, Info});1456}1457} // namespace api_notes1458} // namespace clang145914601461