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 TestModuleFileExtension::Writer::~Writer() { } 19 20 void TestModuleFileExtension::Writer::writeExtensionContents( 21 Sema &SemaRef, 22 llvm::BitstreamWriter &Stream) { 23 using namespace llvm; 24 25 // Write an abbreviation for this record. 26 auto Abv = std::make_shared<llvm::BitCodeAbbrev>(); 27 Abv->Add(BitCodeAbbrevOp(FIRST_EXTENSION_RECORD_ID)); 28 Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # of characters 29 Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // message 30 auto Abbrev = Stream.EmitAbbrev(std::move(Abv)); 31 32 // Write a message into the extension block. 33 SmallString<64> Message; 34 { 35 auto Ext = static_cast<TestModuleFileExtension *>(getExtension()); 36 raw_svector_ostream OS(Message); 37 OS << "Hello from " << Ext->BlockName << " v" << Ext->MajorVersion << "." 38 << Ext->MinorVersion; 39 } 40 uint64_t Record[] = {FIRST_EXTENSION_RECORD_ID, Message.size()}; 41 Stream.EmitRecordWithBlob(Abbrev, Record, Message); 42 } 43 44 TestModuleFileExtension::Reader::Reader(ModuleFileExtension *Ext, 45 const llvm::BitstreamCursor &InStream) 46 : ModuleFileExtensionReader(Ext), Stream(InStream) 47 { 48 // Read the extension block. 49 SmallVector<uint64_t, 4> Record; 50 while (true) { 51 llvm::Expected<llvm::BitstreamEntry> MaybeEntry = 52 Stream.advanceSkippingSubblocks(); 53 if (!MaybeEntry) 54 (void)MaybeEntry.takeError(); 55 llvm::BitstreamEntry Entry = MaybeEntry.get(); 56 57 switch (Entry.Kind) { 58 case llvm::BitstreamEntry::SubBlock: 59 case llvm::BitstreamEntry::EndBlock: 60 case llvm::BitstreamEntry::Error: 61 return; 62 63 case llvm::BitstreamEntry::Record: 64 break; 65 } 66 67 Record.clear(); 68 StringRef Blob; 69 Expected<unsigned> MaybeRecCode = 70 Stream.readRecord(Entry.ID, Record, &Blob); 71 if (!MaybeRecCode) 72 fprintf(stderr, "Failed reading rec code: %s\n", 73 toString(MaybeRecCode.takeError()).c_str()); 74 switch (MaybeRecCode.get()) { 75 case FIRST_EXTENSION_RECORD_ID: { 76 StringRef Message = Blob.substr(0, Record[0]); 77 fprintf(stderr, "Read extension block message: %s\n", 78 Message.str().c_str()); 79 break; 80 } 81 } 82 } 83 } 84 85 TestModuleFileExtension::Reader::~Reader() { } 86 87 TestModuleFileExtension::~TestModuleFileExtension() { } 88 89 ModuleFileExtensionMetadata 90 TestModuleFileExtension::getExtensionMetadata() const { 91 return { BlockName, MajorVersion, MinorVersion, UserInfo }; 92 } 93 94 llvm::hash_code TestModuleFileExtension::hashExtension( 95 llvm::hash_code Code) const { 96 if (Hashed) { 97 Code = llvm::hash_combine(Code, BlockName); 98 Code = llvm::hash_combine(Code, MajorVersion); 99 Code = llvm::hash_combine(Code, MinorVersion); 100 Code = llvm::hash_combine(Code, UserInfo); 101 } 102 103 return Code; 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