//===-- APINotesWriter.cpp - API Notes Writer -------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "clang/APINotes/APINotesWriter.h"
#include "APINotesFormat.h"
#include "clang/APINotes/Types.h"
#include "clang/Basic/FileManager.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Bitstream/BitstreamWriter.h"
#include "llvm/Support/DJB.h"
#include "llvm/Support/OnDiskHashTable.h"
#include "llvm/Support/VersionTuple.h"

namespace clang {
namespace api_notes {
class APINotesWriter::Implementation {
  friend class APINotesWriter;

  template <typename T>
  using VersionedSmallVector =
      llvm::SmallVector<std::pair<llvm::VersionTuple, T>, 1>;

  std::string ModuleName;
  const FileEntry *SourceFile;

  /// Scratch space for bitstream writing.
  llvm::SmallVector<uint64_t, 64> Scratch;

  /// Mapping from strings to identifier IDs.
  llvm::StringMap<IdentifierID> IdentifierIDs;

  /// Information about contexts (Objective-C classes or protocols or C++
  /// namespaces).
  ///
  /// Indexed by the parent context ID, context kind and the identifier ID of
  /// this context and provides both the context ID and information describing
  /// the context within that module.
  llvm::DenseMap<ContextTableKey,
                 std::pair<unsigned, VersionedSmallVector<ObjCContextInfo>>>
      ObjCContexts;

  /// Information about parent contexts for each context.
  ///
  /// Indexed by context ID, provides the parent context ID.
  llvm::DenseMap<uint32_t, uint32_t> ParentContexts;

  /// Mapping from context IDs to the identifier ID holding the name.
  llvm::DenseMap<unsigned, unsigned> ObjCContextNames;

  /// Information about Objective-C properties.
  ///
  /// Indexed by the context ID, property name, and whether this is an
  /// instance property.
  llvm::DenseMap<
      std::tuple<unsigned, unsigned, char>,
      llvm::SmallVector<std::pair<VersionTuple, ObjCPropertyInfo>, 1>>
      ObjCProperties;

  /// Information about Objective-C methods.
  ///
  /// Indexed by the context ID, selector ID, and Boolean (stored as a char)
  /// indicating whether this is a class or instance method.
  llvm::DenseMap<std::tuple<unsigned, unsigned, char>,
                 llvm::SmallVector<std::pair<VersionTuple, ObjCMethodInfo>, 1>>
      ObjCMethods;

  /// Mapping from selectors to selector ID.
  llvm::DenseMap<StoredObjCSelector, SelectorID> SelectorIDs;

  /// Information about global variables.
  ///
  /// Indexed by the context ID, contextKind, identifier ID.
  llvm::DenseMap<
      ContextTableKey,
      llvm::SmallVector<std::pair<VersionTuple, GlobalVariableInfo>, 1>>
      GlobalVariables;

  /// Information about global functions.
  ///
  /// Indexed by the context ID, contextKind, identifier ID.
  llvm::DenseMap<
      ContextTableKey,
      llvm::SmallVector<std::pair<VersionTuple, GlobalFunctionInfo>, 1>>
      GlobalFunctions;

  /// Information about enumerators.
  ///
  /// Indexed by the identifier ID.
  llvm::DenseMap<
      unsigned, llvm::SmallVector<std::pair<VersionTuple, EnumConstantInfo>, 1>>
      EnumConstants;

  /// Information about tags.
  ///
  /// Indexed by the context ID, contextKind, identifier ID.
  llvm::DenseMap<ContextTableKey,
                 llvm::SmallVector<std::pair<VersionTuple, TagInfo>, 1>>
      Tags;

  /// Information about typedefs.
  ///
  /// Indexed by the context ID, contextKind, identifier ID.
  llvm::DenseMap<ContextTableKey,
                 llvm::SmallVector<std::pair<VersionTuple, TypedefInfo>, 1>>
      Typedefs;

  /// Retrieve the ID for the given identifier.
  IdentifierID getIdentifier(StringRef Identifier) {
    if (Identifier.empty())
      return 0;

    auto Known = IdentifierIDs.find(Identifier);
    if (Known != IdentifierIDs.end())
      return Known->second;

    // Add to the identifier table.
    Known = IdentifierIDs.insert({Identifier, IdentifierIDs.size() + 1}).first;
    return Known->second;
  }

  /// Retrieve the ID for the given selector.
  SelectorID getSelector(ObjCSelectorRef SelectorRef) {
    // Translate the selector reference into a stored selector.
    StoredObjCSelector Selector;
    Selector.NumArgs = SelectorRef.NumArgs;
    Selector.Identifiers.reserve(SelectorRef.Identifiers.size());
    for (auto piece : SelectorRef.Identifiers)
      Selector.Identifiers.push_back(getIdentifier(piece));

    // Look for the stored selector.
    auto Known = SelectorIDs.find(Selector);
    if (Known != SelectorIDs.end())
      return Known->second;

    // Add to the selector table.
    Known = SelectorIDs.insert({Selector, SelectorIDs.size()}).first;
    return Known->second;
  }

private:
  void writeBlockInfoBlock(llvm::BitstreamWriter &Stream);
  void writeControlBlock(llvm::BitstreamWriter &Stream);
  void writeIdentifierBlock(llvm::BitstreamWriter &Stream);
  void writeObjCContextBlock(llvm::BitstreamWriter &Stream);
  void writeObjCPropertyBlock(llvm::BitstreamWriter &Stream);
  void writeObjCMethodBlock(llvm::BitstreamWriter &Stream);
  void writeObjCSelectorBlock(llvm::BitstreamWriter &Stream);
  void writeGlobalVariableBlock(llvm::BitstreamWriter &Stream);
  void writeGlobalFunctionBlock(llvm::BitstreamWriter &Stream);
  void writeEnumConstantBlock(llvm::BitstreamWriter &Stream);
  void writeTagBlock(llvm::BitstreamWriter &Stream);
  void writeTypedefBlock(llvm::BitstreamWriter &Stream);

public:
  Implementation(llvm::StringRef ModuleName, const FileEntry *SF)
      : ModuleName(std::string(ModuleName)), SourceFile(SF) {}

  void writeToStream(llvm::raw_ostream &OS);
};

void APINotesWriter::Implementation::writeToStream(llvm::raw_ostream &OS) {
  llvm::SmallVector<char, 0> Buffer;

  {
    llvm::BitstreamWriter Stream(Buffer);

    // Emit the signature.
    for (unsigned char Byte : API_NOTES_SIGNATURE)
      Stream.Emit(Byte, 8);

    // Emit the blocks.
    writeBlockInfoBlock(Stream);
    writeControlBlock(Stream);
    writeIdentifierBlock(Stream);
    writeObjCContextBlock(Stream);
    writeObjCPropertyBlock(Stream);
    writeObjCMethodBlock(Stream);
    writeObjCSelectorBlock(Stream);
    writeGlobalVariableBlock(Stream);
    writeGlobalFunctionBlock(Stream);
    writeEnumConstantBlock(Stream);
    writeTagBlock(Stream);
    writeTypedefBlock(Stream);
  }

  OS.write(Buffer.data(), Buffer.size());
  OS.flush();
}

namespace {
/// Record the name of a block.
void emitBlockID(llvm::BitstreamWriter &Stream, unsigned ID,
                 llvm::StringRef Name) {
  Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID,
                    llvm::ArrayRef<unsigned>{ID});

  // Emit the block name if present.
  if (Name.empty())
    return;
  Stream.EmitRecord(
      llvm::bitc::BLOCKINFO_CODE_BLOCKNAME,
      llvm::ArrayRef<unsigned char>(
          const_cast<unsigned char *>(
              reinterpret_cast<const unsigned char *>(Name.data())),
          Name.size()));
}

/// Record the name of a record within a block.
void emitRecordID(llvm::BitstreamWriter &Stream, unsigned ID,
                  llvm::StringRef Name) {
  assert(ID < 256 && "can't fit record ID in next to name");

  llvm::SmallVector<unsigned char, 64> Buffer;
  Buffer.resize(Name.size() + 1);
  Buffer[0] = ID;
  memcpy(Buffer.data() + 1, Name.data(), Name.size());

  Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Buffer);
}
} // namespace

void APINotesWriter::Implementation::writeBlockInfoBlock(
    llvm::BitstreamWriter &Stream) {
  llvm::BCBlockRAII Scope(Stream, llvm::bitc::BLOCKINFO_BLOCK_ID, 2);

#define BLOCK(Block) emitBlockID(Stream, Block##_ID, #Block)
#define BLOCK_RECORD(NameSpace, Block)                                         \
  emitRecordID(Stream, NameSpace::Block, #Block)
  BLOCK(CONTROL_BLOCK);
  BLOCK_RECORD(control_block, METADATA);
  BLOCK_RECORD(control_block, MODULE_NAME);

  BLOCK(IDENTIFIER_BLOCK);
  BLOCK_RECORD(identifier_block, IDENTIFIER_DATA);

  BLOCK(OBJC_CONTEXT_BLOCK);
  BLOCK_RECORD(objc_context_block, OBJC_CONTEXT_ID_DATA);

  BLOCK(OBJC_PROPERTY_BLOCK);
  BLOCK_RECORD(objc_property_block, OBJC_PROPERTY_DATA);

  BLOCK(OBJC_METHOD_BLOCK);
  BLOCK_RECORD(objc_method_block, OBJC_METHOD_DATA);

  BLOCK(OBJC_SELECTOR_BLOCK);
  BLOCK_RECORD(objc_selector_block, OBJC_SELECTOR_DATA);

  BLOCK(GLOBAL_VARIABLE_BLOCK);
  BLOCK_RECORD(global_variable_block, GLOBAL_VARIABLE_DATA);

  BLOCK(GLOBAL_FUNCTION_BLOCK);
  BLOCK_RECORD(global_function_block, GLOBAL_FUNCTION_DATA);
#undef BLOCK_RECORD
#undef BLOCK
}

void APINotesWriter::Implementation::writeControlBlock(
    llvm::BitstreamWriter &Stream) {
  llvm::BCBlockRAII Scope(Stream, CONTROL_BLOCK_ID, 3);

  control_block::MetadataLayout Metadata(Stream);
  Metadata.emit(Scratch, VERSION_MAJOR, VERSION_MINOR);

  control_block::ModuleNameLayout ModuleName(Stream);
  ModuleName.emit(Scratch, this->ModuleName);

  if (SourceFile) {
    control_block::SourceFileLayout SourceFile(Stream);
    SourceFile.emit(Scratch, this->SourceFile->getSize(),
                    this->SourceFile->getModificationTime());
  }
}

namespace {
/// Used to serialize the on-disk identifier table.
class IdentifierTableInfo {
public:
  using key_type = StringRef;
  using key_type_ref = key_type;
  using data_type = IdentifierID;
  using data_type_ref = const data_type &;
  using hash_value_type = uint32_t;
  using offset_type = unsigned;

  hash_value_type ComputeHash(key_type_ref Key) { return llvm::djbHash(Key); }

  std::pair<unsigned, unsigned>
  EmitKeyDataLength(raw_ostream &OS, key_type_ref Key, data_type_ref) {
    uint32_t KeyLength = Key.size();
    uint32_t DataLength = sizeof(uint32_t);

    llvm::support::endian::Writer writer(OS, llvm::endianness::little);
    writer.write<uint16_t>(KeyLength);
    writer.write<uint16_t>(DataLength);
    return {KeyLength, DataLength};
  }

  void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) { OS << Key; }

  void EmitData(raw_ostream &OS, key_type_ref, data_type_ref Data, unsigned) {
    llvm::support::endian::Writer writer(OS, llvm::endianness::little);
    writer.write<uint32_t>(Data);
  }
};
} // namespace

void APINotesWriter::Implementation::writeIdentifierBlock(
    llvm::BitstreamWriter &Stream) {
  llvm::BCBlockRAII restoreBlock(Stream, IDENTIFIER_BLOCK_ID, 3);

  if (IdentifierIDs.empty())
    return;

  llvm::SmallString<4096> HashTableBlob;
  uint32_t Offset;
  {
    llvm::OnDiskChainedHashTableGenerator<IdentifierTableInfo> Generator;
    for (auto &II : IdentifierIDs)
      Generator.insert(II.first(), II.second);

    llvm::raw_svector_ostream BlobStream(HashTableBlob);
    // Make sure that no bucket is at offset 0
    llvm::support::endian::write<uint32_t>(BlobStream, 0,
                                           llvm::endianness::little);
    Offset = Generator.Emit(BlobStream);
  }

  identifier_block::IdentifierDataLayout IdentifierData(Stream);
  IdentifierData.emit(Scratch, Offset, HashTableBlob);
}

namespace {
/// Used to serialize the on-disk Objective-C context table.
class ObjCContextIDTableInfo {
public:
  using key_type = ContextTableKey;
  using key_type_ref = key_type;
  using data_type = unsigned;
  using data_type_ref = const data_type &;
  using hash_value_type = size_t;
  using offset_type = unsigned;

  hash_value_type ComputeHash(key_type_ref Key) {
    return static_cast<size_t>(Key.hashValue());
  }

  std::pair<unsigned, unsigned> EmitKeyDataLength(raw_ostream &OS, key_type_ref,
                                                  data_type_ref) {
    uint32_t KeyLength = sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint32_t);
    uint32_t DataLength = sizeof(uint32_t);

    llvm::support::endian::Writer writer(OS, llvm::endianness::little);
    writer.write<uint16_t>(KeyLength);
    writer.write<uint16_t>(DataLength);
    return {KeyLength, DataLength};
  }

  void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
    llvm::support::endian::Writer writer(OS, llvm::endianness::little);
    writer.write<uint32_t>(Key.parentContextID);
    writer.write<uint8_t>(Key.contextKind);
    writer.write<uint32_t>(Key.contextID);
  }

  void EmitData(raw_ostream &OS, key_type_ref, data_type_ref Data, unsigned) {
    llvm::support::endian::Writer writer(OS, llvm::endianness::little);
    writer.write<uint32_t>(Data);
  }
};

/// Localized helper to make a type dependent, thwarting template argument
/// deduction.
template <typename T> struct MakeDependent { typedef T Type; };

/// Retrieve the serialized size of the given VersionTuple, for use in
/// on-disk hash tables.
unsigned getVersionTupleSize(const VersionTuple &VT) {
  unsigned size = sizeof(uint8_t) + /*major*/ sizeof(uint32_t);
  if (VT.getMinor())
    size += sizeof(uint32_t);
  if (VT.getSubminor())
    size += sizeof(uint32_t);
  if (VT.getBuild())
    size += sizeof(uint32_t);
  return size;
}

/// Determine the size of an array of versioned information,
template <typename T>
unsigned getVersionedInfoSize(
    const llvm::SmallVectorImpl<std::pair<llvm::VersionTuple, T>> &VI,
    llvm::function_ref<unsigned(const typename MakeDependent<T>::Type &)>
        getInfoSize) {
  unsigned result = sizeof(uint16_t); // # of elements
  for (const auto &E : VI) {
    result += getVersionTupleSize(E.first);
    result += getInfoSize(E.second);
  }
  return result;
}

/// Emit a serialized representation of a version tuple.
void emitVersionTuple(raw_ostream &OS, const VersionTuple &VT) {
  llvm::support::endian::Writer writer(OS, llvm::endianness::little);

  // First byte contains the number of components beyond the 'major' component.
  uint8_t descriptor;
  if (VT.getBuild())
    descriptor = 3;
  else if (VT.getSubminor())
    descriptor = 2;
  else if (VT.getMinor())
    descriptor = 1;
  else
    descriptor = 0;
  writer.write<uint8_t>(descriptor);

  // Write the components.
  writer.write<uint32_t>(VT.getMajor());
  if (auto minor = VT.getMinor())
    writer.write<uint32_t>(*minor);
  if (auto subminor = VT.getSubminor())
    writer.write<uint32_t>(*subminor);
  if (auto build = VT.getBuild())
    writer.write<uint32_t>(*build);
}

/// Emit versioned information.
template <typename T>
void emitVersionedInfo(
    raw_ostream &OS, llvm::SmallVectorImpl<std::pair<VersionTuple, T>> &VI,
    llvm::function_ref<void(raw_ostream &,
                            const typename MakeDependent<T>::Type &)>
        emitInfo) {
  std::sort(VI.begin(), VI.end(),
            [](const std::pair<VersionTuple, T> &LHS,
               const std::pair<VersionTuple, T> &RHS) -> bool {
              assert((&LHS == &RHS || LHS.first != RHS.first) &&
                     "two entries for the same version");
              return LHS.first < RHS.first;
            });

  llvm::support::endian::Writer writer(OS, llvm::endianness::little);
  writer.write<uint16_t>(VI.size());
  for (const auto &E : VI) {
    emitVersionTuple(OS, E.first);
    emitInfo(OS, E.second);
  }
}

/// On-disk hash table info key base for handling versioned data.
template <typename Derived, typename KeyType, typename UnversionedDataType>
class VersionedTableInfo {
  Derived &asDerived() { return *static_cast<Derived *>(this); }

  const Derived &asDerived() const {
    return *static_cast<const Derived *>(this);
  }

public:
  using key_type = KeyType;
  using key_type_ref = key_type;
  using data_type =
      llvm::SmallVector<std::pair<llvm::VersionTuple, UnversionedDataType>, 1>;
  using data_type_ref = data_type &;
  using hash_value_type = size_t;
  using offset_type = unsigned;

  std::pair<unsigned, unsigned>
  EmitKeyDataLength(raw_ostream &OS, key_type_ref Key, data_type_ref Data) {
    uint32_t KeyLength = asDerived().getKeyLength(Key);
    uint32_t DataLength =
        getVersionedInfoSize(Data, [this](const UnversionedDataType &UI) {
          return asDerived().getUnversionedInfoSize(UI);
        });

    llvm::support::endian::Writer writer(OS, llvm::endianness::little);
    writer.write<uint16_t>(KeyLength);
    writer.write<uint16_t>(DataLength);
    return {KeyLength, DataLength};
  }

  void EmitData(raw_ostream &OS, key_type_ref, data_type_ref Data, unsigned) {
    emitVersionedInfo(
        OS, Data, [this](llvm::raw_ostream &OS, const UnversionedDataType &UI) {
          asDerived().emitUnversionedInfo(OS, UI);
        });
  }
};

/// Emit a serialized representation of the common entity information.
void emitCommonEntityInfo(raw_ostream &OS, const CommonEntityInfo &CEI) {
  llvm::support::endian::Writer writer(OS, llvm::endianness::little);

  uint8_t payload = 0;
  if (auto swiftPrivate = CEI.isSwiftPrivate()) {
    payload |= 0x01;
    if (*swiftPrivate)
      payload |= 0x02;
  }
  payload <<= 1;
  payload |= CEI.Unavailable;
  payload <<= 1;
  payload |= CEI.UnavailableInSwift;

  writer.write<uint8_t>(payload);

  writer.write<uint16_t>(CEI.UnavailableMsg.size());
  OS.write(CEI.UnavailableMsg.c_str(), CEI.UnavailableMsg.size());

  writer.write<uint16_t>(CEI.SwiftName.size());
  OS.write(CEI.SwiftName.c_str(), CEI.SwiftName.size());
}

/// Retrieve the serialized size of the given CommonEntityInfo, for use in
/// on-disk hash tables.
unsigned getCommonEntityInfoSize(const CommonEntityInfo &CEI) {
  return 5 + CEI.UnavailableMsg.size() + CEI.SwiftName.size();
}

// Retrieve the serialized size of the given CommonTypeInfo, for use
// in on-disk hash tables.
unsigned getCommonTypeInfoSize(const CommonTypeInfo &CTI) {
  return 2 + (CTI.getSwiftBridge() ? CTI.getSwiftBridge()->size() : 0) + 2 +
         (CTI.getNSErrorDomain() ? CTI.getNSErrorDomain()->size() : 0) +
         getCommonEntityInfoSize(CTI);
}

/// Emit a serialized representation of the common type information.
void emitCommonTypeInfo(raw_ostream &OS, const CommonTypeInfo &CTI) {
  emitCommonEntityInfo(OS, CTI);

  llvm::support::endian::Writer writer(OS, llvm::endianness::little);
  if (auto swiftBridge = CTI.getSwiftBridge()) {
    writer.write<uint16_t>(swiftBridge->size() + 1);
    OS.write(swiftBridge->c_str(), swiftBridge->size());
  } else {
    writer.write<uint16_t>(0);
  }
  if (auto nsErrorDomain = CTI.getNSErrorDomain()) {
    writer.write<uint16_t>(nsErrorDomain->size() + 1);
    OS.write(nsErrorDomain->c_str(), CTI.getNSErrorDomain()->size());
  } else {
    writer.write<uint16_t>(0);
  }
}

/// Used to serialize the on-disk Objective-C property table.
class ObjCContextInfoTableInfo
    : public VersionedTableInfo<ObjCContextInfoTableInfo, unsigned,
                                ObjCContextInfo> {
public:
  unsigned getKeyLength(key_type_ref) { return sizeof(uint32_t); }

  void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
    llvm::support::endian::Writer writer(OS, llvm::endianness::little);
    writer.write<uint32_t>(Key);
  }

  hash_value_type ComputeHash(key_type_ref Key) {
    return static_cast<size_t>(llvm::hash_value(Key));
  }

  unsigned getUnversionedInfoSize(const ObjCContextInfo &OCI) {
    return getCommonTypeInfoSize(OCI) + 1;
  }

  void emitUnversionedInfo(raw_ostream &OS, const ObjCContextInfo &OCI) {
    emitCommonTypeInfo(OS, OCI);

    uint8_t payload = 0;
    if (auto swiftImportAsNonGeneric = OCI.getSwiftImportAsNonGeneric())
      payload |= (0x01 << 1) | (uint8_t)swiftImportAsNonGeneric.value();
    payload <<= 2;
    if (auto swiftObjCMembers = OCI.getSwiftObjCMembers())
      payload |= (0x01 << 1) | (uint8_t)swiftObjCMembers.value();
    payload <<= 3;
    if (auto nullable = OCI.getDefaultNullability())
      payload |= (0x01 << 2) | static_cast<uint8_t>(*nullable);
    payload = (payload << 1) | (OCI.hasDesignatedInits() ? 1 : 0);

    OS << payload;
  }
};
} // namespace

void APINotesWriter::Implementation::writeObjCContextBlock(
    llvm::BitstreamWriter &Stream) {
  llvm::BCBlockRAII restoreBlock(Stream, OBJC_CONTEXT_BLOCK_ID, 3);

  if (ObjCContexts.empty())
    return;

  {
    llvm::SmallString<4096> HashTableBlob;
    uint32_t Offset;
    {
      llvm::OnDiskChainedHashTableGenerator<ObjCContextIDTableInfo> Generator;
      for (auto &OC : ObjCContexts)
        Generator.insert(OC.first, OC.second.first);

      llvm::raw_svector_ostream BlobStream(HashTableBlob);
      // Make sure that no bucket is at offset 0
      llvm::support::endian::write<uint32_t>(BlobStream, 0,
                                             llvm::endianness::little);
      Offset = Generator.Emit(BlobStream);
    }

    objc_context_block::ObjCContextIDLayout ObjCContextID(Stream);
    ObjCContextID.emit(Scratch, Offset, HashTableBlob);
  }

  {
    llvm::SmallString<4096> HashTableBlob;
    uint32_t Offset;
    {
      llvm::OnDiskChainedHashTableGenerator<ObjCContextInfoTableInfo> Generator;
      for (auto &OC : ObjCContexts)
        Generator.insert(OC.second.first, OC.second.second);

      llvm::raw_svector_ostream BlobStream(HashTableBlob);
      // Make sure that no bucket is at offset 0
      llvm::support::endian::write<uint32_t>(BlobStream, 0,
                                             llvm::endianness::little);
      Offset = Generator.Emit(BlobStream);
    }

    objc_context_block::ObjCContextInfoLayout ObjCContextInfo(Stream);
    ObjCContextInfo.emit(Scratch, Offset, HashTableBlob);
  }
}

namespace {
/// Retrieve the serialized size of the given VariableInfo, for use in
/// on-disk hash tables.
unsigned getVariableInfoSize(const VariableInfo &VI) {
  return 2 + getCommonEntityInfoSize(VI) + 2 + VI.getType().size();
}

/// Emit a serialized representation of the variable information.
void emitVariableInfo(raw_ostream &OS, const VariableInfo &VI) {
  emitCommonEntityInfo(OS, VI);

  uint8_t bytes[2] = {0, 0};
  if (auto nullable = VI.getNullability()) {
    bytes[0] = 1;
    bytes[1] = static_cast<uint8_t>(*nullable);
  } else {
    // Nothing to do.
  }

  OS.write(reinterpret_cast<const char *>(bytes), 2);

  llvm::support::endian::Writer writer(OS, llvm::endianness::little);
  writer.write<uint16_t>(VI.getType().size());
  OS.write(VI.getType().data(), VI.getType().size());
}

/// Used to serialize the on-disk Objective-C property table.
class ObjCPropertyTableInfo
    : public VersionedTableInfo<ObjCPropertyTableInfo,
                                std::tuple<unsigned, unsigned, char>,
                                ObjCPropertyInfo> {
public:
  unsigned getKeyLength(key_type_ref) {
    return sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint8_t);
  }

  void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
    llvm::support::endian::Writer writer(OS, llvm::endianness::little);
    writer.write<uint32_t>(std::get<0>(Key));
    writer.write<uint32_t>(std::get<1>(Key));
    writer.write<uint8_t>(std::get<2>(Key));
  }

  hash_value_type ComputeHash(key_type_ref Key) {
    return static_cast<size_t>(llvm::hash_value(Key));
  }

  unsigned getUnversionedInfoSize(const ObjCPropertyInfo &OPI) {
    return getVariableInfoSize(OPI) + 1;
  }

  void emitUnversionedInfo(raw_ostream &OS, const ObjCPropertyInfo &OPI) {
    emitVariableInfo(OS, OPI);

    uint8_t flags = 0;
    if (auto value = OPI.getSwiftImportAsAccessors()) {
      flags |= 1 << 0;
      flags |= value.value() << 1;
    }
    OS << flags;
  }
};
} // namespace

void APINotesWriter::Implementation::writeObjCPropertyBlock(
    llvm::BitstreamWriter &Stream) {
  llvm::BCBlockRAII Scope(Stream, OBJC_PROPERTY_BLOCK_ID, 3);

  if (ObjCProperties.empty())
    return;

  {
    llvm::SmallString<4096> HashTableBlob;
    uint32_t Offset;
    {
      llvm::OnDiskChainedHashTableGenerator<ObjCPropertyTableInfo> Generator;
      for (auto &OP : ObjCProperties)
        Generator.insert(OP.first, OP.second);

      llvm::raw_svector_ostream BlobStream(HashTableBlob);
      // Make sure that no bucket is at offset 0
      llvm::support::endian::write<uint32_t>(BlobStream, 0,
                                             llvm::endianness::little);
      Offset = Generator.Emit(BlobStream);
    }

    objc_property_block::ObjCPropertyDataLayout ObjCPropertyData(Stream);
    ObjCPropertyData.emit(Scratch, Offset, HashTableBlob);
  }
}

namespace {
unsigned getFunctionInfoSize(const FunctionInfo &);
void emitFunctionInfo(llvm::raw_ostream &, const FunctionInfo &);

/// Used to serialize the on-disk Objective-C method table.
class ObjCMethodTableInfo
    : public VersionedTableInfo<ObjCMethodTableInfo,
                                std::tuple<unsigned, unsigned, char>,
                                ObjCMethodInfo> {
public:
  unsigned getKeyLength(key_type_ref) {
    return sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint8_t);
  }

  void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
    llvm::support::endian::Writer writer(OS, llvm::endianness::little);
    writer.write<uint32_t>(std::get<0>(Key));
    writer.write<uint32_t>(std::get<1>(Key));
    writer.write<uint8_t>(std::get<2>(Key));
  }

  hash_value_type ComputeHash(key_type_ref key) {
    return static_cast<size_t>(llvm::hash_value(key));
  }

  unsigned getUnversionedInfoSize(const ObjCMethodInfo &OMI) {
    return getFunctionInfoSize(OMI) + 1;
  }

  void emitUnversionedInfo(raw_ostream &OS, const ObjCMethodInfo &OMI) {
    uint8_t flags = 0;
    llvm::support::endian::Writer writer(OS, llvm::endianness::little);
    flags = (flags << 1) | OMI.DesignatedInit;
    flags = (flags << 1) | OMI.RequiredInit;
    writer.write<uint8_t>(flags);

    emitFunctionInfo(OS, OMI);
  }
};
} // namespace

void APINotesWriter::Implementation::writeObjCMethodBlock(
    llvm::BitstreamWriter &Stream) {
  llvm::BCBlockRAII Scope(Stream, OBJC_METHOD_BLOCK_ID, 3);

  if (ObjCMethods.empty())
    return;

  {
    llvm::SmallString<4096> HashTableBlob;
    uint32_t Offset;
    {
      llvm::OnDiskChainedHashTableGenerator<ObjCMethodTableInfo> Generator;
      for (auto &OM : ObjCMethods)
        Generator.insert(OM.first, OM.second);

      llvm::raw_svector_ostream BlobStream(HashTableBlob);
      // Make sure that no bucket is at offset 0
      llvm::support::endian::write<uint32_t>(BlobStream, 0,
                                             llvm::endianness::little);
      Offset = Generator.Emit(BlobStream);
    }

    objc_method_block::ObjCMethodDataLayout ObjCMethodData(Stream);
    ObjCMethodData.emit(Scratch, Offset, HashTableBlob);
  }
}

namespace {
/// Used to serialize the on-disk Objective-C selector table.
class ObjCSelectorTableInfo {
public:
  using key_type = StoredObjCSelector;
  using key_type_ref = const key_type &;
  using data_type = SelectorID;
  using data_type_ref = data_type;
  using hash_value_type = unsigned;
  using offset_type = unsigned;

  hash_value_type ComputeHash(key_type_ref Key) {
    return llvm::DenseMapInfo<StoredObjCSelector>::getHashValue(Key);
  }

  std::pair<unsigned, unsigned>
  EmitKeyDataLength(raw_ostream &OS, key_type_ref Key, data_type_ref) {
    uint32_t KeyLength =
        sizeof(uint16_t) + sizeof(uint32_t) * Key.Identifiers.size();
    uint32_t DataLength = sizeof(uint32_t);

    llvm::support::endian::Writer writer(OS, llvm::endianness::little);
    writer.write<uint16_t>(KeyLength);
    writer.write<uint16_t>(DataLength);
    return {KeyLength, DataLength};
  }

  void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
    llvm::support::endian::Writer writer(OS, llvm::endianness::little);
    writer.write<uint16_t>(Key.NumArgs);
    for (auto Identifier : Key.Identifiers)
      writer.write<uint32_t>(Identifier);
  }

  void EmitData(raw_ostream &OS, key_type_ref, data_type_ref Data, unsigned) {
    llvm::support::endian::Writer writer(OS, llvm::endianness::little);
    writer.write<uint32_t>(Data);
  }
};
} // namespace

void APINotesWriter::Implementation::writeObjCSelectorBlock(
    llvm::BitstreamWriter &Stream) {
  llvm::BCBlockRAII Scope(Stream, OBJC_SELECTOR_BLOCK_ID, 3);

  if (SelectorIDs.empty())
    return;

  {
    llvm::SmallString<4096> HashTableBlob;
    uint32_t Offset;
    {
      llvm::OnDiskChainedHashTableGenerator<ObjCSelectorTableInfo> Generator;
      for (auto &S : SelectorIDs)
        Generator.insert(S.first, S.second);

      llvm::raw_svector_ostream BlobStream(HashTableBlob);
      // Make sure that no bucket is at offset 0
      llvm::support::endian::write<uint32_t>(BlobStream, 0,
                                             llvm::endianness::little);
      Offset = Generator.Emit(BlobStream);
    }

    objc_selector_block::ObjCSelectorDataLayout ObjCSelectorData(Stream);
    ObjCSelectorData.emit(Scratch, Offset, HashTableBlob);
  }
}

namespace {
/// Used to serialize the on-disk global variable table.
class GlobalVariableTableInfo
    : public VersionedTableInfo<GlobalVariableTableInfo, ContextTableKey,
                                GlobalVariableInfo> {
public:
  unsigned getKeyLength(key_type_ref) {
    return sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint32_t);
  }

  void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
    llvm::support::endian::Writer writer(OS, llvm::endianness::little);
    writer.write<uint32_t>(Key.parentContextID);
    writer.write<uint8_t>(Key.contextKind);
    writer.write<uint32_t>(Key.contextID);
  }

  hash_value_type ComputeHash(key_type_ref Key) {
    return static_cast<size_t>(Key.hashValue());
  }

  unsigned getUnversionedInfoSize(const GlobalVariableInfo &GVI) {
    return getVariableInfoSize(GVI);
  }

  void emitUnversionedInfo(raw_ostream &OS, const GlobalVariableInfo &GVI) {
    emitVariableInfo(OS, GVI);
  }
};
} // namespace

void APINotesWriter::Implementation::writeGlobalVariableBlock(
    llvm::BitstreamWriter &Stream) {
  llvm::BCBlockRAII Scope(Stream, GLOBAL_VARIABLE_BLOCK_ID, 3);

  if (GlobalVariables.empty())
    return;

  {
    llvm::SmallString<4096> HashTableBlob;
    uint32_t Offset;
    {
      llvm::OnDiskChainedHashTableGenerator<GlobalVariableTableInfo> Generator;
      for (auto &GV : GlobalVariables)
        Generator.insert(GV.first, GV.second);

      llvm::raw_svector_ostream BlobStream(HashTableBlob);
      // Make sure that no bucket is at offset 0
      llvm::support::endian::write<uint32_t>(BlobStream, 0,
                                             llvm::endianness::little);
      Offset = Generator.Emit(BlobStream);
    }

    global_variable_block::GlobalVariableDataLayout GlobalVariableData(Stream);
    GlobalVariableData.emit(Scratch, Offset, HashTableBlob);
  }
}

namespace {
unsigned getParamInfoSize(const ParamInfo &PI) {
  return getVariableInfoSize(PI) + 1;
}

void emitParamInfo(raw_ostream &OS, const ParamInfo &PI) {
  emitVariableInfo(OS, PI);

  uint8_t flags = 0;
  if (auto noescape = PI.isNoEscape()) {
    flags |= 0x01;
    if (*noescape)
      flags |= 0x02;
  }
  flags <<= 3;
  if (auto RCC = PI.getRetainCountConvention())
    flags |= static_cast<uint8_t>(RCC.value()) + 1;

  llvm::support::endian::Writer writer(OS, llvm::endianness::little);
  writer.write<uint8_t>(flags);
}

/// Retrieve the serialized size of the given FunctionInfo, for use in on-disk
/// hash tables.
unsigned getFunctionInfoSize(const FunctionInfo &FI) {
  unsigned size = getCommonEntityInfoSize(FI) + 2 + sizeof(uint64_t);
  size += sizeof(uint16_t);
  for (const auto &P : FI.Params)
    size += getParamInfoSize(P);
  size += sizeof(uint16_t) + FI.ResultType.size();
  return size;
}

/// Emit a serialized representation of the function information.
void emitFunctionInfo(raw_ostream &OS, const FunctionInfo &FI) {
  emitCommonEntityInfo(OS, FI);

  uint8_t flags = 0;
  flags |= FI.NullabilityAudited;
  flags <<= 3;
  if (auto RCC = FI.getRetainCountConvention())
    flags |= static_cast<uint8_t>(RCC.value()) + 1;

  llvm::support::endian::Writer writer(OS, llvm::endianness::little);

  writer.write<uint8_t>(flags);
  writer.write<uint8_t>(FI.NumAdjustedNullable);
  writer.write<uint64_t>(FI.NullabilityPayload);

  writer.write<uint16_t>(FI.Params.size());
  for (const auto &PI : FI.Params)
    emitParamInfo(OS, PI);

  writer.write<uint16_t>(FI.ResultType.size());
  writer.write(ArrayRef<char>{FI.ResultType.data(), FI.ResultType.size()});
}

/// Used to serialize the on-disk global function table.
class GlobalFunctionTableInfo
    : public VersionedTableInfo<GlobalFunctionTableInfo, ContextTableKey,
                                GlobalFunctionInfo> {
public:
  unsigned getKeyLength(key_type_ref) {
    return sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint32_t);
  }

  void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
    llvm::support::endian::Writer writer(OS, llvm::endianness::little);
    writer.write<uint32_t>(Key.parentContextID);
    writer.write<uint8_t>(Key.contextKind);
    writer.write<uint32_t>(Key.contextID);
  }

  hash_value_type ComputeHash(key_type_ref Key) {
    return static_cast<size_t>(Key.hashValue());
  }

  unsigned getUnversionedInfoSize(const GlobalFunctionInfo &GFI) {
    return getFunctionInfoSize(GFI);
  }

  void emitUnversionedInfo(raw_ostream &OS, const GlobalFunctionInfo &GFI) {
    emitFunctionInfo(OS, GFI);
  }
};
} // namespace

void APINotesWriter::Implementation::writeGlobalFunctionBlock(
    llvm::BitstreamWriter &Stream) {
  llvm::BCBlockRAII Scope(Stream, GLOBAL_FUNCTION_BLOCK_ID, 3);

  if (GlobalFunctions.empty())
    return;

  {
    llvm::SmallString<4096> HashTableBlob;
    uint32_t Offset;
    {
      llvm::OnDiskChainedHashTableGenerator<GlobalFunctionTableInfo> Generator;
      for (auto &F : GlobalFunctions)
        Generator.insert(F.first, F.second);

      llvm::raw_svector_ostream BlobStream(HashTableBlob);
      // Make sure that no bucket is at offset 0
      llvm::support::endian::write<uint32_t>(BlobStream, 0,
                                             llvm::endianness::little);
      Offset = Generator.Emit(BlobStream);
    }

    global_function_block::GlobalFunctionDataLayout GlobalFunctionData(Stream);
    GlobalFunctionData.emit(Scratch, Offset, HashTableBlob);
  }
}

namespace {
/// Used to serialize the on-disk global enum constant.
class EnumConstantTableInfo
    : public VersionedTableInfo<EnumConstantTableInfo, unsigned,
                                EnumConstantInfo> {
public:
  unsigned getKeyLength(key_type_ref) { return sizeof(uint32_t); }

  void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
    llvm::support::endian::Writer writer(OS, llvm::endianness::little);
    writer.write<uint32_t>(Key);
  }

  hash_value_type ComputeHash(key_type_ref Key) {
    return static_cast<size_t>(llvm::hash_value(Key));
  }

  unsigned getUnversionedInfoSize(const EnumConstantInfo &ECI) {
    return getCommonEntityInfoSize(ECI);
  }

  void emitUnversionedInfo(raw_ostream &OS, const EnumConstantInfo &ECI) {
    emitCommonEntityInfo(OS, ECI);
  }
};
} // namespace

void APINotesWriter::Implementation::writeEnumConstantBlock(
    llvm::BitstreamWriter &Stream) {
  llvm::BCBlockRAII Scope(Stream, ENUM_CONSTANT_BLOCK_ID, 3);

  if (EnumConstants.empty())
    return;

  {
    llvm::SmallString<4096> HashTableBlob;
    uint32_t Offset;
    {
      llvm::OnDiskChainedHashTableGenerator<EnumConstantTableInfo> Generator;
      for (auto &EC : EnumConstants)
        Generator.insert(EC.first, EC.second);

      llvm::raw_svector_ostream BlobStream(HashTableBlob);
      // Make sure that no bucket is at offset 0
      llvm::support::endian::write<uint32_t>(BlobStream, 0,
                                             llvm::endianness::little);
      Offset = Generator.Emit(BlobStream);
    }

    enum_constant_block::EnumConstantDataLayout EnumConstantData(Stream);
    EnumConstantData.emit(Scratch, Offset, HashTableBlob);
  }
}

namespace {
template <typename Derived, typename UnversionedDataType>
class CommonTypeTableInfo
    : public VersionedTableInfo<Derived, ContextTableKey, UnversionedDataType> {
public:
  using key_type_ref = typename CommonTypeTableInfo::key_type_ref;
  using hash_value_type = typename CommonTypeTableInfo::hash_value_type;

  unsigned getKeyLength(key_type_ref) {
    return sizeof(uint32_t) + sizeof(uint8_t) + sizeof(IdentifierID);
  }

  void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
    llvm::support::endian::Writer writer(OS, llvm::endianness::little);
    writer.write<uint32_t>(Key.parentContextID);
    writer.write<uint8_t>(Key.contextKind);
    writer.write<IdentifierID>(Key.contextID);
  }

  hash_value_type ComputeHash(key_type_ref Key) {
    return static_cast<size_t>(Key.hashValue());
  }

  unsigned getUnversionedInfoSize(const UnversionedDataType &UDT) {
    return getCommonTypeInfoSize(UDT);
  }

  void emitUnversionedInfo(raw_ostream &OS, const UnversionedDataType &UDT) {
    emitCommonTypeInfo(OS, UDT);
  }
};

/// Used to serialize the on-disk tag table.
class TagTableInfo : public CommonTypeTableInfo<TagTableInfo, TagInfo> {
public:
  unsigned getUnversionedInfoSize(const TagInfo &TI) {
    return 2 + (TI.SwiftImportAs ? TI.SwiftImportAs->size() : 0) +
           2 + (TI.SwiftRetainOp ? TI.SwiftRetainOp->size() : 0) +
           2 + (TI.SwiftReleaseOp ? TI.SwiftReleaseOp->size() : 0) +
           2 + getCommonTypeInfoSize(TI);
  }

  void emitUnversionedInfo(raw_ostream &OS, const TagInfo &TI) {
    llvm::support::endian::Writer writer(OS, llvm::endianness::little);

    uint8_t Flags = 0;
    if (auto extensibility = TI.EnumExtensibility) {
      Flags |= static_cast<uint8_t>(extensibility.value()) + 1;
      assert((Flags < (1 << 2)) && "must fit in two bits");
    }

    Flags <<= 2;
    if (auto value = TI.isFlagEnum())
      Flags |= (value.value() << 1 | 1 << 0);

    writer.write<uint8_t>(Flags);

    if (auto Copyable = TI.isSwiftCopyable())
      writer.write<uint8_t>(*Copyable ? kSwiftCopyable : kSwiftNonCopyable);
    else
      writer.write<uint8_t>(0);

    if (auto ImportAs = TI.SwiftImportAs) {
      writer.write<uint16_t>(ImportAs->size() + 1);
      OS.write(ImportAs->c_str(), ImportAs->size());
    } else {
      writer.write<uint16_t>(0);
    }
    if (auto RetainOp = TI.SwiftRetainOp) {
      writer.write<uint16_t>(RetainOp->size() + 1);
      OS.write(RetainOp->c_str(), RetainOp->size());
    } else {
      writer.write<uint16_t>(0);
    }
    if (auto ReleaseOp = TI.SwiftReleaseOp) {
      writer.write<uint16_t>(ReleaseOp->size() + 1);
      OS.write(ReleaseOp->c_str(), ReleaseOp->size());
    } else {
      writer.write<uint16_t>(0);
    }

    emitCommonTypeInfo(OS, TI);
  }
};
} // namespace

void APINotesWriter::Implementation::writeTagBlock(
    llvm::BitstreamWriter &Stream) {
  llvm::BCBlockRAII Scope(Stream, TAG_BLOCK_ID, 3);

  if (Tags.empty())
    return;

  {
    llvm::SmallString<4096> HashTableBlob;
    uint32_t Offset;
    {
      llvm::OnDiskChainedHashTableGenerator<TagTableInfo> Generator;
      for (auto &T : Tags)
        Generator.insert(T.first, T.second);

      llvm::raw_svector_ostream BlobStream(HashTableBlob);
      // Make sure that no bucket is at offset 0
      llvm::support::endian::write<uint32_t>(BlobStream, 0,
                                             llvm::endianness::little);
      Offset = Generator.Emit(BlobStream);
    }

    tag_block::TagDataLayout TagData(Stream);
    TagData.emit(Scratch, Offset, HashTableBlob);
  }
}

namespace {
/// Used to serialize the on-disk typedef table.
class TypedefTableInfo
    : public CommonTypeTableInfo<TypedefTableInfo, TypedefInfo> {
public:
  unsigned getUnversionedInfoSize(const TypedefInfo &TI) {
    return 1 + getCommonTypeInfoSize(TI);
  }

  void emitUnversionedInfo(raw_ostream &OS, const TypedefInfo &TI) {
    llvm::support::endian::Writer writer(OS, llvm::endianness::little);

    uint8_t Flags = 0;
    if (auto swiftWrapper = TI.SwiftWrapper)
      Flags |= static_cast<uint8_t>(*swiftWrapper) + 1;

    writer.write<uint8_t>(Flags);

    emitCommonTypeInfo(OS, TI);
  }
};
} // namespace

void APINotesWriter::Implementation::writeTypedefBlock(
    llvm::BitstreamWriter &Stream) {
  llvm::BCBlockRAII Scope(Stream, TYPEDEF_BLOCK_ID, 3);

  if (Typedefs.empty())
    return;

  {
    llvm::SmallString<4096> HashTableBlob;
    uint32_t Offset;
    {
      llvm::OnDiskChainedHashTableGenerator<TypedefTableInfo> Generator;
      for (auto &T : Typedefs)
        Generator.insert(T.first, T.second);

      llvm::raw_svector_ostream BlobStream(HashTableBlob);
      // Make sure that no bucket is at offset 0
      llvm::support::endian::write<uint32_t>(BlobStream, 0,
                                             llvm::endianness::little);
      Offset = Generator.Emit(BlobStream);
    }

    typedef_block::TypedefDataLayout TypedefData(Stream);
    TypedefData.emit(Scratch, Offset, HashTableBlob);
  }
}

// APINotesWriter

APINotesWriter::APINotesWriter(llvm::StringRef ModuleName, const FileEntry *SF)
    : Implementation(new class Implementation(ModuleName, SF)) {}

APINotesWriter::~APINotesWriter() = default;

void APINotesWriter::writeToStream(llvm::raw_ostream &OS) {
  Implementation->writeToStream(OS);
}

ContextID APINotesWriter::addObjCContext(std::optional<ContextID> ParentCtxID,
                                         StringRef Name, ContextKind Kind,
                                         const ObjCContextInfo &Info,
                                         VersionTuple SwiftVersion) {
  IdentifierID NameID = Implementation->getIdentifier(Name);

  uint32_t RawParentCtxID = ParentCtxID ? ParentCtxID->Value : -1;
  ContextTableKey Key(RawParentCtxID, static_cast<uint8_t>(Kind), NameID);
  auto Known = Implementation->ObjCContexts.find(Key);
  if (Known == Implementation->ObjCContexts.end()) {
    unsigned NextID = Implementation->ObjCContexts.size() + 1;

    Implementation::VersionedSmallVector<ObjCContextInfo> EmptyVersionedInfo;
    Known = Implementation->ObjCContexts
                .insert(std::make_pair(
                    Key, std::make_pair(NextID, EmptyVersionedInfo)))
                .first;

    Implementation->ObjCContextNames[NextID] = NameID;
    Implementation->ParentContexts[NextID] = RawParentCtxID;
  }

  // Add this version information.
  auto &VersionedVec = Known->second.second;
  bool Found = false;
  for (auto &Versioned : VersionedVec) {
    if (Versioned.first == SwiftVersion) {
      Versioned.second |= Info;
      Found = true;
      break;
    }
  }

  if (!Found)
    VersionedVec.push_back({SwiftVersion, Info});

  return ContextID(Known->second.first);
}

void APINotesWriter::addObjCProperty(ContextID CtxID, StringRef Name,
                                     bool IsInstanceProperty,
                                     const ObjCPropertyInfo &Info,
                                     VersionTuple SwiftVersion) {
  IdentifierID NameID = Implementation->getIdentifier(Name);
  Implementation
      ->ObjCProperties[std::make_tuple(CtxID.Value, NameID, IsInstanceProperty)]
      .push_back({SwiftVersion, Info});
}

void APINotesWriter::addObjCMethod(ContextID CtxID, ObjCSelectorRef Selector,
                                   bool IsInstanceMethod,
                                   const ObjCMethodInfo &Info,
                                   VersionTuple SwiftVersion) {
  SelectorID SelID = Implementation->getSelector(Selector);
  auto Key = std::tuple<unsigned, unsigned, char>{CtxID.Value, SelID,
                                                  IsInstanceMethod};
  Implementation->ObjCMethods[Key].push_back({SwiftVersion, Info});

  // If this method is a designated initializer, update the class to note that
  // it has designated initializers.
  if (Info.DesignatedInit) {
    assert(Implementation->ParentContexts.contains(CtxID.Value));
    uint32_t ParentCtxID = Implementation->ParentContexts[CtxID.Value];
    ContextTableKey CtxKey(ParentCtxID,
                           static_cast<uint8_t>(ContextKind::ObjCClass),
                           Implementation->ObjCContextNames[CtxID.Value]);
    assert(Implementation->ObjCContexts.contains(CtxKey));
    auto &VersionedVec = Implementation->ObjCContexts[CtxKey].second;
    bool Found = false;
    for (auto &Versioned : VersionedVec) {
      if (Versioned.first == SwiftVersion) {
        Versioned.second.setHasDesignatedInits(true);
        Found = true;
        break;
      }
    }

    if (!Found) {
      VersionedVec.push_back({SwiftVersion, ObjCContextInfo()});
      VersionedVec.back().second.setHasDesignatedInits(true);
    }
  }
}

void APINotesWriter::addGlobalVariable(std::optional<Context> Ctx,
                                       llvm::StringRef Name,
                                       const GlobalVariableInfo &Info,
                                       VersionTuple SwiftVersion) {
  IdentifierID VariableID = Implementation->getIdentifier(Name);
  ContextTableKey Key(Ctx, VariableID);
  Implementation->GlobalVariables[Key].push_back({SwiftVersion, Info});
}

void APINotesWriter::addGlobalFunction(std::optional<Context> Ctx,
                                       llvm::StringRef Name,
                                       const GlobalFunctionInfo &Info,
                                       VersionTuple SwiftVersion) {
  IdentifierID NameID = Implementation->getIdentifier(Name);
  ContextTableKey Key(Ctx, NameID);
  Implementation->GlobalFunctions[Key].push_back({SwiftVersion, Info});
}

void APINotesWriter::addEnumConstant(llvm::StringRef Name,
                                     const EnumConstantInfo &Info,
                                     VersionTuple SwiftVersion) {
  IdentifierID EnumConstantID = Implementation->getIdentifier(Name);
  Implementation->EnumConstants[EnumConstantID].push_back({SwiftVersion, Info});
}

void APINotesWriter::addTag(std::optional<Context> Ctx, llvm::StringRef Name,
                            const TagInfo &Info, VersionTuple SwiftVersion) {
  IdentifierID TagID = Implementation->getIdentifier(Name);
  ContextTableKey Key(Ctx, TagID);
  Implementation->Tags[Key].push_back({SwiftVersion, Info});
}

void APINotesWriter::addTypedef(std::optional<Context> Ctx,
                                llvm::StringRef Name, const TypedefInfo &Info,
                                VersionTuple SwiftVersion) {
  IdentifierID TypedefID = Implementation->getIdentifier(Name);
  ContextTableKey Key(Ctx, TypedefID);
  Implementation->Typedefs[Key].push_back({SwiftVersion, Info});
}
} // namespace api_notes
} // namespace clang
