16623e1f1SDouglas Gregor //===-- TestModuleFileExtension.cpp - Module Extension Tester -------------===//
26623e1f1SDouglas Gregor //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler 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"
12e0308279SFrancis Visoiu Mistrih #include "llvm/Bitstream/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) {
510e828958SJF Bastien     llvm::Expected<llvm::BitstreamEntry> MaybeEntry =
520e828958SJF Bastien         Stream.advanceSkippingSubblocks();
530e828958SJF Bastien     if (!MaybeEntry)
540e828958SJF Bastien       (void)MaybeEntry.takeError();
550e828958SJF Bastien     llvm::BitstreamEntry Entry = MaybeEntry.get();
560e828958SJF Bastien 
576623e1f1SDouglas Gregor     switch (Entry.Kind) {
586623e1f1SDouglas Gregor     case llvm::BitstreamEntry::SubBlock:
596623e1f1SDouglas Gregor     case llvm::BitstreamEntry::EndBlock:
606623e1f1SDouglas Gregor     case llvm::BitstreamEntry::Error:
616623e1f1SDouglas Gregor       return;
626623e1f1SDouglas Gregor 
636623e1f1SDouglas Gregor     case llvm::BitstreamEntry::Record:
646623e1f1SDouglas Gregor       break;
656623e1f1SDouglas Gregor     }
666623e1f1SDouglas Gregor 
676623e1f1SDouglas Gregor     Record.clear();
686623e1f1SDouglas Gregor     StringRef Blob;
690e828958SJF Bastien     Expected<unsigned> MaybeRecCode =
700e828958SJF Bastien         Stream.readRecord(Entry.ID, Record, &Blob);
710e828958SJF Bastien     if (!MaybeRecCode)
720e828958SJF Bastien       fprintf(stderr, "Failed reading rec code: %s\n",
730e828958SJF Bastien               toString(MaybeRecCode.takeError()).c_str());
740e828958SJF Bastien     switch (MaybeRecCode.get()) {
756623e1f1SDouglas Gregor     case FIRST_EXTENSION_RECORD_ID: {
766623e1f1SDouglas Gregor       StringRef Message = Blob.substr(0, Record[0]);
776623e1f1SDouglas Gregor       fprintf(stderr, "Read extension block message: %s\n",
786623e1f1SDouglas Gregor               Message.str().c_str());
796623e1f1SDouglas Gregor       break;
806623e1f1SDouglas Gregor     }
816623e1f1SDouglas Gregor     }
826623e1f1SDouglas Gregor   }
836623e1f1SDouglas Gregor }
846623e1f1SDouglas Gregor 
856623e1f1SDouglas Gregor TestModuleFileExtension::Reader::~Reader() { }
866623e1f1SDouglas Gregor 
876623e1f1SDouglas Gregor TestModuleFileExtension::~TestModuleFileExtension() { }
886623e1f1SDouglas Gregor 
896623e1f1SDouglas Gregor ModuleFileExtensionMetadata
906623e1f1SDouglas Gregor TestModuleFileExtension::getExtensionMetadata() const {
916623e1f1SDouglas Gregor   return { BlockName, MajorVersion, MinorVersion, UserInfo };
926623e1f1SDouglas Gregor }
936623e1f1SDouglas Gregor 
946623e1f1SDouglas Gregor llvm::hash_code TestModuleFileExtension::hashExtension(
956623e1f1SDouglas Gregor                   llvm::hash_code Code) const {
966623e1f1SDouglas Gregor   if (Hashed) {
976623e1f1SDouglas Gregor     Code = llvm::hash_combine(Code, BlockName);
986623e1f1SDouglas Gregor     Code = llvm::hash_combine(Code, MajorVersion);
996623e1f1SDouglas Gregor     Code = llvm::hash_combine(Code, MinorVersion);
1006623e1f1SDouglas Gregor     Code = llvm::hash_combine(Code, UserInfo);
1016623e1f1SDouglas Gregor   }
1026623e1f1SDouglas Gregor 
1036623e1f1SDouglas Gregor   return Code;
1046623e1f1SDouglas Gregor }
1056623e1f1SDouglas Gregor 
1066623e1f1SDouglas Gregor std::unique_ptr<ModuleFileExtensionWriter>
1076623e1f1SDouglas Gregor TestModuleFileExtension::createExtensionWriter(ASTWriter &) {
1086623e1f1SDouglas Gregor   return std::unique_ptr<ModuleFileExtensionWriter>(new Writer(this));
1096623e1f1SDouglas Gregor }
1106623e1f1SDouglas Gregor 
1116623e1f1SDouglas Gregor std::unique_ptr<ModuleFileExtensionReader>
1126623e1f1SDouglas Gregor TestModuleFileExtension::createExtensionReader(
1136623e1f1SDouglas Gregor   const ModuleFileExtensionMetadata &Metadata,
1146623e1f1SDouglas Gregor   ASTReader &Reader, serialization::ModuleFile &Mod,
1156623e1f1SDouglas Gregor   const llvm::BitstreamCursor &Stream)
1166623e1f1SDouglas Gregor {
1176623e1f1SDouglas Gregor   assert(Metadata.BlockName == BlockName && "Wrong block name");
1186623e1f1SDouglas Gregor   if (std::make_pair(Metadata.MajorVersion, Metadata.MinorVersion) !=
1196623e1f1SDouglas Gregor         std::make_pair(MajorVersion, MinorVersion)) {
1206623e1f1SDouglas Gregor     Reader.getDiags().Report(Mod.ImportLoc,
1216623e1f1SDouglas Gregor                              diag::err_test_module_file_extension_version)
1226623e1f1SDouglas Gregor       << BlockName << Metadata.MajorVersion << Metadata.MinorVersion
1236623e1f1SDouglas Gregor       << MajorVersion << MinorVersion;
1246623e1f1SDouglas Gregor     return nullptr;
1256623e1f1SDouglas Gregor   }
1266623e1f1SDouglas Gregor 
1276623e1f1SDouglas Gregor   return std::unique_ptr<ModuleFileExtensionReader>(
1286623e1f1SDouglas Gregor                                                     new TestModuleFileExtension::Reader(this, Stream));
1296623e1f1SDouglas Gregor }
130*5e8a246aSJan Svoboda 
131*5e8a246aSJan Svoboda llvm::raw_ostream &clang::operator<<(llvm::raw_ostream &OS,
132*5e8a246aSJan Svoboda                                      const TestModuleFileExtension &Extension) {
133*5e8a246aSJan Svoboda   return OS << Extension.BlockName << ":" << Extension.MajorVersion << ":"
134*5e8a246aSJan Svoboda             << Extension.MinorVersion << ":" << Extension.Hashed << ":"
135*5e8a246aSJan Svoboda             << Extension.UserInfo;
136*5e8a246aSJan Svoboda }
137