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