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