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