16623e1f1SDouglas Gregor //===-- TestModuleFileExtension.cpp - Module Extension Tester -------------===// 26623e1f1SDouglas Gregor // 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 66623e1f1SDouglas Gregor // 76623e1f1SDouglas Gregor //===----------------------------------------------------------------------===// 86623e1f1SDouglas Gregor #include "TestModuleFileExtension.h" 96623e1f1SDouglas Gregor #include "clang/Frontend/FrontendDiagnostic.h" 106623e1f1SDouglas Gregor #include "clang/Serialization/ASTReader.h" 116623e1f1SDouglas Gregor #include "llvm/ADT/Hashing.h" 12e0308279SFrancis Visoiu Mistrih #include "llvm/Bitstream/BitstreamWriter.h" 136623e1f1SDouglas Gregor #include "llvm/Support/raw_ostream.h" 143ee9b16bSNAKAMURA Takumi #include <cstdio> 156623e1f1SDouglas Gregor using namespace clang; 166623e1f1SDouglas Gregor using namespace clang::serialization; 176623e1f1SDouglas Gregor 186623e1f1SDouglas Gregor TestModuleFileExtension::Writer::~Writer() { } 196623e1f1SDouglas Gregor 206623e1f1SDouglas Gregor void TestModuleFileExtension::Writer::writeExtensionContents( 218f64ca15SDouglas Gregor Sema &SemaRef, 226623e1f1SDouglas Gregor llvm::BitstreamWriter &Stream) { 236623e1f1SDouglas Gregor using namespace llvm; 246623e1f1SDouglas Gregor 256623e1f1SDouglas Gregor // Write an abbreviation for this record. 26b44f0bfbSDavid Blaikie auto Abv = std::make_shared<llvm::BitCodeAbbrev>(); 276623e1f1SDouglas Gregor Abv->Add(BitCodeAbbrevOp(FIRST_EXTENSION_RECORD_ID)); 286623e1f1SDouglas Gregor Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # of characters 296623e1f1SDouglas Gregor Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // message 30b44f0bfbSDavid Blaikie auto Abbrev = Stream.EmitAbbrev(std::move(Abv)); 316623e1f1SDouglas Gregor 326623e1f1SDouglas Gregor // Write a message into the extension block. 336623e1f1SDouglas Gregor SmallString<64> Message; 346623e1f1SDouglas Gregor { 356623e1f1SDouglas Gregor auto Ext = static_cast<TestModuleFileExtension *>(getExtension()); 366623e1f1SDouglas Gregor raw_svector_ostream OS(Message); 376623e1f1SDouglas Gregor OS << "Hello from " << Ext->BlockName << " v" << Ext->MajorVersion << "." 386623e1f1SDouglas Gregor << Ext->MinorVersion; 396623e1f1SDouglas Gregor } 4030934738SBenjamin Kramer uint64_t Record[] = {FIRST_EXTENSION_RECORD_ID, Message.size()}; 416623e1f1SDouglas Gregor Stream.EmitRecordWithBlob(Abbrev, Record, Message); 426623e1f1SDouglas Gregor } 436623e1f1SDouglas Gregor 446623e1f1SDouglas Gregor TestModuleFileExtension::Reader::Reader(ModuleFileExtension *Ext, 456623e1f1SDouglas Gregor const llvm::BitstreamCursor &InStream) 466623e1f1SDouglas Gregor : ModuleFileExtensionReader(Ext), Stream(InStream) 476623e1f1SDouglas Gregor { 486623e1f1SDouglas Gregor // Read the extension block. 496623e1f1SDouglas Gregor SmallVector<uint64_t, 4> Record; 506623e1f1SDouglas Gregor while (true) { 510e828958SJF Bastien llvm::Expected<llvm::BitstreamEntry> MaybeEntry = 520e828958SJF Bastien Stream.advanceSkippingSubblocks(); 530e828958SJF Bastien if (!MaybeEntry) 540e828958SJF Bastien (void)MaybeEntry.takeError(); 550e828958SJF Bastien llvm::BitstreamEntry Entry = MaybeEntry.get(); 560e828958SJF Bastien 576623e1f1SDouglas Gregor switch (Entry.Kind) { 586623e1f1SDouglas Gregor case llvm::BitstreamEntry::SubBlock: 596623e1f1SDouglas Gregor case llvm::BitstreamEntry::EndBlock: 606623e1f1SDouglas Gregor case llvm::BitstreamEntry::Error: 616623e1f1SDouglas Gregor return; 626623e1f1SDouglas Gregor 636623e1f1SDouglas Gregor case llvm::BitstreamEntry::Record: 646623e1f1SDouglas Gregor break; 656623e1f1SDouglas Gregor } 666623e1f1SDouglas Gregor 676623e1f1SDouglas Gregor Record.clear(); 686623e1f1SDouglas Gregor StringRef Blob; 690e828958SJF Bastien Expected<unsigned> MaybeRecCode = 700e828958SJF Bastien Stream.readRecord(Entry.ID, Record, &Blob); 710e828958SJF Bastien if (!MaybeRecCode) 720e828958SJF Bastien fprintf(stderr, "Failed reading rec code: %s\n", 730e828958SJF Bastien toString(MaybeRecCode.takeError()).c_str()); 740e828958SJF Bastien switch (MaybeRecCode.get()) { 756623e1f1SDouglas Gregor case FIRST_EXTENSION_RECORD_ID: { 766623e1f1SDouglas Gregor StringRef Message = Blob.substr(0, Record[0]); 776623e1f1SDouglas Gregor fprintf(stderr, "Read extension block message: %s\n", 786623e1f1SDouglas Gregor Message.str().c_str()); 796623e1f1SDouglas Gregor break; 806623e1f1SDouglas Gregor } 816623e1f1SDouglas Gregor } 826623e1f1SDouglas Gregor } 836623e1f1SDouglas Gregor } 846623e1f1SDouglas Gregor 856623e1f1SDouglas Gregor TestModuleFileExtension::Reader::~Reader() { } 866623e1f1SDouglas Gregor 876623e1f1SDouglas Gregor TestModuleFileExtension::~TestModuleFileExtension() { } 886623e1f1SDouglas Gregor 896623e1f1SDouglas Gregor ModuleFileExtensionMetadata 906623e1f1SDouglas Gregor TestModuleFileExtension::getExtensionMetadata() const { 916623e1f1SDouglas Gregor return { BlockName, MajorVersion, MinorVersion, UserInfo }; 926623e1f1SDouglas Gregor } 936623e1f1SDouglas Gregor 946623e1f1SDouglas Gregor llvm::hash_code TestModuleFileExtension::hashExtension( 956623e1f1SDouglas Gregor llvm::hash_code Code) const { 966623e1f1SDouglas Gregor if (Hashed) { 976623e1f1SDouglas Gregor Code = llvm::hash_combine(Code, BlockName); 986623e1f1SDouglas Gregor Code = llvm::hash_combine(Code, MajorVersion); 996623e1f1SDouglas Gregor Code = llvm::hash_combine(Code, MinorVersion); 1006623e1f1SDouglas Gregor Code = llvm::hash_combine(Code, UserInfo); 1016623e1f1SDouglas Gregor } 1026623e1f1SDouglas Gregor 1036623e1f1SDouglas Gregor return Code; 1046623e1f1SDouglas Gregor } 1056623e1f1SDouglas Gregor 1066623e1f1SDouglas Gregor std::unique_ptr<ModuleFileExtensionWriter> 1076623e1f1SDouglas Gregor TestModuleFileExtension::createExtensionWriter(ASTWriter &) { 1086623e1f1SDouglas Gregor return std::unique_ptr<ModuleFileExtensionWriter>(new Writer(this)); 1096623e1f1SDouglas Gregor } 1106623e1f1SDouglas Gregor 1116623e1f1SDouglas Gregor std::unique_ptr<ModuleFileExtensionReader> 1126623e1f1SDouglas Gregor TestModuleFileExtension::createExtensionReader( 1136623e1f1SDouglas Gregor const ModuleFileExtensionMetadata &Metadata, 1146623e1f1SDouglas Gregor ASTReader &Reader, serialization::ModuleFile &Mod, 1156623e1f1SDouglas Gregor const llvm::BitstreamCursor &Stream) 1166623e1f1SDouglas Gregor { 1176623e1f1SDouglas Gregor assert(Metadata.BlockName == BlockName && "Wrong block name"); 1186623e1f1SDouglas Gregor if (std::make_pair(Metadata.MajorVersion, Metadata.MinorVersion) != 1196623e1f1SDouglas Gregor std::make_pair(MajorVersion, MinorVersion)) { 1206623e1f1SDouglas Gregor Reader.getDiags().Report(Mod.ImportLoc, 1216623e1f1SDouglas Gregor diag::err_test_module_file_extension_version) 1226623e1f1SDouglas Gregor << BlockName << Metadata.MajorVersion << Metadata.MinorVersion 1236623e1f1SDouglas Gregor << MajorVersion << MinorVersion; 1246623e1f1SDouglas Gregor return nullptr; 1256623e1f1SDouglas Gregor } 1266623e1f1SDouglas Gregor 1276623e1f1SDouglas Gregor return std::unique_ptr<ModuleFileExtensionReader>( 1286623e1f1SDouglas Gregor new TestModuleFileExtension::Reader(this, Stream)); 1296623e1f1SDouglas Gregor } 130*5e8a246aSJan Svoboda 131*5e8a246aSJan Svoboda llvm::raw_ostream &clang::operator<<(llvm::raw_ostream &OS, 132*5e8a246aSJan Svoboda const TestModuleFileExtension &Extension) { 133*5e8a246aSJan Svoboda return OS << Extension.BlockName << ":" << Extension.MajorVersion << ":" 134*5e8a246aSJan Svoboda << Extension.MinorVersion << ":" << Extension.Hashed << ":" 135*5e8a246aSJan Svoboda << Extension.UserInfo; 136*5e8a246aSJan Svoboda } 137