xref: /llvm-project/clang-tools-extra/clang-doc/BitcodeWriter.cpp (revision 5ef2456a438578b0783241a2744efc62d47e5ab6)
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 
13 namespace clang {
14 namespace doc {
15 
16 // Empty SymbolID for comparison, so we don't have to construct one every time.
17 static 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.
21 struct BlockIdToIndexFunctor {
22   using argument_type = unsigned;
23   unsigned operator()(unsigned ID) const { return ID - BI_FIRST; }
24 };
25 
26 struct RecordIdToIndexFunctor {
27   using argument_type = unsigned;
28   unsigned operator()(unsigned ID) const { return ID - RI_FIRST; }
29 };
30 
31 using AbbrevDsc = void (*)(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev);
32 
33 static 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(Op);
37 }
38 
39 static void BoolAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {
40   AbbrevGen(Abbrev,
41             {// 0. Boolean
42              llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
43                                    BitCodeConstants::BoolSize)});
44 }
45 
46 static void IntAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {
47   AbbrevGen(Abbrev,
48             {// 0. Fixed-size integer
49              llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
50                                    BitCodeConstants::IntSize)});
51 }
52 
53 static void SymbolIDAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {
54   AbbrevGen(Abbrev,
55             {// 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 
64 static void StringAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {
65   AbbrevGen(Abbrev,
66             {// 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.
74 static void LocationAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {
75   AbbrevGen(
76       Abbrev,
77       {// 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 
90 struct 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 
104 static const llvm::IndexedMap<llvm::StringRef, BlockIdToIndexFunctor>
105     BlockIdNameMap = []() {
106       llvm::IndexedMap<llvm::StringRef, BlockIdToIndexFunctor> BlockIdNameMap;
107       BlockIdNameMap.resize(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 
135 static const llvm::IndexedMap<RecordIdDsc, RecordIdToIndexFunctor>
136     RecordIdNameMap = []() {
137       llvm::IndexedMap<RecordIdDsc, RecordIdToIndexFunctor> RecordIdNameMap;
138       RecordIdNameMap.resize(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 
211 static 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 
262 constexpr unsigned char BitCodeConstants::Signature[];
263 
264 void 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 
271 unsigned ClangDocBitcodeWriter::AbbreviationMap::get(RecordId RID) const {
272   assert(RecordIdNameMap[RID] && "Unknown RecordId.");
273   assert(Abbrevs.contains(RID) && "Unknown abbreviation.");
274   return Abbrevs.lookup(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'.
281 void ClangDocBitcodeWriter::emitHeader() {
282   for (char C : BitCodeConstants::Signature)
283     Stream.Emit((unsigned)C, BitCodeConstants::SignatureBitSize);
284 }
285 
286 void ClangDocBitcodeWriter::emitVersionBlock() {
287   StreamSubBlockGuard Block(Stream, BI_VERSION_BLOCK_ID);
288   emitRecord(VersionNumber, VERSION);
289 }
290 
291 /// Emits a block ID and the block name to the BLOCKINFO block.
292 void 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(BID);
298   Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record);
299   Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME,
300                     ArrayRef<unsigned char>(BlockIdName.bytes_begin(),
301                                             BlockIdName.bytes_end()));
302 }
303 
304 /// Emits a record name to the BLOCKINFO block.
305 void ClangDocBitcodeWriter::emitRecordID(RecordId ID) {
306   assert(RecordIdNameMap[ID] && "Unknown RecordId.");
307   prepRecordData(ID);
308   Record.append(RecordIdNameMap[ID].Name.begin(),
309                 RecordIdNameMap[ID].Name.end());
310   Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);
311 }
312 
313 // Abbreviations
314 
315 void ClangDocBitcodeWriter::emitAbbrev(RecordId ID, BlockId Block) {
316   assert(RecordIdNameMap[ID] && "Unknown abbreviation.");
317   auto Abbrev = std::make_shared<llvm::BitCodeAbbrev>();
318   Abbrev->Add(llvm::BitCodeAbbrevOp(ID));
319   RecordIdNameMap[ID].Abbrev(Abbrev);
320   Abbrevs.add(ID, Stream.EmitBlockInfoAbbrev(Block, std::move(Abbrev)));
321 }
322 
323 // Records
324 
325 void 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, Sym != EmptySID))
330     return;
331   assert(Sym.size() == 20);
332   Record.push_back(Sym.size());
333   Record.append(Sym.begin(), Sym.end());
334   Stream.EmitRecordWithAbbrev(Abbrevs.get(ID), Record);
335 }
336 
337 void 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, !Str.empty()))
342     return;
343   assert(Str.size() < (1U << BitCodeConstants::StringLengthSize));
344   Record.push_back(Str.size());
345   Stream.EmitRecordWithBlob(Abbrevs.get(ID), Record, Str);
346 }
347 
348 void 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, true))
353     return;
354   // FIXME: Assert that the line number is of the appropriate size.
355   Record.push_back(Loc.LineNumber);
356   assert(Loc.Filename.size() < (1U << BitCodeConstants::StringLengthSize));
357   Record.push_back(Loc.IsFileInRootDir);
358   Record.push_back(Loc.Filename.size());
359   Stream.EmitRecordWithBlob(Abbrevs.get(ID), Record, Loc.Filename);
360 }
361 
362 void 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, Val))
366     return;
367   Record.push_back(Val);
368   Stream.EmitRecordWithAbbrev(Abbrevs.get(ID), Record);
369 }
370 
371 void 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, Val))
375     return;
376   // FIXME: Assert that the integer is of the appropriate size.
377   Record.push_back(Val);
378   Stream.EmitRecordWithAbbrev(Abbrevs.get(ID), Record);
379 }
380 
381 void 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, Val))
385     return;
386   assert(Val < (1U << BitCodeConstants::IntSize));
387   Record.push_back(Val);
388   Stream.EmitRecordWithAbbrev(Abbrevs.get(ID), Record);
389 }
390 
391 void ClangDocBitcodeWriter::emitRecord(const TemplateInfo &Templ) {}
392 
393 bool 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(ID);
399   return true;
400 }
401 
402 // BlockInfo Block
403 
404 void ClangDocBitcodeWriter::emitBlockInfoBlock() {
405   Stream.EnterBlockInfoBlock();
406   for (const auto &Block : RecordsByBlock) {
407     assert(Block.second.size() < (1U << BitCodeConstants::SubblockIDSize));
408     emitBlockInfo(Block.first, Block.second);
409   }
410   Stream.ExitBlock();
411 }
412 
413 void 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(RID);
419     emitAbbrev(RID, BID);
420   }
421 }
422 
423 // Block emission
424 
425 void 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(R.USR, REFERENCE_USR);
430   emitRecord(R.Name, REFERENCE_NAME);
431   emitRecord(R.QualName, REFERENCE_QUAL_NAME);
432   emitRecord((unsigned)R.RefType, REFERENCE_TYPE);
433   emitRecord(R.Path, REFERENCE_PATH);
434   emitRecord((unsigned)Field, REFERENCE_FIELD);
435 }
436 
437 void ClangDocBitcodeWriter::emitBlock(const TypeInfo &T) {
438   StreamSubBlockGuard Block(Stream, BI_TYPE_BLOCK_ID);
439   emitBlock(T.Type, FieldId::F_type);
440 }
441 
442 void ClangDocBitcodeWriter::emitBlock(const TypedefInfo &T) {
443   StreamSubBlockGuard Block(Stream, BI_TYPEDEF_BLOCK_ID);
444   emitRecord(T.USR, TYPEDEF_USR);
445   emitRecord(T.Name, TYPEDEF_NAME);
446   for (const auto &N : T.Namespace)
447     emitBlock(N, FieldId::F_namespace);
448   for (const auto &CI : T.Description)
449     emitBlock(CI);
450   if (T.DefLoc)
451     emitRecord(*T.DefLoc, TYPEDEF_DEFLOCATION);
452   emitRecord(T.IsUsing, TYPEDEF_IS_USING);
453   emitBlock(T.Underlying);
454 }
455 
456 void ClangDocBitcodeWriter::emitBlock(const FieldTypeInfo &T) {
457   StreamSubBlockGuard Block(Stream, BI_FIELD_TYPE_BLOCK_ID);
458   emitBlock(T.Type, FieldId::F_type);
459   emitRecord(T.Name, FIELD_TYPE_NAME);
460   emitRecord(T.DefaultValue, FIELD_DEFAULT_VALUE);
461 }
462 
463 void ClangDocBitcodeWriter::emitBlock(const MemberTypeInfo &T) {
464   StreamSubBlockGuard Block(Stream, BI_MEMBER_TYPE_BLOCK_ID);
465   emitBlock(T.Type, FieldId::F_type);
466   emitRecord(T.Name, MEMBER_TYPE_NAME);
467   emitRecord(T.Access, MEMBER_TYPE_ACCESS);
468   for (const auto &CI : T.Description)
469     emitBlock(CI);
470 }
471 
472 void 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(L.first, L.second);
482   emitRecord(I.SelfClosing, COMMENT_SELFCLOSING);
483   emitRecord(I.Explicit, COMMENT_EXPLICIT);
484   for (const auto &A : I.AttrKeys)
485     emitRecord(A, COMMENT_ATTRKEY);
486   for (const auto &A : I.AttrValues)
487     emitRecord(A, COMMENT_ATTRVAL);
488   for (const auto &A : I.Args)
489     emitRecord(A, COMMENT_ARG);
490   for (const auto &C : I.Children)
491     emitBlock(*C);
492 }
493 
494 void ClangDocBitcodeWriter::emitBlock(const NamespaceInfo &I) {
495   StreamSubBlockGuard Block(Stream, BI_NAMESPACE_BLOCK_ID);
496   emitRecord(I.USR, NAMESPACE_USR);
497   emitRecord(I.Name, NAMESPACE_NAME);
498   emitRecord(I.Path, NAMESPACE_PATH);
499   for (const auto &N : I.Namespace)
500     emitBlock(N, FieldId::F_namespace);
501   for (const auto &CI : I.Description)
502     emitBlock(CI);
503   for (const auto &C : I.Children.Namespaces)
504     emitBlock(C, FieldId::F_child_namespace);
505   for (const auto &C : I.Children.Records)
506     emitBlock(C, FieldId::F_child_record);
507   for (const auto &C : I.Children.Functions)
508     emitBlock(C);
509   for (const auto &C : I.Children.Enums)
510     emitBlock(C);
511   for (const auto &C : I.Children.Typedefs)
512     emitBlock(C);
513 }
514 
515 void ClangDocBitcodeWriter::emitBlock(const EnumInfo &I) {
516   StreamSubBlockGuard Block(Stream, BI_ENUM_BLOCK_ID);
517   emitRecord(I.USR, ENUM_USR);
518   emitRecord(I.Name, ENUM_NAME);
519   for (const auto &N : I.Namespace)
520     emitBlock(N, FieldId::F_namespace);
521   for (const auto &CI : I.Description)
522     emitBlock(CI);
523   if (I.DefLoc)
524     emitRecord(*I.DefLoc, ENUM_DEFLOCATION);
525   for (const auto &L : I.Loc)
526     emitRecord(L, ENUM_LOCATION);
527   emitRecord(I.Scoped, ENUM_SCOPED);
528   if (I.BaseType)
529     emitBlock(*I.BaseType);
530   for (const auto &N : I.Members)
531     emitBlock(N);
532 }
533 
534 void ClangDocBitcodeWriter::emitBlock(const EnumValueInfo &I) {
535   StreamSubBlockGuard Block(Stream, BI_ENUM_VALUE_BLOCK_ID);
536   emitRecord(I.Name, ENUM_VALUE_NAME);
537   emitRecord(I.Value, ENUM_VALUE_VALUE);
538   emitRecord(I.ValueExpr, ENUM_VALUE_EXPR);
539   for (const auto &CI : I.Description)
540     emitBlock(CI);
541 }
542 
543 void ClangDocBitcodeWriter::emitBlock(const RecordInfo &I) {
544   StreamSubBlockGuard Block(Stream, BI_RECORD_BLOCK_ID);
545   emitRecord(I.USR, RECORD_USR);
546   emitRecord(I.Name, RECORD_NAME);
547   emitRecord(I.Path, RECORD_PATH);
548   for (const auto &N : I.Namespace)
549     emitBlock(N, FieldId::F_namespace);
550   for (const auto &CI : I.Description)
551     emitBlock(CI);
552   if (I.DefLoc)
553     emitRecord(*I.DefLoc, RECORD_DEFLOCATION);
554   for (const auto &L : I.Loc)
555     emitRecord(L, RECORD_LOCATION);
556   emitRecord(llvm::to_underlying(I.TagType), RECORD_TAG_TYPE);
557   emitRecord(I.IsTypeDef, RECORD_IS_TYPE_DEF);
558   for (const auto &N : I.Members)
559     emitBlock(N);
560   for (const auto &P : I.Parents)
561     emitBlock(P, FieldId::F_parent);
562   for (const auto &P : I.VirtualParents)
563     emitBlock(P, FieldId::F_vparent);
564   for (const auto &PB : I.Bases)
565     emitBlock(PB);
566   for (const auto &C : I.Children.Records)
567     emitBlock(C, FieldId::F_child_record);
568   for (const auto &C : I.Children.Functions)
569     emitBlock(C);
570   for (const auto &C : I.Children.Enums)
571     emitBlock(C);
572   for (const auto &C : I.Children.Typedefs)
573     emitBlock(C);
574   if (I.Template)
575     emitBlock(*I.Template);
576 }
577 
578 void ClangDocBitcodeWriter::emitBlock(const BaseRecordInfo &I) {
579   StreamSubBlockGuard Block(Stream, BI_BASE_RECORD_BLOCK_ID);
580   emitRecord(I.USR, BASE_RECORD_USR);
581   emitRecord(I.Name, BASE_RECORD_NAME);
582   emitRecord(I.Path, BASE_RECORD_PATH);
583   emitRecord(llvm::to_underlying(I.TagType), BASE_RECORD_TAG_TYPE);
584   emitRecord(I.IsVirtual, BASE_RECORD_IS_VIRTUAL);
585   emitRecord(I.Access, BASE_RECORD_ACCESS);
586   emitRecord(I.IsParent, BASE_RECORD_IS_PARENT);
587   for (const auto &M : I.Members)
588     emitBlock(M);
589   for (const auto &C : I.Children.Functions)
590     emitBlock(C);
591 }
592 
593 void ClangDocBitcodeWriter::emitBlock(const FunctionInfo &I) {
594   StreamSubBlockGuard Block(Stream, BI_FUNCTION_BLOCK_ID);
595   emitRecord(I.USR, FUNCTION_USR);
596   emitRecord(I.Name, FUNCTION_NAME);
597   for (const auto &N : I.Namespace)
598     emitBlock(N, FieldId::F_namespace);
599   for (const auto &CI : I.Description)
600     emitBlock(CI);
601   emitRecord(I.Access, FUNCTION_ACCESS);
602   emitRecord(I.IsMethod, FUNCTION_IS_METHOD);
603   if (I.DefLoc)
604     emitRecord(*I.DefLoc, FUNCTION_DEFLOCATION);
605   for (const auto &L : I.Loc)
606     emitRecord(L, FUNCTION_LOCATION);
607   emitBlock(I.Parent, FieldId::F_parent);
608   emitBlock(I.ReturnType);
609   for (const auto &N : I.Params)
610     emitBlock(N);
611   if (I.Template)
612     emitBlock(*I.Template);
613 }
614 
615 void ClangDocBitcodeWriter::emitBlock(const TemplateInfo &T) {
616   StreamSubBlockGuard Block(Stream, BI_TEMPLATE_BLOCK_ID);
617   for (const auto &P : T.Params)
618     emitBlock(P);
619   if (T.Specialization)
620     emitBlock(*T.Specialization);
621 }
622 
623 void ClangDocBitcodeWriter::emitBlock(const TemplateSpecializationInfo &T) {
624   StreamSubBlockGuard Block(Stream, BI_TEMPLATE_SPECIALIZATION_BLOCK_ID);
625   emitRecord(T.SpecializationOf, TEMPLATE_SPECIALIZATION_OF);
626   for (const auto &P : T.Params)
627     emitBlock(P);
628 }
629 
630 void ClangDocBitcodeWriter::emitBlock(const TemplateParamInfo &T) {
631   StreamSubBlockGuard Block(Stream, BI_TEMPLATE_PARAM_BLOCK_ID);
632   emitRecord(T.Contents, TEMPLATE_PARAM_CONTENTS);
633 }
634 
635 bool ClangDocBitcodeWriter::dispatchInfoForWrite(Info *I) {
636   switch (I->IT) {
637   case InfoType::IT_namespace:
638     emitBlock(*static_cast<clang::doc::NamespaceInfo *>(I));
639     break;
640   case InfoType::IT_record:
641     emitBlock(*static_cast<clang::doc::RecordInfo *>(I));
642     break;
643   case InfoType::IT_enum:
644     emitBlock(*static_cast<clang::doc::EnumInfo *>(I));
645     break;
646   case InfoType::IT_function:
647     emitBlock(*static_cast<clang::doc::FunctionInfo *>(I));
648     break;
649   case InfoType::IT_typedef:
650     emitBlock(*static_cast<clang::doc::TypedefInfo *>(I));
651     break;
652   default:
653     llvm::errs() << "Unexpected info, unable to write.\n";
654     return true;
655   }
656   return false;
657 }
658 
659 } // namespace doc
660 } // namespace clang
661