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