16623e1f1SDouglas Gregor //===-- TestModuleFileExtension.cpp - Module Extension Tester -------------===//
26623e1f1SDouglas Gregor //
36623e1f1SDouglas Gregor //                     The LLVM Compiler Infrastructure
46623e1f1SDouglas Gregor //
56623e1f1SDouglas Gregor // This file is distributed under the University of Illinois Open Source
66623e1f1SDouglas Gregor // License. See LICENSE.TXT for details.
76623e1f1SDouglas Gregor //
86623e1f1SDouglas Gregor //===----------------------------------------------------------------------===//
96623e1f1SDouglas Gregor #include "TestModuleFileExtension.h"
106623e1f1SDouglas Gregor #include "clang/Frontend/FrontendDiagnostic.h"
116623e1f1SDouglas Gregor #include "clang/Serialization/ASTReader.h"
126623e1f1SDouglas Gregor #include "llvm/ADT/Hashing.h"
136623e1f1SDouglas Gregor #include "llvm/Bitcode/BitstreamWriter.h"
146623e1f1SDouglas Gregor #include "llvm/Support/raw_ostream.h"
153ee9b16bSNAKAMURA Takumi #include <cstdio>
166623e1f1SDouglas Gregor using namespace clang;
176623e1f1SDouglas Gregor using namespace clang::serialization;
186623e1f1SDouglas Gregor 
196623e1f1SDouglas Gregor TestModuleFileExtension::Writer::~Writer() { }
206623e1f1SDouglas Gregor 
216623e1f1SDouglas Gregor void TestModuleFileExtension::Writer::writeExtensionContents(
228f64ca15SDouglas Gregor        Sema &SemaRef,
236623e1f1SDouglas Gregor        llvm::BitstreamWriter &Stream) {
246623e1f1SDouglas Gregor   using namespace llvm;
256623e1f1SDouglas Gregor 
266623e1f1SDouglas Gregor   // Write an abbreviation for this record.
27*b44f0bfbSDavid Blaikie   auto Abv = std::make_shared<llvm::BitCodeAbbrev>();
286623e1f1SDouglas Gregor   Abv->Add(BitCodeAbbrevOp(FIRST_EXTENSION_RECORD_ID));
296623e1f1SDouglas Gregor   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # of characters
306623e1f1SDouglas Gregor   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));   // message
31*b44f0bfbSDavid Blaikie   auto Abbrev = Stream.EmitAbbrev(std::move(Abv));
326623e1f1SDouglas Gregor 
336623e1f1SDouglas Gregor   // Write a message into the extension block.
346623e1f1SDouglas Gregor   SmallString<64> Message;
356623e1f1SDouglas Gregor   {
366623e1f1SDouglas Gregor     auto Ext = static_cast<TestModuleFileExtension *>(getExtension());
376623e1f1SDouglas Gregor     raw_svector_ostream OS(Message);
386623e1f1SDouglas Gregor     OS << "Hello from " << Ext->BlockName << " v" << Ext->MajorVersion << "."
396623e1f1SDouglas Gregor        << Ext->MinorVersion;
406623e1f1SDouglas Gregor   }
4130934738SBenjamin Kramer   uint64_t Record[] = {FIRST_EXTENSION_RECORD_ID, Message.size()};
426623e1f1SDouglas Gregor   Stream.EmitRecordWithBlob(Abbrev, Record, Message);
436623e1f1SDouglas Gregor }
446623e1f1SDouglas Gregor 
456623e1f1SDouglas Gregor TestModuleFileExtension::Reader::Reader(ModuleFileExtension *Ext,
466623e1f1SDouglas Gregor                                         const llvm::BitstreamCursor &InStream)
476623e1f1SDouglas Gregor   : ModuleFileExtensionReader(Ext), Stream(InStream)
486623e1f1SDouglas Gregor {
496623e1f1SDouglas Gregor   // Read the extension block.
506623e1f1SDouglas Gregor   SmallVector<uint64_t, 4> Record;
516623e1f1SDouglas Gregor   while (true) {
526623e1f1SDouglas Gregor     llvm::BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
536623e1f1SDouglas Gregor     switch (Entry.Kind) {
546623e1f1SDouglas Gregor     case llvm::BitstreamEntry::SubBlock:
556623e1f1SDouglas Gregor     case llvm::BitstreamEntry::EndBlock:
566623e1f1SDouglas Gregor     case llvm::BitstreamEntry::Error:
576623e1f1SDouglas Gregor       return;
586623e1f1SDouglas Gregor 
596623e1f1SDouglas Gregor     case llvm::BitstreamEntry::Record:
606623e1f1SDouglas Gregor       break;
616623e1f1SDouglas Gregor     }
626623e1f1SDouglas Gregor 
636623e1f1SDouglas Gregor     Record.clear();
646623e1f1SDouglas Gregor     StringRef Blob;
656623e1f1SDouglas Gregor     unsigned RecCode = Stream.readRecord(Entry.ID, Record, &Blob);
666623e1f1SDouglas Gregor     switch (RecCode) {
676623e1f1SDouglas Gregor     case FIRST_EXTENSION_RECORD_ID: {
686623e1f1SDouglas Gregor       StringRef Message = Blob.substr(0, Record[0]);
696623e1f1SDouglas Gregor       fprintf(stderr, "Read extension block message: %s\n",
706623e1f1SDouglas Gregor               Message.str().c_str());
716623e1f1SDouglas Gregor       break;
726623e1f1SDouglas Gregor     }
736623e1f1SDouglas Gregor     }
746623e1f1SDouglas Gregor   }
756623e1f1SDouglas Gregor }
766623e1f1SDouglas Gregor 
776623e1f1SDouglas Gregor TestModuleFileExtension::Reader::~Reader() { }
786623e1f1SDouglas Gregor 
796623e1f1SDouglas Gregor TestModuleFileExtension::~TestModuleFileExtension() { }
806623e1f1SDouglas Gregor 
816623e1f1SDouglas Gregor ModuleFileExtensionMetadata
826623e1f1SDouglas Gregor TestModuleFileExtension::getExtensionMetadata() const {
836623e1f1SDouglas Gregor   return { BlockName, MajorVersion, MinorVersion, UserInfo };
846623e1f1SDouglas Gregor }
856623e1f1SDouglas Gregor 
866623e1f1SDouglas Gregor llvm::hash_code TestModuleFileExtension::hashExtension(
876623e1f1SDouglas Gregor                   llvm::hash_code Code) const {
886623e1f1SDouglas Gregor   if (Hashed) {
896623e1f1SDouglas Gregor     Code = llvm::hash_combine(Code, BlockName);
906623e1f1SDouglas Gregor     Code = llvm::hash_combine(Code, MajorVersion);
916623e1f1SDouglas Gregor     Code = llvm::hash_combine(Code, MinorVersion);
926623e1f1SDouglas Gregor     Code = llvm::hash_combine(Code, UserInfo);
936623e1f1SDouglas Gregor   }
946623e1f1SDouglas Gregor 
956623e1f1SDouglas Gregor   return Code;
966623e1f1SDouglas Gregor }
976623e1f1SDouglas Gregor 
986623e1f1SDouglas Gregor std::unique_ptr<ModuleFileExtensionWriter>
996623e1f1SDouglas Gregor TestModuleFileExtension::createExtensionWriter(ASTWriter &) {
1006623e1f1SDouglas Gregor   return std::unique_ptr<ModuleFileExtensionWriter>(new Writer(this));
1016623e1f1SDouglas Gregor }
1026623e1f1SDouglas Gregor 
1036623e1f1SDouglas Gregor std::unique_ptr<ModuleFileExtensionReader>
1046623e1f1SDouglas Gregor TestModuleFileExtension::createExtensionReader(
1056623e1f1SDouglas Gregor   const ModuleFileExtensionMetadata &Metadata,
1066623e1f1SDouglas Gregor   ASTReader &Reader, serialization::ModuleFile &Mod,
1076623e1f1SDouglas Gregor   const llvm::BitstreamCursor &Stream)
1086623e1f1SDouglas Gregor {
1096623e1f1SDouglas Gregor   assert(Metadata.BlockName == BlockName && "Wrong block name");
1106623e1f1SDouglas Gregor   if (std::make_pair(Metadata.MajorVersion, Metadata.MinorVersion) !=
1116623e1f1SDouglas Gregor         std::make_pair(MajorVersion, MinorVersion)) {
1126623e1f1SDouglas Gregor     Reader.getDiags().Report(Mod.ImportLoc,
1136623e1f1SDouglas Gregor                              diag::err_test_module_file_extension_version)
1146623e1f1SDouglas Gregor       << BlockName << Metadata.MajorVersion << Metadata.MinorVersion
1156623e1f1SDouglas Gregor       << MajorVersion << MinorVersion;
1166623e1f1SDouglas Gregor     return nullptr;
1176623e1f1SDouglas Gregor   }
1186623e1f1SDouglas Gregor 
1196623e1f1SDouglas Gregor   return std::unique_ptr<ModuleFileExtensionReader>(
1206623e1f1SDouglas Gregor                                                     new TestModuleFileExtension::Reader(this, Stream));
1216623e1f1SDouglas Gregor }
122