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