================ @@ -0,0 +1,2001 @@ +//===--- APINotesReader.cpp - API Notes Reader ------------------*- 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/APINotesReader.h" +#include "APINotesFormat.h" +#include "llvm/ADT/Hashing.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Bitstream/BitstreamReader.h" +#include "llvm/Support/DJB.h" +#include "llvm/Support/EndianStream.h" +#include "llvm/Support/OnDiskHashTable.h" + +namespace clang { +namespace api_notes { +using namespace llvm::support; + +namespace { +/// Deserialize a version tuple. +llvm::VersionTuple ReadVersionTuple(const uint8_t *&Data) { + uint8_t NumVersions = (*Data++) & 0x03; + + unsigned Major = endian::readNext<uint32_t, little, unaligned>(Data); + if (NumVersions == 0) + return llvm::VersionTuple(Major); + + unsigned Minor = endian::readNext<uint32_t, little, unaligned>(Data); + if (NumVersions == 1) + return llvm::VersionTuple(Major, Minor); + + unsigned Subminor = endian::readNext<uint32_t, little, unaligned>(Data); + if (NumVersions == 2) + return llvm::VersionTuple(Major, Minor, Subminor); + + unsigned Build = endian::readNext<uint32_t, little, unaligned>(Data); + return llvm::VersionTuple(Major, Minor, Subminor, Build); +} + +/// An on-disk hash table whose data is versioned based on the Swift version. +template <typename Derived, typename KeyType, typename UnversionedDataType> +class VersionedTableInfo { +public: + using internal_key_type = KeyType; + using external_key_type = KeyType; + using data_type = + llvm::SmallVector<std::pair<llvm::VersionTuple, UnversionedDataType>, 1>; + using hash_value_type = size_t; + using offset_type = unsigned; + + internal_key_type GetInternalKey(external_key_type Key) { return Key; } + + external_key_type GetExternalKey(internal_key_type Key) { return Key; } + + static bool EqualKey(internal_key_type LHS, internal_key_type RHS) { + return LHS == RHS; + } + + static std::pair<unsigned, unsigned> ReadKeyDataLength(const uint8_t *&Data) { + unsigned KeyLength = endian::readNext<uint16_t, little, unaligned>(Data); + unsigned DataLength = endian::readNext<uint16_t, little, unaligned>(Data); + return {KeyLength, DataLength}; + } + + static data_type ReadData(internal_key_type Key, const uint8_t *Data, + unsigned Length) { + unsigned NumElements = endian::readNext<uint16_t, little, unaligned>(Data); + data_type Result; + Result.reserve(NumElements); + for (unsigned i = 0; i != NumElements; ++i) { + auto version = ReadVersionTuple(Data); + const auto *DataBefore = Data; + (void)DataBefore; + auto UnversionedData = Derived::readUnversioned(Key, Data); + assert(Data != DataBefore && + "Unversioned data reader didn't move pointer"); + Result.push_back({version, UnversionedData}); + } + return Result; + } +}; + +/// Read serialized CommonEntityInfo. +void ReadCommonEntityInfo(const uint8_t *&Data, CommonEntityInfo &Info) { + uint8_t UnavailableBits = *Data++; + Info.Unavailable = (UnavailableBits >> 1) & 0x01; + Info.UnavailableInSwift = UnavailableBits & 0x01; + if ((UnavailableBits >> 2) & 0x01) + Info.setSwiftPrivate(static_cast<bool>((UnavailableBits >> 3) & 0x01)); + + unsigned MsgLength = endian::readNext<uint16_t, little, unaligned>(Data); + Info.UnavailableMsg = + std::string(reinterpret_cast<const char *>(Data), + reinterpret_cast<const char *>(Data) + MsgLength); + Data += MsgLength; + + unsigned SwiftNameLength = + endian::readNext<uint16_t, little, unaligned>(Data); + Info.SwiftName = + std::string(reinterpret_cast<const char *>(Data), + reinterpret_cast<const char *>(Data) + SwiftNameLength); + Data += SwiftNameLength; +} + +/// Read serialized CommonTypeInfo. +void ReadCommonTypeInfo(const uint8_t *&Data, CommonTypeInfo &Info) { + ReadCommonEntityInfo(Data, Info); + + unsigned SwiftBridgeLength = + endian::readNext<uint16_t, little, unaligned>(Data); + if (SwiftBridgeLength > 0) { + Info.setSwiftBridge(std::optional<std::string>(std::string( + reinterpret_cast<const char *>(Data), SwiftBridgeLength - 1))); + Data += SwiftBridgeLength - 1; + } + + unsigned ErrorDomainLength = + endian::readNext<uint16_t, little, unaligned>(Data); + if (ErrorDomainLength > 0) { + Info.setNSErrorDomain(std::optional<std::string>(std::string( + reinterpret_cast<const char *>(Data), ErrorDomainLength - 1))); + Data += ErrorDomainLength - 1; + } +} + +/// Used to deserialize the on-disk identifier table. +class IdentifierTableInfo { +public: + using internal_key_type = llvm::StringRef; + using external_key_type = llvm::StringRef; + using data_type = IdentifierID; + using hash_value_type = uint32_t; + using offset_type = unsigned; + + internal_key_type GetInternalKey(external_key_type Key) { return Key; } + + external_key_type GetExternalKey(internal_key_type Key) { return Key; } + + hash_value_type ComputeHash(internal_key_type Key) { + return llvm::djbHash(Key); + } + + static bool EqualKey(internal_key_type LHS, internal_key_type RHS) { + return LHS == RHS; + } + + static std::pair<unsigned, unsigned> ReadKeyDataLength(const uint8_t *&Data) { + unsigned KeyLength = endian::readNext<uint16_t, little, unaligned>(Data); + unsigned DataLength = endian::readNext<uint16_t, little, unaligned>(Data); + return {KeyLength, DataLength}; + } + + static internal_key_type ReadKey(const uint8_t *Data, unsigned Length) { + return llvm::StringRef(reinterpret_cast<const char *>(Data), Length); + } + + static data_type ReadData(internal_key_type key, const uint8_t *Data, + unsigned Length) { + return endian::readNext<uint32_t, little, unaligned>(Data); + } +}; + +/// Used to deserialize the on-disk Objective-C class table. +class ObjCContextIDTableInfo { +public: + using internal_key_type = ContextTableKey; + using external_key_type = internal_key_type; + using data_type = unsigned; + using hash_value_type = size_t; + using offset_type = unsigned; + + internal_key_type GetInternalKey(external_key_type Key) { return Key; } + + external_key_type GetExternalKey(internal_key_type Key) { return Key; } + + hash_value_type ComputeHash(internal_key_type Key) { + return static_cast<size_t>(Key.hashValue()); + } + + static bool EqualKey(internal_key_type LHS, internal_key_type RHS) { + return LHS == RHS; + } + + static std::pair<unsigned, unsigned> ReadKeyDataLength(const uint8_t *&Data) { + unsigned KeyLength = endian::readNext<uint16_t, little, unaligned>(Data); + unsigned DataLength = endian::readNext<uint16_t, little, unaligned>(Data); + return {KeyLength, DataLength}; + } + + static internal_key_type ReadKey(const uint8_t *Data, unsigned Length) { + auto ParentCtxID = endian::readNext<uint32_t, little, unaligned>(Data); + auto ContextKind = endian::readNext<uint8_t, little, unaligned>(Data); + auto NameID = endian::readNext<uint32_t, little, unaligned>(Data); + return {ParentCtxID, ContextKind, NameID}; + } + + static data_type ReadData(internal_key_type Key, const uint8_t *Data, + unsigned Length) { + return endian::readNext<uint32_t, little, unaligned>(Data); + } +}; + +/// Used to deserialize the on-disk Objective-C property table. +class ObjCContextInfoTableInfo + : public VersionedTableInfo<ObjCContextInfoTableInfo, unsigned, + ObjCContextInfo> { +public: + static internal_key_type ReadKey(const uint8_t *Data, unsigned Length) { + return endian::readNext<uint32_t, little, unaligned>(Data); + } + + hash_value_type ComputeHash(internal_key_type Key) { + return static_cast<size_t>(llvm::hash_value(Key)); + } + + static ObjCContextInfo readUnversioned(internal_key_type Key, + const uint8_t *&Data) { + ObjCContextInfo Info; + ReadCommonTypeInfo(Data, Info); + uint8_t Payload = *Data++; + + if (Payload & 0x01) + Info.setHasDesignatedInits(true); + Payload = Payload >> 1; + + if (Payload & 0x4) + Info.setDefaultNullability(static_cast<NullabilityKind>(Payload & 0x03)); + Payload >>= 3; + + if (Payload & (1 << 1)) + Info.setSwiftObjCMembers(Payload & 1); + Payload >>= 2; + + if (Payload & (1 << 1)) + Info.setSwiftImportAsNonGeneric(Payload & 1); + + return Info; + } +}; + +/// Read serialized VariableInfo. +void ReadVariableInfo(const uint8_t *&Data, VariableInfo &Info) { + ReadCommonEntityInfo(Data, Info); + if (*Data++) { + Info.setNullabilityAudited(static_cast<NullabilityKind>(*Data)); + } + ++Data; + + auto TypeLen = endian::readNext<uint16_t, little, unaligned>(Data); + Info.setType(std::string(Data, Data + TypeLen)); + Data += TypeLen; +} + +/// Used to deserialize the on-disk Objective-C property table. +class ObjCPropertyTableInfo + : public VersionedTableInfo<ObjCPropertyTableInfo, + std::tuple<uint32_t, uint32_t, uint8_t>, + ObjCPropertyInfo> { +public: + static internal_key_type ReadKey(const uint8_t *Data, unsigned Length) { + auto ClassID = endian::readNext<uint32_t, little, unaligned>(Data); + auto NameID = endian::readNext<uint32_t, little, unaligned>(Data); + char IsInstance = endian::readNext<uint8_t, little, unaligned>(Data); + return {ClassID, NameID, IsInstance}; + } + + hash_value_type ComputeHash(internal_key_type Key) { + return static_cast<size_t>(llvm::hash_value(Key)); + } + + static ObjCPropertyInfo readUnversioned(internal_key_type Key, + const uint8_t *&Data) { + ObjCPropertyInfo Info; + ReadVariableInfo(Data, Info); + uint8_t Flags = *Data++; + if (Flags & (1 << 0)) + Info.setSwiftImportAsAccessors(Flags & (1 << 1)); + return Info; + } +}; + +/// Read serialized ParamInfo. +void ReadParamInfo(const uint8_t *&Data, ParamInfo &Info) { + ReadVariableInfo(Data, Info); + + uint8_t Payload = endian::readNext<uint8_t, little, unaligned>(Data); + if (auto RawConvention = Payload & 0x7) { + auto Convention = static_cast<RetainCountConventionKind>(RawConvention - 1); + Info.setRetainCountConvention(Convention); + } + Payload >>= 3; + if (Payload & 0x01) { + Info.setNoEscape(Payload & 0x02); + } + Payload >>= 2; + assert(Payload == 0 && "Bad API notes"); +} + +/// Read serialized FunctionInfo. +void ReadFunctionInfo(const uint8_t *&Data, FunctionInfo &Info) { + ReadCommonEntityInfo(Data, Info); + + uint8_t Payload = endian::readNext<uint8_t, little, unaligned>(Data); + if (auto RawConvention = Payload & 0x7) { + auto Convention = static_cast<RetainCountConventionKind>(RawConvention - 1); + Info.setRetainCountConvention(Convention); + } + Payload >>= 3; + Info.NullabilityAudited = Payload & 0x1; + Payload >>= 1; + assert(Payload == 0 && "Bad API notes"); + + Info.NumAdjustedNullable = endian::readNext<uint8_t, little, unaligned>(Data); + Info.NullabilityPayload = endian::readNext<uint64_t, little, unaligned>(Data); + + unsigned NumParams = endian::readNext<uint16_t, little, unaligned>(Data); + while (NumParams > 0) { + ParamInfo pi; + ReadParamInfo(Data, pi); + Info.Params.push_back(pi); + --NumParams; + } + + unsigned ResultTypeLen = endian::readNext<uint16_t, little, unaligned>(Data); + Info.ResultType = std::string(Data, Data + ResultTypeLen); + Data += ResultTypeLen; +} + +/// Used to deserialize the on-disk Objective-C method table. +class ObjCMethodTableInfo + : public VersionedTableInfo<ObjCMethodTableInfo, + std::tuple<uint32_t, uint32_t, uint8_t>, + ObjCMethodInfo> { +public: + static internal_key_type ReadKey(const uint8_t *Data, unsigned Length) { + auto ClassID = endian::readNext<uint32_t, little, unaligned>(Data); + auto SelectorID = endian::readNext<uint32_t, little, unaligned>(Data); + auto IsInstance = endian::readNext<uint8_t, little, unaligned>(Data); + return {ClassID, SelectorID, IsInstance}; + } + + hash_value_type ComputeHash(internal_key_type Key) { + return static_cast<size_t>(llvm::hash_value(Key)); + } + + static ObjCMethodInfo readUnversioned(internal_key_type Key, + const uint8_t *&Data) { + ObjCMethodInfo Info; + uint8_t Payload = *Data++; + Info.RequiredInit = Payload & 0x01; + Payload >>= 1; + Info.DesignatedInit = Payload & 0x01; + Payload >>= 1; + + ReadFunctionInfo(Data, Info); + return Info; + } +}; + +/// Used to deserialize the on-disk Objective-C selector table. +class ObjCSelectorTableInfo { +public: + using internal_key_type = StoredObjCSelector; + using external_key_type = internal_key_type; + using data_type = SelectorID; + using hash_value_type = unsigned; + using offset_type = unsigned; + + internal_key_type GetInternalKey(external_key_type Key) { return Key; } + + external_key_type GetExternalKey(internal_key_type Key) { return Key; } + + hash_value_type ComputeHash(internal_key_type Key) { + return llvm::DenseMapInfo<StoredObjCSelector>::getHashValue(Key); + } + + static bool EqualKey(internal_key_type LHS, internal_key_type RHS) { + return llvm::DenseMapInfo<StoredObjCSelector>::isEqual(LHS, RHS); + } + + static std::pair<unsigned, unsigned> ReadKeyDataLength(const uint8_t *&Data) { + unsigned KeyLength = endian::readNext<uint16_t, little, unaligned>(Data); + unsigned DataLength = endian::readNext<uint16_t, little, unaligned>(Data); + return {KeyLength, DataLength}; + } + + static internal_key_type ReadKey(const uint8_t *Data, unsigned Length) { + internal_key_type Key; + Key.NumPieces = endian::readNext<uint16_t, little, unaligned>(Data); + unsigned NumIdents = (Length - sizeof(uint16_t)) / sizeof(uint32_t); + for (unsigned i = 0; i != NumIdents; ++i) { + Key.Identifiers.push_back( + endian::readNext<uint32_t, little, unaligned>(Data)); + } + return Key; + } + + static data_type ReadData(internal_key_type Key, const uint8_t *Data, + unsigned Length) { + return endian::readNext<uint32_t, little, unaligned>(Data); + } +}; + +/// Used to deserialize the on-disk global variable table. +class GlobalVariableTableInfo + : public VersionedTableInfo<GlobalVariableTableInfo, ContextTableKey, + GlobalVariableInfo> { +public: + static internal_key_type ReadKey(const uint8_t *Data, unsigned Length) { + auto CtxID = endian::readNext<uint32_t, little, unaligned>(Data); + auto ContextKind = endian::readNext<uint8_t, little, unaligned>(Data); + auto NameID = endian::readNext<uint32_t, little, unaligned>(Data); + return {CtxID, ContextKind, NameID}; + } + + hash_value_type ComputeHash(internal_key_type Key) { + return static_cast<size_t>(Key.hashValue()); + } + + static GlobalVariableInfo readUnversioned(internal_key_type Key, + const uint8_t *&Data) { + GlobalVariableInfo Info; + ReadVariableInfo(Data, Info); + return Info; + } +}; + +/// Used to deserialize the on-disk global function table. +class GlobalFunctionTableInfo + : public VersionedTableInfo<GlobalFunctionTableInfo, ContextTableKey, + GlobalFunctionInfo> { +public: + static internal_key_type ReadKey(const uint8_t *Data, unsigned Length) { + auto CtxID = endian::readNext<uint32_t, little, unaligned>(Data); + auto ContextKind = endian::readNext<uint8_t, little, unaligned>(Data); + auto NameID = endian::readNext<uint32_t, little, unaligned>(Data); + return {CtxID, ContextKind, NameID}; + } + + hash_value_type ComputeHash(internal_key_type Key) { + return static_cast<size_t>(Key.hashValue()); + } + + static GlobalFunctionInfo readUnversioned(internal_key_type Key, + const uint8_t *&Data) { + GlobalFunctionInfo Info; + ReadFunctionInfo(Data, Info); + return Info; + } +}; + +/// Used to deserialize the on-disk enumerator table. +class EnumConstantTableInfo + : public VersionedTableInfo<EnumConstantTableInfo, uint32_t, + EnumConstantInfo> { +public: + static internal_key_type ReadKey(const uint8_t *Data, unsigned Length) { + auto NameID = endian::readNext<uint32_t, little, unaligned>(Data); + return NameID; + } + + hash_value_type ComputeHash(internal_key_type Key) { + return static_cast<size_t>(llvm::hash_value(Key)); + } + + static EnumConstantInfo readUnversioned(internal_key_type Key, + const uint8_t *&Data) { + EnumConstantInfo Info; + ReadCommonEntityInfo(Data, Info); + return Info; + } +}; + +/// Used to deserialize the on-disk tag table. +class TagTableInfo + : public VersionedTableInfo<TagTableInfo, ContextTableKey, TagInfo> { +public: + static internal_key_type ReadKey(const uint8_t *Data, unsigned Length) { + auto CtxID = endian::readNext<uint32_t, little, unaligned>(Data); + auto ContextKind = endian::readNext<uint8_t, little, unaligned>(Data); + auto NameID = endian::readNext<IdentifierID, little, unaligned>(Data); + return {CtxID, ContextKind, NameID}; + } + + hash_value_type ComputeHash(internal_key_type Key) { + return static_cast<size_t>(Key.hashValue()); + } + + static TagInfo readUnversioned(internal_key_type Key, const uint8_t *&Data) { + TagInfo Info; + + uint8_t Payload = *Data++; + if (Payload & 1) { + Info.setFlagEnum(Payload & 2); + } + Payload >>= 2; + if (Payload > 0) { + Info.EnumExtensibility = + static_cast<EnumExtensibilityKind>((Payload & 0x3) - 1); + } + + unsigned ImportAsLength = + endian::readNext<uint16_t, little, unaligned>(Data); + if (ImportAsLength > 0) { + Info.SwiftImportAs = + std::string(reinterpret_cast<const char *>(Data), ImportAsLength - 1); + Data += ImportAsLength - 1; + } + unsigned RetainOpLength = + endian::readNext<uint16_t, little, unaligned>(Data); + if (RetainOpLength > 0) { + Info.SwiftRetainOp = + std::string(reinterpret_cast<const char *>(Data), RetainOpLength - 1); + Data += RetainOpLength - 1; + } + unsigned ReleaseOpLength = + endian::readNext<uint16_t, little, unaligned>(Data); + if (ReleaseOpLength > 0) { + Info.SwiftReleaseOp = std::string(reinterpret_cast<const char *>(Data), + ReleaseOpLength - 1); + Data += ReleaseOpLength - 1; + } + + ReadCommonTypeInfo(Data, Info); + return Info; + } +}; + +/// Used to deserialize the on-disk typedef table. +class TypedefTableInfo + : public VersionedTableInfo<TypedefTableInfo, ContextTableKey, + TypedefInfo> { +public: + static internal_key_type ReadKey(const uint8_t *Data, unsigned Length) { + auto CtxID = endian::readNext<uint32_t, little, unaligned>(Data); + auto ContextKind = endian::readNext<uint8_t, little, unaligned>(Data); + auto nameID = endian::readNext<IdentifierID, little, unaligned>(Data); + return {CtxID, ContextKind, nameID}; + } + + hash_value_type ComputeHash(internal_key_type Key) { + return static_cast<size_t>(Key.hashValue()); + } + + static TypedefInfo readUnversioned(internal_key_type Key, + const uint8_t *&Data) { + TypedefInfo Info; + + uint8_t Payload = *Data++; + if (Payload > 0) { + Info.SwiftWrapper = static_cast<SwiftNewTypeKind>((Payload & 0x3) - 1); + } ---------------- compnerd wrote:
Same https://github.com/llvm/llvm-project/pull/66769 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits