xref: /llvm-project/clang/lib/Frontend/TestModuleFileExtension.cpp (revision 2946cd701067404b99c39fb29dc9c74bd7193eb3)
1 //===-- TestModuleFileExtension.cpp - Module Extension Tester -------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 #include "TestModuleFileExtension.h"
9 #include "clang/Frontend/FrontendDiagnostic.h"
10 #include "clang/Serialization/ASTReader.h"
11 #include "llvm/ADT/Hashing.h"
12 #include "llvm/Bitcode/BitstreamWriter.h"
13 #include "llvm/Support/raw_ostream.h"
14 #include <cstdio>
15 using namespace clang;
16 using namespace clang::serialization;
17 
18 TestModuleFileExtension::Writer::~Writer() { }
19 
20 void TestModuleFileExtension::Writer::writeExtensionContents(
21        Sema &SemaRef,
22        llvm::BitstreamWriter &Stream) {
23   using namespace llvm;
24 
25   // Write an abbreviation for this record.
26   auto Abv = std::make_shared<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(std::move(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   uint64_t Record[] = {FIRST_EXTENSION_RECORD_ID, Message.size()};
41   Stream.EmitRecordWithBlob(Abbrev, Record, Message);
42 }
43 
44 TestModuleFileExtension::Reader::Reader(ModuleFileExtension *Ext,
45                                         const llvm::BitstreamCursor &InStream)
46   : ModuleFileExtensionReader(Ext), Stream(InStream)
47 {
48   // Read the extension block.
49   SmallVector<uint64_t, 4> Record;
50   while (true) {
51     llvm::BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
52     switch (Entry.Kind) {
53     case llvm::BitstreamEntry::SubBlock:
54     case llvm::BitstreamEntry::EndBlock:
55     case llvm::BitstreamEntry::Error:
56       return;
57 
58     case llvm::BitstreamEntry::Record:
59       break;
60     }
61 
62     Record.clear();
63     StringRef Blob;
64     unsigned RecCode = Stream.readRecord(Entry.ID, Record, &Blob);
65     switch (RecCode) {
66     case FIRST_EXTENSION_RECORD_ID: {
67       StringRef Message = Blob.substr(0, Record[0]);
68       fprintf(stderr, "Read extension block message: %s\n",
69               Message.str().c_str());
70       break;
71     }
72     }
73   }
74 }
75 
76 TestModuleFileExtension::Reader::~Reader() { }
77 
78 TestModuleFileExtension::~TestModuleFileExtension() { }
79 
80 ModuleFileExtensionMetadata
81 TestModuleFileExtension::getExtensionMetadata() const {
82   return { BlockName, MajorVersion, MinorVersion, UserInfo };
83 }
84 
85 llvm::hash_code TestModuleFileExtension::hashExtension(
86                   llvm::hash_code Code) const {
87   if (Hashed) {
88     Code = llvm::hash_combine(Code, BlockName);
89     Code = llvm::hash_combine(Code, MajorVersion);
90     Code = llvm::hash_combine(Code, MinorVersion);
91     Code = llvm::hash_combine(Code, UserInfo);
92   }
93 
94   return Code;
95 }
96 
97 std::unique_ptr<ModuleFileExtensionWriter>
98 TestModuleFileExtension::createExtensionWriter(ASTWriter &) {
99   return std::unique_ptr<ModuleFileExtensionWriter>(new Writer(this));
100 }
101 
102 std::unique_ptr<ModuleFileExtensionReader>
103 TestModuleFileExtension::createExtensionReader(
104   const ModuleFileExtensionMetadata &Metadata,
105   ASTReader &Reader, serialization::ModuleFile &Mod,
106   const llvm::BitstreamCursor &Stream)
107 {
108   assert(Metadata.BlockName == BlockName && "Wrong block name");
109   if (std::make_pair(Metadata.MajorVersion, Metadata.MinorVersion) !=
110         std::make_pair(MajorVersion, MinorVersion)) {
111     Reader.getDiags().Report(Mod.ImportLoc,
112                              diag::err_test_module_file_extension_version)
113       << BlockName << Metadata.MajorVersion << Metadata.MinorVersion
114       << MajorVersion << MinorVersion;
115     return nullptr;
116   }
117 
118   return std::unique_ptr<ModuleFileExtensionReader>(
119                                                     new TestModuleFileExtension::Reader(this, Stream));
120 }
121