1 //===-- BitcodeWriter.cpp - ClangDoc Bitcode Writer ------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "BitcodeWriter.h"
10 #include "llvm/ADT/IndexedMap.h"
11 #include <initializer_list>
16 // Empty SymbolID for comparison, so we don't have to construct one every time.
17 static const SymbolID EmptySID
= SymbolID();
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;
23 unsigned operator()(unsigned ID
) const { return ID
- BI_FIRST
; }
26 struct RecordIdToIndexFunctor
{
27 using argument_type
= unsigned;
28 unsigned operator()(unsigned ID
) const { return ID
- RI_FIRST
; }
31 using AbbrevDsc
= void (*)(std::shared_ptr
<llvm::BitCodeAbbrev
> &Abbrev
);
33 static void AbbrevGen(std::shared_ptr
<llvm::BitCodeAbbrev
> &Abbrev
,
34 const std::initializer_list
<llvm::BitCodeAbbrevOp
> Ops
) {
35 for (const auto &Op
: Ops
)
39 static void BoolAbbrev(std::shared_ptr
<llvm::BitCodeAbbrev
> &Abbrev
) {
42 llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed
,
43 BitCodeConstants::BoolSize
)});
46 static void IntAbbrev(std::shared_ptr
<llvm::BitCodeAbbrev
> &Abbrev
) {
48 {// 0. Fixed-size integer
49 llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed
,
50 BitCodeConstants::IntSize
)});
53 static void SymbolIDAbbrev(std::shared_ptr
<llvm::BitCodeAbbrev
> &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
)});
64 static void StringAbbrev(std::shared_ptr
<llvm::BitCodeAbbrev
> &Abbrev
) {
66 {// 0. Fixed-size integer (length of the following string)
67 llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed
,
68 BitCodeConstants::StringLengthSize
),
70 llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob
)});
73 // Assumes that the file will not have more than 65535 lines.
74 static void LocationAbbrev(std::shared_ptr
<llvm::BitCodeAbbrev
> &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
),
87 llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob
)});
92 AbbrevDsc Abbrev
= nullptr;
94 RecordIdDsc() = default;
95 RecordIdDsc(llvm::StringRef Name
, AbbrevDsc Abbrev
)
96 : Name(Name
), Abbrev(Abbrev
) {}
98 // Is this 'description' valid?
99 operator bool() const {
100 return Abbrev
!= nullptr && Name
.data() != nullptr && !Name
.empty();
104 static const llvm::IndexedMap
<llvm::StringRef
, BlockIdToIndexFunctor
>
105 BlockIdNameMap
= []() {
106 llvm::IndexedMap
<llvm::StringRef
, BlockIdToIndexFunctor
> BlockIdNameMap
;
107 BlockIdNameMap
.resize(BlockIdCount
);
109 // There is no init-list constructor for the IndexedMap, so have to
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
;
130 static const llvm::IndexedMap
<RecordIdDsc
, RecordIdToIndexFunctor
>
131 RecordIdNameMap
= []() {
132 llvm::IndexedMap
<RecordIdDsc
, RecordIdToIndexFunctor
> RecordIdNameMap
;
133 RecordIdNameMap
.resize(RecordIdCount
);
135 // There is no init-list constructor for the IndexedMap, so have to
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
);
194 assert(RecordIdNameMap
.size() == RecordIdCount
);
195 return RecordIdNameMap
;
198 static const std::vector
<std::pair
<BlockId
, std::vector
<RecordId
>>>
201 {BI_VERSION_BLOCK_ID
, {VERSION
}},
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
}},
208 {BI_TYPE_BLOCK_ID
, {}},
210 {BI_FIELD_TYPE_BLOCK_ID
, {FIELD_TYPE_NAME
}},
212 {BI_MEMBER_TYPE_BLOCK_ID
, {MEMBER_TYPE_NAME
, MEMBER_TYPE_ACCESS
}},
215 {ENUM_USR
, ENUM_NAME
, ENUM_DEFLOCATION
, ENUM_LOCATION
, ENUM_MEMBER
,
218 {BI_NAMESPACE_BLOCK_ID
,
219 {NAMESPACE_USR
, NAMESPACE_NAME
, NAMESPACE_PATH
}},
222 {RECORD_USR
, RECORD_NAME
, RECORD_PATH
, RECORD_DEFLOCATION
,
223 RECORD_LOCATION
, RECORD_TAG_TYPE
, RECORD_IS_TYPE_DEF
}},
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
}},
230 {BI_FUNCTION_BLOCK_ID
,
231 {FUNCTION_USR
, FUNCTION_NAME
, FUNCTION_DEFLOCATION
, FUNCTION_LOCATION
,
232 FUNCTION_ACCESS
, FUNCTION_IS_METHOD
}},
234 {BI_REFERENCE_BLOCK_ID
,
235 {REFERENCE_USR
, REFERENCE_NAME
, REFERENCE_TYPE
, REFERENCE_PATH
,
236 REFERENCE_IS_IN_GLOBAL_NAMESPACE
, REFERENCE_FIELD
}}};
240 constexpr unsigned char BitCodeConstants::Signature
[];
242 void ClangDocBitcodeWriter::AbbreviationMap::add(RecordId RID
,
244 assert(RecordIdNameMap
[RID
] && "Unknown RecordId.");
245 assert(Abbrevs
.find(RID
) == Abbrevs
.end() && "Abbreviation already added.");
246 Abbrevs
[RID
] = AbbrevID
;
249 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
);
255 // Validation and Overview Blocks
257 /// Emits the magic number header to check that its the right format,
258 /// in this case, 'DOCS'.
259 void ClangDocBitcodeWriter::emitHeader() {
260 for (char C
: BitCodeConstants::Signature
)
261 Stream
.Emit((unsigned)C
, BitCodeConstants::SignatureBitSize
);
264 void ClangDocBitcodeWriter::emitVersionBlock() {
265 StreamSubBlockGuard
Block(Stream
, BI_VERSION_BLOCK_ID
);
266 emitRecord(VersionNumber
, VERSION
);
269 /// Emits a block ID and the block name to the BLOCKINFO block.
270 void ClangDocBitcodeWriter::emitBlockID(BlockId BID
) {
271 const auto &BlockIdName
= BlockIdNameMap
[BID
];
272 assert(BlockIdName
.data() && BlockIdName
.size() && "Unknown BlockId.");
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()));
282 /// Emits a record name to the BLOCKINFO block.
283 void ClangDocBitcodeWriter::emitRecordID(RecordId ID
) {
284 assert(RecordIdNameMap
[ID
] && "Unknown RecordId.");
286 Record
.append(RecordIdNameMap
[ID
].Name
.begin(),
287 RecordIdNameMap
[ID
].Name
.end());
288 Stream
.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME
, Record
);
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
)));
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
))
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
);
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()))
321 assert(Str
.size() < (1U << BitCodeConstants::StringLengthSize
));
322 Record
.push_back(Str
.size());
323 Stream
.EmitRecordWithBlob(Abbrevs
.get(ID
), Record
, Str
);
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))
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
);
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
))
345 Record
.push_back(Val
);
346 Stream
.EmitRecordWithAbbrev(Abbrevs
.get(ID
), Record
);
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
))
354 // FIXME: Assert that the integer is of the appropriate size.
355 Record
.push_back(Val
);
356 Stream
.EmitRecordWithAbbrev(Abbrevs
.get(ID
), Record
);
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
))
364 assert(Val
< (1U << BitCodeConstants::IntSize
));
365 Record
.push_back(Val
);
366 Stream
.EmitRecordWithAbbrev(Abbrevs
.get(ID
), Record
);
369 bool ClangDocBitcodeWriter::prepRecordData(RecordId ID
, bool ShouldEmit
) {
370 assert(RecordIdNameMap
[ID
] && "Unknown RecordId.");
374 Record
.push_back(ID
);
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
);
389 void ClangDocBitcodeWriter::emitBlockInfo(BlockId BID
,
390 const std::vector
<RecordId
> &RIDs
) {
391 assert(RIDs
.size() < (1U << BitCodeConstants::SubblockIDSize
));
393 for (RecordId RID
: RIDs
) {
395 emitAbbrev(RID
, BID
);
401 void ClangDocBitcodeWriter::emitBlock(const Reference
&R
, FieldId Field
) {
402 if (R
.USR
== EmptySID
&& R
.Name
.empty())
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
);
413 void ClangDocBitcodeWriter::emitBlock(const TypeInfo
&T
) {
414 StreamSubBlockGuard
Block(Stream
, BI_TYPE_BLOCK_ID
);
415 emitBlock(T
.Type
, FieldId::F_type
);
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
);
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
);
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
)
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
)
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
)
468 for (const auto &C
: I
.ChildEnums
)
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
)
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
);
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
)
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
)
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
)
512 for (const auto &C
: I
.ChildRecords
)
513 emitBlock(C
, FieldId::F_child_record
);
514 for (const auto &C
: I
.ChildFunctions
)
516 for (const auto &C
: I
.ChildEnums
)
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
)
531 for (const auto &C
: I
.ChildFunctions
)
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
)
543 emitRecord(I
.Access
, FUNCTION_ACCESS
);
544 emitRecord(I
.IsMethod
, FUNCTION_IS_METHOD
);
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
)
555 bool ClangDocBitcodeWriter::dispatchInfoForWrite(Info
*I
) {
557 case InfoType::IT_namespace
:
558 emitBlock(*static_cast<clang::doc::NamespaceInfo
*>(I
));
560 case InfoType::IT_record
:
561 emitBlock(*static_cast<clang::doc::RecordInfo
*>(I
));
563 case InfoType::IT_enum
:
564 emitBlock(*static_cast<clang::doc::EnumInfo
*>(I
));
566 case InfoType::IT_function
:
567 emitBlock(*static_cast<clang::doc::FunctionInfo
*>(I
));
570 llvm::errs() << "Unexpected info, unable to write.\n";