diff --git a/clang/include/clang/APINotes/Types.h b/clang/include/clang/APINotes/Types.h --- a/clang/include/clang/APINotes/Types.h +++ b/clang/include/clang/APINotes/Types.h @@ -727,6 +727,28 @@ inline bool operator!=(const TypedefInfo &LHS, const TypedefInfo &RHS) { return !(LHS == RHS); } + +/// Opaque context ID used to refer to an Objective-C class or protocol or a C++ +/// namespace. +class ContextID { +public: + unsigned Value; + + explicit ContextID(unsigned value) : Value(value) {} +}; + +enum class ContextKind : uint8_t { + ObjCClass = 0, + ObjCProtocol = 1, + Namespace = 2, +}; + +struct Context { + ContextID id; + ContextKind kind; + + Context(ContextID id, ContextKind kind) : id(id), kind(kind) {} +}; } // namespace api_notes } // namespace clang diff --git a/clang/lib/APINotes/APINotesFormat.h b/clang/lib/APINotes/APINotesFormat.h --- a/clang/lib/APINotes/APINotesFormat.h +++ b/clang/lib/APINotes/APINotesFormat.h @@ -9,6 +9,7 @@ #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" @@ -249,6 +250,38 @@ unsigned NumPieces; 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 ? (uint8_t)context->kind : (uint8_t)-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 @@ -282,6 +315,28 @@ return LHS.NumPieces == RHS.NumPieces && 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 diff --git a/clang/lib/APINotes/APINotesWriter.cpp b/clang/lib/APINotes/APINotesWriter.cpp --- a/clang/lib/APINotes/APINotesWriter.cpp +++ b/clang/lib/APINotes/APINotesWriter.cpp @@ -33,15 +33,21 @@ /// Mapping from strings to identifier IDs. llvm::StringMap IdentifierIDs; - /// Information about Objective-C contexts (classes or protocols). + /// Information about contexts (Objective-C classes or protocols or C++ + /// namespaces). /// - /// Indexed by the identifier ID and a bit indication whether we're looking - /// for a class (0) or protocol (1) and provides both the context ID and - /// information describing the context within that module. - llvm::DenseMap, + /// 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>> ObjCContexts; + /// Information about parent contexts for each context. + /// + /// Indexed by context ID, provides the parent context ID. + llvm::DenseMap ParentContexts; + /// Information about Objective-C properties. /// /// Indexed by the context ID, property name, and whether this is an @@ -64,16 +70,18 @@ /// Information about global variables. /// - /// Indexed by the identifier ID. - llvm::DenseMap, 1>> + /// Indexed by the context ID, contextKind, identifier ID. + llvm::DenseMap< + ContextTableKey, + llvm::SmallVector, 1>> GlobalVariables; /// Information about global functions. /// - /// Indexed by the identifier ID. - llvm::DenseMap, 1>> + /// Indexed by the context ID, contextKind, identifier ID. + llvm::DenseMap< + ContextTableKey, + llvm::SmallVector, 1>> GlobalFunctions; /// Information about enumerators. @@ -85,15 +93,15 @@ /// Information about tags. /// - /// Indexed by the identifier ID. - llvm::DenseMap, 1>> Tags; /// Information about typedefs. /// - /// Indexed by the identifier ID. - llvm::DenseMap, 1>> Typedefs; @@ -292,7 +300,7 @@ /// Used to serialize the on-disk Objective-C context table. class ObjCContextIDTableInfo { public: - using key_type = std::pair; // identifier ID, is-protocol + using key_type = ContextTableKey; using key_type_ref = key_type; using data_type = unsigned; using data_type_ref = const data_type &; @@ -300,12 +308,12 @@ using offset_type = unsigned; hash_value_type ComputeHash(key_type_ref Key) { - return static_cast(llvm::hash_value(Key)); + return static_cast(Key.hashValue()); } std::pair EmitKeyDataLength(raw_ostream &OS, key_type_ref, data_type_ref) { - uint32_t KeyLength = sizeof(uint32_t) + 1; + 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::support::little); @@ -316,8 +324,9 @@ void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) { llvm::support::endian::Writer writer(OS, llvm::support::little); - writer.write(Key.first); - writer.write(Key.second); + writer.write(Key.parentContextID); + writer.write(Key.contextKind); + writer.write(Key.contextID); } void EmitData(raw_ostream &OS, key_type_ref, data_type_ref Data, unsigned) { @@ -519,6 +528,10 @@ writer.write(Key); } + hash_value_type ComputeHash(key_type_ref Key) { + return static_cast(llvm::hash_value(Key)); + } + unsigned getUnversionedInfoSize(const ObjCContextInfo &OCI) { return getCommonTypeInfoSize(OCI) + 1; } @@ -631,6 +644,10 @@ writer.write(std::get<2>(Key)); } + hash_value_type ComputeHash(key_type_ref Key) { + return static_cast(llvm::hash_value(Key)); + } + unsigned getUnversionedInfoSize(const ObjCPropertyInfo &OPI) { return getVariableInfoSize(OPI) + 1; } @@ -696,6 +713,10 @@ writer.write(std::get<2>(Key)); } + hash_value_type ComputeHash(key_type_ref key) { + return static_cast(llvm::hash_value(key)); + } + unsigned getUnversionedInfoSize(const ObjCMethodInfo &OMI) { return getFunctionInfoSize(OMI) + 1; } @@ -810,14 +831,22 @@ namespace { /// Used to serialize the on-disk global variable table. class GlobalVariableTableInfo - : public VersionedTableInfo { public: - unsigned getKeyLength(key_type_ref) { return sizeof(uint32_t); } + 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::support::little); - writer.write(Key); + writer.write(Key.parentContextID); + writer.write(Key.contextKind); + writer.write(Key.contextID); + } + + hash_value_type ComputeHash(key_type_ref Key) { + return static_cast(Key.hashValue()); } unsigned getUnversionedInfoSize(const GlobalVariableInfo &GVI) { @@ -916,14 +945,22 @@ /// Used to serialize the on-disk global function table. class GlobalFunctionTableInfo - : public VersionedTableInfo { public: - unsigned getKeyLength(key_type_ref) { return sizeof(uint32_t); } + 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::support::little); - writer.write(Key); + writer.write(Key.parentContextID); + writer.write(Key.contextKind); + writer.write(Key.contextID); + } + + hash_value_type ComputeHash(key_type_ref Key) { + return static_cast(Key.hashValue()); } unsigned getUnversionedInfoSize(const GlobalFunctionInfo &GFI) { @@ -976,6 +1013,10 @@ writer.write(Key); } + hash_value_type ComputeHash(key_type_ref Key) { + return static_cast(llvm::hash_value(Key)); + } + unsigned getUnversionedInfoSize(const EnumConstantInfo &ECI) { return getCommonEntityInfoSize(ECI); } @@ -1016,15 +1057,24 @@ namespace { template class CommonTypeTableInfo - : public VersionedTableInfo { + : public VersionedTableInfo { 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(IdentifierID); } + 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::support::little); - writer.write(Key); + writer.write(Key.parentContextID); + writer.write(Key.contextKind); + writer.write(Key.contextID); + } + + hash_value_type ComputeHash(key_type_ref Key) { + return static_cast(Key.hashValue()); } unsigned getUnversionedInfoSize(const UnversionedDataType &UDT) { diff --git a/clang/lib/APINotes/APINotesYAMLCompiler.cpp b/clang/lib/APINotes/APINotesYAMLCompiler.cpp --- a/clang/lib/APINotes/APINotesYAMLCompiler.cpp +++ b/clang/lib/APINotes/APINotesYAMLCompiler.cpp @@ -495,6 +495,9 @@ } // namespace llvm namespace { +struct Namespace; +typedef std::vector NamespacesSeq; + struct TopLevelItems { ClassesSeq Classes; ClassesSeq Protocols; @@ -503,6 +506,7 @@ EnumConstantsSeq EnumConstants; TagsSeq Tags; TypedefsSeq Typedefs; + NamespacesSeq Namespaces; }; } // namespace @@ -516,10 +520,39 @@ IO.mapOptional("Enumerators", TLI.EnumConstants); IO.mapOptional("Tags", TLI.Tags); IO.mapOptional("Typedefs", TLI.Typedefs); + IO.mapOptional("Namespaces", TLI.Namespaces); } } // namespace yaml } // namespace llvm +namespace { +struct Namespace { + StringRef Name; + AvailabilityItem Availability; + StringRef SwiftName; + std::optional SwiftPrivate; + TopLevelItems Items; +}; +} // namespace + +LLVM_YAML_IS_SEQUENCE_VECTOR(Namespace) + +namespace llvm { +namespace yaml { +template <> struct MappingTraits { + static void mapping(IO &IO, Namespace &T) { + IO.mapRequired("Name", T.Name); + IO.mapOptional("Availability", T.Availability.Mode, + APIAvailability::Available); + IO.mapOptional("AvailabilityMsg", T.Availability.Msg, StringRef("")); + IO.mapOptional("SwiftPrivate", T.SwiftPrivate); + IO.mapOptional("SwiftName", T.SwiftName, StringRef("")); + mapTopLevelItems(IO, T.Items); + } +}; +} // namespace yaml +} // namespace llvm + namespace { struct Versioned { VersionTuple Version;