xref: /llvm-project/clang-tools-extra/clang-doc/BitcodeWriter.cpp (revision 0afc60858e1183344e0786eaa3b123f9faed185e)
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_TYPE_BLOCK_ID, "TypeBlock"},
117           {BI_FIELD_TYPE_BLOCK_ID, "FieldTypeBlock"},
118           {BI_MEMBER_TYPE_BLOCK_ID, "MemberTypeBlock"},
119           {BI_RECORD_BLOCK_ID, "RecordBlock"},
120           {BI_BASE_RECORD_BLOCK_ID, "BaseRecordBlock"},
121           {BI_FUNCTION_BLOCK_ID, "FunctionBlock"},
122           {BI_COMMENT_BLOCK_ID, "CommentBlock"},
123           {BI_REFERENCE_BLOCK_ID, "ReferenceBlock"}};
124       assert(Inits.size() == BlockIdCount);
125       for (const auto &Init : Inits)
126         BlockIdNameMap[Init.first] = Init.second;
127       assert(BlockIdNameMap.size() == BlockIdCount);
128       return BlockIdNameMap;
129     }();
130 
131 static const llvm::IndexedMap<RecordIdDsc, RecordIdToIndexFunctor>
132     RecordIdNameMap = []() {
133       llvm::IndexedMap<RecordIdDsc, RecordIdToIndexFunctor> RecordIdNameMap;
134       RecordIdNameMap.resize(RecordIdCount);
135 
136       // There is no init-list constructor for the IndexedMap, so have to
137       // improvise
138       static const std::vector<std::pair<RecordId, RecordIdDsc>> Inits = {
139           {VERSION, {"Version", &IntAbbrev}},
140           {COMMENT_KIND, {"Kind", &StringAbbrev}},
141           {COMMENT_TEXT, {"Text", &StringAbbrev}},
142           {COMMENT_NAME, {"Name", &StringAbbrev}},
143           {COMMENT_DIRECTION, {"Direction", &StringAbbrev}},
144           {COMMENT_PARAMNAME, {"ParamName", &StringAbbrev}},
145           {COMMENT_CLOSENAME, {"CloseName", &StringAbbrev}},
146           {COMMENT_SELFCLOSING, {"SelfClosing", &BoolAbbrev}},
147           {COMMENT_EXPLICIT, {"Explicit", &BoolAbbrev}},
148           {COMMENT_ATTRKEY, {"AttrKey", &StringAbbrev}},
149           {COMMENT_ATTRVAL, {"AttrVal", &StringAbbrev}},
150           {COMMENT_ARG, {"Arg", &StringAbbrev}},
151           {FIELD_TYPE_NAME, {"Name", &StringAbbrev}},
152           {FIELD_DEFAULT_VALUE, {"DefaultValue", &StringAbbrev}},
153           {MEMBER_TYPE_NAME, {"Name", &StringAbbrev}},
154           {MEMBER_TYPE_ACCESS, {"Access", &IntAbbrev}},
155           {NAMESPACE_USR, {"USR", &SymbolIDAbbrev}},
156           {NAMESPACE_NAME, {"Name", &StringAbbrev}},
157           {NAMESPACE_PATH, {"Path", &StringAbbrev}},
158           {ENUM_USR, {"USR", &SymbolIDAbbrev}},
159           {ENUM_NAME, {"Name", &StringAbbrev}},
160           {ENUM_DEFLOCATION, {"DefLocation", &LocationAbbrev}},
161           {ENUM_LOCATION, {"Location", &LocationAbbrev}},
162           {ENUM_SCOPED, {"Scoped", &BoolAbbrev}},
163           {ENUM_VALUE_NAME, {"Name", &StringAbbrev}},
164           {ENUM_VALUE_VALUE, {"Value", &StringAbbrev}},
165           {ENUM_VALUE_EXPR, {"Expr", &StringAbbrev}},
166           {RECORD_USR, {"USR", &SymbolIDAbbrev}},
167           {RECORD_NAME, {"Name", &StringAbbrev}},
168           {RECORD_PATH, {"Path", &StringAbbrev}},
169           {RECORD_DEFLOCATION, {"DefLocation", &LocationAbbrev}},
170           {RECORD_LOCATION, {"Location", &LocationAbbrev}},
171           {RECORD_TAG_TYPE, {"TagType", &IntAbbrev}},
172           {RECORD_IS_TYPE_DEF, {"IsTypeDef", &BoolAbbrev}},
173           {BASE_RECORD_USR, {"USR", &SymbolIDAbbrev}},
174           {BASE_RECORD_NAME, {"Name", &StringAbbrev}},
175           {BASE_RECORD_PATH, {"Path", &StringAbbrev}},
176           {BASE_RECORD_TAG_TYPE, {"TagType", &IntAbbrev}},
177           {BASE_RECORD_IS_VIRTUAL, {"IsVirtual", &BoolAbbrev}},
178           {BASE_RECORD_ACCESS, {"Access", &IntAbbrev}},
179           {BASE_RECORD_IS_PARENT, {"IsParent", &BoolAbbrev}},
180           {FUNCTION_USR, {"USR", &SymbolIDAbbrev}},
181           {FUNCTION_NAME, {"Name", &StringAbbrev}},
182           {FUNCTION_DEFLOCATION, {"DefLocation", &LocationAbbrev}},
183           {FUNCTION_LOCATION, {"Location", &LocationAbbrev}},
184           {FUNCTION_ACCESS, {"Access", &IntAbbrev}},
185           {FUNCTION_IS_METHOD, {"IsMethod", &BoolAbbrev}},
186           {REFERENCE_USR, {"USR", &SymbolIDAbbrev}},
187           {REFERENCE_NAME, {"Name", &StringAbbrev}},
188           {REFERENCE_TYPE, {"RefType", &IntAbbrev}},
189           {REFERENCE_PATH, {"Path", &StringAbbrev}},
190           {REFERENCE_FIELD, {"Field", &IntAbbrev}}};
191       assert(Inits.size() == RecordIdCount);
192       for (const auto &Init : Inits) {
193         RecordIdNameMap[Init.first] = Init.second;
194         assert((Init.second.Name.size() + 1) <= BitCodeConstants::RecordSize);
195       }
196       assert(RecordIdNameMap.size() == RecordIdCount);
197       return RecordIdNameMap;
198     }();
199 
200 static const std::vector<std::pair<BlockId, std::vector<RecordId>>>
201     RecordsByBlock{
202         // Version Block
203         {BI_VERSION_BLOCK_ID, {VERSION}},
204         // Comment Block
205         {BI_COMMENT_BLOCK_ID,
206          {COMMENT_KIND, COMMENT_TEXT, COMMENT_NAME, COMMENT_DIRECTION,
207           COMMENT_PARAMNAME, COMMENT_CLOSENAME, COMMENT_SELFCLOSING,
208           COMMENT_EXPLICIT, COMMENT_ATTRKEY, COMMENT_ATTRVAL, COMMENT_ARG}},
209         // Type Block
210         {BI_TYPE_BLOCK_ID, {}},
211         // FieldType Block
212         {BI_FIELD_TYPE_BLOCK_ID, {FIELD_TYPE_NAME, FIELD_DEFAULT_VALUE}},
213         // MemberType Block
214         {BI_MEMBER_TYPE_BLOCK_ID, {MEMBER_TYPE_NAME, MEMBER_TYPE_ACCESS}},
215         // Enum Block
216         {BI_ENUM_BLOCK_ID,
217          {ENUM_USR, ENUM_NAME, ENUM_DEFLOCATION, ENUM_LOCATION, ENUM_SCOPED}},
218         // Enum Value Block
219         {BI_ENUM_VALUE_BLOCK_ID,
220          {ENUM_VALUE_NAME, ENUM_VALUE_VALUE, ENUM_VALUE_EXPR}},
221         // Namespace Block
222         {BI_NAMESPACE_BLOCK_ID,
223          {NAMESPACE_USR, NAMESPACE_NAME, NAMESPACE_PATH}},
224         // Record Block
225         {BI_RECORD_BLOCK_ID,
226          {RECORD_USR, RECORD_NAME, RECORD_PATH, RECORD_DEFLOCATION,
227           RECORD_LOCATION, RECORD_TAG_TYPE, RECORD_IS_TYPE_DEF}},
228         // BaseRecord Block
229         {BI_BASE_RECORD_BLOCK_ID,
230          {BASE_RECORD_USR, BASE_RECORD_NAME, BASE_RECORD_PATH,
231           BASE_RECORD_TAG_TYPE, BASE_RECORD_IS_VIRTUAL, BASE_RECORD_ACCESS,
232           BASE_RECORD_IS_PARENT}},
233         // Function Block
234         {BI_FUNCTION_BLOCK_ID,
235          {FUNCTION_USR, FUNCTION_NAME, FUNCTION_DEFLOCATION, FUNCTION_LOCATION,
236           FUNCTION_ACCESS, FUNCTION_IS_METHOD}},
237         // Reference Block
238         {BI_REFERENCE_BLOCK_ID,
239          {REFERENCE_USR, REFERENCE_NAME, REFERENCE_TYPE, REFERENCE_PATH,
240           REFERENCE_FIELD}}};
241 
242 // AbbreviationMap
243 
244 constexpr unsigned char BitCodeConstants::Signature[];
245 
246 void ClangDocBitcodeWriter::AbbreviationMap::add(RecordId RID,
247                                                  unsigned AbbrevID) {
248   assert(RecordIdNameMap[RID] && "Unknown RecordId.");
249   assert(Abbrevs.find(RID) == Abbrevs.end() && "Abbreviation already added.");
250   Abbrevs[RID] = AbbrevID;
251 }
252 
253 unsigned ClangDocBitcodeWriter::AbbreviationMap::get(RecordId RID) const {
254   assert(RecordIdNameMap[RID] && "Unknown RecordId.");
255   assert(Abbrevs.find(RID) != Abbrevs.end() && "Unknown abbreviation.");
256   return Abbrevs.lookup(RID);
257 }
258 
259 // Validation and Overview Blocks
260 
261 /// Emits the magic number header to check that its the right format,
262 /// in this case, 'DOCS'.
263 void ClangDocBitcodeWriter::emitHeader() {
264   for (char C : BitCodeConstants::Signature)
265     Stream.Emit((unsigned)C, BitCodeConstants::SignatureBitSize);
266 }
267 
268 void ClangDocBitcodeWriter::emitVersionBlock() {
269   StreamSubBlockGuard Block(Stream, BI_VERSION_BLOCK_ID);
270   emitRecord(VersionNumber, VERSION);
271 }
272 
273 /// Emits a block ID and the block name to the BLOCKINFO block.
274 void ClangDocBitcodeWriter::emitBlockID(BlockId BID) {
275   const auto &BlockIdName = BlockIdNameMap[BID];
276   assert(BlockIdName.data() && BlockIdName.size() && "Unknown BlockId.");
277 
278   Record.clear();
279   Record.push_back(BID);
280   Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record);
281   Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME,
282                     ArrayRef<unsigned char>(BlockIdName.bytes_begin(),
283                                             BlockIdName.bytes_end()));
284 }
285 
286 /// Emits a record name to the BLOCKINFO block.
287 void ClangDocBitcodeWriter::emitRecordID(RecordId ID) {
288   assert(RecordIdNameMap[ID] && "Unknown RecordId.");
289   prepRecordData(ID);
290   Record.append(RecordIdNameMap[ID].Name.begin(),
291                 RecordIdNameMap[ID].Name.end());
292   Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);
293 }
294 
295 // Abbreviations
296 
297 void ClangDocBitcodeWriter::emitAbbrev(RecordId ID, BlockId Block) {
298   assert(RecordIdNameMap[ID] && "Unknown abbreviation.");
299   auto Abbrev = std::make_shared<llvm::BitCodeAbbrev>();
300   Abbrev->Add(llvm::BitCodeAbbrevOp(ID));
301   RecordIdNameMap[ID].Abbrev(Abbrev);
302   Abbrevs.add(ID, Stream.EmitBlockInfoAbbrev(Block, std::move(Abbrev)));
303 }
304 
305 // Records
306 
307 void ClangDocBitcodeWriter::emitRecord(const SymbolID &Sym, RecordId ID) {
308   assert(RecordIdNameMap[ID] && "Unknown RecordId.");
309   assert(RecordIdNameMap[ID].Abbrev == &SymbolIDAbbrev &&
310          "Abbrev type mismatch.");
311   if (!prepRecordData(ID, Sym != EmptySID))
312     return;
313   assert(Sym.size() == 20);
314   Record.push_back(Sym.size());
315   Record.append(Sym.begin(), Sym.end());
316   Stream.EmitRecordWithAbbrev(Abbrevs.get(ID), Record);
317 }
318 
319 void ClangDocBitcodeWriter::emitRecord(llvm::StringRef Str, RecordId ID) {
320   assert(RecordIdNameMap[ID] && "Unknown RecordId.");
321   assert(RecordIdNameMap[ID].Abbrev == &StringAbbrev &&
322          "Abbrev type mismatch.");
323   if (!prepRecordData(ID, !Str.empty()))
324     return;
325   assert(Str.size() < (1U << BitCodeConstants::StringLengthSize));
326   Record.push_back(Str.size());
327   Stream.EmitRecordWithBlob(Abbrevs.get(ID), Record, Str);
328 }
329 
330 void ClangDocBitcodeWriter::emitRecord(const Location &Loc, RecordId ID) {
331   assert(RecordIdNameMap[ID] && "Unknown RecordId.");
332   assert(RecordIdNameMap[ID].Abbrev == &LocationAbbrev &&
333          "Abbrev type mismatch.");
334   if (!prepRecordData(ID, true))
335     return;
336   // FIXME: Assert that the line number is of the appropriate size.
337   Record.push_back(Loc.LineNumber);
338   assert(Loc.Filename.size() < (1U << BitCodeConstants::StringLengthSize));
339   Record.push_back(Loc.IsFileInRootDir);
340   Record.push_back(Loc.Filename.size());
341   Stream.EmitRecordWithBlob(Abbrevs.get(ID), Record, Loc.Filename);
342 }
343 
344 void ClangDocBitcodeWriter::emitRecord(bool Val, RecordId ID) {
345   assert(RecordIdNameMap[ID] && "Unknown RecordId.");
346   assert(RecordIdNameMap[ID].Abbrev == &BoolAbbrev && "Abbrev type mismatch.");
347   if (!prepRecordData(ID, Val))
348     return;
349   Record.push_back(Val);
350   Stream.EmitRecordWithAbbrev(Abbrevs.get(ID), Record);
351 }
352 
353 void ClangDocBitcodeWriter::emitRecord(int Val, RecordId ID) {
354   assert(RecordIdNameMap[ID] && "Unknown RecordId.");
355   assert(RecordIdNameMap[ID].Abbrev == &IntAbbrev && "Abbrev type mismatch.");
356   if (!prepRecordData(ID, Val))
357     return;
358   // FIXME: Assert that the integer is of the appropriate size.
359   Record.push_back(Val);
360   Stream.EmitRecordWithAbbrev(Abbrevs.get(ID), Record);
361 }
362 
363 void ClangDocBitcodeWriter::emitRecord(unsigned Val, RecordId ID) {
364   assert(RecordIdNameMap[ID] && "Unknown RecordId.");
365   assert(RecordIdNameMap[ID].Abbrev == &IntAbbrev && "Abbrev type mismatch.");
366   if (!prepRecordData(ID, Val))
367     return;
368   assert(Val < (1U << BitCodeConstants::IntSize));
369   Record.push_back(Val);
370   Stream.EmitRecordWithAbbrev(Abbrevs.get(ID), Record);
371 }
372 
373 bool ClangDocBitcodeWriter::prepRecordData(RecordId ID, bool ShouldEmit) {
374   assert(RecordIdNameMap[ID] && "Unknown RecordId.");
375   if (!ShouldEmit)
376     return false;
377   Record.clear();
378   Record.push_back(ID);
379   return true;
380 }
381 
382 // BlockInfo Block
383 
384 void ClangDocBitcodeWriter::emitBlockInfoBlock() {
385   Stream.EnterBlockInfoBlock();
386   for (const auto &Block : RecordsByBlock) {
387     assert(Block.second.size() < (1U << BitCodeConstants::SubblockIDSize));
388     emitBlockInfo(Block.first, Block.second);
389   }
390   Stream.ExitBlock();
391 }
392 
393 void ClangDocBitcodeWriter::emitBlockInfo(BlockId BID,
394                                           const std::vector<RecordId> &RIDs) {
395   assert(RIDs.size() < (1U << BitCodeConstants::SubblockIDSize));
396   emitBlockID(BID);
397   for (RecordId RID : RIDs) {
398     emitRecordID(RID);
399     emitAbbrev(RID, BID);
400   }
401 }
402 
403 // Block emission
404 
405 void ClangDocBitcodeWriter::emitBlock(const Reference &R, FieldId Field) {
406   if (R.USR == EmptySID && R.Name.empty())
407     return;
408   StreamSubBlockGuard Block(Stream, BI_REFERENCE_BLOCK_ID);
409   emitRecord(R.USR, REFERENCE_USR);
410   emitRecord(R.Name, REFERENCE_NAME);
411   emitRecord((unsigned)R.RefType, REFERENCE_TYPE);
412   emitRecord(R.Path, REFERENCE_PATH);
413   emitRecord((unsigned)Field, REFERENCE_FIELD);
414 }
415 
416 void ClangDocBitcodeWriter::emitBlock(const TypeInfo &T) {
417   StreamSubBlockGuard Block(Stream, BI_TYPE_BLOCK_ID);
418   emitBlock(T.Type, FieldId::F_type);
419 }
420 
421 void ClangDocBitcodeWriter::emitBlock(const FieldTypeInfo &T) {
422   StreamSubBlockGuard Block(Stream, BI_FIELD_TYPE_BLOCK_ID);
423   emitBlock(T.Type, FieldId::F_type);
424   emitRecord(T.Name, FIELD_TYPE_NAME);
425   emitRecord(T.DefaultValue, FIELD_DEFAULT_VALUE);
426 }
427 
428 void ClangDocBitcodeWriter::emitBlock(const MemberTypeInfo &T) {
429   StreamSubBlockGuard Block(Stream, BI_MEMBER_TYPE_BLOCK_ID);
430   emitBlock(T.Type, FieldId::F_type);
431   emitRecord(T.Name, MEMBER_TYPE_NAME);
432   emitRecord(T.Access, MEMBER_TYPE_ACCESS);
433   for (const auto &CI : T.Description)
434     emitBlock(CI);
435 }
436 
437 void ClangDocBitcodeWriter::emitBlock(const CommentInfo &I) {
438   StreamSubBlockGuard Block(Stream, BI_COMMENT_BLOCK_ID);
439   for (const auto &L : std::vector<std::pair<llvm::StringRef, RecordId>>{
440            {I.Kind, COMMENT_KIND},
441            {I.Text, COMMENT_TEXT},
442            {I.Name, COMMENT_NAME},
443            {I.Direction, COMMENT_DIRECTION},
444            {I.ParamName, COMMENT_PARAMNAME},
445            {I.CloseName, COMMENT_CLOSENAME}})
446     emitRecord(L.first, L.second);
447   emitRecord(I.SelfClosing, COMMENT_SELFCLOSING);
448   emitRecord(I.Explicit, COMMENT_EXPLICIT);
449   for (const auto &A : I.AttrKeys)
450     emitRecord(A, COMMENT_ATTRKEY);
451   for (const auto &A : I.AttrValues)
452     emitRecord(A, COMMENT_ATTRVAL);
453   for (const auto &A : I.Args)
454     emitRecord(A, COMMENT_ARG);
455   for (const auto &C : I.Children)
456     emitBlock(*C);
457 }
458 
459 void ClangDocBitcodeWriter::emitBlock(const NamespaceInfo &I) {
460   StreamSubBlockGuard Block(Stream, BI_NAMESPACE_BLOCK_ID);
461   emitRecord(I.USR, NAMESPACE_USR);
462   emitRecord(I.Name, NAMESPACE_NAME);
463   emitRecord(I.Path, NAMESPACE_PATH);
464   for (const auto &N : I.Namespace)
465     emitBlock(N, FieldId::F_namespace);
466   for (const auto &CI : I.Description)
467     emitBlock(CI);
468   for (const auto &C : I.ChildNamespaces)
469     emitBlock(C, FieldId::F_child_namespace);
470   for (const auto &C : I.ChildRecords)
471     emitBlock(C, FieldId::F_child_record);
472   for (const auto &C : I.ChildFunctions)
473     emitBlock(C);
474   for (const auto &C : I.ChildEnums)
475     emitBlock(C);
476 }
477 
478 void ClangDocBitcodeWriter::emitBlock(const EnumInfo &I) {
479   StreamSubBlockGuard Block(Stream, BI_ENUM_BLOCK_ID);
480   emitRecord(I.USR, ENUM_USR);
481   emitRecord(I.Name, ENUM_NAME);
482   for (const auto &N : I.Namespace)
483     emitBlock(N, FieldId::F_namespace);
484   for (const auto &CI : I.Description)
485     emitBlock(CI);
486   if (I.DefLoc)
487     emitRecord(*I.DefLoc, ENUM_DEFLOCATION);
488   for (const auto &L : I.Loc)
489     emitRecord(L, ENUM_LOCATION);
490   emitRecord(I.Scoped, ENUM_SCOPED);
491   if (I.BaseType)
492     emitBlock(*I.BaseType);
493   for (const auto &N : I.Members)
494     emitBlock(N);
495 }
496 
497 void ClangDocBitcodeWriter::emitBlock(const EnumValueInfo &I) {
498   StreamSubBlockGuard Block(Stream, BI_ENUM_VALUE_BLOCK_ID);
499   emitRecord(I.Name, ENUM_VALUE_NAME);
500   emitRecord(I.Value, ENUM_VALUE_VALUE);
501   emitRecord(I.ValueExpr, ENUM_VALUE_EXPR);
502 }
503 
504 void ClangDocBitcodeWriter::emitBlock(const RecordInfo &I) {
505   StreamSubBlockGuard Block(Stream, BI_RECORD_BLOCK_ID);
506   emitRecord(I.USR, RECORD_USR);
507   emitRecord(I.Name, RECORD_NAME);
508   emitRecord(I.Path, RECORD_PATH);
509   for (const auto &N : I.Namespace)
510     emitBlock(N, FieldId::F_namespace);
511   for (const auto &CI : I.Description)
512     emitBlock(CI);
513   if (I.DefLoc)
514     emitRecord(*I.DefLoc, RECORD_DEFLOCATION);
515   for (const auto &L : I.Loc)
516     emitRecord(L, RECORD_LOCATION);
517   emitRecord(I.TagType, RECORD_TAG_TYPE);
518   emitRecord(I.IsTypeDef, RECORD_IS_TYPE_DEF);
519   for (const auto &N : I.Members)
520     emitBlock(N);
521   for (const auto &P : I.Parents)
522     emitBlock(P, FieldId::F_parent);
523   for (const auto &P : I.VirtualParents)
524     emitBlock(P, FieldId::F_vparent);
525   for (const auto &PB : I.Bases)
526     emitBlock(PB);
527   for (const auto &C : I.ChildRecords)
528     emitBlock(C, FieldId::F_child_record);
529   for (const auto &C : I.ChildFunctions)
530     emitBlock(C);
531   for (const auto &C : I.ChildEnums)
532     emitBlock(C);
533 }
534 
535 void ClangDocBitcodeWriter::emitBlock(const BaseRecordInfo &I) {
536   StreamSubBlockGuard Block(Stream, BI_BASE_RECORD_BLOCK_ID);
537   emitRecord(I.USR, BASE_RECORD_USR);
538   emitRecord(I.Name, BASE_RECORD_NAME);
539   emitRecord(I.Path, BASE_RECORD_PATH);
540   emitRecord(I.TagType, BASE_RECORD_TAG_TYPE);
541   emitRecord(I.IsVirtual, BASE_RECORD_IS_VIRTUAL);
542   emitRecord(I.Access, BASE_RECORD_ACCESS);
543   emitRecord(I.IsParent, BASE_RECORD_IS_PARENT);
544   for (const auto &M : I.Members)
545     emitBlock(M);
546   for (const auto &C : I.ChildFunctions)
547     emitBlock(C);
548 }
549 
550 void ClangDocBitcodeWriter::emitBlock(const FunctionInfo &I) {
551   StreamSubBlockGuard Block(Stream, BI_FUNCTION_BLOCK_ID);
552   emitRecord(I.USR, FUNCTION_USR);
553   emitRecord(I.Name, FUNCTION_NAME);
554   for (const auto &N : I.Namespace)
555     emitBlock(N, FieldId::F_namespace);
556   for (const auto &CI : I.Description)
557     emitBlock(CI);
558   emitRecord(I.Access, FUNCTION_ACCESS);
559   emitRecord(I.IsMethod, FUNCTION_IS_METHOD);
560   if (I.DefLoc)
561     emitRecord(*I.DefLoc, FUNCTION_DEFLOCATION);
562   for (const auto &L : I.Loc)
563     emitRecord(L, FUNCTION_LOCATION);
564   emitBlock(I.Parent, FieldId::F_parent);
565   emitBlock(I.ReturnType);
566   for (const auto &N : I.Params)
567     emitBlock(N);
568 }
569 
570 bool ClangDocBitcodeWriter::dispatchInfoForWrite(Info *I) {
571   switch (I->IT) {
572   case InfoType::IT_namespace:
573     emitBlock(*static_cast<clang::doc::NamespaceInfo *>(I));
574     break;
575   case InfoType::IT_record:
576     emitBlock(*static_cast<clang::doc::RecordInfo *>(I));
577     break;
578   case InfoType::IT_enum:
579     emitBlock(*static_cast<clang::doc::EnumInfo *>(I));
580     break;
581   case InfoType::IT_function:
582     emitBlock(*static_cast<clang::doc::FunctionInfo *>(I));
583     break;
584   default:
585     llvm::errs() << "Unexpected info, unable to write.\n";
586     return true;
587   }
588   return false;
589 }
590 
591 } // namespace doc
592 } // namespace clang
593