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