1e5dd7070Spatrick //===-- TestModuleFileExtension.cpp - Module Extension Tester -------------===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick #include "TestModuleFileExtension.h"
9e5dd7070Spatrick #include "clang/Frontend/FrontendDiagnostic.h"
10e5dd7070Spatrick #include "clang/Serialization/ASTReader.h"
11e5dd7070Spatrick #include "llvm/ADT/Hashing.h"
12e5dd7070Spatrick #include "llvm/Bitstream/BitstreamWriter.h"
13e5dd7070Spatrick #include "llvm/Support/raw_ostream.h"
14e5dd7070Spatrick #include <cstdio>
15e5dd7070Spatrick using namespace clang;
16e5dd7070Spatrick using namespace clang::serialization;
17e5dd7070Spatrick
18a9ac8606Spatrick char TestModuleFileExtension::ID = 0;
19a9ac8606Spatrick
~Writer()20e5dd7070Spatrick TestModuleFileExtension::Writer::~Writer() { }
21e5dd7070Spatrick
writeExtensionContents(Sema & SemaRef,llvm::BitstreamWriter & Stream)22e5dd7070Spatrick void TestModuleFileExtension::Writer::writeExtensionContents(
23e5dd7070Spatrick Sema &SemaRef,
24e5dd7070Spatrick llvm::BitstreamWriter &Stream) {
25e5dd7070Spatrick using namespace llvm;
26e5dd7070Spatrick
27e5dd7070Spatrick // Write an abbreviation for this record.
28e5dd7070Spatrick auto Abv = std::make_shared<llvm::BitCodeAbbrev>();
29e5dd7070Spatrick Abv->Add(BitCodeAbbrevOp(FIRST_EXTENSION_RECORD_ID));
30e5dd7070Spatrick Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # of characters
31e5dd7070Spatrick Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // message
32e5dd7070Spatrick auto Abbrev = Stream.EmitAbbrev(std::move(Abv));
33e5dd7070Spatrick
34e5dd7070Spatrick // Write a message into the extension block.
35e5dd7070Spatrick SmallString<64> Message;
36e5dd7070Spatrick {
37e5dd7070Spatrick auto Ext = static_cast<TestModuleFileExtension *>(getExtension());
38e5dd7070Spatrick raw_svector_ostream OS(Message);
39e5dd7070Spatrick OS << "Hello from " << Ext->BlockName << " v" << Ext->MajorVersion << "."
40e5dd7070Spatrick << Ext->MinorVersion;
41e5dd7070Spatrick }
42e5dd7070Spatrick uint64_t Record[] = {FIRST_EXTENSION_RECORD_ID, Message.size()};
43e5dd7070Spatrick Stream.EmitRecordWithBlob(Abbrev, Record, Message);
44e5dd7070Spatrick }
45e5dd7070Spatrick
Reader(ModuleFileExtension * Ext,const llvm::BitstreamCursor & InStream)46e5dd7070Spatrick TestModuleFileExtension::Reader::Reader(ModuleFileExtension *Ext,
47e5dd7070Spatrick const llvm::BitstreamCursor &InStream)
48e5dd7070Spatrick : ModuleFileExtensionReader(Ext), Stream(InStream)
49e5dd7070Spatrick {
50e5dd7070Spatrick // Read the extension block.
51e5dd7070Spatrick SmallVector<uint64_t, 4> Record;
52e5dd7070Spatrick while (true) {
53e5dd7070Spatrick llvm::Expected<llvm::BitstreamEntry> MaybeEntry =
54e5dd7070Spatrick Stream.advanceSkippingSubblocks();
55e5dd7070Spatrick if (!MaybeEntry)
56e5dd7070Spatrick (void)MaybeEntry.takeError();
57e5dd7070Spatrick llvm::BitstreamEntry Entry = MaybeEntry.get();
58e5dd7070Spatrick
59e5dd7070Spatrick switch (Entry.Kind) {
60e5dd7070Spatrick case llvm::BitstreamEntry::SubBlock:
61e5dd7070Spatrick case llvm::BitstreamEntry::EndBlock:
62e5dd7070Spatrick case llvm::BitstreamEntry::Error:
63e5dd7070Spatrick return;
64e5dd7070Spatrick
65e5dd7070Spatrick case llvm::BitstreamEntry::Record:
66e5dd7070Spatrick break;
67e5dd7070Spatrick }
68e5dd7070Spatrick
69e5dd7070Spatrick Record.clear();
70e5dd7070Spatrick StringRef Blob;
71e5dd7070Spatrick Expected<unsigned> MaybeRecCode =
72e5dd7070Spatrick Stream.readRecord(Entry.ID, Record, &Blob);
73e5dd7070Spatrick if (!MaybeRecCode)
74e5dd7070Spatrick fprintf(stderr, "Failed reading rec code: %s\n",
75e5dd7070Spatrick toString(MaybeRecCode.takeError()).c_str());
76e5dd7070Spatrick switch (MaybeRecCode.get()) {
77e5dd7070Spatrick case FIRST_EXTENSION_RECORD_ID: {
78e5dd7070Spatrick StringRef Message = Blob.substr(0, Record[0]);
79e5dd7070Spatrick fprintf(stderr, "Read extension block message: %s\n",
80e5dd7070Spatrick Message.str().c_str());
81e5dd7070Spatrick break;
82e5dd7070Spatrick }
83e5dd7070Spatrick }
84e5dd7070Spatrick }
85e5dd7070Spatrick }
86e5dd7070Spatrick
~Reader()87e5dd7070Spatrick TestModuleFileExtension::Reader::~Reader() { }
88e5dd7070Spatrick
~TestModuleFileExtension()89e5dd7070Spatrick TestModuleFileExtension::~TestModuleFileExtension() { }
90e5dd7070Spatrick
91e5dd7070Spatrick ModuleFileExtensionMetadata
getExtensionMetadata() const92e5dd7070Spatrick TestModuleFileExtension::getExtensionMetadata() const {
93e5dd7070Spatrick return { BlockName, MajorVersion, MinorVersion, UserInfo };
94e5dd7070Spatrick }
95e5dd7070Spatrick
hashExtension(ExtensionHashBuilder & HBuilder) const96*12c85518Srobert void TestModuleFileExtension::hashExtension(
97*12c85518Srobert ExtensionHashBuilder &HBuilder) const {
98e5dd7070Spatrick if (Hashed) {
99*12c85518Srobert HBuilder.add(BlockName);
100*12c85518Srobert HBuilder.add(MajorVersion);
101*12c85518Srobert HBuilder.add(MinorVersion);
102*12c85518Srobert HBuilder.add(UserInfo);
103e5dd7070Spatrick }
104e5dd7070Spatrick }
105e5dd7070Spatrick
106e5dd7070Spatrick std::unique_ptr<ModuleFileExtensionWriter>
createExtensionWriter(ASTWriter &)107e5dd7070Spatrick TestModuleFileExtension::createExtensionWriter(ASTWriter &) {
108e5dd7070Spatrick return std::unique_ptr<ModuleFileExtensionWriter>(new Writer(this));
109e5dd7070Spatrick }
110e5dd7070Spatrick
111e5dd7070Spatrick std::unique_ptr<ModuleFileExtensionReader>
createExtensionReader(const ModuleFileExtensionMetadata & Metadata,ASTReader & Reader,serialization::ModuleFile & Mod,const llvm::BitstreamCursor & Stream)112e5dd7070Spatrick TestModuleFileExtension::createExtensionReader(
113e5dd7070Spatrick const ModuleFileExtensionMetadata &Metadata,
114e5dd7070Spatrick ASTReader &Reader, serialization::ModuleFile &Mod,
115e5dd7070Spatrick const llvm::BitstreamCursor &Stream)
116e5dd7070Spatrick {
117e5dd7070Spatrick assert(Metadata.BlockName == BlockName && "Wrong block name");
118e5dd7070Spatrick if (std::make_pair(Metadata.MajorVersion, Metadata.MinorVersion) !=
119e5dd7070Spatrick std::make_pair(MajorVersion, MinorVersion)) {
120e5dd7070Spatrick Reader.getDiags().Report(Mod.ImportLoc,
121e5dd7070Spatrick diag::err_test_module_file_extension_version)
122e5dd7070Spatrick << BlockName << Metadata.MajorVersion << Metadata.MinorVersion
123e5dd7070Spatrick << MajorVersion << MinorVersion;
124e5dd7070Spatrick return nullptr;
125e5dd7070Spatrick }
126e5dd7070Spatrick
127e5dd7070Spatrick return std::unique_ptr<ModuleFileExtensionReader>(
128e5dd7070Spatrick new TestModuleFileExtension::Reader(this, Stream));
129e5dd7070Spatrick }
130a9ac8606Spatrick
str() const131a9ac8606Spatrick std::string TestModuleFileExtension::str() const {
132a9ac8606Spatrick std::string Buffer;
133a9ac8606Spatrick llvm::raw_string_ostream OS(Buffer);
134a9ac8606Spatrick OS << BlockName << ":" << MajorVersion << ":" << MinorVersion << ":" << Hashed
135a9ac8606Spatrick << ":" << UserInfo;
136*12c85518Srobert return Buffer;
137a9ac8606Spatrick }
138