145b53394SDimitry Andric //===-- TestModuleFileExtension.cpp - Module Extension Tester -------------===//
245b53394SDimitry Andric //
322989816SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
422989816SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
522989816SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
645b53394SDimitry Andric //
745b53394SDimitry Andric //===----------------------------------------------------------------------===//
845b53394SDimitry Andric #include "TestModuleFileExtension.h"
945b53394SDimitry Andric #include "clang/Frontend/FrontendDiagnostic.h"
1045b53394SDimitry Andric #include "clang/Serialization/ASTReader.h"
1145b53394SDimitry Andric #include "llvm/ADT/Hashing.h"
1222989816SDimitry Andric #include "llvm/Bitstream/BitstreamWriter.h"
1345b53394SDimitry Andric #include "llvm/Support/raw_ostream.h"
1445b53394SDimitry Andric #include <cstdio>
1545b53394SDimitry Andric using namespace clang;
1645b53394SDimitry Andric using namespace clang::serialization;
1745b53394SDimitry Andric
18344a3780SDimitry Andric char TestModuleFileExtension::ID = 0;
19344a3780SDimitry Andric
~Writer()2045b53394SDimitry Andric TestModuleFileExtension::Writer::~Writer() { }
2145b53394SDimitry Andric
writeExtensionContents(Sema & SemaRef,llvm::BitstreamWriter & Stream)2245b53394SDimitry Andric void TestModuleFileExtension::Writer::writeExtensionContents(
2345b53394SDimitry Andric Sema &SemaRef,
2445b53394SDimitry Andric llvm::BitstreamWriter &Stream) {
2545b53394SDimitry Andric using namespace llvm;
2645b53394SDimitry Andric
2745b53394SDimitry Andric // Write an abbreviation for this record.
286694ed09SDimitry Andric auto Abv = std::make_shared<llvm::BitCodeAbbrev>();
2945b53394SDimitry Andric Abv->Add(BitCodeAbbrevOp(FIRST_EXTENSION_RECORD_ID));
3045b53394SDimitry Andric Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # of characters
3145b53394SDimitry Andric Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // message
326694ed09SDimitry Andric auto Abbrev = Stream.EmitAbbrev(std::move(Abv));
3345b53394SDimitry Andric
3445b53394SDimitry Andric // Write a message into the extension block.
3545b53394SDimitry Andric SmallString<64> Message;
3645b53394SDimitry Andric {
3745b53394SDimitry Andric auto Ext = static_cast<TestModuleFileExtension *>(getExtension());
3845b53394SDimitry Andric raw_svector_ostream OS(Message);
3945b53394SDimitry Andric OS << "Hello from " << Ext->BlockName << " v" << Ext->MajorVersion << "."
4045b53394SDimitry Andric << Ext->MinorVersion;
4145b53394SDimitry Andric }
422b6b257fSDimitry Andric uint64_t Record[] = {FIRST_EXTENSION_RECORD_ID, Message.size()};
4345b53394SDimitry Andric Stream.EmitRecordWithBlob(Abbrev, Record, Message);
4445b53394SDimitry Andric }
4545b53394SDimitry Andric
Reader(ModuleFileExtension * Ext,const llvm::BitstreamCursor & InStream)4645b53394SDimitry Andric TestModuleFileExtension::Reader::Reader(ModuleFileExtension *Ext,
4745b53394SDimitry Andric const llvm::BitstreamCursor &InStream)
4845b53394SDimitry Andric : ModuleFileExtensionReader(Ext), Stream(InStream)
4945b53394SDimitry Andric {
5045b53394SDimitry Andric // Read the extension block.
5145b53394SDimitry Andric SmallVector<uint64_t, 4> Record;
5245b53394SDimitry Andric while (true) {
5322989816SDimitry Andric llvm::Expected<llvm::BitstreamEntry> MaybeEntry =
5422989816SDimitry Andric Stream.advanceSkippingSubblocks();
5522989816SDimitry Andric if (!MaybeEntry)
5622989816SDimitry Andric (void)MaybeEntry.takeError();
5722989816SDimitry Andric llvm::BitstreamEntry Entry = MaybeEntry.get();
5822989816SDimitry Andric
5945b53394SDimitry Andric switch (Entry.Kind) {
6045b53394SDimitry Andric case llvm::BitstreamEntry::SubBlock:
6145b53394SDimitry Andric case llvm::BitstreamEntry::EndBlock:
6245b53394SDimitry Andric case llvm::BitstreamEntry::Error:
6345b53394SDimitry Andric return;
6445b53394SDimitry Andric
6545b53394SDimitry Andric case llvm::BitstreamEntry::Record:
6645b53394SDimitry Andric break;
6745b53394SDimitry Andric }
6845b53394SDimitry Andric
6945b53394SDimitry Andric Record.clear();
7045b53394SDimitry Andric StringRef Blob;
7122989816SDimitry Andric Expected<unsigned> MaybeRecCode =
7222989816SDimitry Andric Stream.readRecord(Entry.ID, Record, &Blob);
7322989816SDimitry Andric if (!MaybeRecCode)
7422989816SDimitry Andric fprintf(stderr, "Failed reading rec code: %s\n",
7522989816SDimitry Andric toString(MaybeRecCode.takeError()).c_str());
7622989816SDimitry Andric switch (MaybeRecCode.get()) {
7745b53394SDimitry Andric case FIRST_EXTENSION_RECORD_ID: {
7845b53394SDimitry Andric StringRef Message = Blob.substr(0, Record[0]);
7945b53394SDimitry Andric fprintf(stderr, "Read extension block message: %s\n",
8045b53394SDimitry Andric Message.str().c_str());
8145b53394SDimitry Andric break;
8245b53394SDimitry Andric }
8345b53394SDimitry Andric }
8445b53394SDimitry Andric }
8545b53394SDimitry Andric }
8645b53394SDimitry Andric
~Reader()8745b53394SDimitry Andric TestModuleFileExtension::Reader::~Reader() { }
8845b53394SDimitry Andric
~TestModuleFileExtension()8945b53394SDimitry Andric TestModuleFileExtension::~TestModuleFileExtension() { }
9045b53394SDimitry Andric
9145b53394SDimitry Andric ModuleFileExtensionMetadata
getExtensionMetadata() const9245b53394SDimitry Andric TestModuleFileExtension::getExtensionMetadata() const {
9345b53394SDimitry Andric return { BlockName, MajorVersion, MinorVersion, UserInfo };
9445b53394SDimitry Andric }
9545b53394SDimitry Andric
hashExtension(ExtensionHashBuilder & HBuilder) const96c0981da4SDimitry Andric void TestModuleFileExtension::hashExtension(
97c0981da4SDimitry Andric ExtensionHashBuilder &HBuilder) const {
9845b53394SDimitry Andric if (Hashed) {
99c0981da4SDimitry Andric HBuilder.add(BlockName);
100c0981da4SDimitry Andric HBuilder.add(MajorVersion);
101c0981da4SDimitry Andric HBuilder.add(MinorVersion);
102c0981da4SDimitry Andric HBuilder.add(UserInfo);
10345b53394SDimitry Andric }
10445b53394SDimitry Andric }
10545b53394SDimitry Andric
10645b53394SDimitry Andric std::unique_ptr<ModuleFileExtensionWriter>
createExtensionWriter(ASTWriter &)10745b53394SDimitry Andric TestModuleFileExtension::createExtensionWriter(ASTWriter &) {
10845b53394SDimitry Andric return std::unique_ptr<ModuleFileExtensionWriter>(new Writer(this));
10945b53394SDimitry Andric }
11045b53394SDimitry Andric
11145b53394SDimitry Andric std::unique_ptr<ModuleFileExtensionReader>
createExtensionReader(const ModuleFileExtensionMetadata & Metadata,ASTReader & Reader,serialization::ModuleFile & Mod,const llvm::BitstreamCursor & Stream)11245b53394SDimitry Andric TestModuleFileExtension::createExtensionReader(
11345b53394SDimitry Andric const ModuleFileExtensionMetadata &Metadata,
11445b53394SDimitry Andric ASTReader &Reader, serialization::ModuleFile &Mod,
11545b53394SDimitry Andric const llvm::BitstreamCursor &Stream)
11645b53394SDimitry Andric {
11745b53394SDimitry Andric assert(Metadata.BlockName == BlockName && "Wrong block name");
11845b53394SDimitry Andric if (std::make_pair(Metadata.MajorVersion, Metadata.MinorVersion) !=
11945b53394SDimitry Andric std::make_pair(MajorVersion, MinorVersion)) {
12045b53394SDimitry Andric Reader.getDiags().Report(Mod.ImportLoc,
12145b53394SDimitry Andric diag::err_test_module_file_extension_version)
12245b53394SDimitry Andric << BlockName << Metadata.MajorVersion << Metadata.MinorVersion
12345b53394SDimitry Andric << MajorVersion << MinorVersion;
12445b53394SDimitry Andric return nullptr;
12545b53394SDimitry Andric }
12645b53394SDimitry Andric
12745b53394SDimitry Andric return std::unique_ptr<ModuleFileExtensionReader>(
12845b53394SDimitry Andric new TestModuleFileExtension::Reader(this, Stream));
12945b53394SDimitry Andric }
130344a3780SDimitry Andric
str() const131344a3780SDimitry Andric std::string TestModuleFileExtension::str() const {
132344a3780SDimitry Andric std::string Buffer;
133344a3780SDimitry Andric llvm::raw_string_ostream OS(Buffer);
134344a3780SDimitry Andric OS << BlockName << ":" << MajorVersion << ":" << MinorVersion << ":" << Hashed
135344a3780SDimitry Andric << ":" << UserInfo;
13677fc4c14SDimitry Andric return Buffer;
137344a3780SDimitry Andric }
138