10623d748SDimitry Andric //===-- TestModuleFileExtension.cpp - Module Extension Tester -------------===//
20623d748SDimitry Andric //
30623d748SDimitry Andric //                     The LLVM Compiler Infrastructure
40623d748SDimitry Andric //
50623d748SDimitry Andric // This file is distributed under the University of Illinois Open Source
60623d748SDimitry Andric // License. See LICENSE.TXT for details.
70623d748SDimitry Andric //
80623d748SDimitry Andric //===----------------------------------------------------------------------===//
90623d748SDimitry Andric #include "TestModuleFileExtension.h"
100623d748SDimitry Andric #include "clang/Frontend/FrontendDiagnostic.h"
110623d748SDimitry Andric #include "clang/Serialization/ASTReader.h"
120623d748SDimitry Andric #include "llvm/ADT/Hashing.h"
130623d748SDimitry Andric #include "llvm/Bitcode/BitstreamWriter.h"
140623d748SDimitry Andric #include "llvm/Support/raw_ostream.h"
150623d748SDimitry Andric #include <cstdio>
160623d748SDimitry Andric using namespace clang;
170623d748SDimitry Andric using namespace clang::serialization;
180623d748SDimitry Andric 
~Writer()190623d748SDimitry Andric TestModuleFileExtension::Writer::~Writer() { }
200623d748SDimitry Andric 
writeExtensionContents(Sema & SemaRef,llvm::BitstreamWriter & Stream)210623d748SDimitry Andric void TestModuleFileExtension::Writer::writeExtensionContents(
220623d748SDimitry Andric        Sema &SemaRef,
230623d748SDimitry Andric        llvm::BitstreamWriter &Stream) {
240623d748SDimitry Andric   using namespace llvm;
250623d748SDimitry Andric 
260623d748SDimitry Andric   // Write an abbreviation for this record.
2795ec533aSDimitry Andric   auto Abv = std::make_shared<llvm::BitCodeAbbrev>();
280623d748SDimitry Andric   Abv->Add(BitCodeAbbrevOp(FIRST_EXTENSION_RECORD_ID));
290623d748SDimitry Andric   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # of characters
300623d748SDimitry Andric   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));   // message
3195ec533aSDimitry Andric   auto Abbrev = Stream.EmitAbbrev(std::move(Abv));
320623d748SDimitry Andric 
330623d748SDimitry Andric   // Write a message into the extension block.
340623d748SDimitry Andric   SmallString<64> Message;
350623d748SDimitry Andric   {
360623d748SDimitry Andric     auto Ext = static_cast<TestModuleFileExtension *>(getExtension());
370623d748SDimitry Andric     raw_svector_ostream OS(Message);
380623d748SDimitry Andric     OS << "Hello from " << Ext->BlockName << " v" << Ext->MajorVersion << "."
390623d748SDimitry Andric        << Ext->MinorVersion;
400623d748SDimitry Andric   }
41e7145dcbSDimitry Andric   uint64_t Record[] = {FIRST_EXTENSION_RECORD_ID, Message.size()};
420623d748SDimitry Andric   Stream.EmitRecordWithBlob(Abbrev, Record, Message);
430623d748SDimitry Andric }
440623d748SDimitry Andric 
Reader(ModuleFileExtension * Ext,const llvm::BitstreamCursor & InStream)450623d748SDimitry Andric TestModuleFileExtension::Reader::Reader(ModuleFileExtension *Ext,
460623d748SDimitry Andric                                         const llvm::BitstreamCursor &InStream)
470623d748SDimitry Andric   : ModuleFileExtensionReader(Ext), Stream(InStream)
480623d748SDimitry Andric {
490623d748SDimitry Andric   // Read the extension block.
500623d748SDimitry Andric   SmallVector<uint64_t, 4> Record;
510623d748SDimitry Andric   while (true) {
520623d748SDimitry Andric     llvm::BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
530623d748SDimitry Andric     switch (Entry.Kind) {
540623d748SDimitry Andric     case llvm::BitstreamEntry::SubBlock:
550623d748SDimitry Andric     case llvm::BitstreamEntry::EndBlock:
560623d748SDimitry Andric     case llvm::BitstreamEntry::Error:
570623d748SDimitry Andric       return;
580623d748SDimitry Andric 
590623d748SDimitry Andric     case llvm::BitstreamEntry::Record:
600623d748SDimitry Andric       break;
610623d748SDimitry Andric     }
620623d748SDimitry Andric 
630623d748SDimitry Andric     Record.clear();
640623d748SDimitry Andric     StringRef Blob;
650623d748SDimitry Andric     unsigned RecCode = Stream.readRecord(Entry.ID, Record, &Blob);
660623d748SDimitry Andric     switch (RecCode) {
670623d748SDimitry Andric     case FIRST_EXTENSION_RECORD_ID: {
680623d748SDimitry Andric       StringRef Message = Blob.substr(0, Record[0]);
690623d748SDimitry Andric       fprintf(stderr, "Read extension block message: %s\n",
700623d748SDimitry Andric               Message.str().c_str());
710623d748SDimitry Andric       break;
720623d748SDimitry Andric     }
730623d748SDimitry Andric     }
740623d748SDimitry Andric   }
750623d748SDimitry Andric }
760623d748SDimitry Andric 
~Reader()770623d748SDimitry Andric TestModuleFileExtension::Reader::~Reader() { }
780623d748SDimitry Andric 
~TestModuleFileExtension()790623d748SDimitry Andric TestModuleFileExtension::~TestModuleFileExtension() { }
800623d748SDimitry Andric 
810623d748SDimitry Andric ModuleFileExtensionMetadata
getExtensionMetadata() const820623d748SDimitry Andric TestModuleFileExtension::getExtensionMetadata() const {
830623d748SDimitry Andric   return { BlockName, MajorVersion, MinorVersion, UserInfo };
840623d748SDimitry Andric }
850623d748SDimitry Andric 
hashExtension(llvm::hash_code Code) const860623d748SDimitry Andric llvm::hash_code TestModuleFileExtension::hashExtension(
870623d748SDimitry Andric                   llvm::hash_code Code) const {
880623d748SDimitry Andric   if (Hashed) {
890623d748SDimitry Andric     Code = llvm::hash_combine(Code, BlockName);
900623d748SDimitry Andric     Code = llvm::hash_combine(Code, MajorVersion);
910623d748SDimitry Andric     Code = llvm::hash_combine(Code, MinorVersion);
920623d748SDimitry Andric     Code = llvm::hash_combine(Code, UserInfo);
930623d748SDimitry Andric   }
940623d748SDimitry Andric 
950623d748SDimitry Andric   return Code;
960623d748SDimitry Andric }
970623d748SDimitry Andric 
980623d748SDimitry Andric std::unique_ptr<ModuleFileExtensionWriter>
createExtensionWriter(ASTWriter &)990623d748SDimitry Andric TestModuleFileExtension::createExtensionWriter(ASTWriter &) {
1000623d748SDimitry Andric   return std::unique_ptr<ModuleFileExtensionWriter>(new Writer(this));
1010623d748SDimitry Andric }
1020623d748SDimitry Andric 
1030623d748SDimitry Andric std::unique_ptr<ModuleFileExtensionReader>
createExtensionReader(const ModuleFileExtensionMetadata & Metadata,ASTReader & Reader,serialization::ModuleFile & Mod,const llvm::BitstreamCursor & Stream)1040623d748SDimitry Andric TestModuleFileExtension::createExtensionReader(
1050623d748SDimitry Andric   const ModuleFileExtensionMetadata &Metadata,
1060623d748SDimitry Andric   ASTReader &Reader, serialization::ModuleFile &Mod,
1070623d748SDimitry Andric   const llvm::BitstreamCursor &Stream)
1080623d748SDimitry Andric {
1090623d748SDimitry Andric   assert(Metadata.BlockName == BlockName && "Wrong block name");
1100623d748SDimitry Andric   if (std::make_pair(Metadata.MajorVersion, Metadata.MinorVersion) !=
1110623d748SDimitry Andric         std::make_pair(MajorVersion, MinorVersion)) {
1120623d748SDimitry Andric     Reader.getDiags().Report(Mod.ImportLoc,
1130623d748SDimitry Andric                              diag::err_test_module_file_extension_version)
1140623d748SDimitry Andric       << BlockName << Metadata.MajorVersion << Metadata.MinorVersion
1150623d748SDimitry Andric       << MajorVersion << MinorVersion;
1160623d748SDimitry Andric     return nullptr;
1170623d748SDimitry Andric   }
1180623d748SDimitry Andric 
1190623d748SDimitry Andric   return std::unique_ptr<ModuleFileExtensionReader>(
1200623d748SDimitry Andric                                                     new TestModuleFileExtension::Reader(this, Stream));
1210623d748SDimitry Andric }
122