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