1//===-- BitcodeWriter.cpp - ClangDoc Bitcode Writer ------------*- C++ -*-===//
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
9#include "BitcodeWriter.h"
10#include "llvm/ADT/IndexedMap.h"
11#include <initializer_list>
12
13namespace clang {
14namespace doc {
15
16// Empty SymbolID for comparison, so we don't have to construct one every time.
17static const SymbolID EmptySID = SymbolID();
18
19// Since id enums are not zero-indexed, we need to transform the given id into
20// its associated index.
21struct BlockIdToIndexFunctor {
22 using argument_type = unsigned;
23 unsigned operator()(unsigned ID) const { return ID - BI_FIRST; }
24};
25
26struct RecordIdToIndexFunctor {
27 using argument_type = unsigned;
28 unsigned operator()(unsigned ID) const { return ID - RI_FIRST; }
29};
30
31using AbbrevDsc = void (*)(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev);
32
33static void AbbrevGen(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev,
34 const std::initializer_list<llvm::BitCodeAbbrevOp> Ops) {
35 for (const auto &Op : Ops)
36 Abbrev->Add(OpInfo: Op);
37}
38
39static void BoolAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {
40 AbbrevGen(Abbrev,
41 Ops: {// 0. Boolean
42 llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
43 BitCodeConstants::BoolSize)});
44}
45
46static void IntAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {
47 AbbrevGen(Abbrev,
48 Ops: {// 0. Fixed-size integer
49 llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
50 BitCodeConstants::IntSize)});
51}
52
53static void SymbolIDAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {
54 AbbrevGen(Abbrev,
55 Ops: {// 0. Fixed-size integer (length of the sha1'd USR)
56 llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
57 BitCodeConstants::USRLengthSize),
58 // 1. Fixed-size array of Char6 (USR)
59 llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Array),
60 llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
61 BitCodeConstants::USRBitLengthSize)});
62}
63
64static void StringAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {
65 AbbrevGen(Abbrev,
66 Ops: {// 0. Fixed-size integer (length of the following string)
67 llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
68 BitCodeConstants::StringLengthSize),
69 // 1. The string blob
70 llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)});
71}
72
73// Assumes that the file will not have more than 65535 lines.
74static void LocationAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {
75 AbbrevGen(
76 Abbrev,
77 Ops: {// 0. Fixed-size integer (line number)
78 llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
79 BitCodeConstants::LineNumberSize),
80 // 1. Boolean (IsFileInRootDir)
81 llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
82 BitCodeConstants::BoolSize),
83 // 2. Fixed-size integer (length of the following string (filename))
84 llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
85 BitCodeConstants::StringLengthSize),
86 // 3. The string blob
87 llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)});
88}
89
90struct RecordIdDsc {
91 llvm::StringRef Name;
92 AbbrevDsc Abbrev = nullptr;
93
94 RecordIdDsc() = default;
95 RecordIdDsc(llvm::StringRef Name, AbbrevDsc Abbrev)
96 : Name(Name), Abbrev(Abbrev) {}
97
98 // Is this 'description' valid?
99 operator bool() const {
100 return Abbrev != nullptr && Name.data() != nullptr && !Name.empty();
101 }
102};
103
104static const llvm::IndexedMap<llvm::StringRef, BlockIdToIndexFunctor>
105 BlockIdNameMap = []() {
106 llvm::IndexedMap<llvm::StringRef, BlockIdToIndexFunctor> BlockIdNameMap;
107 BlockIdNameMap.resize(s: BlockIdCount);
108
109 // There is no init-list constructor for the IndexedMap, so have to
110 // improvise
111 static const std::vector<std::pair<BlockId, const char *const>> Inits = {
112 {BI_VERSION_BLOCK_ID, "VersionBlock"},
113 {BI_NAMESPACE_BLOCK_ID, "NamespaceBlock"},
114 {BI_ENUM_BLOCK_ID, "EnumBlock"},
115 {BI_ENUM_VALUE_BLOCK_ID, "EnumValueBlock"},
116 {BI_TYPEDEF_BLOCK_ID, "TypedefBlock"},
117 {BI_TYPE_BLOCK_ID, "TypeBlock"},
118 {BI_FIELD_TYPE_BLOCK_ID, "FieldTypeBlock"},
119 {BI_MEMBER_TYPE_BLOCK_ID, "MemberTypeBlock"},
120 {BI_RECORD_BLOCK_ID, "RecordBlock"},
121 {BI_BASE_RECORD_BLOCK_ID, "BaseRecordBlock"},
122 {BI_FUNCTION_BLOCK_ID, "FunctionBlock"},
123 {BI_COMMENT_BLOCK_ID, "CommentBlock"},
124 {BI_REFERENCE_BLOCK_ID, "ReferenceBlock"},
125 {BI_TEMPLATE_BLOCK_ID, "TemplateBlock"},
126 {BI_TEMPLATE_SPECIALIZATION_BLOCK_ID, "TemplateSpecializationBlock"},
127 {BI_TEMPLATE_PARAM_BLOCK_ID, "TemplateParamBlock"}};
128 assert(Inits.size() == BlockIdCount);
129 for (const auto &Init : Inits)
130 BlockIdNameMap[Init.first] = Init.second;
131 assert(BlockIdNameMap.size() == BlockIdCount);
132 return BlockIdNameMap;
133 }();
134
135static const llvm::IndexedMap<RecordIdDsc, RecordIdToIndexFunctor>
136 RecordIdNameMap = []() {
137 llvm::IndexedMap<RecordIdDsc, RecordIdToIndexFunctor> RecordIdNameMap;
138 RecordIdNameMap.resize(s: RecordIdCount);
139
140 // There is no init-list constructor for the IndexedMap, so have to
141 // improvise
142 static const std::vector<std::pair<RecordId, RecordIdDsc>> Inits = {
143 {VERSION, {"Version", &IntAbbrev}},
144 {COMMENT_KIND, {"Kind", &StringAbbrev}},
145 {COMMENT_TEXT, {"Text", &StringAbbrev}},
146 {COMMENT_NAME, {"Name", &StringAbbrev}},
147 {COMMENT_DIRECTION, {"Direction", &StringAbbrev}},
148 {COMMENT_PARAMNAME, {"ParamName", &StringAbbrev}},
149 {COMMENT_CLOSENAME, {"CloseName", &StringAbbrev}},
150 {COMMENT_SELFCLOSING, {"SelfClosing", &BoolAbbrev}},
151 {COMMENT_EXPLICIT, {"Explicit", &BoolAbbrev}},
152 {COMMENT_ATTRKEY, {"AttrKey", &StringAbbrev}},
153 {COMMENT_ATTRVAL, {"AttrVal", &StringAbbrev}},
154 {COMMENT_ARG, {"Arg", &StringAbbrev}},
155 {FIELD_TYPE_NAME, {"Name", &StringAbbrev}},
156 {FIELD_DEFAULT_VALUE, {"DefaultValue", &StringAbbrev}},
157 {MEMBER_TYPE_NAME, {"Name", &StringAbbrev}},
158 {MEMBER_TYPE_ACCESS, {"Access", &IntAbbrev}},
159 {NAMESPACE_USR, {"USR", &SymbolIDAbbrev}},
160 {NAMESPACE_NAME, {"Name", &StringAbbrev}},
161 {NAMESPACE_PATH, {"Path", &StringAbbrev}},
162 {ENUM_USR, {"USR", &SymbolIDAbbrev}},
163 {ENUM_NAME, {"Name", &StringAbbrev}},
164 {ENUM_DEFLOCATION, {"DefLocation", &LocationAbbrev}},
165 {ENUM_LOCATION, {"Location", &LocationAbbrev}},
166 {ENUM_SCOPED, {"Scoped", &BoolAbbrev}},
167 {ENUM_VALUE_NAME, {"Name", &StringAbbrev}},
168 {ENUM_VALUE_VALUE, {"Value", &StringAbbrev}},
169 {ENUM_VALUE_EXPR, {"Expr", &StringAbbrev}},
170 {RECORD_USR, {"USR", &SymbolIDAbbrev}},
171 {RECORD_NAME, {"Name", &StringAbbrev}},
172 {RECORD_PATH, {"Path", &StringAbbrev}},
173 {RECORD_DEFLOCATION, {"DefLocation", &LocationAbbrev}},
174 {RECORD_LOCATION, {"Location", &LocationAbbrev}},
175 {RECORD_TAG_TYPE, {"TagType", &IntAbbrev}},
176 {RECORD_IS_TYPE_DEF, {"IsTypeDef", &BoolAbbrev}},
177 {BASE_RECORD_USR, {"USR", &SymbolIDAbbrev}},
178 {BASE_RECORD_NAME, {"Name", &StringAbbrev}},
179 {BASE_RECORD_PATH, {"Path", &StringAbbrev}},
180 {BASE_RECORD_TAG_TYPE, {"TagType", &IntAbbrev}},
181 {BASE_RECORD_IS_VIRTUAL, {"IsVirtual", &BoolAbbrev}},
182 {BASE_RECORD_ACCESS, {"Access", &IntAbbrev}},
183 {BASE_RECORD_IS_PARENT, {"IsParent", &BoolAbbrev}},
184 {FUNCTION_USR, {"USR", &SymbolIDAbbrev}},
185 {FUNCTION_NAME, {"Name", &StringAbbrev}},
186 {FUNCTION_DEFLOCATION, {"DefLocation", &LocationAbbrev}},
187 {FUNCTION_LOCATION, {"Location", &LocationAbbrev}},
188 {FUNCTION_ACCESS, {"Access", &IntAbbrev}},
189 {FUNCTION_IS_METHOD, {"IsMethod", &BoolAbbrev}},
190 {REFERENCE_USR, {"USR", &SymbolIDAbbrev}},
191 {REFERENCE_NAME, {"Name", &StringAbbrev}},
192 {REFERENCE_QUAL_NAME, {"QualName", &StringAbbrev}},
193 {REFERENCE_TYPE, {"RefType", &IntAbbrev}},
194 {REFERENCE_PATH, {"Path", &StringAbbrev}},
195 {REFERENCE_FIELD, {"Field", &IntAbbrev}},
196 {TEMPLATE_PARAM_CONTENTS, {"Contents", &StringAbbrev}},
197 {TEMPLATE_SPECIALIZATION_OF, {"SpecializationOf", &SymbolIDAbbrev}},
198 {TYPEDEF_USR, {"USR", &SymbolIDAbbrev}},
199 {TYPEDEF_NAME, {"Name", &StringAbbrev}},
200 {TYPEDEF_DEFLOCATION, {"DefLocation", &LocationAbbrev}},
201 {TYPEDEF_IS_USING, {"IsUsing", &BoolAbbrev}}};
202 assert(Inits.size() == RecordIdCount);
203 for (const auto &Init : Inits) {
204 RecordIdNameMap[Init.first] = Init.second;
205 assert((Init.second.Name.size() + 1) <= BitCodeConstants::RecordSize);
206 }
207 assert(RecordIdNameMap.size() == RecordIdCount);
208 return RecordIdNameMap;
209 }();
210
211static const std::vector<std::pair<BlockId, std::vector<RecordId>>>
212 RecordsByBlock{
213 // Version Block
214 {BI_VERSION_BLOCK_ID, {VERSION}},
215 // Comment Block
216 {BI_COMMENT_BLOCK_ID,
217 {COMMENT_KIND, COMMENT_TEXT, COMMENT_NAME, COMMENT_DIRECTION,
218 COMMENT_PARAMNAME, COMMENT_CLOSENAME, COMMENT_SELFCLOSING,
219 COMMENT_EXPLICIT, COMMENT_ATTRKEY, COMMENT_ATTRVAL, COMMENT_ARG}},
220 // Type Block
221 {BI_TYPE_BLOCK_ID, {}},
222 // FieldType Block
223 {BI_FIELD_TYPE_BLOCK_ID, {FIELD_TYPE_NAME, FIELD_DEFAULT_VALUE}},
224 // MemberType Block
225 {BI_MEMBER_TYPE_BLOCK_ID, {MEMBER_TYPE_NAME, MEMBER_TYPE_ACCESS}},
226 // Enum Block
227 {BI_ENUM_BLOCK_ID,
228 {ENUM_USR, ENUM_NAME, ENUM_DEFLOCATION, ENUM_LOCATION, ENUM_SCOPED}},
229 // Enum Value Block
230 {BI_ENUM_VALUE_BLOCK_ID,
231 {ENUM_VALUE_NAME, ENUM_VALUE_VALUE, ENUM_VALUE_EXPR}},
232 // Typedef Block
233 {BI_TYPEDEF_BLOCK_ID,
234 {TYPEDEF_USR, TYPEDEF_NAME, TYPEDEF_DEFLOCATION, TYPEDEF_IS_USING}},
235 // Namespace Block
236 {BI_NAMESPACE_BLOCK_ID,
237 {NAMESPACE_USR, NAMESPACE_NAME, NAMESPACE_PATH}},
238 // Record Block
239 {BI_RECORD_BLOCK_ID,
240 {RECORD_USR, RECORD_NAME, RECORD_PATH, RECORD_DEFLOCATION,
241 RECORD_LOCATION, RECORD_TAG_TYPE, RECORD_IS_TYPE_DEF}},
242 // BaseRecord Block
243 {BI_BASE_RECORD_BLOCK_ID,
244 {BASE_RECORD_USR, BASE_RECORD_NAME, BASE_RECORD_PATH,
245 BASE_RECORD_TAG_TYPE, BASE_RECORD_IS_VIRTUAL, BASE_RECORD_ACCESS,
246 BASE_RECORD_IS_PARENT}},
247 // Function Block
248 {BI_FUNCTION_BLOCK_ID,
249 {FUNCTION_USR, FUNCTION_NAME, FUNCTION_DEFLOCATION, FUNCTION_LOCATION,
250 FUNCTION_ACCESS, FUNCTION_IS_METHOD}},
251 // Reference Block
252 {BI_REFERENCE_BLOCK_ID,
253 {REFERENCE_USR, REFERENCE_NAME, REFERENCE_QUAL_NAME, REFERENCE_TYPE,
254 REFERENCE_PATH, REFERENCE_FIELD}},
255 // Template Blocks.
256 {BI_TEMPLATE_BLOCK_ID, {}},
257 {BI_TEMPLATE_PARAM_BLOCK_ID, {TEMPLATE_PARAM_CONTENTS}},
258 {BI_TEMPLATE_SPECIALIZATION_BLOCK_ID, {TEMPLATE_SPECIALIZATION_OF}}};
259
260// AbbreviationMap
261
262constexpr unsigned char BitCodeConstants::Signature[];
263
264void ClangDocBitcodeWriter::AbbreviationMap::add(RecordId RID,
265 unsigned AbbrevID) {
266 assert(RecordIdNameMap[RID] && "Unknown RecordId.");
267 assert(!Abbrevs.contains(RID) && "Abbreviation already added.");
268 Abbrevs[RID] = AbbrevID;
269}
270
271unsigned ClangDocBitcodeWriter::AbbreviationMap::get(RecordId RID) const {
272 assert(RecordIdNameMap[RID] && "Unknown RecordId.");
273 assert(Abbrevs.contains(RID) && "Unknown abbreviation.");
274 return Abbrevs.lookup(Val: RID);
275}
276
277// Validation and Overview Blocks
278
279/// Emits the magic number header to check that its the right format,
280/// in this case, 'DOCS'.
281void ClangDocBitcodeWriter::emitHeader() {
282 for (char C : BitCodeConstants::Signature)
283 Stream.Emit(Val: (unsigned)C, NumBits: BitCodeConstants::SignatureBitSize);
284}
285
286void ClangDocBitcodeWriter::emitVersionBlock() {
287 StreamSubBlockGuard Block(Stream, BI_VERSION_BLOCK_ID);
288 emitRecord(Value: VersionNumber, ID: VERSION);
289}
290
291/// Emits a block ID and the block name to the BLOCKINFO block.
292void ClangDocBitcodeWriter::emitBlockID(BlockId BID) {
293 const auto &BlockIdName = BlockIdNameMap[BID];
294 assert(BlockIdName.data() && BlockIdName.size() && "Unknown BlockId.");
295
296 Record.clear();
297 Record.push_back(Elt: BID);
298 Stream.EmitRecord(Code: llvm::bitc::BLOCKINFO_CODE_SETBID, Vals: Record);
299 Stream.EmitRecord(Code: llvm::bitc::BLOCKINFO_CODE_BLOCKNAME,
300 Vals: ArrayRef<unsigned char>(BlockIdName.bytes_begin(),
301 BlockIdName.bytes_end()));
302}
303
304/// Emits a record name to the BLOCKINFO block.
305void ClangDocBitcodeWriter::emitRecordID(RecordId ID) {
306 assert(RecordIdNameMap[ID] && "Unknown RecordId.");
307 prepRecordData(ID);
308 Record.append(in_start: RecordIdNameMap[ID].Name.begin(),
309 in_end: RecordIdNameMap[ID].Name.end());
310 Stream.EmitRecord(Code: llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Vals: Record);
311}
312
313// Abbreviations
314
315void ClangDocBitcodeWriter::emitAbbrev(RecordId ID, BlockId Block) {
316 assert(RecordIdNameMap[ID] && "Unknown abbreviation.");
317 auto Abbrev = std::make_shared<llvm::BitCodeAbbrev>();
318 Abbrev->Add(OpInfo: llvm::BitCodeAbbrevOp(ID));
319 RecordIdNameMap[ID].Abbrev(Abbrev);
320 Abbrevs.add(RID: ID, AbbrevID: Stream.EmitBlockInfoAbbrev(BlockID: Block, Abbv: std::move(Abbrev)));
321}
322
323// Records
324
325void ClangDocBitcodeWriter::emitRecord(const SymbolID &Sym, RecordId ID) {
326 assert(RecordIdNameMap[ID] && "Unknown RecordId.");
327 assert(RecordIdNameMap[ID].Abbrev == &SymbolIDAbbrev &&
328 "Abbrev type mismatch.");
329 if (!prepRecordData(ID, ShouldEmit: Sym != EmptySID))
330 return;
331 assert(Sym.size() == 20);
332 Record.push_back(Elt: Sym.size());
333 Record.append(in_start: Sym.begin(), in_end: Sym.end());
334 Stream.EmitRecordWithAbbrev(Abbrev: Abbrevs.get(RID: ID), Vals: Record);
335}
336
337void ClangDocBitcodeWriter::emitRecord(llvm::StringRef Str, RecordId ID) {
338 assert(RecordIdNameMap[ID] && "Unknown RecordId.");
339 assert(RecordIdNameMap[ID].Abbrev == &StringAbbrev &&
340 "Abbrev type mismatch.");
341 if (!prepRecordData(ID, ShouldEmit: !Str.empty()))
342 return;
343 assert(Str.size() < (1U << BitCodeConstants::StringLengthSize));
344 Record.push_back(Elt: Str.size());
345 Stream.EmitRecordWithBlob(Abbrev: Abbrevs.get(RID: ID), Vals: Record, Blob: Str);
346}
347
348void ClangDocBitcodeWriter::emitRecord(const Location &Loc, RecordId ID) {
349 assert(RecordIdNameMap[ID] && "Unknown RecordId.");
350 assert(RecordIdNameMap[ID].Abbrev == &LocationAbbrev &&
351 "Abbrev type mismatch.");
352 if (!prepRecordData(ID, ShouldEmit: true))
353 return;
354 // FIXME: Assert that the line number is of the appropriate size.
355 Record.push_back(Elt: Loc.LineNumber);
356 assert(Loc.Filename.size() < (1U << BitCodeConstants::StringLengthSize));
357 Record.push_back(Elt: Loc.IsFileInRootDir);
358 Record.push_back(Elt: Loc.Filename.size());
359 Stream.EmitRecordWithBlob(Abbrev: Abbrevs.get(RID: ID), Vals: Record, Blob: Loc.Filename);
360}
361
362void ClangDocBitcodeWriter::emitRecord(bool Val, RecordId ID) {
363 assert(RecordIdNameMap[ID] && "Unknown RecordId.");
364 assert(RecordIdNameMap[ID].Abbrev == &BoolAbbrev && "Abbrev type mismatch.");
365 if (!prepRecordData(ID, ShouldEmit: Val))
366 return;
367 Record.push_back(Elt: Val);
368 Stream.EmitRecordWithAbbrev(Abbrev: Abbrevs.get(RID: ID), Vals: Record);
369}
370
371void ClangDocBitcodeWriter::emitRecord(int Val, RecordId ID) {
372 assert(RecordIdNameMap[ID] && "Unknown RecordId.");
373 assert(RecordIdNameMap[ID].Abbrev == &IntAbbrev && "Abbrev type mismatch.");
374 if (!prepRecordData(ID, ShouldEmit: Val))
375 return;
376 // FIXME: Assert that the integer is of the appropriate size.
377 Record.push_back(Elt: Val);
378 Stream.EmitRecordWithAbbrev(Abbrev: Abbrevs.get(RID: ID), Vals: Record);
379}
380
381void ClangDocBitcodeWriter::emitRecord(unsigned Val, RecordId ID) {
382 assert(RecordIdNameMap[ID] && "Unknown RecordId.");
383 assert(RecordIdNameMap[ID].Abbrev == &IntAbbrev && "Abbrev type mismatch.");
384 if (!prepRecordData(ID, ShouldEmit: Val))
385 return;
386 assert(Val < (1U << BitCodeConstants::IntSize));
387 Record.push_back(Elt: Val);
388 Stream.EmitRecordWithAbbrev(Abbrev: Abbrevs.get(RID: ID), Vals: Record);
389}
390
391void ClangDocBitcodeWriter::emitRecord(const TemplateInfo &Templ) {}
392
393bool ClangDocBitcodeWriter::prepRecordData(RecordId ID, bool ShouldEmit) {
394 assert(RecordIdNameMap[ID] && "Unknown RecordId.");
395 if (!ShouldEmit)
396 return false;
397 Record.clear();
398 Record.push_back(Elt: ID);
399 return true;
400}
401
402// BlockInfo Block
403
404void ClangDocBitcodeWriter::emitBlockInfoBlock() {
405 Stream.EnterBlockInfoBlock();
406 for (const auto &Block : RecordsByBlock) {
407 assert(Block.second.size() < (1U << BitCodeConstants::SubblockIDSize));
408 emitBlockInfo(BID: Block.first, RIDs: Block.second);
409 }
410 Stream.ExitBlock();
411}
412
413void ClangDocBitcodeWriter::emitBlockInfo(BlockId BID,
414 const std::vector<RecordId> &RIDs) {
415 assert(RIDs.size() < (1U << BitCodeConstants::SubblockIDSize));
416 emitBlockID(BID);
417 for (RecordId RID : RIDs) {
418 emitRecordID(ID: RID);
419 emitAbbrev(ID: RID, Block: BID);
420 }
421}
422
423// Block emission
424
425void ClangDocBitcodeWriter::emitBlock(const Reference &R, FieldId Field) {
426 if (R.USR == EmptySID && R.Name.empty())
427 return;
428 StreamSubBlockGuard Block(Stream, BI_REFERENCE_BLOCK_ID);
429 emitRecord(Sym: R.USR, ID: REFERENCE_USR);
430 emitRecord(Str: R.Name, ID: REFERENCE_NAME);
431 emitRecord(Str: R.QualName, ID: REFERENCE_QUAL_NAME);
432 emitRecord(Val: (unsigned)R.RefType, ID: REFERENCE_TYPE);
433 emitRecord(Str: R.Path, ID: REFERENCE_PATH);
434 emitRecord(Val: (unsigned)Field, ID: REFERENCE_FIELD);
435}
436
437void ClangDocBitcodeWriter::emitBlock(const TypeInfo &T) {
438 StreamSubBlockGuard Block(Stream, BI_TYPE_BLOCK_ID);
439 emitBlock(R: T.Type, Field: FieldId::F_type);
440}
441
442void ClangDocBitcodeWriter::emitBlock(const TypedefInfo &T) {
443 StreamSubBlockGuard Block(Stream, BI_TYPEDEF_BLOCK_ID);
444 emitRecord(Sym: T.USR, ID: TYPEDEF_USR);
445 emitRecord(Str: T.Name, ID: TYPEDEF_NAME);
446 for (const auto &N : T.Namespace)
447 emitBlock(R: N, Field: FieldId::F_namespace);
448 for (const auto &CI : T.Description)
449 emitBlock(B: CI);
450 if (T.DefLoc)
451 emitRecord(Loc: *T.DefLoc, ID: TYPEDEF_DEFLOCATION);
452 emitRecord(Val: T.IsUsing, ID: TYPEDEF_IS_USING);
453 emitBlock(T: T.Underlying);
454}
455
456void ClangDocBitcodeWriter::emitBlock(const FieldTypeInfo &T) {
457 StreamSubBlockGuard Block(Stream, BI_FIELD_TYPE_BLOCK_ID);
458 emitBlock(R: T.Type, Field: FieldId::F_type);
459 emitRecord(Str: T.Name, ID: FIELD_TYPE_NAME);
460 emitRecord(Str: T.DefaultValue, ID: FIELD_DEFAULT_VALUE);
461}
462
463void ClangDocBitcodeWriter::emitBlock(const MemberTypeInfo &T) {
464 StreamSubBlockGuard Block(Stream, BI_MEMBER_TYPE_BLOCK_ID);
465 emitBlock(R: T.Type, Field: FieldId::F_type);
466 emitRecord(Str: T.Name, ID: MEMBER_TYPE_NAME);
467 emitRecord(Val: T.Access, ID: MEMBER_TYPE_ACCESS);
468 for (const auto &CI : T.Description)
469 emitBlock(B: CI);
470}
471
472void ClangDocBitcodeWriter::emitBlock(const CommentInfo &I) {
473 StreamSubBlockGuard Block(Stream, BI_COMMENT_BLOCK_ID);
474 for (const auto &L : std::vector<std::pair<llvm::StringRef, RecordId>>{
475 {I.Kind, COMMENT_KIND},
476 {I.Text, COMMENT_TEXT},
477 {I.Name, COMMENT_NAME},
478 {I.Direction, COMMENT_DIRECTION},
479 {I.ParamName, COMMENT_PARAMNAME},
480 {I.CloseName, COMMENT_CLOSENAME}})
481 emitRecord(Str: L.first, ID: L.second);
482 emitRecord(Val: I.SelfClosing, ID: COMMENT_SELFCLOSING);
483 emitRecord(Val: I.Explicit, ID: COMMENT_EXPLICIT);
484 for (const auto &A : I.AttrKeys)
485 emitRecord(Str: A, ID: COMMENT_ATTRKEY);
486 for (const auto &A : I.AttrValues)
487 emitRecord(Str: A, ID: COMMENT_ATTRVAL);
488 for (const auto &A : I.Args)
489 emitRecord(Str: A, ID: COMMENT_ARG);
490 for (const auto &C : I.Children)
491 emitBlock(I: *C);
492}
493
494void ClangDocBitcodeWriter::emitBlock(const NamespaceInfo &I) {
495 StreamSubBlockGuard Block(Stream, BI_NAMESPACE_BLOCK_ID);
496 emitRecord(Sym: I.USR, ID: NAMESPACE_USR);
497 emitRecord(Str: I.Name, ID: NAMESPACE_NAME);
498 emitRecord(Str: I.Path, ID: NAMESPACE_PATH);
499 for (const auto &N : I.Namespace)
500 emitBlock(R: N, Field: FieldId::F_namespace);
501 for (const auto &CI : I.Description)
502 emitBlock(I: CI);
503 for (const auto &C : I.Children.Namespaces)
504 emitBlock(R: C, Field: FieldId::F_child_namespace);
505 for (const auto &C : I.Children.Records)
506 emitBlock(R: C, Field: FieldId::F_child_record);
507 for (const auto &C : I.Children.Functions)
508 emitBlock(I: C);
509 for (const auto &C : I.Children.Enums)
510 emitBlock(I: C);
511 for (const auto &C : I.Children.Typedefs)
512 emitBlock(T: C);
513}
514
515void ClangDocBitcodeWriter::emitBlock(const EnumInfo &I) {
516 StreamSubBlockGuard Block(Stream, BI_ENUM_BLOCK_ID);
517 emitRecord(Sym: I.USR, ID: ENUM_USR);
518 emitRecord(Str: I.Name, ID: ENUM_NAME);
519 for (const auto &N : I.Namespace)
520 emitBlock(R: N, Field: FieldId::F_namespace);
521 for (const auto &CI : I.Description)
522 emitBlock(I: CI);
523 if (I.DefLoc)
524 emitRecord(Loc: *I.DefLoc, ID: ENUM_DEFLOCATION);
525 for (const auto &L : I.Loc)
526 emitRecord(Loc: L, ID: ENUM_LOCATION);
527 emitRecord(Val: I.Scoped, ID: ENUM_SCOPED);
528 if (I.BaseType)
529 emitBlock(T: *I.BaseType);
530 for (const auto &N : I.Members)
531 emitBlock(I: N);
532}
533
534void ClangDocBitcodeWriter::emitBlock(const EnumValueInfo &I) {
535 StreamSubBlockGuard Block(Stream, BI_ENUM_VALUE_BLOCK_ID);
536 emitRecord(Str: I.Name, ID: ENUM_VALUE_NAME);
537 emitRecord(Str: I.Value, ID: ENUM_VALUE_VALUE);
538 emitRecord(Str: I.ValueExpr, ID: ENUM_VALUE_EXPR);
539}
540
541void ClangDocBitcodeWriter::emitBlock(const RecordInfo &I) {
542 StreamSubBlockGuard Block(Stream, BI_RECORD_BLOCK_ID);
543 emitRecord(Sym: I.USR, ID: RECORD_USR);
544 emitRecord(Str: I.Name, ID: RECORD_NAME);
545 emitRecord(Str: I.Path, ID: RECORD_PATH);
546 for (const auto &N : I.Namespace)
547 emitBlock(R: N, Field: FieldId::F_namespace);
548 for (const auto &CI : I.Description)
549 emitBlock(I: CI);
550 if (I.DefLoc)
551 emitRecord(Loc: *I.DefLoc, ID: RECORD_DEFLOCATION);
552 for (const auto &L : I.Loc)
553 emitRecord(Loc: L, ID: RECORD_LOCATION);
554 emitRecord(Val: llvm::to_underlying(E: I.TagType), ID: RECORD_TAG_TYPE);
555 emitRecord(Val: I.IsTypeDef, ID: RECORD_IS_TYPE_DEF);
556 for (const auto &N : I.Members)
557 emitBlock(T: N);
558 for (const auto &P : I.Parents)
559 emitBlock(R: P, Field: FieldId::F_parent);
560 for (const auto &P : I.VirtualParents)
561 emitBlock(R: P, Field: FieldId::F_vparent);
562 for (const auto &PB : I.Bases)
563 emitBlock(I: PB);
564 for (const auto &C : I.Children.Records)
565 emitBlock(R: C, Field: FieldId::F_child_record);
566 for (const auto &C : I.Children.Functions)
567 emitBlock(I: C);
568 for (const auto &C : I.Children.Enums)
569 emitBlock(I: C);
570 for (const auto &C : I.Children.Typedefs)
571 emitBlock(T: C);
572 if (I.Template)
573 emitBlock(T: *I.Template);
574}
575
576void ClangDocBitcodeWriter::emitBlock(const BaseRecordInfo &I) {
577 StreamSubBlockGuard Block(Stream, BI_BASE_RECORD_BLOCK_ID);
578 emitRecord(Sym: I.USR, ID: BASE_RECORD_USR);
579 emitRecord(Str: I.Name, ID: BASE_RECORD_NAME);
580 emitRecord(Str: I.Path, ID: BASE_RECORD_PATH);
581 emitRecord(Val: llvm::to_underlying(E: I.TagType), ID: BASE_RECORD_TAG_TYPE);
582 emitRecord(Val: I.IsVirtual, ID: BASE_RECORD_IS_VIRTUAL);
583 emitRecord(Val: I.Access, ID: BASE_RECORD_ACCESS);
584 emitRecord(Val: I.IsParent, ID: BASE_RECORD_IS_PARENT);
585 for (const auto &M : I.Members)
586 emitBlock(T: M);
587 for (const auto &C : I.Children.Functions)
588 emitBlock(I: C);
589}
590
591void ClangDocBitcodeWriter::emitBlock(const FunctionInfo &I) {
592 StreamSubBlockGuard Block(Stream, BI_FUNCTION_BLOCK_ID);
593 emitRecord(Sym: I.USR, ID: FUNCTION_USR);
594 emitRecord(Str: I.Name, ID: FUNCTION_NAME);
595 for (const auto &N : I.Namespace)
596 emitBlock(R: N, Field: FieldId::F_namespace);
597 for (const auto &CI : I.Description)
598 emitBlock(I: CI);
599 emitRecord(Val: I.Access, ID: FUNCTION_ACCESS);
600 emitRecord(Val: I.IsMethod, ID: FUNCTION_IS_METHOD);
601 if (I.DefLoc)
602 emitRecord(Loc: *I.DefLoc, ID: FUNCTION_DEFLOCATION);
603 for (const auto &L : I.Loc)
604 emitRecord(Loc: L, ID: FUNCTION_LOCATION);
605 emitBlock(R: I.Parent, Field: FieldId::F_parent);
606 emitBlock(T: I.ReturnType);
607 for (const auto &N : I.Params)
608 emitBlock(T: N);
609 if (I.Template)
610 emitBlock(T: *I.Template);
611}
612
613void ClangDocBitcodeWriter::emitBlock(const TemplateInfo &T) {
614 StreamSubBlockGuard Block(Stream, BI_TEMPLATE_BLOCK_ID);
615 for (const auto &P : T.Params)
616 emitBlock(T: P);
617 if (T.Specialization)
618 emitBlock(T: *T.Specialization);
619}
620
621void ClangDocBitcodeWriter::emitBlock(const TemplateSpecializationInfo &T) {
622 StreamSubBlockGuard Block(Stream, BI_TEMPLATE_SPECIALIZATION_BLOCK_ID);
623 emitRecord(Sym: T.SpecializationOf, ID: TEMPLATE_SPECIALIZATION_OF);
624 for (const auto &P : T.Params)
625 emitBlock(T: P);
626}
627
628void ClangDocBitcodeWriter::emitBlock(const TemplateParamInfo &T) {
629 StreamSubBlockGuard Block(Stream, BI_TEMPLATE_PARAM_BLOCK_ID);
630 emitRecord(Str: T.Contents, ID: TEMPLATE_PARAM_CONTENTS);
631}
632
633bool ClangDocBitcodeWriter::dispatchInfoForWrite(Info *I) {
634 switch (I->IT) {
635 case InfoType::IT_namespace:
636 emitBlock(I: *static_cast<clang::doc::NamespaceInfo *>(I));
637 break;
638 case InfoType::IT_record:
639 emitBlock(I: *static_cast<clang::doc::RecordInfo *>(I));
640 break;
641 case InfoType::IT_enum:
642 emitBlock(I: *static_cast<clang::doc::EnumInfo *>(I));
643 break;
644 case InfoType::IT_function:
645 emitBlock(I: *static_cast<clang::doc::FunctionInfo *>(I));
646 break;
647 case InfoType::IT_typedef:
648 emitBlock(T: *static_cast<clang::doc::TypedefInfo *>(I));
649 break;
650 default:
651 llvm::errs() << "Unexpected info, unable to write.\n";
652 return true;
653 }
654 return false;
655}
656
657} // namespace doc
658} // namespace clang
659

source code of clang-tools-extra/clang-doc/BitcodeWriter.cpp