1 //===--  BitcodeWriter.cpp - ClangDoc Bitcode Writer ------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "BitcodeWriter.h"
11 #include "llvm/ADT/IndexedMap.h"
12 #include <initializer_list>
13 
14 namespace clang {
15 namespace doc {
16 
17 // Empty SymbolID for comparison, so we don't have to construct one every time.
18 static const SymbolID EmptySID = SymbolID();
19 
20 // Since id enums are not zero-indexed, we need to transform the given id into
21 // its associated index.
22 struct BlockIdToIndexFunctor {
23   using argument_type = unsigned;
24   unsigned operator()(unsigned ID) const { return ID - BI_FIRST; }
25 };
26 
27 struct RecordIdToIndexFunctor {
28   using argument_type = unsigned;
29   unsigned operator()(unsigned ID) const { return ID - RI_FIRST; }
30 };
31 
32 using AbbrevDsc = void (*)(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev);
33 
34 static void AbbrevGen(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev,
35                       const std::initializer_list<llvm::BitCodeAbbrevOp> Ops) {
36   for (const auto &Op : Ops)
37     Abbrev->Add(Op);
38 }
39 
40 static void BoolAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {
41   AbbrevGen(Abbrev,
42             {// 0. Boolean
43              llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
44                                    BitCodeConstants::BoolSize)});
45 }
46 
47 static void IntAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {
48   AbbrevGen(Abbrev,
49             {// 0. Fixed-size integer
50              llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
51                                    BitCodeConstants::IntSize)});
52 }
53 
54 static void SymbolIDAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {
55   AbbrevGen(Abbrev,
56             {// 0. Fixed-size integer (length of the sha1'd USR)
57              llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
58                                    BitCodeConstants::USRLengthSize),
59              // 1. Fixed-size array of Char6 (USR)
60              llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Array),
61              llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
62                                    BitCodeConstants::USRBitLengthSize)});
63 }
64 
65 static void StringAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {
66   AbbrevGen(Abbrev,
67             {// 0. Fixed-size integer (length of the following string)
68              llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
69                                    BitCodeConstants::StringLengthSize),
70              // 1. The string blob
71              llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)});
72 }
73 
74 // Assumes that the file will not have more than 65535 lines.
75 static void LocationAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {
76   AbbrevGen(
77       Abbrev,
78       {// 0. Fixed-size integer (line number)
79        llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
80                              BitCodeConstants::LineNumberSize),
81        // 1. Fixed-size integer (length of the following string (filename))
82        llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
83                              BitCodeConstants::StringLengthSize),
84        // 2. The string blob
85        llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)});
86 }
87 
88 struct RecordIdDsc {
89   llvm::StringRef Name;
90   AbbrevDsc Abbrev = nullptr;
91 
92   RecordIdDsc() = default;
93   RecordIdDsc(llvm::StringRef Name, AbbrevDsc Abbrev)
94       : Name(Name), Abbrev(Abbrev) {}
95 
96   // Is this 'description' valid?
97   operator bool() const {
98     return Abbrev != nullptr && Name.data() != nullptr && !Name.empty();
99   }
100 };
101 
102 static const llvm::IndexedMap<llvm::StringRef, BlockIdToIndexFunctor>
103     BlockIdNameMap = []() {
104       llvm::IndexedMap<llvm::StringRef, BlockIdToIndexFunctor> BlockIdNameMap;
105       BlockIdNameMap.resize(BlockIdCount);
106 
107       // There is no init-list constructor for the IndexedMap, so have to
108       // improvise
109       static const std::vector<std::pair<BlockId, const char *const>> Inits = {
110           {BI_VERSION_BLOCK_ID, "VersionBlock"},
111           {BI_NAMESPACE_BLOCK_ID, "NamespaceBlock"},
112           {BI_ENUM_BLOCK_ID, "EnumBlock"},
113           {BI_TYPE_BLOCK_ID, "TypeBlock"},
114           {BI_FIELD_TYPE_BLOCK_ID, "FieldTypeBlock"},
115           {BI_MEMBER_TYPE_BLOCK_ID, "MemberTypeBlock"},
116           {BI_RECORD_BLOCK_ID, "RecordBlock"},
117           {BI_FUNCTION_BLOCK_ID, "FunctionBlock"},
118           {BI_COMMENT_BLOCK_ID, "CommentBlock"},
119           {BI_REFERENCE_BLOCK_ID, "ReferenceBlock"}};
120       assert(Inits.size() == BlockIdCount);
121       for (const auto &Init : Inits)
122         BlockIdNameMap[Init.first] = Init.second;
123       assert(BlockIdNameMap.size() == BlockIdCount);
124       return BlockIdNameMap;
125     }();
126 
127 static const llvm::IndexedMap<RecordIdDsc, RecordIdToIndexFunctor>
128     RecordIdNameMap = []() {
129       llvm::IndexedMap<RecordIdDsc, RecordIdToIndexFunctor> RecordIdNameMap;
130       RecordIdNameMap.resize(RecordIdCount);
131 
132       // There is no init-list constructor for the IndexedMap, so have to
133       // improvise
134       static const std::vector<std::pair<RecordId, RecordIdDsc>> Inits = {
135           {VERSION, {"Version", &IntAbbrev}},
136           {COMMENT_KIND, {"Kind", &StringAbbrev}},
137           {COMMENT_TEXT, {"Text", &StringAbbrev}},
138           {COMMENT_NAME, {"Name", &StringAbbrev}},
139           {COMMENT_DIRECTION, {"Direction", &StringAbbrev}},
140           {COMMENT_PARAMNAME, {"ParamName", &StringAbbrev}},
141           {COMMENT_CLOSENAME, {"CloseName", &StringAbbrev}},
142           {COMMENT_SELFCLOSING, {"SelfClosing", &BoolAbbrev}},
143           {COMMENT_EXPLICIT, {"Explicit", &BoolAbbrev}},
144           {COMMENT_ATTRKEY, {"AttrKey", &StringAbbrev}},
145           {COMMENT_ATTRVAL, {"AttrVal", &StringAbbrev}},
146           {COMMENT_ARG, {"Arg", &StringAbbrev}},
147           {FIELD_TYPE_NAME, {"Name", &StringAbbrev}},
148           {MEMBER_TYPE_NAME, {"Name", &StringAbbrev}},
149           {MEMBER_TYPE_ACCESS, {"Access", &IntAbbrev}},
150           {NAMESPACE_USR, {"USR", &SymbolIDAbbrev}},
151           {NAMESPACE_NAME, {"Name", &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_DEFLOCATION, {"DefLocation", &LocationAbbrev}},
161           {RECORD_LOCATION, {"Location", &LocationAbbrev}},
162           {RECORD_TAG_TYPE, {"TagType", &IntAbbrev}},
163           {FUNCTION_USR, {"USR", &SymbolIDAbbrev}},
164           {FUNCTION_NAME, {"Name", &StringAbbrev}},
165           {FUNCTION_DEFLOCATION, {"DefLocation", &LocationAbbrev}},
166           {FUNCTION_LOCATION, {"Location", &LocationAbbrev}},
167           {FUNCTION_ACCESS, {"Access", &IntAbbrev}},
168           {FUNCTION_IS_METHOD, {"IsMethod", &BoolAbbrev}},
169           {REFERENCE_USR, {"USR", &SymbolIDAbbrev}},
170           {REFERENCE_NAME, {"Name", &StringAbbrev}},
171           {REFERENCE_TYPE, {"RefType", &IntAbbrev}},
172           {REFERENCE_FIELD, {"Field", &IntAbbrev}}};
173       assert(Inits.size() == RecordIdCount);
174       for (const auto &Init : Inits) {
175         RecordIdNameMap[Init.first] = Init.second;
176         assert((Init.second.Name.size() + 1) <= BitCodeConstants::RecordSize);
177       }
178       assert(RecordIdNameMap.size() == RecordIdCount);
179       return RecordIdNameMap;
180     }();
181 
182 static const std::vector<std::pair<BlockId, std::vector<RecordId>>>
183     RecordsByBlock{
184         // Version Block
185         {BI_VERSION_BLOCK_ID, {VERSION}},
186         // Comment Block
187         {BI_COMMENT_BLOCK_ID,
188          {COMMENT_KIND, COMMENT_TEXT, COMMENT_NAME, COMMENT_DIRECTION,
189           COMMENT_PARAMNAME, COMMENT_CLOSENAME, COMMENT_SELFCLOSING,
190           COMMENT_EXPLICIT, COMMENT_ATTRKEY, COMMENT_ATTRVAL, COMMENT_ARG}},
191         // Type Block
192         {BI_TYPE_BLOCK_ID, {}},
193         // FieldType Block
194         {BI_FIELD_TYPE_BLOCK_ID, {FIELD_TYPE_NAME}},
195         // MemberType Block
196         {BI_MEMBER_TYPE_BLOCK_ID, {MEMBER_TYPE_NAME, MEMBER_TYPE_ACCESS}},
197         // Enum Block
198         {BI_ENUM_BLOCK_ID,
199          {ENUM_USR, ENUM_NAME, ENUM_DEFLOCATION, ENUM_LOCATION, ENUM_MEMBER,
200           ENUM_SCOPED}},
201         // Namespace Block
202         {BI_NAMESPACE_BLOCK_ID, {NAMESPACE_USR, NAMESPACE_NAME}},
203         // Record Block
204         {BI_RECORD_BLOCK_ID,
205          {RECORD_USR, RECORD_NAME, RECORD_DEFLOCATION, RECORD_LOCATION,
206           RECORD_TAG_TYPE}},
207         // Function Block
208         {BI_FUNCTION_BLOCK_ID,
209          {FUNCTION_USR, FUNCTION_NAME, FUNCTION_DEFLOCATION, FUNCTION_LOCATION,
210           FUNCTION_ACCESS, FUNCTION_IS_METHOD}},
211         // Reference Block
212         {BI_REFERENCE_BLOCK_ID,
213          {REFERENCE_USR, REFERENCE_NAME, REFERENCE_TYPE, REFERENCE_FIELD}}};
214 
215 // AbbreviationMap
216 
217 constexpr char BitCodeConstants::Signature[];
218 
219 void ClangDocBitcodeWriter::AbbreviationMap::add(RecordId RID,
220                                                  unsigned AbbrevID) {
221   assert(RecordIdNameMap[RID] && "Unknown RecordId.");
222   assert(Abbrevs.find(RID) == Abbrevs.end() && "Abbreviation already added.");
223   Abbrevs[RID] = AbbrevID;
224 }
225 
226 unsigned ClangDocBitcodeWriter::AbbreviationMap::get(RecordId RID) const {
227   assert(RecordIdNameMap[RID] && "Unknown RecordId.");
228   assert(Abbrevs.find(RID) != Abbrevs.end() && "Unknown abbreviation.");
229   return Abbrevs.lookup(RID);
230 }
231 
232 // Validation and Overview Blocks
233 
234 /// \brief Emits the magic number header to check that its the right format,
235 /// in this case, 'DOCS'.
236 void ClangDocBitcodeWriter::emitHeader() {
237   for (char C : BitCodeConstants::Signature)
238     Stream.Emit((unsigned)C, BitCodeConstants::SignatureBitSize);
239 }
240 
241 void ClangDocBitcodeWriter::emitVersionBlock() {
242   StreamSubBlockGuard Block(Stream, BI_VERSION_BLOCK_ID);
243   emitRecord(VersionNumber, VERSION);
244 }
245 
246 /// \brief Emits a block ID and the block name to the BLOCKINFO block.
247 void ClangDocBitcodeWriter::emitBlockID(BlockId BID) {
248   const auto &BlockIdName = BlockIdNameMap[BID];
249   assert(BlockIdName.data() && BlockIdName.size() && "Unknown BlockId.");
250 
251   Record.clear();
252   Record.push_back(BID);
253   Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record);
254   Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME,
255                     ArrayRef<unsigned char>(BlockIdName.bytes_begin(),
256                                             BlockIdName.bytes_end()));
257 }
258 
259 /// \brief Emits a record name to the BLOCKINFO block.
260 void ClangDocBitcodeWriter::emitRecordID(RecordId ID) {
261   assert(RecordIdNameMap[ID] && "Unknown RecordId.");
262   prepRecordData(ID);
263   Record.append(RecordIdNameMap[ID].Name.begin(),
264                 RecordIdNameMap[ID].Name.end());
265   Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);
266 }
267 
268 // Abbreviations
269 
270 void ClangDocBitcodeWriter::emitAbbrev(RecordId ID, BlockId Block) {
271   assert(RecordIdNameMap[ID] && "Unknown abbreviation.");
272   auto Abbrev = std::make_shared<llvm::BitCodeAbbrev>();
273   Abbrev->Add(llvm::BitCodeAbbrevOp(ID));
274   RecordIdNameMap[ID].Abbrev(Abbrev);
275   Abbrevs.add(ID, Stream.EmitBlockInfoAbbrev(Block, std::move(Abbrev)));
276 }
277 
278 // Records
279 
280 void ClangDocBitcodeWriter::emitRecord(const SymbolID &Sym, RecordId ID) {
281   assert(RecordIdNameMap[ID] && "Unknown RecordId.");
282   assert(RecordIdNameMap[ID].Abbrev == &SymbolIDAbbrev &&
283          "Abbrev type mismatch.");
284   if (!prepRecordData(ID, Sym != EmptySID))
285     return;
286   assert(Sym.size() == 20);
287   Record.push_back(Sym.size());
288   Record.append(Sym.begin(), Sym.end());
289   Stream.EmitRecordWithAbbrev(Abbrevs.get(ID), Record);
290 }
291 
292 void ClangDocBitcodeWriter::emitRecord(llvm::StringRef Str, RecordId ID) {
293   assert(RecordIdNameMap[ID] && "Unknown RecordId.");
294   assert(RecordIdNameMap[ID].Abbrev == &StringAbbrev &&
295          "Abbrev type mismatch.");
296   if (!prepRecordData(ID, !Str.empty()))
297     return;
298   assert(Str.size() < (1U << BitCodeConstants::StringLengthSize));
299   Record.push_back(Str.size());
300   Stream.EmitRecordWithBlob(Abbrevs.get(ID), Record, Str);
301 }
302 
303 void ClangDocBitcodeWriter::emitRecord(const Location &Loc, RecordId ID) {
304   assert(RecordIdNameMap[ID] && "Unknown RecordId.");
305   assert(RecordIdNameMap[ID].Abbrev == &LocationAbbrev &&
306          "Abbrev type mismatch.");
307   if (!prepRecordData(ID, true))
308     return;
309   // FIXME: Assert that the line number is of the appropriate size.
310   Record.push_back(Loc.LineNumber);
311   assert(Loc.Filename.size() < (1U << BitCodeConstants::StringLengthSize));
312   // Record.push_back(Loc.Filename.size());
313   // Stream.EmitRecordWithBlob(Abbrevs.get(ID), Record, Loc.Filename);
314   Record.push_back(4);
315   Stream.EmitRecordWithBlob(Abbrevs.get(ID), Record, "test");
316 }
317 
318 void ClangDocBitcodeWriter::emitRecord(bool Val, RecordId ID) {
319   assert(RecordIdNameMap[ID] && "Unknown RecordId.");
320   assert(RecordIdNameMap[ID].Abbrev == &BoolAbbrev && "Abbrev type mismatch.");
321   if (!prepRecordData(ID, Val))
322     return;
323   Record.push_back(Val);
324   Stream.EmitRecordWithAbbrev(Abbrevs.get(ID), Record);
325 }
326 
327 void ClangDocBitcodeWriter::emitRecord(int Val, RecordId ID) {
328   assert(RecordIdNameMap[ID] && "Unknown RecordId.");
329   assert(RecordIdNameMap[ID].Abbrev == &IntAbbrev && "Abbrev type mismatch.");
330   if (!prepRecordData(ID, Val))
331     return;
332   // FIXME: Assert that the integer is of the appropriate size.
333   Record.push_back(Val);
334   Stream.EmitRecordWithAbbrev(Abbrevs.get(ID), Record);
335 }
336 
337 void ClangDocBitcodeWriter::emitRecord(unsigned Val, RecordId ID) {
338   assert(RecordIdNameMap[ID] && "Unknown RecordId.");
339   assert(RecordIdNameMap[ID].Abbrev == &IntAbbrev && "Abbrev type mismatch.");
340   if (!prepRecordData(ID, Val))
341     return;
342   assert(Val < (1U << BitCodeConstants::IntSize));
343   Record.push_back(Val);
344   Stream.EmitRecordWithAbbrev(Abbrevs.get(ID), Record);
345 }
346 
347 bool ClangDocBitcodeWriter::prepRecordData(RecordId ID, bool ShouldEmit) {
348   assert(RecordIdNameMap[ID] && "Unknown RecordId.");
349   if (!ShouldEmit)
350     return false;
351   Record.clear();
352   Record.push_back(ID);
353   return true;
354 }
355 
356 // BlockInfo Block
357 
358 void ClangDocBitcodeWriter::emitBlockInfoBlock() {
359   Stream.EnterBlockInfoBlock();
360   for (const auto &Block : RecordsByBlock) {
361     assert(Block.second.size() < (1U << BitCodeConstants::SubblockIDSize));
362     emitBlockInfo(Block.first, Block.second);
363   }
364   Stream.ExitBlock();
365 }
366 
367 void ClangDocBitcodeWriter::emitBlockInfo(BlockId BID,
368                                           const std::vector<RecordId> &RIDs) {
369   assert(RIDs.size() < (1U << BitCodeConstants::SubblockIDSize));
370   emitBlockID(BID);
371   for (RecordId RID : RIDs) {
372     emitRecordID(RID);
373     emitAbbrev(RID, BID);
374   }
375 }
376 
377 // Block emission
378 
379 void ClangDocBitcodeWriter::emitBlock(const Reference &R, FieldId Field) {
380   if (R.USR == EmptySID && R.Name.empty())
381     return;
382   StreamSubBlockGuard Block(Stream, BI_REFERENCE_BLOCK_ID);
383   emitRecord(R.USR, REFERENCE_USR);
384   emitRecord(R.Name, REFERENCE_NAME);
385   emitRecord((unsigned)R.RefType, REFERENCE_TYPE);
386   emitRecord((unsigned)Field, REFERENCE_FIELD);
387 }
388 
389 void ClangDocBitcodeWriter::emitBlock(const TypeInfo &T) {
390   StreamSubBlockGuard Block(Stream, BI_TYPE_BLOCK_ID);
391   emitBlock(T.Type, FieldId::F_type);
392 }
393 
394 void ClangDocBitcodeWriter::emitBlock(const FieldTypeInfo &T) {
395   StreamSubBlockGuard Block(Stream, BI_FIELD_TYPE_BLOCK_ID);
396   emitBlock(T.Type, FieldId::F_type);
397   emitRecord(T.Name, FIELD_TYPE_NAME);
398 }
399 
400 void ClangDocBitcodeWriter::emitBlock(const MemberTypeInfo &T) {
401   StreamSubBlockGuard Block(Stream, BI_MEMBER_TYPE_BLOCK_ID);
402   emitBlock(T.Type, FieldId::F_type);
403   emitRecord(T.Name, MEMBER_TYPE_NAME);
404   emitRecord(T.Access, MEMBER_TYPE_ACCESS);
405 }
406 
407 void ClangDocBitcodeWriter::emitBlock(const CommentInfo &I) {
408   StreamSubBlockGuard Block(Stream, BI_COMMENT_BLOCK_ID);
409   for (const auto &L : std::vector<std::pair<llvm::StringRef, RecordId>>{
410            {I.Kind, COMMENT_KIND},
411            {I.Text, COMMENT_TEXT},
412            {I.Name, COMMENT_NAME},
413            {I.Direction, COMMENT_DIRECTION},
414            {I.ParamName, COMMENT_PARAMNAME},
415            {I.CloseName, COMMENT_CLOSENAME}})
416     emitRecord(L.first, L.second);
417   emitRecord(I.SelfClosing, COMMENT_SELFCLOSING);
418   emitRecord(I.Explicit, COMMENT_EXPLICIT);
419   for (const auto &A : I.AttrKeys)
420     emitRecord(A, COMMENT_ATTRKEY);
421   for (const auto &A : I.AttrValues)
422     emitRecord(A, COMMENT_ATTRVAL);
423   for (const auto &A : I.Args)
424     emitRecord(A, COMMENT_ARG);
425   for (const auto &C : I.Children)
426     emitBlock(*C);
427 }
428 
429 void ClangDocBitcodeWriter::emitBlock(const NamespaceInfo &I) {
430   StreamSubBlockGuard Block(Stream, BI_NAMESPACE_BLOCK_ID);
431   emitRecord(I.USR, NAMESPACE_USR);
432   emitRecord(I.Name, NAMESPACE_NAME);
433   for (const auto &N : I.Namespace)
434     emitBlock(N, FieldId::F_namespace);
435   for (const auto &CI : I.Description)
436     emitBlock(CI);
437 }
438 
439 void ClangDocBitcodeWriter::emitBlock(const EnumInfo &I) {
440   StreamSubBlockGuard Block(Stream, BI_ENUM_BLOCK_ID);
441   emitRecord(I.USR, ENUM_USR);
442   emitRecord(I.Name, ENUM_NAME);
443   for (const auto &N : I.Namespace)
444     emitBlock(N, FieldId::F_namespace);
445   for (const auto &CI : I.Description)
446     emitBlock(CI);
447   if (I.DefLoc)
448     emitRecord(I.DefLoc.getValue(), ENUM_DEFLOCATION);
449   for (const auto &L : I.Loc)
450     emitRecord(L, ENUM_LOCATION);
451   emitRecord(I.Scoped, ENUM_SCOPED);
452   for (const auto &N : I.Members)
453     emitRecord(N, ENUM_MEMBER);
454 }
455 
456 void ClangDocBitcodeWriter::emitBlock(const RecordInfo &I) {
457   StreamSubBlockGuard Block(Stream, BI_RECORD_BLOCK_ID);
458   emitRecord(I.USR, RECORD_USR);
459   emitRecord(I.Name, RECORD_NAME);
460   for (const auto &N : I.Namespace)
461     emitBlock(N, FieldId::F_namespace);
462   for (const auto &CI : I.Description)
463     emitBlock(CI);
464   if (I.DefLoc)
465     emitRecord(I.DefLoc.getValue(), RECORD_DEFLOCATION);
466   for (const auto &L : I.Loc)
467     emitRecord(L, RECORD_LOCATION);
468   emitRecord(I.TagType, RECORD_TAG_TYPE);
469   for (const auto &N : I.Members)
470     emitBlock(N);
471   for (const auto &P : I.Parents)
472     emitBlock(P, FieldId::F_parent);
473   for (const auto &P : I.VirtualParents)
474     emitBlock(P, FieldId::F_vparent);
475 }
476 
477 void ClangDocBitcodeWriter::emitBlock(const FunctionInfo &I) {
478   StreamSubBlockGuard Block(Stream, BI_FUNCTION_BLOCK_ID);
479   emitRecord(I.USR, FUNCTION_USR);
480   emitRecord(I.Name, FUNCTION_NAME);
481   for (const auto &N : I.Namespace)
482     emitBlock(N, FieldId::F_namespace);
483   for (const auto &CI : I.Description)
484     emitBlock(CI);
485   emitRecord(I.IsMethod, FUNCTION_IS_METHOD);
486   if (I.DefLoc)
487     emitRecord(I.DefLoc.getValue(), FUNCTION_DEFLOCATION);
488   for (const auto &L : I.Loc)
489     emitRecord(L, FUNCTION_LOCATION);
490   emitBlock(I.Parent, FieldId::F_parent);
491   emitBlock(I.ReturnType);
492   for (const auto &N : I.Params)
493     emitBlock(N);
494 }
495 
496 bool ClangDocBitcodeWriter::dispatchInfoForWrite(Info *I) {
497   switch (I->IT) {
498   case InfoType::IT_namespace:
499     emitBlock(*static_cast<clang::doc::NamespaceInfo *>(I));
500     break;
501   case InfoType::IT_record:
502     emitBlock(*static_cast<clang::doc::RecordInfo *>(I));
503     break;
504   case InfoType::IT_enum:
505     emitBlock(*static_cast<clang::doc::EnumInfo *>(I));
506     break;
507   case InfoType::IT_function:
508     emitBlock(*static_cast<clang::doc::FunctionInfo *>(I));
509     break;
510   default:
511     llvm::errs() << "Unexpected info, unable to write.\n";
512     return true;
513   }
514   return false;
515 }
516 
517 } // namespace doc
518 } // namespace clang
519