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  uint64_t Record[] = {FIRST_EXTENSION_RECORD_ID, Message.size()};
42  Stream.EmitRecordWithBlob(Abbrev, Record, Message);
43}
44
45TestModuleFileExtension::Reader::Reader(ModuleFileExtension *Ext,
46                                        const llvm::BitstreamCursor &InStream)
47  : ModuleFileExtensionReader(Ext), Stream(InStream)
48{
49  // Read the extension block.
50  SmallVector<uint64_t, 4> Record;
51  while (true) {
52    llvm::BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
53    switch (Entry.Kind) {
54    case llvm::BitstreamEntry::SubBlock:
55    case llvm::BitstreamEntry::EndBlock:
56    case llvm::BitstreamEntry::Error:
57      return;
58
59    case llvm::BitstreamEntry::Record:
60      break;
61    }
62
63    Record.clear();
64    StringRef Blob;
65    unsigned RecCode = Stream.readRecord(Entry.ID, Record, &Blob);
66    switch (RecCode) {
67    case FIRST_EXTENSION_RECORD_ID: {
68      StringRef Message = Blob.substr(0, Record[0]);
69      fprintf(stderr, "Read extension block message: %s\n",
70              Message.str().c_str());
71      break;
72    }
73    }
74  }
75}
76
77TestModuleFileExtension::Reader::~Reader() { }
78
79TestModuleFileExtension::~TestModuleFileExtension() { }
80
81ModuleFileExtensionMetadata
82TestModuleFileExtension::getExtensionMetadata() const {
83  return { BlockName, MajorVersion, MinorVersion, UserInfo };
84}
85
86llvm::hash_code TestModuleFileExtension::hashExtension(
87                  llvm::hash_code Code) const {
88  if (Hashed) {
89    Code = llvm::hash_combine(Code, BlockName);
90    Code = llvm::hash_combine(Code, MajorVersion);
91    Code = llvm::hash_combine(Code, MinorVersion);
92    Code = llvm::hash_combine(Code, UserInfo);
93  }
94
95  return Code;
96}
97
98std::unique_ptr<ModuleFileExtensionWriter>
99TestModuleFileExtension::createExtensionWriter(ASTWriter &) {
100  return std::unique_ptr<ModuleFileExtensionWriter>(new Writer(this));
101}
102
103std::unique_ptr<ModuleFileExtensionReader>
104TestModuleFileExtension::createExtensionReader(
105  const ModuleFileExtensionMetadata &Metadata,
106  ASTReader &Reader, serialization::ModuleFile &Mod,
107  const llvm::BitstreamCursor &Stream)
108{
109  assert(Metadata.BlockName == BlockName && "Wrong block name");
110  if (std::make_pair(Metadata.MajorVersion, Metadata.MinorVersion) !=
111        std::make_pair(MajorVersion, MinorVersion)) {
112    Reader.getDiags().Report(Mod.ImportLoc,
113                             diag::err_test_module_file_extension_version)
114      << BlockName << Metadata.MajorVersion << Metadata.MinorVersion
115      << MajorVersion << MinorVersion;
116    return nullptr;
117  }
118
119  return std::unique_ptr<ModuleFileExtensionReader>(
120                                                    new TestModuleFileExtension::Reader(this, Stream));
121}
122