1 //===-- TestModuleFileExtension.cpp - Module Extension Tester -------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 #include "TestModuleFileExtension.h" 10 #include "clang/Frontend/FrontendDiagnostic.h" 11 #include "clang/Serialization/ASTReader.h" 12 #include "llvm/ADT/Hashing.h" 13 #include "llvm/Bitcode/BitstreamWriter.h" 14 #include "llvm/Support/raw_ostream.h" 15 #include <cstdio> 16 using namespace clang; 17 using namespace clang::serialization; 18 19 TestModuleFileExtension::Writer::~Writer() { } 20 21 void TestModuleFileExtension::Writer::writeExtensionContents( 22 llvm::BitstreamWriter &Stream) { 23 using namespace llvm; 24 25 // Write an abbreviation for this record. 26 BitCodeAbbrev *Abv = new 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(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 SmallVector<uint64_t, 4> Record; 41 Record.push_back(FIRST_EXTENSION_RECORD_ID); 42 Record.push_back(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::BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); 54 switch (Entry.Kind) { 55 case llvm::BitstreamEntry::SubBlock: 56 case llvm::BitstreamEntry::EndBlock: 57 case llvm::BitstreamEntry::Error: 58 return; 59 60 case llvm::BitstreamEntry::Record: 61 break; 62 } 63 64 Record.clear(); 65 StringRef Blob; 66 unsigned RecCode = Stream.readRecord(Entry.ID, Record, &Blob); 67 switch (RecCode) { 68 case FIRST_EXTENSION_RECORD_ID: { 69 StringRef Message = Blob.substr(0, Record[0]); 70 fprintf(stderr, "Read extension block message: %s\n", 71 Message.str().c_str()); 72 break; 73 } 74 } 75 } 76 } 77 78 TestModuleFileExtension::Reader::~Reader() { } 79 80 TestModuleFileExtension::~TestModuleFileExtension() { } 81 82 ModuleFileExtensionMetadata 83 TestModuleFileExtension::getExtensionMetadata() const { 84 return { BlockName, MajorVersion, MinorVersion, UserInfo }; 85 } 86 87 llvm::hash_code TestModuleFileExtension::hashExtension( 88 llvm::hash_code Code) const { 89 if (Hashed) { 90 Code = llvm::hash_combine(Code, BlockName); 91 Code = llvm::hash_combine(Code, MajorVersion); 92 Code = llvm::hash_combine(Code, MinorVersion); 93 Code = llvm::hash_combine(Code, UserInfo); 94 } 95 96 return Code; 97 } 98 99 std::unique_ptr<ModuleFileExtensionWriter> 100 TestModuleFileExtension::createExtensionWriter(ASTWriter &) { 101 return std::unique_ptr<ModuleFileExtensionWriter>(new Writer(this)); 102 } 103 104 std::unique_ptr<ModuleFileExtensionReader> 105 TestModuleFileExtension::createExtensionReader( 106 const ModuleFileExtensionMetadata &Metadata, 107 ASTReader &Reader, serialization::ModuleFile &Mod, 108 const llvm::BitstreamCursor &Stream) 109 { 110 assert(Metadata.BlockName == BlockName && "Wrong block name"); 111 if (std::make_pair(Metadata.MajorVersion, Metadata.MinorVersion) != 112 std::make_pair(MajorVersion, MinorVersion)) { 113 Reader.getDiags().Report(Mod.ImportLoc, 114 diag::err_test_module_file_extension_version) 115 << BlockName << Metadata.MajorVersion << Metadata.MinorVersion 116 << MajorVersion << MinorVersion; 117 return nullptr; 118 } 119 120 return std::unique_ptr<ModuleFileExtensionReader>( 121 new TestModuleFileExtension::Reader(this, Stream)); 122 } 123