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