[clang] [APINotes] Upstream APINotesReader (PR #66769)
Saleem Abdulrasool via cfe-commits
cfe-commits at lists.llvm.org
Mon Oct 9 13:34:46 PDT 2023
================
@@ -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);
+ }
----------------
compnerd wrote:
The braces are unnecessary
https://github.com/llvm/llvm-project/pull/66769
More information about the cfe-commits
mailing list