1*0b57cec5SDimitry Andric //===-- TestModuleFileExtension.cpp - Module Extension Tester -------------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric #include "TestModuleFileExtension.h" 9*0b57cec5SDimitry Andric #include "clang/Frontend/FrontendDiagnostic.h" 10*0b57cec5SDimitry Andric #include "clang/Serialization/ASTReader.h" 11*0b57cec5SDimitry Andric #include "llvm/ADT/Hashing.h" 12*0b57cec5SDimitry Andric #include "llvm/Bitstream/BitstreamWriter.h" 13*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 14*0b57cec5SDimitry Andric #include <cstdio> 15*0b57cec5SDimitry Andric using namespace clang; 16*0b57cec5SDimitry Andric using namespace clang::serialization; 17*0b57cec5SDimitry Andric 18*0b57cec5SDimitry Andric TestModuleFileExtension::Writer::~Writer() { } 19*0b57cec5SDimitry Andric 20*0b57cec5SDimitry Andric void TestModuleFileExtension::Writer::writeExtensionContents( 21*0b57cec5SDimitry Andric Sema &SemaRef, 22*0b57cec5SDimitry Andric llvm::BitstreamWriter &Stream) { 23*0b57cec5SDimitry Andric using namespace llvm; 24*0b57cec5SDimitry Andric 25*0b57cec5SDimitry Andric // Write an abbreviation for this record. 26*0b57cec5SDimitry Andric auto Abv = std::make_shared<llvm::BitCodeAbbrev>(); 27*0b57cec5SDimitry Andric Abv->Add(BitCodeAbbrevOp(FIRST_EXTENSION_RECORD_ID)); 28*0b57cec5SDimitry Andric Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # of characters 29*0b57cec5SDimitry Andric Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // message 30*0b57cec5SDimitry Andric auto Abbrev = Stream.EmitAbbrev(std::move(Abv)); 31*0b57cec5SDimitry Andric 32*0b57cec5SDimitry Andric // Write a message into the extension block. 33*0b57cec5SDimitry Andric SmallString<64> Message; 34*0b57cec5SDimitry Andric { 35*0b57cec5SDimitry Andric auto Ext = static_cast<TestModuleFileExtension *>(getExtension()); 36*0b57cec5SDimitry Andric raw_svector_ostream OS(Message); 37*0b57cec5SDimitry Andric OS << "Hello from " << Ext->BlockName << " v" << Ext->MajorVersion << "." 38*0b57cec5SDimitry Andric << Ext->MinorVersion; 39*0b57cec5SDimitry Andric } 40*0b57cec5SDimitry Andric uint64_t Record[] = {FIRST_EXTENSION_RECORD_ID, Message.size()}; 41*0b57cec5SDimitry Andric Stream.EmitRecordWithBlob(Abbrev, Record, Message); 42*0b57cec5SDimitry Andric } 43*0b57cec5SDimitry Andric 44*0b57cec5SDimitry Andric TestModuleFileExtension::Reader::Reader(ModuleFileExtension *Ext, 45*0b57cec5SDimitry Andric const llvm::BitstreamCursor &InStream) 46*0b57cec5SDimitry Andric : ModuleFileExtensionReader(Ext), Stream(InStream) 47*0b57cec5SDimitry Andric { 48*0b57cec5SDimitry Andric // Read the extension block. 49*0b57cec5SDimitry Andric SmallVector<uint64_t, 4> Record; 50*0b57cec5SDimitry Andric while (true) { 51*0b57cec5SDimitry Andric llvm::Expected<llvm::BitstreamEntry> MaybeEntry = 52*0b57cec5SDimitry Andric Stream.advanceSkippingSubblocks(); 53*0b57cec5SDimitry Andric if (!MaybeEntry) 54*0b57cec5SDimitry Andric (void)MaybeEntry.takeError(); 55*0b57cec5SDimitry Andric llvm::BitstreamEntry Entry = MaybeEntry.get(); 56*0b57cec5SDimitry Andric 57*0b57cec5SDimitry Andric switch (Entry.Kind) { 58*0b57cec5SDimitry Andric case llvm::BitstreamEntry::SubBlock: 59*0b57cec5SDimitry Andric case llvm::BitstreamEntry::EndBlock: 60*0b57cec5SDimitry Andric case llvm::BitstreamEntry::Error: 61*0b57cec5SDimitry Andric return; 62*0b57cec5SDimitry Andric 63*0b57cec5SDimitry Andric case llvm::BitstreamEntry::Record: 64*0b57cec5SDimitry Andric break; 65*0b57cec5SDimitry Andric } 66*0b57cec5SDimitry Andric 67*0b57cec5SDimitry Andric Record.clear(); 68*0b57cec5SDimitry Andric StringRef Blob; 69*0b57cec5SDimitry Andric Expected<unsigned> MaybeRecCode = 70*0b57cec5SDimitry Andric Stream.readRecord(Entry.ID, Record, &Blob); 71*0b57cec5SDimitry Andric if (!MaybeRecCode) 72*0b57cec5SDimitry Andric fprintf(stderr, "Failed reading rec code: %s\n", 73*0b57cec5SDimitry Andric toString(MaybeRecCode.takeError()).c_str()); 74*0b57cec5SDimitry Andric switch (MaybeRecCode.get()) { 75*0b57cec5SDimitry Andric case FIRST_EXTENSION_RECORD_ID: { 76*0b57cec5SDimitry Andric StringRef Message = Blob.substr(0, Record[0]); 77*0b57cec5SDimitry Andric fprintf(stderr, "Read extension block message: %s\n", 78*0b57cec5SDimitry Andric Message.str().c_str()); 79*0b57cec5SDimitry Andric break; 80*0b57cec5SDimitry Andric } 81*0b57cec5SDimitry Andric } 82*0b57cec5SDimitry Andric } 83*0b57cec5SDimitry Andric } 84*0b57cec5SDimitry Andric 85*0b57cec5SDimitry Andric TestModuleFileExtension::Reader::~Reader() { } 86*0b57cec5SDimitry Andric 87*0b57cec5SDimitry Andric TestModuleFileExtension::~TestModuleFileExtension() { } 88*0b57cec5SDimitry Andric 89*0b57cec5SDimitry Andric ModuleFileExtensionMetadata 90*0b57cec5SDimitry Andric TestModuleFileExtension::getExtensionMetadata() const { 91*0b57cec5SDimitry Andric return { BlockName, MajorVersion, MinorVersion, UserInfo }; 92*0b57cec5SDimitry Andric } 93*0b57cec5SDimitry Andric 94*0b57cec5SDimitry Andric llvm::hash_code TestModuleFileExtension::hashExtension( 95*0b57cec5SDimitry Andric llvm::hash_code Code) const { 96*0b57cec5SDimitry Andric if (Hashed) { 97*0b57cec5SDimitry Andric Code = llvm::hash_combine(Code, BlockName); 98*0b57cec5SDimitry Andric Code = llvm::hash_combine(Code, MajorVersion); 99*0b57cec5SDimitry Andric Code = llvm::hash_combine(Code, MinorVersion); 100*0b57cec5SDimitry Andric Code = llvm::hash_combine(Code, UserInfo); 101*0b57cec5SDimitry Andric } 102*0b57cec5SDimitry Andric 103*0b57cec5SDimitry Andric return Code; 104*0b57cec5SDimitry Andric } 105*0b57cec5SDimitry Andric 106*0b57cec5SDimitry Andric std::unique_ptr<ModuleFileExtensionWriter> 107*0b57cec5SDimitry Andric TestModuleFileExtension::createExtensionWriter(ASTWriter &) { 108*0b57cec5SDimitry Andric return std::unique_ptr<ModuleFileExtensionWriter>(new Writer(this)); 109*0b57cec5SDimitry Andric } 110*0b57cec5SDimitry Andric 111*0b57cec5SDimitry Andric std::unique_ptr<ModuleFileExtensionReader> 112*0b57cec5SDimitry Andric TestModuleFileExtension::createExtensionReader( 113*0b57cec5SDimitry Andric const ModuleFileExtensionMetadata &Metadata, 114*0b57cec5SDimitry Andric ASTReader &Reader, serialization::ModuleFile &Mod, 115*0b57cec5SDimitry Andric const llvm::BitstreamCursor &Stream) 116*0b57cec5SDimitry Andric { 117*0b57cec5SDimitry Andric assert(Metadata.BlockName == BlockName && "Wrong block name"); 118*0b57cec5SDimitry Andric if (std::make_pair(Metadata.MajorVersion, Metadata.MinorVersion) != 119*0b57cec5SDimitry Andric std::make_pair(MajorVersion, MinorVersion)) { 120*0b57cec5SDimitry Andric Reader.getDiags().Report(Mod.ImportLoc, 121*0b57cec5SDimitry Andric diag::err_test_module_file_extension_version) 122*0b57cec5SDimitry Andric << BlockName << Metadata.MajorVersion << Metadata.MinorVersion 123*0b57cec5SDimitry Andric << MajorVersion << MinorVersion; 124*0b57cec5SDimitry Andric return nullptr; 125*0b57cec5SDimitry Andric } 126*0b57cec5SDimitry Andric 127*0b57cec5SDimitry Andric return std::unique_ptr<ModuleFileExtensionReader>( 128*0b57cec5SDimitry Andric new TestModuleFileExtension::Reader(this, Stream)); 129*0b57cec5SDimitry Andric } 130