//===-- APINotesWriter.h - 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 // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_LIB_APINOTES_APINOTESFORMAT_H #define LLVM_CLANG_LIB_APINOTES_APINOTESFORMAT_H #include "clang/APINotes/Types.h" #include "llvm/ADT/PointerEmbeddedInt.h" #include "llvm/Bitcode/BitcodeConvenience.h" namespace clang { namespace api_notes { /// Magic number for API notes files. const unsigned char API_NOTES_SIGNATURE[] = {0xE2, 0x9C, 0xA8, 0x01}; /// API notes file major version number. const uint16_t VERSION_MAJOR = 0; /// API notes file minor version number. /// /// When the format changes IN ANY WAY, this number should be incremented. const uint16_t VERSION_MINOR = 25; // SwiftImportAs using IdentifierID = llvm::PointerEmbeddedInt; using IdentifierIDField = llvm::BCVBR<16>; using SelectorID = llvm::PointerEmbeddedInt; using SelectorIDField = llvm::BCVBR<16>; /// The various types of blocks that can occur within a API notes file. /// /// These IDs must \em not be renumbered or reordered without incrementing /// VERSION_MAJOR. enum BlockID { /// The control block, which contains all of the information that needs to /// be validated prior to committing to loading the API notes file. /// /// \sa control_block CONTROL_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID, /// The identifier data block, which maps identifier strings to IDs. IDENTIFIER_BLOCK_ID, /// The Objective-C context data block, which contains information about /// Objective-C classes and protocols. OBJC_CONTEXT_BLOCK_ID, /// The Objective-C property data block, which maps Objective-C /// (class name, property name) pairs to information about the /// property. OBJC_PROPERTY_BLOCK_ID, /// The Objective-C property data block, which maps Objective-C /// (class name, selector, is_instance_method) tuples to information /// about the method. OBJC_METHOD_BLOCK_ID, /// The Objective-C selector data block, which maps Objective-C /// selector names (# of pieces, identifier IDs) to the selector ID /// used in other tables. OBJC_SELECTOR_BLOCK_ID, /// The global variables data block, which maps global variable names to /// information about the global variable. GLOBAL_VARIABLE_BLOCK_ID, /// The (global) functions data block, which maps global function names to /// information about the global function. GLOBAL_FUNCTION_BLOCK_ID, /// The tag data block, which maps tag names to information about /// the tags. TAG_BLOCK_ID, /// The typedef data block, which maps typedef names to information about /// the typedefs. TYPEDEF_BLOCK_ID, /// The enum constant data block, which maps enumerator names to /// information about the enumerators. ENUM_CONSTANT_BLOCK_ID, }; namespace control_block { // These IDs must \em not be renumbered or reordered without incrementing // VERSION_MAJOR. enum { METADATA = 1, MODULE_NAME = 2, MODULE_OPTIONS = 3, SOURCE_FILE = 4, }; using MetadataLayout = llvm::BCRecordLayout, // Module format major version llvm::BCFixed<16> // Module format minor version >; using ModuleNameLayout = llvm::BCRecordLayout; using ModuleOptionsLayout = llvm::BCRecordLayout // SwiftInferImportAsMember >; using SourceFileLayout = llvm::BCRecordLayout, // file size llvm::BCVBR<16> // creation time >; } // namespace control_block namespace identifier_block { enum { IDENTIFIER_DATA = 1, }; using IdentifierDataLayout = llvm::BCRecordLayout< IDENTIFIER_DATA, // record ID llvm::BCVBR<16>, // table offset within the blob (see below) llvm::BCBlob // map from identifier strings to decl kinds / decl IDs >; } // namespace identifier_block namespace objc_context_block { enum { OBJC_CONTEXT_ID_DATA = 1, OBJC_CONTEXT_INFO_DATA = 2, }; using ObjCContextIDLayout = llvm::BCRecordLayout, // table offset within the blob (see // below) llvm::BCBlob // map from ObjC class names/protocol (as // IDs) to context IDs >; using ObjCContextInfoLayout = llvm::BCRecordLayout< OBJC_CONTEXT_INFO_DATA, // record ID llvm::BCVBR<16>, // table offset within the blob (see below) llvm::BCBlob // map from ObjC context IDs to context information. >; } // namespace objc_context_block namespace objc_property_block { enum { OBJC_PROPERTY_DATA = 1, }; using ObjCPropertyDataLayout = llvm::BCRecordLayout< OBJC_PROPERTY_DATA, // record ID llvm::BCVBR<16>, // table offset within the blob (see below) llvm::BCBlob // map from ObjC (class name, property name) pairs to // ObjC property information >; } // namespace objc_property_block namespace objc_method_block { enum { OBJC_METHOD_DATA = 1, }; using ObjCMethodDataLayout = llvm::BCRecordLayout, // table offset within the blob (see // below) llvm::BCBlob // map from ObjC (class names, selector, // is-instance-method) tuples to ObjC // method information >; } // namespace objc_method_block namespace objc_selector_block { enum { OBJC_SELECTOR_DATA = 1, }; using ObjCSelectorDataLayout = llvm::BCRecordLayout, // table offset within the blob (see // below) llvm::BCBlob // map from (# pieces, identifier IDs) to // Objective-C selector ID. >; } // namespace objc_selector_block namespace global_variable_block { enum { GLOBAL_VARIABLE_DATA = 1 }; using GlobalVariableDataLayout = llvm::BCRecordLayout< GLOBAL_VARIABLE_DATA, // record ID llvm::BCVBR<16>, // table offset within the blob (see below) llvm::BCBlob // map from name to global variable information >; } // namespace global_variable_block namespace global_function_block { enum { GLOBAL_FUNCTION_DATA = 1 }; using GlobalFunctionDataLayout = llvm::BCRecordLayout< GLOBAL_FUNCTION_DATA, // record ID llvm::BCVBR<16>, // table offset within the blob (see below) llvm::BCBlob // map from name to global function information >; } // namespace global_function_block namespace tag_block { enum { TAG_DATA = 1 }; using TagDataLayout = llvm::BCRecordLayout, // table offset within the blob (see // below) llvm::BCBlob // map from name to tag information >; } // namespace tag_block namespace typedef_block { enum { TYPEDEF_DATA = 1 }; using TypedefDataLayout = llvm::BCRecordLayout, // table offset within the blob (see // below) llvm::BCBlob // map from name to typedef information >; } // namespace typedef_block namespace enum_constant_block { enum { ENUM_CONSTANT_DATA = 1 }; using EnumConstantDataLayout = llvm::BCRecordLayout, // table offset within the blob (see // below) llvm::BCBlob // map from name to enumerator information >; } // namespace enum_constant_block /// A stored Objective-C selector. struct StoredObjCSelector { unsigned NumArgs; llvm::SmallVector Identifiers; }; /// A stored Objective-C or C++ context, represented by the ID of its parent /// context, the kind of this context (Objective-C class / C++ namespace / etc), /// and the ID of this context. struct ContextTableKey { uint32_t parentContextID; uint8_t contextKind; uint32_t contextID; ContextTableKey() : parentContextID(-1), contextKind(-1), contextID(-1) {} ContextTableKey(uint32_t parentContextID, uint8_t contextKind, uint32_t contextID) : parentContextID(parentContextID), contextKind(contextKind), contextID(contextID) {} ContextTableKey(std::optional context, IdentifierID nameID) : parentContextID(context ? context->id.Value : (uint32_t)-1), contextKind(context ? static_cast(context->kind) : static_cast(-1)), contextID(nameID) {} llvm::hash_code hashValue() const { return llvm::hash_value( std::tuple{parentContextID, contextKind, contextID}); } }; inline bool operator==(const ContextTableKey &lhs, const ContextTableKey &rhs) { return lhs.parentContextID == rhs.parentContextID && lhs.contextKind == rhs.contextKind && lhs.contextID == rhs.contextID; } } // namespace api_notes } // namespace clang namespace llvm { template <> struct DenseMapInfo { typedef DenseMapInfo UnsignedInfo; static inline clang::api_notes::StoredObjCSelector getEmptyKey() { return clang::api_notes::StoredObjCSelector{UnsignedInfo::getEmptyKey(), {}}; } static inline clang::api_notes::StoredObjCSelector getTombstoneKey() { return clang::api_notes::StoredObjCSelector{UnsignedInfo::getTombstoneKey(), {}}; } static unsigned getHashValue(const clang::api_notes::StoredObjCSelector &Selector) { auto hash = llvm::hash_value(Selector.NumArgs); hash = hash_combine(hash, Selector.Identifiers.size()); for (auto piece : Selector.Identifiers) hash = hash_combine(hash, static_cast(piece)); // FIXME: Mix upper/lower 32-bit values together to produce // unsigned rather than truncating. return hash; } static bool isEqual(const clang::api_notes::StoredObjCSelector &LHS, const clang::api_notes::StoredObjCSelector &RHS) { return LHS.NumArgs == RHS.NumArgs && LHS.Identifiers == RHS.Identifiers; } }; template <> struct DenseMapInfo { static inline clang::api_notes::ContextTableKey getEmptyKey() { return clang::api_notes::ContextTableKey(); } static inline clang::api_notes::ContextTableKey getTombstoneKey() { return clang::api_notes::ContextTableKey{ DenseMapInfo::getTombstoneKey(), DenseMapInfo::getTombstoneKey(), DenseMapInfo::getTombstoneKey()}; } static unsigned getHashValue(const clang::api_notes::ContextTableKey &value) { return value.hashValue(); } static bool isEqual(const clang::api_notes::ContextTableKey &lhs, const clang::api_notes::ContextTableKey &rhs) { return lhs == rhs; } }; } // namespace llvm #endif