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 {BI_CONSTRAINT_BLOCK_ID, "ConstraintBlock"},
133 {BI_CONCEPT_BLOCK_ID, "ConceptBlock"},
134 {BI_VAR_BLOCK_ID, "VarBlock"},
135 {BI_FRIEND_BLOCK_ID, "FriendBlock"}};
136 assert(Inits.size() == BlockIdCount);
137 for (const auto &Init : Inits)
138 BlockIdNameMap[Init.first] = Init.second;
139 assert(BlockIdNameMap.size() == BlockIdCount);
140 return BlockIdNameMap;
141 }();
142
143static const llvm::IndexedMap<RecordIdDsc, RecordIdToIndexFunctor>
144 RecordIdNameMap = []() {
145 llvm::IndexedMap<RecordIdDsc, RecordIdToIndexFunctor> RecordIdNameMap;
146 RecordIdNameMap.resize(s: RecordIdCount);
147
148 // There is no init-list constructor for the IndexedMap, so have to
149 // improvise
150 static const std::vector<std::pair<RecordId, RecordIdDsc>> Inits = {
151 {VERSION, {"Version", &genIntAbbrev}},
152 {COMMENT_KIND, {"Kind", &genStringAbbrev}},
153 {COMMENT_TEXT, {"Text", &genStringAbbrev}},
154 {COMMENT_NAME, {"Name", &genStringAbbrev}},
155 {COMMENT_DIRECTION, {"Direction", &genStringAbbrev}},
156 {COMMENT_PARAMNAME, {"ParamName", &genStringAbbrev}},
157 {COMMENT_CLOSENAME, {"CloseName", &genStringAbbrev}},
158 {COMMENT_SELFCLOSING, {"SelfClosing", &genBoolAbbrev}},
159 {COMMENT_EXPLICIT, {"Explicit", &genBoolAbbrev}},
160 {COMMENT_ATTRKEY, {"AttrKey", &genStringAbbrev}},
161 {COMMENT_ATTRVAL, {"AttrVal", &genStringAbbrev}},
162 {COMMENT_ARG, {"Arg", &genStringAbbrev}},
163 {FIELD_TYPE_NAME, {"Name", &genStringAbbrev}},
164 {FIELD_DEFAULT_VALUE, {"DefaultValue", &genStringAbbrev}},
165 {FIELD_TYPE_IS_BUILTIN, {"IsBuiltin", &genBoolAbbrev}},
166 {FIELD_TYPE_IS_TEMPLATE, {"IsTemplate", &genBoolAbbrev}},
167 {MEMBER_TYPE_NAME, {"Name", &genStringAbbrev}},
168 {MEMBER_TYPE_ACCESS, {"Access", &genIntAbbrev}},
169 {MEMBER_TYPE_IS_STATIC, {"IsStatic", &genBoolAbbrev}},
170 {MEMBER_TYPE_IS_BUILTIN, {"IsBuiltin", &genBoolAbbrev}},
171 {MEMBER_TYPE_IS_TEMPLATE, {"IsTemplate", &genBoolAbbrev}},
172 {TYPE_IS_BUILTIN, {"IsBuiltin", &genBoolAbbrev}},
173 {TYPE_IS_TEMPLATE, {"IsTemplate", &genBoolAbbrev}},
174 {NAMESPACE_USR, {"USR", &genSymbolIdAbbrev}},
175 {NAMESPACE_NAME, {"Name", &genStringAbbrev}},
176 {NAMESPACE_PATH, {"Path", &genStringAbbrev}},
177 {ENUM_USR, {"USR", &genSymbolIdAbbrev}},
178 {ENUM_NAME, {"Name", &genStringAbbrev}},
179 {ENUM_DEFLOCATION, {"DefLocation", &genLocationAbbrev}},
180 {ENUM_LOCATION, {"Location", &genLocationAbbrev}},
181 {ENUM_SCOPED, {"Scoped", &genBoolAbbrev}},
182 {ENUM_VALUE_NAME, {"Name", &genStringAbbrev}},
183 {ENUM_VALUE_VALUE, {"Value", &genStringAbbrev}},
184 {ENUM_VALUE_EXPR, {"Expr", &genStringAbbrev}},
185 {RECORD_USR, {"USR", &genSymbolIdAbbrev}},
186 {RECORD_NAME, {"Name", &genStringAbbrev}},
187 {RECORD_PATH, {"Path", &genStringAbbrev}},
188 {RECORD_DEFLOCATION, {"DefLocation", &genLocationAbbrev}},
189 {RECORD_LOCATION, {"Location", &genLocationAbbrev}},
190 {RECORD_TAG_TYPE, {"TagType", &genIntAbbrev}},
191 {RECORD_IS_TYPE_DEF, {"IsTypeDef", &genBoolAbbrev}},
192 {RECORD_MANGLED_NAME, {"MangledName", &genStringAbbrev}},
193 {BASE_RECORD_USR, {"USR", &genSymbolIdAbbrev}},
194 {BASE_RECORD_NAME, {"Name", &genStringAbbrev}},
195 {BASE_RECORD_PATH, {"Path", &genStringAbbrev}},
196 {BASE_RECORD_TAG_TYPE, {"TagType", &genIntAbbrev}},
197 {BASE_RECORD_IS_VIRTUAL, {"IsVirtual", &genBoolAbbrev}},
198 {BASE_RECORD_ACCESS, {"Access", &genIntAbbrev}},
199 {BASE_RECORD_IS_PARENT, {"IsParent", &genBoolAbbrev}},
200 {FUNCTION_USR, {"USR", &genSymbolIdAbbrev}},
201 {FUNCTION_NAME, {"Name", &genStringAbbrev}},
202 {FUNCTION_DEFLOCATION, {"DefLocation", &genLocationAbbrev}},
203 {FUNCTION_LOCATION, {"Location", &genLocationAbbrev}},
204 {FUNCTION_ACCESS, {"Access", &genIntAbbrev}},
205 {FUNCTION_IS_METHOD, {"IsMethod", &genBoolAbbrev}},
206 {FUNCTION_IS_STATIC, {"IsStatic", &genBoolAbbrev}},
207 {REFERENCE_USR, {"USR", &genSymbolIdAbbrev}},
208 {REFERENCE_NAME, {"Name", &genStringAbbrev}},
209 {REFERENCE_QUAL_NAME, {"QualName", &genStringAbbrev}},
210 {REFERENCE_TYPE, {"RefType", &genIntAbbrev}},
211 {REFERENCE_PATH, {"Path", &genStringAbbrev}},
212 {REFERENCE_FIELD, {"Field", &genIntAbbrev}},
213 {TEMPLATE_PARAM_CONTENTS, {"Contents", &genStringAbbrev}},
214 {TEMPLATE_SPECIALIZATION_OF,
215 {"SpecializationOf", &genSymbolIdAbbrev}},
216 {TYPEDEF_USR, {"USR", &genSymbolIdAbbrev}},
217 {TYPEDEF_NAME, {"Name", &genStringAbbrev}},
218 {TYPEDEF_DEFLOCATION, {"DefLocation", &genLocationAbbrev}},
219 {TYPEDEF_IS_USING, {"IsUsing", &genBoolAbbrev}},
220 {CONCEPT_USR, {"USR", &genSymbolIdAbbrev}},
221 {CONCEPT_NAME, {"Name", &genStringAbbrev}},
222 {CONCEPT_IS_TYPE, {"IsType", &genBoolAbbrev}},
223 {CONCEPT_CONSTRAINT_EXPRESSION,
224 {"ConstraintExpression", &genStringAbbrev}},
225 {CONSTRAINT_EXPRESSION, {"Expression", &genStringAbbrev}},
226 {VAR_USR, {"USR", &genSymbolIdAbbrev}},
227 {VAR_NAME, {"Name", &genStringAbbrev}},
228 {VAR_DEFLOCATION, {"DefLocation", &genLocationAbbrev}},
229 {VAR_IS_STATIC, {"IsStatic", &genBoolAbbrev}},
230 {FRIEND_IS_CLASS, {"IsClass", &genBoolAbbrev}}};
231
232 assert(Inits.size() == RecordIdCount);
233 for (const auto &Init : Inits) {
234 RecordIdNameMap[Init.first] = Init.second;
235 assert((Init.second.Name.size() + 1) <= BitCodeConstants::RecordSize);
236 }
237 assert(RecordIdNameMap.size() == RecordIdCount);
238 return RecordIdNameMap;
239 }();
240
241static const std::vector<std::pair<BlockId, std::vector<RecordId>>>
242 RecordsByBlock{
243 // Version Block
244 {BI_VERSION_BLOCK_ID, {VERSION}},
245 // Comment Block
246 {BI_COMMENT_BLOCK_ID,
247 {COMMENT_KIND, COMMENT_TEXT, COMMENT_NAME, COMMENT_DIRECTION,
248 COMMENT_PARAMNAME, COMMENT_CLOSENAME, COMMENT_SELFCLOSING,
249 COMMENT_EXPLICIT, COMMENT_ATTRKEY, COMMENT_ATTRVAL, COMMENT_ARG}},
250 // Type Block
251 {BI_TYPE_BLOCK_ID, {TYPE_IS_BUILTIN, TYPE_IS_TEMPLATE}},
252 // FieldType Block
253 {BI_FIELD_TYPE_BLOCK_ID,
254 {FIELD_TYPE_NAME, FIELD_DEFAULT_VALUE, FIELD_TYPE_IS_BUILTIN,
255 FIELD_TYPE_IS_TEMPLATE}},
256 // MemberType Block
257 {BI_MEMBER_TYPE_BLOCK_ID,
258 {MEMBER_TYPE_NAME, MEMBER_TYPE_ACCESS, MEMBER_TYPE_IS_STATIC,
259 MEMBER_TYPE_IS_BUILTIN, MEMBER_TYPE_IS_TEMPLATE}},
260 // Enum Block
261 {BI_ENUM_BLOCK_ID,
262 {ENUM_USR, ENUM_NAME, ENUM_DEFLOCATION, ENUM_LOCATION, ENUM_SCOPED}},
263 // Enum Value Block
264 {BI_ENUM_VALUE_BLOCK_ID,
265 {ENUM_VALUE_NAME, ENUM_VALUE_VALUE, ENUM_VALUE_EXPR}},
266 // Typedef Block
267 {BI_TYPEDEF_BLOCK_ID,
268 {TYPEDEF_USR, TYPEDEF_NAME, TYPEDEF_DEFLOCATION, TYPEDEF_IS_USING}},
269 // Namespace Block
270 {BI_NAMESPACE_BLOCK_ID,
271 {NAMESPACE_USR, NAMESPACE_NAME, NAMESPACE_PATH}},
272 // Record Block
273 {BI_RECORD_BLOCK_ID,
274 {RECORD_USR, RECORD_NAME, RECORD_PATH, RECORD_DEFLOCATION,
275 RECORD_LOCATION, RECORD_TAG_TYPE, RECORD_IS_TYPE_DEF,
276 RECORD_MANGLED_NAME}},
277 // BaseRecord Block
278 {BI_BASE_RECORD_BLOCK_ID,
279 {BASE_RECORD_USR, BASE_RECORD_NAME, BASE_RECORD_PATH,
280 BASE_RECORD_TAG_TYPE, BASE_RECORD_IS_VIRTUAL, BASE_RECORD_ACCESS,
281 BASE_RECORD_IS_PARENT}},
282 // Function Block
283 {BI_FUNCTION_BLOCK_ID,
284 {FUNCTION_USR, FUNCTION_NAME, FUNCTION_DEFLOCATION, FUNCTION_LOCATION,
285 FUNCTION_ACCESS, FUNCTION_IS_METHOD, FUNCTION_IS_STATIC}},
286 // Reference Block
287 {BI_REFERENCE_BLOCK_ID,
288 {REFERENCE_USR, REFERENCE_NAME, REFERENCE_QUAL_NAME, REFERENCE_TYPE,
289 REFERENCE_PATH, REFERENCE_FIELD}},
290 // Template Blocks.
291 {BI_TEMPLATE_BLOCK_ID, {}},
292 {BI_TEMPLATE_PARAM_BLOCK_ID, {TEMPLATE_PARAM_CONTENTS}},
293 {BI_TEMPLATE_SPECIALIZATION_BLOCK_ID, {TEMPLATE_SPECIALIZATION_OF}},
294 // Concept Block
295 {BI_CONCEPT_BLOCK_ID,
296 {CONCEPT_USR, CONCEPT_NAME, CONCEPT_IS_TYPE,
297 CONCEPT_CONSTRAINT_EXPRESSION}},
298 // Constraint Block
299 {BI_CONSTRAINT_BLOCK_ID, {CONSTRAINT_EXPRESSION}},
300 {BI_VAR_BLOCK_ID, {VAR_NAME, VAR_USR, VAR_DEFLOCATION, VAR_IS_STATIC}},
301 {BI_FRIEND_BLOCK_ID, {FRIEND_IS_CLASS}}};
302
303// AbbreviationMap
304
305constexpr unsigned char BitCodeConstants::Signature[];
306
307void ClangDocBitcodeWriter::AbbreviationMap::add(RecordId RID,
308 unsigned AbbrevID) {
309 assert(RecordIdNameMap[RID] && "Unknown RecordId.");
310 assert(!Abbrevs.contains(RID) && "Abbreviation already added.");
311 Abbrevs[RID] = AbbrevID;
312}
313
314unsigned ClangDocBitcodeWriter::AbbreviationMap::get(RecordId RID) const {
315 assert(RecordIdNameMap[RID] && "Unknown RecordId.");
316 assert(Abbrevs.contains(RID) && "Unknown abbreviation.");
317 return Abbrevs.lookup(Val: RID);
318}
319
320// Validation and Overview Blocks
321
322/// Emits the magic number header to check that its the right format,
323/// in this case, 'DOCS'.
324void ClangDocBitcodeWriter::emitHeader() {
325 for (char C : BitCodeConstants::Signature)
326 Stream.Emit(Val: (unsigned)C, NumBits: BitCodeConstants::SignatureBitSize);
327}
328
329void ClangDocBitcodeWriter::emitVersionBlock() {
330 StreamSubBlockGuard Block(Stream, BI_VERSION_BLOCK_ID);
331 emitRecord(Value: VersionNumber, ID: VERSION);
332}
333
334/// Emits a block ID and the block name to the BLOCKINFO block.
335void ClangDocBitcodeWriter::emitBlockID(BlockId BID) {
336 const auto &BlockIdName = BlockIdNameMap[BID];
337 assert(BlockIdName.data() && BlockIdName.size() && "Unknown BlockId.");
338
339 Record.clear();
340 Record.push_back(Elt: BID);
341 Stream.EmitRecord(Code: llvm::bitc::BLOCKINFO_CODE_SETBID, Vals: Record);
342 Stream.EmitRecord(Code: llvm::bitc::BLOCKINFO_CODE_BLOCKNAME,
343 Vals: ArrayRef<unsigned char>(BlockIdName.bytes_begin(),
344 BlockIdName.bytes_end()));
345}
346
347/// Emits a record name to the BLOCKINFO block.
348void ClangDocBitcodeWriter::emitRecordID(RecordId ID) {
349 assert(RecordIdNameMap[ID] && "Unknown RecordId.");
350 prepRecordData(ID);
351 Record.append(in_start: RecordIdNameMap[ID].Name.begin(),
352 in_end: RecordIdNameMap[ID].Name.end());
353 Stream.EmitRecord(Code: llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Vals: Record);
354}
355
356// Abbreviations
357
358void ClangDocBitcodeWriter::emitAbbrev(RecordId ID, BlockId Block) {
359 assert(RecordIdNameMap[ID] && "Unknown abbreviation.");
360 auto Abbrev = std::make_shared<llvm::BitCodeAbbrev>();
361 Abbrev->Add(OpInfo: llvm::BitCodeAbbrevOp(ID));
362 RecordIdNameMap[ID].Abbrev(Abbrev);
363 Abbrevs.add(RID: ID, AbbrevID: Stream.EmitBlockInfoAbbrev(BlockID: Block, Abbv: std::move(Abbrev)));
364}
365
366// Records
367
368void ClangDocBitcodeWriter::emitRecord(const SymbolID &Sym, RecordId ID) {
369 assert(RecordIdNameMap[ID] && "Unknown RecordId.");
370 assert(RecordIdNameMap[ID].Abbrev == &genSymbolIdAbbrev &&
371 "Abbrev type mismatch.");
372 if (!prepRecordData(ID, ShouldEmit: Sym != EmptySID))
373 return;
374 assert(Sym.size() == 20);
375 Record.push_back(Elt: Sym.size());
376 Record.append(in_start: Sym.begin(), in_end: Sym.end());
377 Stream.EmitRecordWithAbbrev(Abbrev: Abbrevs.get(RID: ID), Vals: Record);
378}
379
380void ClangDocBitcodeWriter::emitRecord(llvm::StringRef Str, RecordId ID) {
381 assert(RecordIdNameMap[ID] && "Unknown RecordId.");
382 assert(RecordIdNameMap[ID].Abbrev == &genStringAbbrev &&
383 "Abbrev type mismatch.");
384 if (!prepRecordData(ID, ShouldEmit: !Str.empty()))
385 return;
386 assert(Str.size() < (1U << BitCodeConstants::StringLengthSize));
387 Record.push_back(Elt: Str.size());
388 Stream.EmitRecordWithBlob(Abbrev: Abbrevs.get(RID: ID), Vals: Record, Blob: Str);
389}
390
391void ClangDocBitcodeWriter::emitRecord(const Location &Loc, RecordId ID) {
392 assert(RecordIdNameMap[ID] && "Unknown RecordId.");
393 assert(RecordIdNameMap[ID].Abbrev == &genLocationAbbrev &&
394 "Abbrev type mismatch.");
395 if (!prepRecordData(ID, ShouldEmit: true))
396 return;
397 // FIXME: Assert that the line number is of the appropriate size.
398 Record.push_back(Elt: Loc.StartLineNumber);
399 Record.push_back(Elt: Loc.EndLineNumber);
400 assert(Loc.Filename.size() < (1U << BitCodeConstants::StringLengthSize));
401 Record.push_back(Elt: Loc.IsFileInRootDir);
402 Record.push_back(Elt: Loc.Filename.size());
403 Stream.EmitRecordWithBlob(Abbrev: Abbrevs.get(RID: ID), Vals: Record, Blob: Loc.Filename);
404}
405
406void ClangDocBitcodeWriter::emitRecord(bool Val, RecordId ID) {
407 assert(RecordIdNameMap[ID] && "Unknown RecordId.");
408 assert(RecordIdNameMap[ID].Abbrev == &genBoolAbbrev &&
409 "Abbrev type mismatch.");
410 if (!prepRecordData(ID, ShouldEmit: Val))
411 return;
412 Record.push_back(Elt: Val);
413 Stream.EmitRecordWithAbbrev(Abbrev: Abbrevs.get(RID: ID), Vals: Record);
414}
415
416void ClangDocBitcodeWriter::emitRecord(int Val, RecordId ID) {
417 assert(RecordIdNameMap[ID] && "Unknown RecordId.");
418 assert(RecordIdNameMap[ID].Abbrev == &genIntAbbrev &&
419 "Abbrev type mismatch.");
420 if (!prepRecordData(ID, ShouldEmit: Val))
421 return;
422 // FIXME: Assert that the integer is of the appropriate size.
423 Record.push_back(Elt: Val);
424 Stream.EmitRecordWithAbbrev(Abbrev: Abbrevs.get(RID: ID), Vals: Record);
425}
426
427void ClangDocBitcodeWriter::emitRecord(unsigned Val, RecordId ID) {
428 assert(RecordIdNameMap[ID] && "Unknown RecordId.");
429 assert(RecordIdNameMap[ID].Abbrev == &genIntAbbrev &&
430 "Abbrev type mismatch.");
431 if (!prepRecordData(ID, ShouldEmit: Val))
432 return;
433 assert(Val < (1U << BitCodeConstants::IntSize));
434 Record.push_back(Elt: Val);
435 Stream.EmitRecordWithAbbrev(Abbrev: Abbrevs.get(RID: ID), Vals: Record);
436}
437
438void ClangDocBitcodeWriter::emitRecord(const TemplateInfo &Templ) {}
439
440bool ClangDocBitcodeWriter::prepRecordData(RecordId ID, bool ShouldEmit) {
441 assert(RecordIdNameMap[ID] && "Unknown RecordId.");
442 if (!ShouldEmit)
443 return false;
444 Record.clear();
445 Record.push_back(Elt: ID);
446 return true;
447}
448
449// BlockInfo Block
450
451void ClangDocBitcodeWriter::emitBlockInfoBlock() {
452 Stream.EnterBlockInfoBlock();
453 for (const auto &Block : RecordsByBlock) {
454 assert(Block.second.size() < (1U << BitCodeConstants::SubblockIDSize));
455 emitBlockInfo(BID: Block.first, RIDs: Block.second);
456 }
457 Stream.ExitBlock();
458}
459
460void ClangDocBitcodeWriter::emitBlockInfo(BlockId BID,
461 const std::vector<RecordId> &RIDs) {
462 assert(RIDs.size() < (1U << BitCodeConstants::SubblockIDSize));
463 emitBlockID(BID);
464 for (RecordId RID : RIDs) {
465 emitRecordID(ID: RID);
466 emitAbbrev(ID: RID, Block: BID);
467 }
468}
469
470// Block emission
471
472void ClangDocBitcodeWriter::emitBlock(const Reference &R, FieldId Field) {
473 if (R.USR == EmptySID && R.Name.empty())
474 return;
475 StreamSubBlockGuard Block(Stream, BI_REFERENCE_BLOCK_ID);
476 emitRecord(Sym: R.USR, ID: REFERENCE_USR);
477 emitRecord(Str: R.Name, ID: REFERENCE_NAME);
478 emitRecord(Str: R.QualName, ID: REFERENCE_QUAL_NAME);
479 emitRecord(Val: (unsigned)R.RefType, ID: REFERENCE_TYPE);
480 emitRecord(Str: R.Path, ID: REFERENCE_PATH);
481 emitRecord(Val: (unsigned)Field, ID: REFERENCE_FIELD);
482}
483
484void ClangDocBitcodeWriter::emitBlock(const FriendInfo &R) {
485 StreamSubBlockGuard Block(Stream, BI_FRIEND_BLOCK_ID);
486 emitBlock(R: R.Ref, Field: FieldId::F_friend);
487 emitRecord(Val: R.IsClass, ID: FRIEND_IS_CLASS);
488 if (R.Template)
489 emitBlock(T: *R.Template);
490 if (R.Params)
491 for (const auto &P : *R.Params)
492 emitBlock(B: P);
493 if (R.ReturnType)
494 emitBlock(B: *R.ReturnType);
495}
496
497void ClangDocBitcodeWriter::emitBlock(const TypeInfo &T) {
498 StreamSubBlockGuard Block(Stream, BI_TYPE_BLOCK_ID);
499 emitBlock(R: T.Type, Field: FieldId::F_type);
500 emitRecord(Val: T.IsBuiltIn, ID: TYPE_IS_BUILTIN);
501 emitRecord(Val: T.IsTemplate, ID: TYPE_IS_TEMPLATE);
502}
503
504void ClangDocBitcodeWriter::emitBlock(const TypedefInfo &T) {
505 StreamSubBlockGuard Block(Stream, BI_TYPEDEF_BLOCK_ID);
506 emitRecord(Sym: T.USR, ID: TYPEDEF_USR);
507 emitRecord(Str: T.Name, ID: TYPEDEF_NAME);
508 for (const auto &N : T.Namespace)
509 emitBlock(R: N, Field: FieldId::F_namespace);
510 for (const auto &CI : T.Description)
511 emitBlock(B: CI);
512 if (T.DefLoc)
513 emitRecord(Loc: *T.DefLoc, ID: TYPEDEF_DEFLOCATION);
514 emitRecord(Val: T.IsUsing, ID: TYPEDEF_IS_USING);
515 emitBlock(T: T.Underlying);
516}
517
518void ClangDocBitcodeWriter::emitBlock(const FieldTypeInfo &T) {
519 StreamSubBlockGuard Block(Stream, BI_FIELD_TYPE_BLOCK_ID);
520 emitBlock(R: T.Type, Field: FieldId::F_type);
521 emitRecord(Str: T.Name, ID: FIELD_TYPE_NAME);
522 emitRecord(Str: T.DefaultValue, ID: FIELD_DEFAULT_VALUE);
523 emitRecord(Val: T.IsBuiltIn, ID: FIELD_TYPE_IS_BUILTIN);
524 emitRecord(Val: T.IsTemplate, ID: FIELD_TYPE_IS_TEMPLATE);
525}
526
527void ClangDocBitcodeWriter::emitBlock(const MemberTypeInfo &T) {
528 StreamSubBlockGuard Block(Stream, BI_MEMBER_TYPE_BLOCK_ID);
529 emitBlock(R: T.Type, Field: FieldId::F_type);
530 emitRecord(Str: T.Name, ID: MEMBER_TYPE_NAME);
531 emitRecord(Val: T.Access, ID: MEMBER_TYPE_ACCESS);
532 emitRecord(Val: T.IsStatic, ID: MEMBER_TYPE_IS_STATIC);
533 emitRecord(Val: T.IsBuiltIn, ID: MEMBER_TYPE_IS_BUILTIN);
534 emitRecord(Val: T.IsTemplate, ID: MEMBER_TYPE_IS_TEMPLATE);
535 emitRecord(Val: T.IsTemplate, ID: MEMBER_TYPE_IS_TEMPLATE);
536 for (const auto &CI : T.Description)
537 emitBlock(B: CI);
538}
539
540void ClangDocBitcodeWriter::emitBlock(const CommentInfo &I) {
541 StreamSubBlockGuard Block(Stream, BI_COMMENT_BLOCK_ID);
542 // Handle Kind (enum) separately, since it is not a string.
543 emitRecord(Str: commentKindToString(Kind: I.Kind), ID: COMMENT_KIND);
544 for (const auto &L : std::vector<std::pair<llvm::StringRef, RecordId>>{
545 {I.Text, COMMENT_TEXT},
546 {I.Name, COMMENT_NAME},
547 {I.Direction, COMMENT_DIRECTION},
548 {I.ParamName, COMMENT_PARAMNAME},
549 {I.CloseName, COMMENT_CLOSENAME}})
550 emitRecord(Str: L.first, ID: L.second);
551 emitRecord(Val: I.SelfClosing, ID: COMMENT_SELFCLOSING);
552 emitRecord(Val: I.Explicit, ID: COMMENT_EXPLICIT);
553 for (const auto &A : I.AttrKeys)
554 emitRecord(Str: A, ID: COMMENT_ATTRKEY);
555 for (const auto &A : I.AttrValues)
556 emitRecord(Str: A, ID: COMMENT_ATTRVAL);
557 for (const auto &A : I.Args)
558 emitRecord(Str: A, ID: COMMENT_ARG);
559 for (const auto &C : I.Children)
560 emitBlock(I: *C);
561}
562
563void ClangDocBitcodeWriter::emitBlock(const NamespaceInfo &I) {
564 StreamSubBlockGuard Block(Stream, BI_NAMESPACE_BLOCK_ID);
565 emitRecord(Sym: I.USR, ID: NAMESPACE_USR);
566 emitRecord(Str: I.Name, ID: NAMESPACE_NAME);
567 emitRecord(Str: I.Path, ID: NAMESPACE_PATH);
568 for (const auto &N : I.Namespace)
569 emitBlock(R: N, Field: FieldId::F_namespace);
570 for (const auto &CI : I.Description)
571 emitBlock(I: CI);
572 for (const auto &C : I.Children.Namespaces)
573 emitBlock(R: C, Field: FieldId::F_child_namespace);
574 for (const auto &C : I.Children.Records)
575 emitBlock(R: C, Field: FieldId::F_child_record);
576 for (const auto &C : I.Children.Functions)
577 emitBlock(I: C);
578 for (const auto &C : I.Children.Enums)
579 emitBlock(I: C);
580 for (const auto &C : I.Children.Typedefs)
581 emitBlock(T: C);
582 for (const auto &C : I.Children.Concepts)
583 emitBlock(T: C);
584 for (const auto &C : I.Children.Variables)
585 emitBlock(B: C);
586}
587
588void ClangDocBitcodeWriter::emitBlock(const EnumInfo &I) {
589 StreamSubBlockGuard Block(Stream, BI_ENUM_BLOCK_ID);
590 emitRecord(Sym: I.USR, ID: ENUM_USR);
591 emitRecord(Str: I.Name, ID: ENUM_NAME);
592 for (const auto &N : I.Namespace)
593 emitBlock(R: N, Field: FieldId::F_namespace);
594 for (const auto &CI : I.Description)
595 emitBlock(I: CI);
596 if (I.DefLoc)
597 emitRecord(Loc: *I.DefLoc, ID: ENUM_DEFLOCATION);
598 for (const auto &L : I.Loc)
599 emitRecord(Loc: L, ID: ENUM_LOCATION);
600 emitRecord(Val: I.Scoped, ID: ENUM_SCOPED);
601 if (I.BaseType)
602 emitBlock(T: *I.BaseType);
603 for (const auto &N : I.Members)
604 emitBlock(I: N);
605}
606
607void ClangDocBitcodeWriter::emitBlock(const EnumValueInfo &I) {
608 StreamSubBlockGuard Block(Stream, BI_ENUM_VALUE_BLOCK_ID);
609 emitRecord(Str: I.Name, ID: ENUM_VALUE_NAME);
610 emitRecord(Str: I.Value, ID: ENUM_VALUE_VALUE);
611 emitRecord(Str: I.ValueExpr, ID: ENUM_VALUE_EXPR);
612 for (const auto &CI : I.Description)
613 emitBlock(I: CI);
614}
615
616void ClangDocBitcodeWriter::emitBlock(const RecordInfo &I) {
617 StreamSubBlockGuard Block(Stream, BI_RECORD_BLOCK_ID);
618 emitRecord(Sym: I.USR, ID: RECORD_USR);
619 emitRecord(Str: I.Name, ID: RECORD_NAME);
620 emitRecord(Str: I.Path, ID: RECORD_PATH);
621 emitRecord(Str: I.MangledName, ID: RECORD_MANGLED_NAME);
622 for (const auto &N : I.Namespace)
623 emitBlock(R: N, Field: FieldId::F_namespace);
624 for (const auto &CI : I.Description)
625 emitBlock(I: CI);
626 if (I.DefLoc)
627 emitRecord(Loc: *I.DefLoc, ID: RECORD_DEFLOCATION);
628 for (const auto &L : I.Loc)
629 emitRecord(Loc: L, ID: RECORD_LOCATION);
630 emitRecord(Val: llvm::to_underlying(E: I.TagType), ID: RECORD_TAG_TYPE);
631 emitRecord(Val: I.IsTypeDef, ID: RECORD_IS_TYPE_DEF);
632 for (const auto &N : I.Members)
633 emitBlock(T: N);
634 for (const auto &P : I.Parents)
635 emitBlock(R: P, Field: FieldId::F_parent);
636 for (const auto &P : I.VirtualParents)
637 emitBlock(R: P, Field: FieldId::F_vparent);
638 for (const auto &PB : I.Bases)
639 emitBlock(I: PB);
640 for (const auto &C : I.Children.Records)
641 emitBlock(R: C, Field: FieldId::F_child_record);
642 for (const auto &C : I.Children.Functions)
643 emitBlock(I: C);
644 for (const auto &C : I.Children.Enums)
645 emitBlock(I: C);
646 for (const auto &C : I.Children.Typedefs)
647 emitBlock(T: C);
648 if (I.Template)
649 emitBlock(T: *I.Template);
650 for (const auto &C : I.Friends)
651 emitBlock(R: C);
652}
653
654void ClangDocBitcodeWriter::emitBlock(const BaseRecordInfo &I) {
655 StreamSubBlockGuard Block(Stream, BI_BASE_RECORD_BLOCK_ID);
656 emitRecord(Sym: I.USR, ID: BASE_RECORD_USR);
657 emitRecord(Str: I.Name, ID: BASE_RECORD_NAME);
658 emitRecord(Str: I.Path, ID: BASE_RECORD_PATH);
659 emitRecord(Val: llvm::to_underlying(E: I.TagType), ID: BASE_RECORD_TAG_TYPE);
660 emitRecord(Val: I.IsVirtual, ID: BASE_RECORD_IS_VIRTUAL);
661 emitRecord(Val: I.Access, ID: BASE_RECORD_ACCESS);
662 emitRecord(Val: I.IsParent, ID: BASE_RECORD_IS_PARENT);
663 for (const auto &M : I.Members)
664 emitBlock(T: M);
665 for (const auto &C : I.Children.Functions)
666 emitBlock(I: C);
667}
668
669void ClangDocBitcodeWriter::emitBlock(const FunctionInfo &I) {
670 StreamSubBlockGuard Block(Stream, BI_FUNCTION_BLOCK_ID);
671 emitRecord(Sym: I.USR, ID: FUNCTION_USR);
672 emitRecord(Str: I.Name, ID: FUNCTION_NAME);
673 for (const auto &N : I.Namespace)
674 emitBlock(R: N, Field: FieldId::F_namespace);
675 for (const auto &CI : I.Description)
676 emitBlock(I: CI);
677 emitRecord(Val: I.Access, ID: FUNCTION_ACCESS);
678 emitRecord(Val: I.IsMethod, ID: FUNCTION_IS_METHOD);
679 emitRecord(Val: I.IsStatic, ID: FUNCTION_IS_STATIC);
680 if (I.DefLoc)
681 emitRecord(Loc: *I.DefLoc, ID: FUNCTION_DEFLOCATION);
682 for (const auto &L : I.Loc)
683 emitRecord(Loc: L, ID: FUNCTION_LOCATION);
684 emitBlock(R: I.Parent, Field: FieldId::F_parent);
685 emitBlock(T: I.ReturnType);
686 for (const auto &N : I.Params)
687 emitBlock(T: N);
688 if (I.Template)
689 emitBlock(T: *I.Template);
690}
691
692void ClangDocBitcodeWriter::emitBlock(const ConceptInfo &I) {
693 StreamSubBlockGuard Block(Stream, BI_CONCEPT_BLOCK_ID);
694 emitRecord(Sym: I.USR, ID: CONCEPT_USR);
695 emitRecord(Str: I.Name, ID: CONCEPT_NAME);
696 for (const auto &CI : I.Description)
697 emitBlock(I: CI);
698 emitRecord(Val: I.IsType, ID: CONCEPT_IS_TYPE);
699 emitRecord(Str: I.ConstraintExpression, ID: CONCEPT_CONSTRAINT_EXPRESSION);
700 emitBlock(T: I.Template);
701}
702
703void ClangDocBitcodeWriter::emitBlock(const TemplateInfo &T) {
704 StreamSubBlockGuard Block(Stream, BI_TEMPLATE_BLOCK_ID);
705 for (const auto &P : T.Params)
706 emitBlock(T: P);
707 if (T.Specialization)
708 emitBlock(T: *T.Specialization);
709 for (const auto &C : T.Constraints)
710 emitBlock(T: C);
711}
712
713void ClangDocBitcodeWriter::emitBlock(const TemplateSpecializationInfo &T) {
714 StreamSubBlockGuard Block(Stream, BI_TEMPLATE_SPECIALIZATION_BLOCK_ID);
715 emitRecord(Sym: T.SpecializationOf, ID: TEMPLATE_SPECIALIZATION_OF);
716 for (const auto &P : T.Params)
717 emitBlock(T: P);
718}
719
720void ClangDocBitcodeWriter::emitBlock(const TemplateParamInfo &T) {
721 StreamSubBlockGuard Block(Stream, BI_TEMPLATE_PARAM_BLOCK_ID);
722 emitRecord(Str: T.Contents, ID: TEMPLATE_PARAM_CONTENTS);
723}
724
725void ClangDocBitcodeWriter::emitBlock(const ConstraintInfo &C) {
726 StreamSubBlockGuard Block(Stream, BI_CONSTRAINT_BLOCK_ID);
727 emitRecord(Str: C.ConstraintExpr, ID: CONSTRAINT_EXPRESSION);
728 emitBlock(R: C.ConceptRef, Field: FieldId::F_concept);
729}
730
731void ClangDocBitcodeWriter::emitBlock(const VarInfo &I) {
732 StreamSubBlockGuard Block(Stream, BI_VAR_BLOCK_ID);
733 emitRecord(Sym: I.USR, ID: VAR_USR);
734 emitRecord(Str: I.Name, ID: VAR_NAME);
735 for (const auto &N : I.Namespace)
736 emitBlock(R: N, Field: FieldId::F_namespace);
737 for (const auto &CI : I.Description)
738 emitBlock(I: CI);
739 if (I.DefLoc)
740 emitRecord(Loc: *I.DefLoc, ID: VAR_DEFLOCATION);
741 emitRecord(Val: I.IsStatic, ID: VAR_IS_STATIC);
742 emitBlock(T: I.Type);
743}
744
745bool ClangDocBitcodeWriter::dispatchInfoForWrite(Info *I) {
746 switch (I->IT) {
747 case InfoType::IT_namespace:
748 emitBlock(I: *static_cast<clang::doc::NamespaceInfo *>(I));
749 break;
750 case InfoType::IT_record:
751 emitBlock(I: *static_cast<clang::doc::RecordInfo *>(I));
752 break;
753 case InfoType::IT_enum:
754 emitBlock(I: *static_cast<clang::doc::EnumInfo *>(I));
755 break;
756 case InfoType::IT_function:
757 emitBlock(I: *static_cast<clang::doc::FunctionInfo *>(I));
758 break;
759 case InfoType::IT_typedef:
760 emitBlock(T: *static_cast<clang::doc::TypedefInfo *>(I));
761 break;
762 case InfoType::IT_concept:
763 emitBlock(I: *static_cast<clang::doc::ConceptInfo *>(I));
764 break;
765 case InfoType::IT_variable:
766 emitBlock(I: *static_cast<VarInfo *>(I));
767 break;
768 case InfoType::IT_friend:
769 emitBlock(R: *static_cast<FriendInfo *>(I));
770 break;
771 case InfoType::IT_default:
772 llvm::errs() << "Unexpected info, unable to write.\n";
773 return true;
774 }
775 return false;
776}
777
778} // namespace doc
779} // namespace clang
780

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