xref: /freebsd/contrib/llvm-project/clang/lib/Frontend/TestModuleFileExtension.cpp (revision 52d973f52c07b94909a6487be373c269988dc151)
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/Bitstream/BitstreamWriter.h"
13 #include "llvm/Support/raw_ostream.h"
14 #include <cstdio>
15 using namespace clang;
16 using namespace clang::serialization;
17 
18 char TestModuleFileExtension::ID = 0;
19 
20 TestModuleFileExtension::Writer::~Writer() { }
21 
22 void TestModuleFileExtension::Writer::writeExtensionContents(
23        Sema &SemaRef,
24        llvm::BitstreamWriter &Stream) {
25   using namespace llvm;
26 
27   // Write an abbreviation for this record.
28   auto Abv = std::make_shared<llvm::BitCodeAbbrev>();
29   Abv->Add(BitCodeAbbrevOp(FIRST_EXTENSION_RECORD_ID));
30   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # of characters
31   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));   // message
32   auto Abbrev = Stream.EmitAbbrev(std::move(Abv));
33 
34   // Write a message into the extension block.
35   SmallString<64> Message;
36   {
37     auto Ext = static_cast<TestModuleFileExtension *>(getExtension());
38     raw_svector_ostream OS(Message);
39     OS << "Hello from " << Ext->BlockName << " v" << Ext->MajorVersion << "."
40        << Ext->MinorVersion;
41   }
42   uint64_t Record[] = {FIRST_EXTENSION_RECORD_ID, 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::Expected<llvm::BitstreamEntry> MaybeEntry =
54         Stream.advanceSkippingSubblocks();
55     if (!MaybeEntry)
56       (void)MaybeEntry.takeError();
57     llvm::BitstreamEntry Entry = MaybeEntry.get();
58 
59     switch (Entry.Kind) {
60     case llvm::BitstreamEntry::SubBlock:
61     case llvm::BitstreamEntry::EndBlock:
62     case llvm::BitstreamEntry::Error:
63       return;
64 
65     case llvm::BitstreamEntry::Record:
66       break;
67     }
68 
69     Record.clear();
70     StringRef Blob;
71     Expected<unsigned> MaybeRecCode =
72         Stream.readRecord(Entry.ID, Record, &Blob);
73     if (!MaybeRecCode)
74       fprintf(stderr, "Failed reading rec code: %s\n",
75               toString(MaybeRecCode.takeError()).c_str());
76     switch (MaybeRecCode.get()) {
77     case FIRST_EXTENSION_RECORD_ID: {
78       StringRef Message = Blob.substr(0, Record[0]);
79       fprintf(stderr, "Read extension block message: %s\n",
80               Message.str().c_str());
81       break;
82     }
83     }
84   }
85 }
86 
87 TestModuleFileExtension::Reader::~Reader() { }
88 
89 TestModuleFileExtension::~TestModuleFileExtension() { }
90 
91 ModuleFileExtensionMetadata
92 TestModuleFileExtension::getExtensionMetadata() const {
93   return { BlockName, MajorVersion, MinorVersion, UserInfo };
94 }
95 
96 llvm::hash_code TestModuleFileExtension::hashExtension(
97                   llvm::hash_code Code) const {
98   if (Hashed) {
99     Code = llvm::hash_combine(Code, BlockName);
100     Code = llvm::hash_combine(Code, MajorVersion);
101     Code = llvm::hash_combine(Code, MinorVersion);
102     Code = llvm::hash_combine(Code, UserInfo);
103   }
104 
105   return Code;
106 }
107 
108 std::unique_ptr<ModuleFileExtensionWriter>
109 TestModuleFileExtension::createExtensionWriter(ASTWriter &) {
110   return std::unique_ptr<ModuleFileExtensionWriter>(new Writer(this));
111 }
112 
113 std::unique_ptr<ModuleFileExtensionReader>
114 TestModuleFileExtension::createExtensionReader(
115   const ModuleFileExtensionMetadata &Metadata,
116   ASTReader &Reader, serialization::ModuleFile &Mod,
117   const llvm::BitstreamCursor &Stream)
118 {
119   assert(Metadata.BlockName == BlockName && "Wrong block name");
120   if (std::make_pair(Metadata.MajorVersion, Metadata.MinorVersion) !=
121         std::make_pair(MajorVersion, MinorVersion)) {
122     Reader.getDiags().Report(Mod.ImportLoc,
123                              diag::err_test_module_file_extension_version)
124       << BlockName << Metadata.MajorVersion << Metadata.MinorVersion
125       << MajorVersion << MinorVersion;
126     return nullptr;
127   }
128 
129   return std::unique_ptr<ModuleFileExtensionReader>(
130                                                     new TestModuleFileExtension::Reader(this, Stream));
131 }
132 
133 std::string TestModuleFileExtension::str() const {
134   std::string Buffer;
135   llvm::raw_string_ostream OS(Buffer);
136   OS << BlockName << ":" << MajorVersion << ":" << MinorVersion << ":" << Hashed
137      << ":" << UserInfo;
138   return OS.str();
139 }
140