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
13namespace clang {
14namespace doc {
15
16// Empty SymbolID for comparison, so we don't have to construct one every time.
17static 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.
21struct BlockIdToIndexFunctor {
22 using argument_type = unsigned;
23 unsigned operator()(unsigned ID) const { return ID - BI_FIRST; }
24};
25
26struct RecordIdToIndexFunctor {
27 using argument_type = unsigned;
28 unsigned operator()(unsigned ID) const { return ID - RI_FIRST; }
29};
30
31using AbbrevDsc = void (*)(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev);
32
33static void
34generateAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev,
35 const std::initializer_list<llvm::BitCodeAbbrevOp> Ops) {
36 for (const auto &Op : Ops)
37 Abbrev->Add(OpInfo: Op);
38}
39
40static void genBoolAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {
41 generateAbbrev(Abbrev,
42 Ops: {// 0. Boolean
43 llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
44 BitCodeConstants::BoolSize)});
45}
46
47static void genIntAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {
48 generateAbbrev(Abbrev,
49 Ops: {// 0. Fixed-size integer
50 llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
51 BitCodeConstants::IntSize)});
52}
53
54static void genSymbolIdAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {
55 generateAbbrev(Abbrev,
56 Ops: {// 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
65static void genStringAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {
66 generateAbbrev(Abbrev,
67 Ops: {// 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.
75static void genLocationAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {
76 generateAbbrev(
77 Abbrev,
78 Ops: {// 0. Fixed-size integer (line number)
79 llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
80 BitCodeConstants::LineNumberSize),
81 // 1. Fixed-size integer (start line number)
82 llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
83 BitCodeConstants::LineNumberSize),
84 // 2. Boolean (IsFileInRootDir)
85 llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
86 BitCodeConstants::BoolSize),
87 // 3. Fixed-size integer (length of the following string (filename))
88 llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
89 BitCodeConstants::StringLengthSize),
90 // 4. The string blob
91 llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)});
92}
93
94struct RecordIdDsc {
95 llvm::StringRef Name;
96 AbbrevDsc Abbrev = nullptr;
97
98 RecordIdDsc() = default;
99 RecordIdDsc(llvm::StringRef Name, AbbrevDsc Abbrev)
100 : Name(Name), Abbrev(Abbrev) {}
101
102 // Is this 'description' valid?
103 operator bool() const {
104 return Abbrev != nullptr && Name.data() != nullptr && !Name.empty();
105 }
106};
107
108static const llvm::IndexedMap<llvm::StringRef, BlockIdToIndexFunctor>
109 BlockIdNameMap = []() {
110 llvm::IndexedMap<llvm::StringRef, BlockIdToIndexFunctor> BlockIdNameMap;
111 BlockIdNameMap.resize(s: BlockIdCount);
112
113 // There is no init-list constructor for the IndexedMap, so have to
114 // improvise
115 static const std::vector<std::pair<BlockId, const char *const>> Inits = {
116 {BI_VERSION_BLOCK_ID, "VersionBlock"},
117 {BI_NAMESPACE_BLOCK_ID, "NamespaceBlock"},
118 {BI_ENUM_BLOCK_ID, "EnumBlock"},
119 {BI_ENUM_VALUE_BLOCK_ID, "EnumValueBlock"},
120 {BI_TYPEDEF_BLOCK_ID, "TypedefBlock"},
121 {BI_TYPE_BLOCK_ID, "TypeBlock"},
122 {BI_FIELD_TYPE_BLOCK_ID, "FieldTypeBlock"},
123 {BI_MEMBER_TYPE_BLOCK_ID, "MemberTypeBlock"},
124 {BI_RECORD_BLOCK_ID, "RecordBlock"},
125 {BI_BASE_RECORD_BLOCK_ID, "BaseRecordBlock"},
126 {BI_FUNCTION_BLOCK_ID, "FunctionBlock"},
127 {BI_COMMENT_BLOCK_ID, "CommentBlock"},
128 {BI_REFERENCE_BLOCK_ID, "ReferenceBlock"},
129 {BI_TEMPLATE_BLOCK_ID, "TemplateBlock"},
130 {BI_TEMPLATE_SPECIALIZATION_BLOCK_ID, "TemplateSpecializationBlock"},
131 {BI_TEMPLATE_PARAM_BLOCK_ID, "TemplateParamBlock"}};
132 assert(Inits.size() == BlockIdCount);
133 for (const auto &Init : Inits)
134 BlockIdNameMap[Init.first] = Init.second;
135 assert(BlockIdNameMap.size() == BlockIdCount);
136 return BlockIdNameMap;
137 }();
138
139static const llvm::IndexedMap<RecordIdDsc, RecordIdToIndexFunctor>
140 RecordIdNameMap = []() {
141 llvm::IndexedMap<RecordIdDsc, RecordIdToIndexFunctor> RecordIdNameMap;
142 RecordIdNameMap.resize(s: RecordIdCount);
143
144 // There is no init-list constructor for the IndexedMap, so have to
145 // improvise
146 static const std::vector<std::pair<RecordId, RecordIdDsc>> Inits = {
147 {VERSION, {"Version", &genIntAbbrev}},
148 {COMMENT_KIND, {"Kind", &genStringAbbrev}},
149 {COMMENT_TEXT, {"Text", &genStringAbbrev}},
150 {COMMENT_NAME, {"Name", &genStringAbbrev}},
151 {COMMENT_DIRECTION, {"Direction", &genStringAbbrev}},
152 {COMMENT_PARAMNAME, {"ParamName", &genStringAbbrev}},
153 {COMMENT_CLOSENAME, {"CloseName", &genStringAbbrev}},
154 {COMMENT_SELFCLOSING, {"SelfClosing", &genBoolAbbrev}},
155 {COMMENT_EXPLICIT, {"Explicit", &genBoolAbbrev}},
156 {COMMENT_ATTRKEY, {"AttrKey", &genStringAbbrev}},
157 {COMMENT_ATTRVAL, {"AttrVal", &genStringAbbrev}},
158 {COMMENT_ARG, {"Arg", &genStringAbbrev}},
159 {FIELD_TYPE_NAME, {"Name", &genStringAbbrev}},
160 {FIELD_DEFAULT_VALUE, {"DefaultValue", &genStringAbbrev}},
161 {MEMBER_TYPE_NAME, {"Name", &genStringAbbrev}},
162 {MEMBER_TYPE_ACCESS, {"Access", &genIntAbbrev}},
163 {MEMBER_TYPE_IS_STATIC, {"IsStatic", &genBoolAbbrev}},
164 {NAMESPACE_USR, {"USR", &genSymbolIdAbbrev}},
165 {NAMESPACE_NAME, {"Name", &genStringAbbrev}},
166 {NAMESPACE_PATH, {"Path", &genStringAbbrev}},
167 {ENUM_USR, {"USR", &genSymbolIdAbbrev}},
168 {ENUM_NAME, {"Name", &genStringAbbrev}},
169 {ENUM_DEFLOCATION, {"DefLocation", &genLocationAbbrev}},
170 {ENUM_LOCATION, {"Location", &genLocationAbbrev}},
171 {ENUM_SCOPED, {"Scoped", &genBoolAbbrev}},
172 {ENUM_VALUE_NAME, {"Name", &genStringAbbrev}},
173 {ENUM_VALUE_VALUE, {"Value", &genStringAbbrev}},
174 {ENUM_VALUE_EXPR, {"Expr", &genStringAbbrev}},
175 {RECORD_USR, {"USR", &genSymbolIdAbbrev}},
176 {RECORD_NAME, {"Name", &genStringAbbrev}},
177 {RECORD_PATH, {"Path", &genStringAbbrev}},
178 {RECORD_DEFLOCATION, {"DefLocation", &genLocationAbbrev}},
179 {RECORD_LOCATION, {"Location", &genLocationAbbrev}},
180 {RECORD_TAG_TYPE, {"TagType", &genIntAbbrev}},
181 {RECORD_IS_TYPE_DEF, {"IsTypeDef", &genBoolAbbrev}},
182 {BASE_RECORD_USR, {"USR", &genSymbolIdAbbrev}},
183 {BASE_RECORD_NAME, {"Name", &genStringAbbrev}},
184 {BASE_RECORD_PATH, {"Path", &genStringAbbrev}},
185 {BASE_RECORD_TAG_TYPE, {"TagType", &genIntAbbrev}},
186 {BASE_RECORD_IS_VIRTUAL, {"IsVirtual", &genBoolAbbrev}},
187 {BASE_RECORD_ACCESS, {"Access", &genIntAbbrev}},
188 {BASE_RECORD_IS_PARENT, {"IsParent", &genBoolAbbrev}},
189 {FUNCTION_USR, {"USR", &genSymbolIdAbbrev}},
190 {FUNCTION_NAME, {"Name", &genStringAbbrev}},
191 {FUNCTION_DEFLOCATION, {"DefLocation", &genLocationAbbrev}},
192 {FUNCTION_LOCATION, {"Location", &genLocationAbbrev}},
193 {FUNCTION_ACCESS, {"Access", &genIntAbbrev}},
194 {FUNCTION_IS_METHOD, {"IsMethod", &genBoolAbbrev}},
195 {FUNCTION_IS_STATIC, {"IsStatic", &genBoolAbbrev}},
196 {REFERENCE_USR, {"USR", &genSymbolIdAbbrev}},
197 {REFERENCE_NAME, {"Name", &genStringAbbrev}},
198 {REFERENCE_QUAL_NAME, {"QualName", &genStringAbbrev}},
199 {REFERENCE_TYPE, {"RefType", &genIntAbbrev}},
200 {REFERENCE_PATH, {"Path", &genStringAbbrev}},
201 {REFERENCE_FIELD, {"Field", &genIntAbbrev}},
202 {TEMPLATE_PARAM_CONTENTS, {"Contents", &genStringAbbrev}},
203 {TEMPLATE_SPECIALIZATION_OF,
204 {"SpecializationOf", &genSymbolIdAbbrev}},
205 {TYPEDEF_USR, {"USR", &genSymbolIdAbbrev}},
206 {TYPEDEF_NAME, {"Name", &genStringAbbrev}},
207 {TYPEDEF_DEFLOCATION, {"DefLocation", &genLocationAbbrev}},
208 {TYPEDEF_IS_USING, {"IsUsing", &genBoolAbbrev}}};
209 assert(Inits.size() == RecordIdCount);
210 for (const auto &Init : Inits) {
211 RecordIdNameMap[Init.first] = Init.second;
212 assert((Init.second.Name.size() + 1) <= BitCodeConstants::RecordSize);
213 }
214 assert(RecordIdNameMap.size() == RecordIdCount);
215 return RecordIdNameMap;
216 }();
217
218static const std::vector<std::pair<BlockId, std::vector<RecordId>>>
219 RecordsByBlock{
220 // Version Block
221 {BI_VERSION_BLOCK_ID, {VERSION}},
222 // Comment Block
223 {BI_COMMENT_BLOCK_ID,
224 {COMMENT_KIND, COMMENT_TEXT, COMMENT_NAME, COMMENT_DIRECTION,
225 COMMENT_PARAMNAME, COMMENT_CLOSENAME, COMMENT_SELFCLOSING,
226 COMMENT_EXPLICIT, COMMENT_ATTRKEY, COMMENT_ATTRVAL, COMMENT_ARG}},
227 // Type Block
228 {BI_TYPE_BLOCK_ID, {}},
229 // FieldType Block
230 {BI_FIELD_TYPE_BLOCK_ID, {FIELD_TYPE_NAME, FIELD_DEFAULT_VALUE}},
231 // MemberType Block
232 {BI_MEMBER_TYPE_BLOCK_ID,
233 {MEMBER_TYPE_NAME, MEMBER_TYPE_ACCESS, MEMBER_TYPE_IS_STATIC}},
234 // Enum Block
235 {BI_ENUM_BLOCK_ID,
236 {ENUM_USR, ENUM_NAME, ENUM_DEFLOCATION, ENUM_LOCATION, ENUM_SCOPED}},
237 // Enum Value Block
238 {BI_ENUM_VALUE_BLOCK_ID,
239 {ENUM_VALUE_NAME, ENUM_VALUE_VALUE, ENUM_VALUE_EXPR}},
240 // Typedef Block
241 {BI_TYPEDEF_BLOCK_ID,
242 {TYPEDEF_USR, TYPEDEF_NAME, TYPEDEF_DEFLOCATION, TYPEDEF_IS_USING}},
243 // Namespace Block
244 {BI_NAMESPACE_BLOCK_ID,
245 {NAMESPACE_USR, NAMESPACE_NAME, NAMESPACE_PATH}},
246 // Record Block
247 {BI_RECORD_BLOCK_ID,
248 {RECORD_USR, RECORD_NAME, RECORD_PATH, RECORD_DEFLOCATION,
249 RECORD_LOCATION, RECORD_TAG_TYPE, RECORD_IS_TYPE_DEF}},
250 // BaseRecord Block
251 {BI_BASE_RECORD_BLOCK_ID,
252 {BASE_RECORD_USR, BASE_RECORD_NAME, BASE_RECORD_PATH,
253 BASE_RECORD_TAG_TYPE, BASE_RECORD_IS_VIRTUAL, BASE_RECORD_ACCESS,
254 BASE_RECORD_IS_PARENT}},
255 // Function Block
256 {BI_FUNCTION_BLOCK_ID,
257 {FUNCTION_USR, FUNCTION_NAME, FUNCTION_DEFLOCATION, FUNCTION_LOCATION,
258 FUNCTION_ACCESS, FUNCTION_IS_METHOD, FUNCTION_IS_STATIC}},
259 // Reference Block
260 {BI_REFERENCE_BLOCK_ID,
261 {REFERENCE_USR, REFERENCE_NAME, REFERENCE_QUAL_NAME, REFERENCE_TYPE,
262 REFERENCE_PATH, REFERENCE_FIELD}},
263 // Template Blocks.
264 {BI_TEMPLATE_BLOCK_ID, {}},
265 {BI_TEMPLATE_PARAM_BLOCK_ID, {TEMPLATE_PARAM_CONTENTS}},
266 {BI_TEMPLATE_SPECIALIZATION_BLOCK_ID, {TEMPLATE_SPECIALIZATION_OF}}};
267
268// AbbreviationMap
269
270constexpr unsigned char BitCodeConstants::Signature[];
271
272void ClangDocBitcodeWriter::AbbreviationMap::add(RecordId RID,
273 unsigned AbbrevID) {
274 assert(RecordIdNameMap[RID] && "Unknown RecordId.");
275 assert(!Abbrevs.contains(RID) && "Abbreviation already added.");
276 Abbrevs[RID] = AbbrevID;
277}
278
279unsigned ClangDocBitcodeWriter::AbbreviationMap::get(RecordId RID) const {
280 assert(RecordIdNameMap[RID] && "Unknown RecordId.");
281 assert(Abbrevs.contains(RID) && "Unknown abbreviation.");
282 return Abbrevs.lookup(Val: RID);
283}
284
285// Validation and Overview Blocks
286
287/// Emits the magic number header to check that its the right format,
288/// in this case, 'DOCS'.
289void ClangDocBitcodeWriter::emitHeader() {
290 for (char C : BitCodeConstants::Signature)
291 Stream.Emit(Val: (unsigned)C, NumBits: BitCodeConstants::SignatureBitSize);
292}
293
294void ClangDocBitcodeWriter::emitVersionBlock() {
295 StreamSubBlockGuard Block(Stream, BI_VERSION_BLOCK_ID);
296 emitRecord(Value: VersionNumber, ID: VERSION);
297}
298
299/// Emits a block ID and the block name to the BLOCKINFO block.
300void ClangDocBitcodeWriter::emitBlockID(BlockId BID) {
301 const auto &BlockIdName = BlockIdNameMap[BID];
302 assert(BlockIdName.data() && BlockIdName.size() && "Unknown BlockId.");
303
304 Record.clear();
305 Record.push_back(Elt: BID);
306 Stream.EmitRecord(Code: llvm::bitc::BLOCKINFO_CODE_SETBID, Vals: Record);
307 Stream.EmitRecord(Code: llvm::bitc::BLOCKINFO_CODE_BLOCKNAME,
308 Vals: ArrayRef<unsigned char>(BlockIdName.bytes_begin(),
309 BlockIdName.bytes_end()));
310}
311
312/// Emits a record name to the BLOCKINFO block.
313void ClangDocBitcodeWriter::emitRecordID(RecordId ID) {
314 assert(RecordIdNameMap[ID] && "Unknown RecordId.");
315 prepRecordData(ID);
316 Record.append(in_start: RecordIdNameMap[ID].Name.begin(),
317 in_end: RecordIdNameMap[ID].Name.end());
318 Stream.EmitRecord(Code: llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Vals: Record);
319}
320
321// Abbreviations
322
323void ClangDocBitcodeWriter::emitAbbrev(RecordId ID, BlockId Block) {
324 assert(RecordIdNameMap[ID] && "Unknown abbreviation.");
325 auto Abbrev = std::make_shared<llvm::BitCodeAbbrev>();
326 Abbrev->Add(OpInfo: llvm::BitCodeAbbrevOp(ID));
327 RecordIdNameMap[ID].Abbrev(Abbrev);
328 Abbrevs.add(RID: ID, AbbrevID: Stream.EmitBlockInfoAbbrev(BlockID: Block, Abbv: std::move(Abbrev)));
329}
330
331// Records
332
333void ClangDocBitcodeWriter::emitRecord(const SymbolID &Sym, RecordId ID) {
334 assert(RecordIdNameMap[ID] && "Unknown RecordId.");
335 assert(RecordIdNameMap[ID].Abbrev == &genSymbolIdAbbrev &&
336 "Abbrev type mismatch.");
337 if (!prepRecordData(ID, ShouldEmit: Sym != EmptySID))
338 return;
339 assert(Sym.size() == 20);
340 Record.push_back(Elt: Sym.size());
341 Record.append(in_start: Sym.begin(), in_end: Sym.end());
342 Stream.EmitRecordWithAbbrev(Abbrev: Abbrevs.get(RID: ID), Vals: Record);
343}
344
345void ClangDocBitcodeWriter::emitRecord(llvm::StringRef Str, RecordId ID) {
346 assert(RecordIdNameMap[ID] && "Unknown RecordId.");
347 assert(RecordIdNameMap[ID].Abbrev == &genStringAbbrev &&
348 "Abbrev type mismatch.");
349 if (!prepRecordData(ID, ShouldEmit: !Str.empty()))
350 return;
351 assert(Str.size() < (1U << BitCodeConstants::StringLengthSize));
352 Record.push_back(Elt: Str.size());
353 Stream.EmitRecordWithBlob(Abbrev: Abbrevs.get(RID: ID), Vals: Record, Blob: Str);
354}
355
356void ClangDocBitcodeWriter::emitRecord(const Location &Loc, RecordId ID) {
357 assert(RecordIdNameMap[ID] && "Unknown RecordId.");
358 assert(RecordIdNameMap[ID].Abbrev == &genLocationAbbrev &&
359 "Abbrev type mismatch.");
360 if (!prepRecordData(ID, ShouldEmit: true))
361 return;
362 // FIXME: Assert that the line number is of the appropriate size.
363 Record.push_back(Elt: Loc.StartLineNumber);
364 Record.push_back(Elt: Loc.EndLineNumber);
365 assert(Loc.Filename.size() < (1U << BitCodeConstants::StringLengthSize));
366 Record.push_back(Elt: Loc.IsFileInRootDir);
367 Record.push_back(Elt: Loc.Filename.size());
368 Stream.EmitRecordWithBlob(Abbrev: Abbrevs.get(RID: ID), Vals: Record, Blob: Loc.Filename);
369}
370
371void ClangDocBitcodeWriter::emitRecord(bool Val, RecordId ID) {
372 assert(RecordIdNameMap[ID] && "Unknown RecordId.");
373 assert(RecordIdNameMap[ID].Abbrev == &genBoolAbbrev &&
374 "Abbrev type mismatch.");
375 if (!prepRecordData(ID, ShouldEmit: Val))
376 return;
377 Record.push_back(Elt: Val);
378 Stream.EmitRecordWithAbbrev(Abbrev: Abbrevs.get(RID: ID), Vals: Record);
379}
380
381void ClangDocBitcodeWriter::emitRecord(int Val, RecordId ID) {
382 assert(RecordIdNameMap[ID] && "Unknown RecordId.");
383 assert(RecordIdNameMap[ID].Abbrev == &genIntAbbrev &&
384 "Abbrev type mismatch.");
385 if (!prepRecordData(ID, ShouldEmit: Val))
386 return;
387 // FIXME: Assert that the integer is of the appropriate size.
388 Record.push_back(Elt: Val);
389 Stream.EmitRecordWithAbbrev(Abbrev: Abbrevs.get(RID: ID), Vals: Record);
390}
391
392void ClangDocBitcodeWriter::emitRecord(unsigned Val, RecordId ID) {
393 assert(RecordIdNameMap[ID] && "Unknown RecordId.");
394 assert(RecordIdNameMap[ID].Abbrev == &genIntAbbrev &&
395 "Abbrev type mismatch.");
396 if (!prepRecordData(ID, ShouldEmit: Val))
397 return;
398 assert(Val < (1U << BitCodeConstants::IntSize));
399 Record.push_back(Elt: Val);
400 Stream.EmitRecordWithAbbrev(Abbrev: Abbrevs.get(RID: ID), Vals: Record);
401}
402
403void ClangDocBitcodeWriter::emitRecord(const TemplateInfo &Templ) {}
404
405bool ClangDocBitcodeWriter::prepRecordData(RecordId ID, bool ShouldEmit) {
406 assert(RecordIdNameMap[ID] && "Unknown RecordId.");
407 if (!ShouldEmit)
408 return false;
409 Record.clear();
410 Record.push_back(Elt: ID);
411 return true;
412}
413
414// BlockInfo Block
415
416void ClangDocBitcodeWriter::emitBlockInfoBlock() {
417 Stream.EnterBlockInfoBlock();
418 for (const auto &Block : RecordsByBlock) {
419 assert(Block.second.size() < (1U << BitCodeConstants::SubblockIDSize));
420 emitBlockInfo(BID: Block.first, RIDs: Block.second);
421 }
422 Stream.ExitBlock();
423}
424
425void ClangDocBitcodeWriter::emitBlockInfo(BlockId BID,
426 const std::vector<RecordId> &RIDs) {
427 assert(RIDs.size() < (1U << BitCodeConstants::SubblockIDSize));
428 emitBlockID(BID);
429 for (RecordId RID : RIDs) {
430 emitRecordID(ID: RID);
431 emitAbbrev(ID: RID, Block: BID);
432 }
433}
434
435// Block emission
436
437void ClangDocBitcodeWriter::emitBlock(const Reference &R, FieldId Field) {
438 if (R.USR == EmptySID && R.Name.empty())
439 return;
440 StreamSubBlockGuard Block(Stream, BI_REFERENCE_BLOCK_ID);
441 emitRecord(Sym: R.USR, ID: REFERENCE_USR);
442 emitRecord(Str: R.Name, ID: REFERENCE_NAME);
443 emitRecord(Str: R.QualName, ID: REFERENCE_QUAL_NAME);
444 emitRecord(Val: (unsigned)R.RefType, ID: REFERENCE_TYPE);
445 emitRecord(Str: R.Path, ID: REFERENCE_PATH);
446 emitRecord(Val: (unsigned)Field, ID: REFERENCE_FIELD);
447}
448
449void ClangDocBitcodeWriter::emitBlock(const TypeInfo &T) {
450 StreamSubBlockGuard Block(Stream, BI_TYPE_BLOCK_ID);
451 emitBlock(R: T.Type, Field: FieldId::F_type);
452}
453
454void ClangDocBitcodeWriter::emitBlock(const TypedefInfo &T) {
455 StreamSubBlockGuard Block(Stream, BI_TYPEDEF_BLOCK_ID);
456 emitRecord(Sym: T.USR, ID: TYPEDEF_USR);
457 emitRecord(Str: T.Name, ID: TYPEDEF_NAME);
458 for (const auto &N : T.Namespace)
459 emitBlock(R: N, Field: FieldId::F_namespace);
460 for (const auto &CI : T.Description)
461 emitBlock(B: CI);
462 if (T.DefLoc)
463 emitRecord(Loc: *T.DefLoc, ID: TYPEDEF_DEFLOCATION);
464 emitRecord(Val: T.IsUsing, ID: TYPEDEF_IS_USING);
465 emitBlock(T: T.Underlying);
466}
467
468void ClangDocBitcodeWriter::emitBlock(const FieldTypeInfo &T) {
469 StreamSubBlockGuard Block(Stream, BI_FIELD_TYPE_BLOCK_ID);
470 emitBlock(R: T.Type, Field: FieldId::F_type);
471 emitRecord(Str: T.Name, ID: FIELD_TYPE_NAME);
472 emitRecord(Str: T.DefaultValue, ID: FIELD_DEFAULT_VALUE);
473}
474
475void ClangDocBitcodeWriter::emitBlock(const MemberTypeInfo &T) {
476 StreamSubBlockGuard Block(Stream, BI_MEMBER_TYPE_BLOCK_ID);
477 emitBlock(R: T.Type, Field: FieldId::F_type);
478 emitRecord(Str: T.Name, ID: MEMBER_TYPE_NAME);
479 emitRecord(Val: T.Access, ID: MEMBER_TYPE_ACCESS);
480 emitRecord(Val: T.IsStatic, ID: MEMBER_TYPE_IS_STATIC);
481 for (const auto &CI : T.Description)
482 emitBlock(B: CI);
483}
484
485void ClangDocBitcodeWriter::emitBlock(const CommentInfo &I) {
486 StreamSubBlockGuard Block(Stream, BI_COMMENT_BLOCK_ID);
487 // Handle Kind (enum) separately, since it is not a string.
488 emitRecord(Str: commentKindToString(Kind: I.Kind), ID: COMMENT_KIND);
489 for (const auto &L : std::vector<std::pair<llvm::StringRef, RecordId>>{
490 {I.Text, COMMENT_TEXT},
491 {I.Name, COMMENT_NAME},
492 {I.Direction, COMMENT_DIRECTION},
493 {I.ParamName, COMMENT_PARAMNAME},
494 {I.CloseName, COMMENT_CLOSENAME}})
495 emitRecord(Str: L.first, ID: L.second);
496 emitRecord(Val: I.SelfClosing, ID: COMMENT_SELFCLOSING);
497 emitRecord(Val: I.Explicit, ID: COMMENT_EXPLICIT);
498 for (const auto &A : I.AttrKeys)
499 emitRecord(Str: A, ID: COMMENT_ATTRKEY);
500 for (const auto &A : I.AttrValues)
501 emitRecord(Str: A, ID: COMMENT_ATTRVAL);
502 for (const auto &A : I.Args)
503 emitRecord(Str: A, ID: COMMENT_ARG);
504 for (const auto &C : I.Children)
505 emitBlock(I: *C);
506}
507
508void ClangDocBitcodeWriter::emitBlock(const NamespaceInfo &I) {
509 StreamSubBlockGuard Block(Stream, BI_NAMESPACE_BLOCK_ID);
510 emitRecord(Sym: I.USR, ID: NAMESPACE_USR);
511 emitRecord(Str: I.Name, ID: NAMESPACE_NAME);
512 emitRecord(Str: I.Path, ID: NAMESPACE_PATH);
513 for (const auto &N : I.Namespace)
514 emitBlock(R: N, Field: FieldId::F_namespace);
515 for (const auto &CI : I.Description)
516 emitBlock(I: CI);
517 for (const auto &C : I.Children.Namespaces)
518 emitBlock(R: C, Field: FieldId::F_child_namespace);
519 for (const auto &C : I.Children.Records)
520 emitBlock(R: C, Field: FieldId::F_child_record);
521 for (const auto &C : I.Children.Functions)
522 emitBlock(I: C);
523 for (const auto &C : I.Children.Enums)
524 emitBlock(I: C);
525 for (const auto &C : I.Children.Typedefs)
526 emitBlock(T: C);
527}
528
529void ClangDocBitcodeWriter::emitBlock(const EnumInfo &I) {
530 StreamSubBlockGuard Block(Stream, BI_ENUM_BLOCK_ID);
531 emitRecord(Sym: I.USR, ID: ENUM_USR);
532 emitRecord(Str: I.Name, ID: ENUM_NAME);
533 for (const auto &N : I.Namespace)
534 emitBlock(R: N, Field: FieldId::F_namespace);
535 for (const auto &CI : I.Description)
536 emitBlock(I: CI);
537 if (I.DefLoc)
538 emitRecord(Loc: *I.DefLoc, ID: ENUM_DEFLOCATION);
539 for (const auto &L : I.Loc)
540 emitRecord(Loc: L, ID: ENUM_LOCATION);
541 emitRecord(Val: I.Scoped, ID: ENUM_SCOPED);
542 if (I.BaseType)
543 emitBlock(T: *I.BaseType);
544 for (const auto &N : I.Members)
545 emitBlock(I: N);
546}
547
548void ClangDocBitcodeWriter::emitBlock(const EnumValueInfo &I) {
549 StreamSubBlockGuard Block(Stream, BI_ENUM_VALUE_BLOCK_ID);
550 emitRecord(Str: I.Name, ID: ENUM_VALUE_NAME);
551 emitRecord(Str: I.Value, ID: ENUM_VALUE_VALUE);
552 emitRecord(Str: I.ValueExpr, ID: ENUM_VALUE_EXPR);
553 for (const auto &CI : I.Description)
554 emitBlock(I: CI);
555}
556
557void ClangDocBitcodeWriter::emitBlock(const RecordInfo &I) {
558 StreamSubBlockGuard Block(Stream, BI_RECORD_BLOCK_ID);
559 emitRecord(Sym: I.USR, ID: RECORD_USR);
560 emitRecord(Str: I.Name, ID: RECORD_NAME);
561 emitRecord(Str: I.Path, ID: RECORD_PATH);
562 for (const auto &N : I.Namespace)
563 emitBlock(R: N, Field: FieldId::F_namespace);
564 for (const auto &CI : I.Description)
565 emitBlock(I: CI);
566 if (I.DefLoc)
567 emitRecord(Loc: *I.DefLoc, ID: RECORD_DEFLOCATION);
568 for (const auto &L : I.Loc)
569 emitRecord(Loc: L, ID: RECORD_LOCATION);
570 emitRecord(Val: llvm::to_underlying(E: I.TagType), ID: RECORD_TAG_TYPE);
571 emitRecord(Val: I.IsTypeDef, ID: RECORD_IS_TYPE_DEF);
572 for (const auto &N : I.Members)
573 emitBlock(T: N);
574 for (const auto &P : I.Parents)
575 emitBlock(R: P, Field: FieldId::F_parent);
576 for (const auto &P : I.VirtualParents)
577 emitBlock(R: P, Field: FieldId::F_vparent);
578 for (const auto &PB : I.Bases)
579 emitBlock(I: PB);
580 for (const auto &C : I.Children.Records)
581 emitBlock(R: C, Field: FieldId::F_child_record);
582 for (const auto &C : I.Children.Functions)
583 emitBlock(I: C);
584 for (const auto &C : I.Children.Enums)
585 emitBlock(I: C);
586 for (const auto &C : I.Children.Typedefs)
587 emitBlock(T: C);
588 if (I.Template)
589 emitBlock(T: *I.Template);
590}
591
592void ClangDocBitcodeWriter::emitBlock(const BaseRecordInfo &I) {
593 StreamSubBlockGuard Block(Stream, BI_BASE_RECORD_BLOCK_ID);
594 emitRecord(Sym: I.USR, ID: BASE_RECORD_USR);
595 emitRecord(Str: I.Name, ID: BASE_RECORD_NAME);
596 emitRecord(Str: I.Path, ID: BASE_RECORD_PATH);
597 emitRecord(Val: llvm::to_underlying(E: I.TagType), ID: BASE_RECORD_TAG_TYPE);
598 emitRecord(Val: I.IsVirtual, ID: BASE_RECORD_IS_VIRTUAL);
599 emitRecord(Val: I.Access, ID: BASE_RECORD_ACCESS);
600 emitRecord(Val: I.IsParent, ID: BASE_RECORD_IS_PARENT);
601 for (const auto &M : I.Members)
602 emitBlock(T: M);
603 for (const auto &C : I.Children.Functions)
604 emitBlock(I: C);
605}
606
607void ClangDocBitcodeWriter::emitBlock(const FunctionInfo &I) {
608 StreamSubBlockGuard Block(Stream, BI_FUNCTION_BLOCK_ID);
609 emitRecord(Sym: I.USR, ID: FUNCTION_USR);
610 emitRecord(Str: I.Name, ID: FUNCTION_NAME);
611 for (const auto &N : I.Namespace)
612 emitBlock(R: N, Field: FieldId::F_namespace);
613 for (const auto &CI : I.Description)
614 emitBlock(I: CI);
615 emitRecord(Val: I.Access, ID: FUNCTION_ACCESS);
616 emitRecord(Val: I.IsMethod, ID: FUNCTION_IS_METHOD);
617 emitRecord(Val: I.IsStatic, ID: FUNCTION_IS_STATIC);
618 if (I.DefLoc)
619 emitRecord(Loc: *I.DefLoc, ID: FUNCTION_DEFLOCATION);
620 for (const auto &L : I.Loc)
621 emitRecord(Loc: L, ID: FUNCTION_LOCATION);
622 emitBlock(R: I.Parent, Field: FieldId::F_parent);
623 emitBlock(T: I.ReturnType);
624 for (const auto &N : I.Params)
625 emitBlock(T: N);
626 if (I.Template)
627 emitBlock(T: *I.Template);
628}
629
630void ClangDocBitcodeWriter::emitBlock(const TemplateInfo &T) {
631 StreamSubBlockGuard Block(Stream, BI_TEMPLATE_BLOCK_ID);
632 for (const auto &P : T.Params)
633 emitBlock(T: P);
634 if (T.Specialization)
635 emitBlock(T: *T.Specialization);
636}
637
638void ClangDocBitcodeWriter::emitBlock(const TemplateSpecializationInfo &T) {
639 StreamSubBlockGuard Block(Stream, BI_TEMPLATE_SPECIALIZATION_BLOCK_ID);
640 emitRecord(Sym: T.SpecializationOf, ID: TEMPLATE_SPECIALIZATION_OF);
641 for (const auto &P : T.Params)
642 emitBlock(T: P);
643}
644
645void ClangDocBitcodeWriter::emitBlock(const TemplateParamInfo &T) {
646 StreamSubBlockGuard Block(Stream, BI_TEMPLATE_PARAM_BLOCK_ID);
647 emitRecord(Str: T.Contents, ID: TEMPLATE_PARAM_CONTENTS);
648}
649
650bool ClangDocBitcodeWriter::dispatchInfoForWrite(Info *I) {
651 switch (I->IT) {
652 case InfoType::IT_namespace:
653 emitBlock(I: *static_cast<clang::doc::NamespaceInfo *>(I));
654 break;
655 case InfoType::IT_record:
656 emitBlock(I: *static_cast<clang::doc::RecordInfo *>(I));
657 break;
658 case InfoType::IT_enum:
659 emitBlock(I: *static_cast<clang::doc::EnumInfo *>(I));
660 break;
661 case InfoType::IT_function:
662 emitBlock(I: *static_cast<clang::doc::FunctionInfo *>(I));
663 break;
664 case InfoType::IT_typedef:
665 emitBlock(T: *static_cast<clang::doc::TypedefInfo *>(I));
666 break;
667 default:
668 llvm::errs() << "Unexpected info, unable to write.\n";
669 return true;
670 }
671 return false;
672}
673
674} // namespace doc
675} // namespace clang
676

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of clang-tools-extra/clang-doc/BitcodeWriter.cpp