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