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