1//===-- TestModuleFileExtension.cpp - Module Extension Tester -------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9#include "TestModuleFileExtension.h"
10#include "clang/Frontend/FrontendDiagnostic.h"
11#include "clang/Serialization/ASTReader.h"
12#include "llvm/ADT/Hashing.h"
13#include "llvm/Bitcode/BitstreamWriter.h"
14#include "llvm/Support/raw_ostream.h"
15#include <cstdio>
16using namespace clang;
17using namespace clang::serialization;
18
19TestModuleFileExtension::Writer::~Writer() { }
20
21void TestModuleFileExtension::Writer::writeExtensionContents(
22       Sema &SemaRef,
23       llvm::BitstreamWriter &Stream) {
24  using namespace llvm;
25
26  // Write an abbreviation for this record.
27  BitCodeAbbrev *Abv = new llvm::BitCodeAbbrev();
28  Abv->Add(BitCodeAbbrevOp(FIRST_EXTENSION_RECORD_ID));
29  Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # of characters
30  Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));   // message
31  auto Abbrev = Stream.EmitAbbrev(Abv);
32
33  // Write a message into the extension block.
34  SmallString<64> Message;
35  {
36    auto Ext = static_cast<TestModuleFileExtension *>(getExtension());
37    raw_svector_ostream OS(Message);
38    OS << "Hello from " << Ext->BlockName << " v" << Ext->MajorVersion << "."
39       << Ext->MinorVersion;
40  }
41  SmallVector<uint64_t, 4> Record;
42  Record.push_back(FIRST_EXTENSION_RECORD_ID);
43  Record.push_back(Message.size());
44  Stream.EmitRecordWithBlob(Abbrev, Record, Message);
45}
46
47TestModuleFileExtension::Reader::Reader(ModuleFileExtension *Ext,
48                                        const llvm::BitstreamCursor &InStream)
49  : ModuleFileExtensionReader(Ext), Stream(InStream)
50{
51  // Read the extension block.
52  SmallVector<uint64_t, 4> Record;
53  while (true) {
54    llvm::BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
55    switch (Entry.Kind) {
56    case llvm::BitstreamEntry::SubBlock:
57    case llvm::BitstreamEntry::EndBlock:
58    case llvm::BitstreamEntry::Error:
59      return;
60
61    case llvm::BitstreamEntry::Record:
62      break;
63    }
64
65    Record.clear();
66    StringRef Blob;
67    unsigned RecCode = Stream.readRecord(Entry.ID, Record, &Blob);
68    switch (RecCode) {
69    case FIRST_EXTENSION_RECORD_ID: {
70      StringRef Message = Blob.substr(0, Record[0]);
71      fprintf(stderr, "Read extension block message: %s\n",
72              Message.str().c_str());
73      break;
74    }
75    }
76  }
77}
78
79TestModuleFileExtension::Reader::~Reader() { }
80
81TestModuleFileExtension::~TestModuleFileExtension() { }
82
83ModuleFileExtensionMetadata
84TestModuleFileExtension::getExtensionMetadata() const {
85  return { BlockName, MajorVersion, MinorVersion, UserInfo };
86}
87
88llvm::hash_code TestModuleFileExtension::hashExtension(
89                  llvm::hash_code Code) const {
90  if (Hashed) {
91    Code = llvm::hash_combine(Code, BlockName);
92    Code = llvm::hash_combine(Code, MajorVersion);
93    Code = llvm::hash_combine(Code, MinorVersion);
94    Code = llvm::hash_combine(Code, UserInfo);
95  }
96
97  return Code;
98}
99
100std::unique_ptr<ModuleFileExtensionWriter>
101TestModuleFileExtension::createExtensionWriter(ASTWriter &) {
102  return std::unique_ptr<ModuleFileExtensionWriter>(new Writer(this));
103}
104
105std::unique_ptr<ModuleFileExtensionReader>
106TestModuleFileExtension::createExtensionReader(
107  const ModuleFileExtensionMetadata &Metadata,
108  ASTReader &Reader, serialization::ModuleFile &Mod,
109  const llvm::BitstreamCursor &Stream)
110{
111  assert(Metadata.BlockName == BlockName && "Wrong block name");
112  if (std::make_pair(Metadata.MajorVersion, Metadata.MinorVersion) !=
113        std::make_pair(MajorVersion, MinorVersion)) {
114    Reader.getDiags().Report(Mod.ImportLoc,
115                             diag::err_test_module_file_extension_version)
116      << BlockName << Metadata.MajorVersion << Metadata.MinorVersion
117      << MajorVersion << MinorVersion;
118    return nullptr;
119  }
120
121  return std::unique_ptr<ModuleFileExtensionReader>(
122                                                    new TestModuleFileExtension::Reader(this, Stream));
123}
124