1dd3a739dSZachary Turner //===- llvm/unittest/DebugInfo/CodeView/RandomAccessVisitorTest.cpp -------===// 2dd3a739dSZachary Turner // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6dd3a739dSZachary Turner // 7dd3a739dSZachary Turner //===----------------------------------------------------------------------===// 8dd3a739dSZachary Turner 9ca6dbf14SZachary Turner #include "llvm/DebugInfo/CodeView/AppendingTypeTableBuilder.h" 10dd3a739dSZachary Turner #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" 11526f4f2aSZachary Turner #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" 12dd3a739dSZachary Turner #include "llvm/DebugInfo/CodeView/TypeRecord.h" 13dd3a739dSZachary Turner #include "llvm/DebugInfo/CodeView/TypeRecordMapping.h" 14dd3a739dSZachary Turner #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" 15dd3a739dSZachary Turner #include "llvm/DebugInfo/PDB/Native/RawTypes.h" 16dd3a739dSZachary Turner #include "llvm/Support/Allocator.h" 17dd3a739dSZachary Turner #include "llvm/Support/BinaryItemStream.h" 18dd3a739dSZachary Turner #include "llvm/Support/Error.h" 19cb30e705SZachary Turner #include "llvm/Testing/Support/Error.h" 20dd3a739dSZachary Turner 21dd3a739dSZachary Turner #include "gtest/gtest.h" 22dd3a739dSZachary Turner 23dd3a739dSZachary Turner using namespace llvm; 24dd3a739dSZachary Turner using namespace llvm::codeview; 25dd3a739dSZachary Turner using namespace llvm::pdb; 26dd3a739dSZachary Turner 27dd3a739dSZachary Turner namespace llvm { 28dd3a739dSZachary Turner namespace codeview { 29dd3a739dSZachary Turner inline bool operator==(const ArrayRecord &R1, const ArrayRecord &R2) { 30dd3a739dSZachary Turner if (R1.ElementType != R2.ElementType) 31dd3a739dSZachary Turner return false; 32dd3a739dSZachary Turner if (R1.IndexType != R2.IndexType) 33dd3a739dSZachary Turner return false; 34dd3a739dSZachary Turner if (R1.Name != R2.Name) 35dd3a739dSZachary Turner return false; 36dd3a739dSZachary Turner if (R1.Size != R2.Size) 37dd3a739dSZachary Turner return false; 38dd3a739dSZachary Turner return true; 39dd3a739dSZachary Turner } 40dd3a739dSZachary Turner inline bool operator!=(const ArrayRecord &R1, const ArrayRecord &R2) { 41dd3a739dSZachary Turner return !(R1 == R2); 42dd3a739dSZachary Turner } 43dd3a739dSZachary Turner 44dd3a739dSZachary Turner inline bool operator==(const CVType &R1, const CVType &R2) { 45dd3a739dSZachary Turner if (R1.RecordData != R2.RecordData) 46dd3a739dSZachary Turner return false; 47dd3a739dSZachary Turner return true; 48dd3a739dSZachary Turner } 49dd3a739dSZachary Turner inline bool operator!=(const CVType &R1, const CVType &R2) { 50dd3a739dSZachary Turner return !(R1 == R2); 51dd3a739dSZachary Turner } 52dd3a739dSZachary Turner } 53dd3a739dSZachary Turner } 54dd3a739dSZachary Turner 55dd3a739dSZachary Turner namespace llvm { 56dd3a739dSZachary Turner template <> struct BinaryItemTraits<CVType> { 57dd3a739dSZachary Turner static size_t length(const CVType &Item) { return Item.length(); } 58dd3a739dSZachary Turner static ArrayRef<uint8_t> bytes(const CVType &Item) { return Item.data(); } 59dd3a739dSZachary Turner }; 60dd3a739dSZachary Turner } 61dd3a739dSZachary Turner 62dd3a739dSZachary Turner namespace { 63dd3a739dSZachary Turner 64dd3a739dSZachary Turner class MockCallbacks : public TypeVisitorCallbacks { 65dd3a739dSZachary Turner public: 66dd3a739dSZachary Turner virtual Error visitTypeBegin(CVType &CVR, TypeIndex Index) { 67dd3a739dSZachary Turner Indices.push_back(Index); 68dd3a739dSZachary Turner return Error::success(); 69dd3a739dSZachary Turner } 70dd3a739dSZachary Turner virtual Error visitKnownRecord(CVType &CVR, ArrayRecord &AR) { 71dd3a739dSZachary Turner VisitedRecords.push_back(AR); 72dd3a739dSZachary Turner RawRecords.push_back(CVR); 73dd3a739dSZachary Turner return Error::success(); 74dd3a739dSZachary Turner } 75dd3a739dSZachary Turner 76dd3a739dSZachary Turner uint32_t count() const { 77dd3a739dSZachary Turner assert(Indices.size() == RawRecords.size()); 78dd3a739dSZachary Turner assert(Indices.size() == VisitedRecords.size()); 79dd3a739dSZachary Turner return Indices.size(); 80dd3a739dSZachary Turner } 81dd3a739dSZachary Turner std::vector<TypeIndex> Indices; 82dd3a739dSZachary Turner std::vector<CVType> RawRecords; 83dd3a739dSZachary Turner std::vector<ArrayRecord> VisitedRecords; 84dd3a739dSZachary Turner }; 85dd3a739dSZachary Turner 86dd3a739dSZachary Turner class RandomAccessVisitorTest : public testing::Test { 87dd3a739dSZachary Turner public: 88dd3a739dSZachary Turner RandomAccessVisitorTest() {} 89dd3a739dSZachary Turner 90dd3a739dSZachary Turner static void SetUpTestCase() { 91*0eaee545SJonas Devlieghere GlobalState = std::make_unique<GlobalTestState>(); 92dd3a739dSZachary Turner 93ca6dbf14SZachary Turner AppendingTypeTableBuilder Builder(GlobalState->Allocator); 94dd3a739dSZachary Turner 95dd3a739dSZachary Turner uint32_t Offset = 0; 96dd3a739dSZachary Turner for (int I = 0; I < 11; ++I) { 97dd3a739dSZachary Turner ArrayRecord AR(TypeRecordKind::Array); 98dd3a739dSZachary Turner AR.ElementType = TypeIndex::Int32(); 99dd3a739dSZachary Turner AR.IndexType = TypeIndex::UInt32(); 100dd3a739dSZachary Turner AR.Size = I; 101dd3a739dSZachary Turner std::string Name; 102dd3a739dSZachary Turner raw_string_ostream Stream(Name); 103dd3a739dSZachary Turner Stream << "Array [" << I << "]"; 104dd3a739dSZachary Turner AR.Name = GlobalState->Strings.save(Stream.str()); 105dd3a739dSZachary Turner GlobalState->Records.push_back(AR); 1066900de1dSZachary Turner GlobalState->Indices.push_back(Builder.writeLeafType(AR)); 107dd3a739dSZachary Turner 108e10d0041SReid Kleckner CVType Type(Builder.records().back()); 109dd3a739dSZachary Turner GlobalState->TypeVector.push_back(Type); 110dd3a739dSZachary Turner 111dd3a739dSZachary Turner GlobalState->AllOffsets.push_back( 112dd3a739dSZachary Turner {GlobalState->Indices.back(), ulittle32_t(Offset)}); 113dd3a739dSZachary Turner Offset += Type.length(); 114dd3a739dSZachary Turner } 115dd3a739dSZachary Turner 116dd3a739dSZachary Turner GlobalState->ItemStream.setItems(GlobalState->TypeVector); 117dd3a739dSZachary Turner GlobalState->TypeArray = VarStreamArray<CVType>(GlobalState->ItemStream); 118dd3a739dSZachary Turner } 119dd3a739dSZachary Turner 120dd3a739dSZachary Turner static void TearDownTestCase() { GlobalState.reset(); } 121dd3a739dSZachary Turner 122dd3a739dSZachary Turner void SetUp() override { 123*0eaee545SJonas Devlieghere TestState = std::make_unique<PerTestState>(); 124dd3a739dSZachary Turner } 125dd3a739dSZachary Turner 126dd3a739dSZachary Turner void TearDown() override { TestState.reset(); } 127dd3a739dSZachary Turner 128dd3a739dSZachary Turner protected: 129526f4f2aSZachary Turner bool ValidateDatabaseRecord(LazyRandomTypeCollection &Types, uint32_t Index) { 130dd3a739dSZachary Turner TypeIndex TI = TypeIndex::fromArrayIndex(Index); 131526f4f2aSZachary Turner if (!Types.contains(TI)) 132dd3a739dSZachary Turner return false; 133526f4f2aSZachary Turner if (GlobalState->TypeVector[Index] != Types.getType(TI)) 134dd3a739dSZachary Turner return false; 135dd3a739dSZachary Turner return true; 136dd3a739dSZachary Turner } 137dd3a739dSZachary Turner 138dd3a739dSZachary Turner bool ValidateVisitedRecord(uint32_t VisitationOrder, 139dd3a739dSZachary Turner uint32_t GlobalArrayIndex) { 140dd3a739dSZachary Turner TypeIndex TI = TypeIndex::fromArrayIndex(GlobalArrayIndex); 141dd3a739dSZachary Turner if (TI != TestState->Callbacks.Indices[VisitationOrder]) 142dd3a739dSZachary Turner return false; 143dd3a739dSZachary Turner 144dd3a739dSZachary Turner if (GlobalState->TypeVector[TI.toArrayIndex()] != 145dd3a739dSZachary Turner TestState->Callbacks.RawRecords[VisitationOrder]) 146dd3a739dSZachary Turner return false; 147dd3a739dSZachary Turner 148dd3a739dSZachary Turner if (GlobalState->Records[TI.toArrayIndex()] != 149dd3a739dSZachary Turner TestState->Callbacks.VisitedRecords[VisitationOrder]) 150dd3a739dSZachary Turner return false; 151dd3a739dSZachary Turner 152dd3a739dSZachary Turner return true; 153dd3a739dSZachary Turner } 154dd3a739dSZachary Turner 155dd3a739dSZachary Turner struct GlobalTestState { 156dd3a739dSZachary Turner GlobalTestState() : Strings(Allocator), ItemStream(llvm::support::little) {} 157dd3a739dSZachary Turner 158dd3a739dSZachary Turner BumpPtrAllocator Allocator; 159dd3a739dSZachary Turner StringSaver Strings; 160dd3a739dSZachary Turner 161dd3a739dSZachary Turner std::vector<ArrayRecord> Records; 162dd3a739dSZachary Turner std::vector<TypeIndex> Indices; 163dd3a739dSZachary Turner std::vector<TypeIndexOffset> AllOffsets; 164dd3a739dSZachary Turner std::vector<CVType> TypeVector; 165dd3a739dSZachary Turner BinaryItemStream<CVType> ItemStream; 166dd3a739dSZachary Turner VarStreamArray<CVType> TypeArray; 167dd3a739dSZachary Turner 168dd3a739dSZachary Turner MutableBinaryByteStream Stream; 169dd3a739dSZachary Turner }; 170dd3a739dSZachary Turner 171dd3a739dSZachary Turner struct PerTestState { 172dd3a739dSZachary Turner FixedStreamArray<TypeIndexOffset> Offsets; 173dd3a739dSZachary Turner 174dd3a739dSZachary Turner MockCallbacks Callbacks; 175dd3a739dSZachary Turner }; 176dd3a739dSZachary Turner 177dd3a739dSZachary Turner FixedStreamArray<TypeIndexOffset> 178dd3a739dSZachary Turner createPartialOffsets(MutableBinaryByteStream &Storage, 179dd3a739dSZachary Turner std::initializer_list<uint32_t> Indices) { 180dd3a739dSZachary Turner 181dd3a739dSZachary Turner uint32_t Count = Indices.size(); 182dd3a739dSZachary Turner uint32_t Size = Count * sizeof(TypeIndexOffset); 183dd3a739dSZachary Turner uint8_t *Buffer = GlobalState->Allocator.Allocate<uint8_t>(Size); 184dd3a739dSZachary Turner MutableArrayRef<uint8_t> Bytes(Buffer, Size); 185dd3a739dSZachary Turner Storage = MutableBinaryByteStream(Bytes, support::little); 186dd3a739dSZachary Turner BinaryStreamWriter Writer(Storage); 187dd3a739dSZachary Turner for (const auto I : Indices) 188dd3a739dSZachary Turner consumeError(Writer.writeObject(GlobalState->AllOffsets[I])); 189dd3a739dSZachary Turner 190dd3a739dSZachary Turner BinaryStreamReader Reader(Storage); 191dd3a739dSZachary Turner FixedStreamArray<TypeIndexOffset> Result; 192dd3a739dSZachary Turner consumeError(Reader.readArray(Result, Count)); 193dd3a739dSZachary Turner return Result; 194dd3a739dSZachary Turner } 195dd3a739dSZachary Turner 196dd3a739dSZachary Turner static std::unique_ptr<GlobalTestState> GlobalState; 197dd3a739dSZachary Turner std::unique_ptr<PerTestState> TestState; 198dd3a739dSZachary Turner }; 199dd3a739dSZachary Turner 200dd3a739dSZachary Turner std::unique_ptr<RandomAccessVisitorTest::GlobalTestState> 201dd3a739dSZachary Turner RandomAccessVisitorTest::GlobalState; 202dd3a739dSZachary Turner } 203dd3a739dSZachary Turner 204dd3a739dSZachary Turner TEST_F(RandomAccessVisitorTest, MultipleVisits) { 205dd3a739dSZachary Turner TestState->Offsets = createPartialOffsets(GlobalState->Stream, {0, 8}); 206526f4f2aSZachary Turner LazyRandomTypeCollection Types(GlobalState->TypeArray, 207dd3a739dSZachary Turner GlobalState->TypeVector.size(), 208dd3a739dSZachary Turner TestState->Offsets); 209dd3a739dSZachary Turner 210dd3a739dSZachary Turner std::vector<uint32_t> IndicesToVisit = {5, 5, 5}; 211dd3a739dSZachary Turner 212dd3a739dSZachary Turner for (uint32_t I : IndicesToVisit) { 213dd3a739dSZachary Turner TypeIndex TI = TypeIndex::fromArrayIndex(I); 214526f4f2aSZachary Turner CVType T = Types.getType(TI); 215cb30e705SZachary Turner EXPECT_THAT_ERROR(codeview::visitTypeRecord(T, TI, TestState->Callbacks), 216cb30e705SZachary Turner Succeeded()); 217dd3a739dSZachary Turner } 218dd3a739dSZachary Turner 219dd3a739dSZachary Turner // [0,8) should be present 220526f4f2aSZachary Turner EXPECT_EQ(8u, Types.size()); 221dd3a739dSZachary Turner for (uint32_t I = 0; I < 8; ++I) 222526f4f2aSZachary Turner EXPECT_TRUE(ValidateDatabaseRecord(Types, I)); 223dd3a739dSZachary Turner 224dd3a739dSZachary Turner // 5, 5, 5 225bce6d327SJustin Bogner EXPECT_EQ(3u, TestState->Callbacks.count()); 226dd3a739dSZachary Turner for (auto I : enumerate(IndicesToVisit)) 227dd3a739dSZachary Turner EXPECT_TRUE(ValidateVisitedRecord(I.index(), I.value())); 228dd3a739dSZachary Turner } 229dd3a739dSZachary Turner 230dd3a739dSZachary Turner TEST_F(RandomAccessVisitorTest, DescendingWithinChunk) { 231dd3a739dSZachary Turner // Visit multiple items from the same "chunk" in reverse order. In this 232dd3a739dSZachary Turner // example, it's 7 then 4 then 2. At the end, all records from 0 to 7 should 233dd3a739dSZachary Turner // be known by the database, but only 2, 4, and 7 should have been visited. 234dd3a739dSZachary Turner TestState->Offsets = createPartialOffsets(GlobalState->Stream, {0, 8}); 235dd3a739dSZachary Turner 236dd3a739dSZachary Turner std::vector<uint32_t> IndicesToVisit = {7, 4, 2}; 237dd3a739dSZachary Turner 238526f4f2aSZachary Turner LazyRandomTypeCollection Types(GlobalState->TypeArray, 239dd3a739dSZachary Turner GlobalState->TypeVector.size(), 240dd3a739dSZachary Turner TestState->Offsets); 241dd3a739dSZachary Turner for (uint32_t I : IndicesToVisit) { 242dd3a739dSZachary Turner TypeIndex TI = TypeIndex::fromArrayIndex(I); 243526f4f2aSZachary Turner CVType T = Types.getType(TI); 244cb30e705SZachary Turner EXPECT_THAT_ERROR(codeview::visitTypeRecord(T, TI, TestState->Callbacks), 245cb30e705SZachary Turner Succeeded()); 246dd3a739dSZachary Turner } 247dd3a739dSZachary Turner 248dd3a739dSZachary Turner // [0, 7] 249526f4f2aSZachary Turner EXPECT_EQ(8u, Types.size()); 250dd3a739dSZachary Turner for (uint32_t I = 0; I < 8; ++I) 251526f4f2aSZachary Turner EXPECT_TRUE(ValidateDatabaseRecord(Types, I)); 252dd3a739dSZachary Turner 253dd3a739dSZachary Turner // 2, 4, 7 254bce6d327SJustin Bogner EXPECT_EQ(3u, TestState->Callbacks.count()); 255dd3a739dSZachary Turner for (auto I : enumerate(IndicesToVisit)) 256dd3a739dSZachary Turner EXPECT_TRUE(ValidateVisitedRecord(I.index(), I.value())); 257dd3a739dSZachary Turner } 258dd3a739dSZachary Turner 259dd3a739dSZachary Turner TEST_F(RandomAccessVisitorTest, AscendingWithinChunk) { 260dd3a739dSZachary Turner // * Visit multiple items from the same chunk in ascending order, ensuring 261dd3a739dSZachary Turner // that intermediate items are not visited. In the below example, it's 262dd3a739dSZachary Turner // 5 -> 6 -> 7 which come from the [4,8) chunk. 263dd3a739dSZachary Turner TestState->Offsets = createPartialOffsets(GlobalState->Stream, {0, 8}); 264dd3a739dSZachary Turner 265dd3a739dSZachary Turner std::vector<uint32_t> IndicesToVisit = {2, 4, 7}; 266dd3a739dSZachary Turner 267526f4f2aSZachary Turner LazyRandomTypeCollection Types(GlobalState->TypeArray, 268dd3a739dSZachary Turner GlobalState->TypeVector.size(), 269dd3a739dSZachary Turner TestState->Offsets); 270dd3a739dSZachary Turner for (uint32_t I : IndicesToVisit) { 271dd3a739dSZachary Turner TypeIndex TI = TypeIndex::fromArrayIndex(I); 272526f4f2aSZachary Turner CVType T = Types.getType(TI); 273cb30e705SZachary Turner EXPECT_THAT_ERROR(codeview::visitTypeRecord(T, TI, TestState->Callbacks), 274cb30e705SZachary Turner Succeeded()); 275dd3a739dSZachary Turner } 276dd3a739dSZachary Turner 277dd3a739dSZachary Turner // [0, 7] 278526f4f2aSZachary Turner EXPECT_EQ(8u, Types.size()); 279dd3a739dSZachary Turner for (uint32_t I = 0; I < 8; ++I) 280526f4f2aSZachary Turner EXPECT_TRUE(ValidateDatabaseRecord(Types, I)); 281dd3a739dSZachary Turner 282dd3a739dSZachary Turner // 2, 4, 7 283bce6d327SJustin Bogner EXPECT_EQ(3u, TestState->Callbacks.count()); 284dd3a739dSZachary Turner for (auto &I : enumerate(IndicesToVisit)) 285dd3a739dSZachary Turner EXPECT_TRUE(ValidateVisitedRecord(I.index(), I.value())); 286dd3a739dSZachary Turner } 287dd3a739dSZachary Turner 288dd3a739dSZachary Turner TEST_F(RandomAccessVisitorTest, StopPrematurelyInChunk) { 289dd3a739dSZachary Turner // * Don't visit the last item in one chunk, ensuring that visitation stops 290dd3a739dSZachary Turner // at the record you specify, and the chunk is only partially visited. 291dd3a739dSZachary Turner // In the below example, this is tested by visiting 0 and 1 but not 2, 292dd3a739dSZachary Turner // all from the [0,3) chunk. 293dd3a739dSZachary Turner TestState->Offsets = createPartialOffsets(GlobalState->Stream, {0, 8}); 294dd3a739dSZachary Turner 295dd3a739dSZachary Turner std::vector<uint32_t> IndicesToVisit = {0, 1, 2}; 296dd3a739dSZachary Turner 297526f4f2aSZachary Turner LazyRandomTypeCollection Types(GlobalState->TypeArray, 298dd3a739dSZachary Turner GlobalState->TypeVector.size(), 299dd3a739dSZachary Turner TestState->Offsets); 300dd3a739dSZachary Turner 301dd3a739dSZachary Turner for (uint32_t I : IndicesToVisit) { 302dd3a739dSZachary Turner TypeIndex TI = TypeIndex::fromArrayIndex(I); 303526f4f2aSZachary Turner CVType T = Types.getType(TI); 304cb30e705SZachary Turner EXPECT_THAT_ERROR(codeview::visitTypeRecord(T, TI, TestState->Callbacks), 305cb30e705SZachary Turner Succeeded()); 306dd3a739dSZachary Turner } 307dd3a739dSZachary Turner 308dd3a739dSZachary Turner // [0, 8) should be visited. 309526f4f2aSZachary Turner EXPECT_EQ(8u, Types.size()); 310dd3a739dSZachary Turner for (uint32_t I = 0; I < 8; ++I) 311526f4f2aSZachary Turner EXPECT_TRUE(ValidateDatabaseRecord(Types, I)); 312dd3a739dSZachary Turner 313dd3a739dSZachary Turner // [0, 2] 314bce6d327SJustin Bogner EXPECT_EQ(3u, TestState->Callbacks.count()); 315dd3a739dSZachary Turner for (auto I : enumerate(IndicesToVisit)) 316dd3a739dSZachary Turner EXPECT_TRUE(ValidateVisitedRecord(I.index(), I.value())); 317dd3a739dSZachary Turner } 318dd3a739dSZachary Turner 319dd3a739dSZachary Turner TEST_F(RandomAccessVisitorTest, InnerChunk) { 320dd3a739dSZachary Turner // Test that when a request comes from a chunk in the middle of the partial 321dd3a739dSZachary Turner // offsets array, that items from surrounding chunks are not visited or 322dd3a739dSZachary Turner // added to the database. 323dd3a739dSZachary Turner TestState->Offsets = createPartialOffsets(GlobalState->Stream, {0, 4, 9}); 324dd3a739dSZachary Turner 325dd3a739dSZachary Turner std::vector<uint32_t> IndicesToVisit = {5, 7}; 326dd3a739dSZachary Turner 327526f4f2aSZachary Turner LazyRandomTypeCollection Types(GlobalState->TypeArray, 328dd3a739dSZachary Turner GlobalState->TypeVector.size(), 329dd3a739dSZachary Turner TestState->Offsets); 330dd3a739dSZachary Turner 331dd3a739dSZachary Turner for (uint32_t I : IndicesToVisit) { 332dd3a739dSZachary Turner TypeIndex TI = TypeIndex::fromArrayIndex(I); 333526f4f2aSZachary Turner CVType T = Types.getType(TI); 334cb30e705SZachary Turner EXPECT_THAT_ERROR(codeview::visitTypeRecord(T, TI, TestState->Callbacks), 335cb30e705SZachary Turner Succeeded()); 336dd3a739dSZachary Turner } 337dd3a739dSZachary Turner 338dd3a739dSZachary Turner // [4, 9) 339526f4f2aSZachary Turner EXPECT_EQ(5u, Types.size()); 340dd3a739dSZachary Turner for (uint32_t I = 4; I < 9; ++I) 341526f4f2aSZachary Turner EXPECT_TRUE(ValidateDatabaseRecord(Types, I)); 342dd3a739dSZachary Turner 343dd3a739dSZachary Turner // 5, 7 344bce6d327SJustin Bogner EXPECT_EQ(2u, TestState->Callbacks.count()); 345dd3a739dSZachary Turner for (auto &I : enumerate(IndicesToVisit)) 346dd3a739dSZachary Turner EXPECT_TRUE(ValidateVisitedRecord(I.index(), I.value())); 347dd3a739dSZachary Turner } 348ad859bd4SZachary Turner 349ad859bd4SZachary Turner TEST_F(RandomAccessVisitorTest, CrossChunkName) { 350ca6dbf14SZachary Turner AppendingTypeTableBuilder Builder(GlobalState->Allocator); 351ad859bd4SZachary Turner 352ad859bd4SZachary Turner // TypeIndex 0 353ad859bd4SZachary Turner ClassRecord Class(TypeRecordKind::Class); 354ad859bd4SZachary Turner Class.Name = "FooClass"; 355ad859bd4SZachary Turner Class.Options = ClassOptions::None; 356ad859bd4SZachary Turner Class.MemberCount = 0; 357a56e4ee3SZachary Turner Class.Size = 4U; 358ad859bd4SZachary Turner Class.DerivationList = TypeIndex::fromArrayIndex(0); 359ad859bd4SZachary Turner Class.FieldList = TypeIndex::fromArrayIndex(0); 360ad859bd4SZachary Turner Class.VTableShape = TypeIndex::fromArrayIndex(0); 3616900de1dSZachary Turner TypeIndex IndexZero = Builder.writeLeafType(Class); 362ad859bd4SZachary Turner 363ad859bd4SZachary Turner // TypeIndex 1 refers to type index 0. 364ad859bd4SZachary Turner ModifierRecord Modifier(TypeRecordKind::Modifier); 365ad859bd4SZachary Turner Modifier.ModifiedType = TypeIndex::fromArrayIndex(0); 366ad859bd4SZachary Turner Modifier.Modifiers = ModifierOptions::Const; 3676900de1dSZachary Turner TypeIndex IndexOne = Builder.writeLeafType(Modifier); 368ad859bd4SZachary Turner 369ad859bd4SZachary Turner // set up a type stream that refers to the above two serialized records. 370e10d0041SReid Kleckner std::vector<CVType> TypeArray = { 371e10d0041SReid Kleckner {Builder.records()[0]}, 372e10d0041SReid Kleckner {Builder.records()[1]}, 373e10d0041SReid Kleckner }; 374ad859bd4SZachary Turner BinaryItemStream<CVType> ItemStream(llvm::support::little); 375ad859bd4SZachary Turner ItemStream.setItems(TypeArray); 376ad859bd4SZachary Turner VarStreamArray<CVType> TypeStream(ItemStream); 377ad859bd4SZachary Turner 378ad859bd4SZachary Turner // Figure out the byte offset of the second item. 379ad859bd4SZachary Turner auto ItemOneIter = TypeStream.begin(); 380ad859bd4SZachary Turner ++ItemOneIter; 381ad859bd4SZachary Turner 382ad859bd4SZachary Turner // Set up a partial offsets buffer that contains the first and second items 383ad859bd4SZachary Turner // in separate chunks. 384ad859bd4SZachary Turner std::vector<TypeIndexOffset> TIO; 385ad859bd4SZachary Turner TIO.push_back({IndexZero, ulittle32_t(0u)}); 386ad859bd4SZachary Turner TIO.push_back({IndexOne, ulittle32_t(ItemOneIter.offset())}); 387ad859bd4SZachary Turner ArrayRef<uint8_t> Buffer(reinterpret_cast<const uint8_t *>(TIO.data()), 388ad859bd4SZachary Turner TIO.size() * sizeof(TypeIndexOffset)); 389ad859bd4SZachary Turner 390ad859bd4SZachary Turner BinaryStreamReader Reader(Buffer, llvm::support::little); 391ad859bd4SZachary Turner FixedStreamArray<TypeIndexOffset> PartialOffsets; 392ad859bd4SZachary Turner ASSERT_THAT_ERROR(Reader.readArray(PartialOffsets, 2), Succeeded()); 393ad859bd4SZachary Turner 394ad859bd4SZachary Turner LazyRandomTypeCollection Types(TypeStream, 2, PartialOffsets); 395ad859bd4SZachary Turner 396ad859bd4SZachary Turner StringRef Name = Types.getTypeName(IndexOne); 397ad859bd4SZachary Turner EXPECT_EQ("const FooClass", Name); 398ad859bd4SZachary Turner } 399