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_ENUM_VALUE_BLOCK_ID
, "EnumValueBlock"},
116 {BI_TYPEDEF_BLOCK_ID
, "TypedefBlock"},
117 {BI_TYPE_BLOCK_ID
, "TypeBlock"},
118 {BI_FIELD_TYPE_BLOCK_ID
, "FieldTypeBlock"},
119 {BI_MEMBER_TYPE_BLOCK_ID
, "MemberTypeBlock"},
120 {BI_RECORD_BLOCK_ID
, "RecordBlock"},
121 {BI_BASE_RECORD_BLOCK_ID
, "BaseRecordBlock"},
122 {BI_FUNCTION_BLOCK_ID
, "FunctionBlock"},
123 {BI_COMMENT_BLOCK_ID
, "CommentBlock"},
124 {BI_REFERENCE_BLOCK_ID
, "ReferenceBlock"},
125 {BI_TEMPLATE_BLOCK_ID
, "TemplateBlock"},
126 {BI_TEMPLATE_SPECIALIZATION_BLOCK_ID
, "TemplateSpecializationBlock"},
127 {BI_TEMPLATE_PARAM_BLOCK_ID
, "TemplateParamBlock"}};
128 assert(Inits
.size() == BlockIdCount
);
129 for (const auto &Init
: Inits
)
130 BlockIdNameMap
[Init
.first
] = Init
.second
;
131 assert(BlockIdNameMap
.size() == BlockIdCount
);
132 return BlockIdNameMap
;
135 static const llvm::IndexedMap
<RecordIdDsc
, RecordIdToIndexFunctor
>
136 RecordIdNameMap
= []() {
137 llvm::IndexedMap
<RecordIdDsc
, RecordIdToIndexFunctor
> RecordIdNameMap
;
138 RecordIdNameMap
.resize(RecordIdCount
);
140 // There is no init-list constructor for the IndexedMap, so have to
142 static const std::vector
<std::pair
<RecordId
, RecordIdDsc
>> Inits
= {
143 {VERSION
, {"Version", &IntAbbrev
}},
144 {COMMENT_KIND
, {"Kind", &StringAbbrev
}},
145 {COMMENT_TEXT
, {"Text", &StringAbbrev
}},
146 {COMMENT_NAME
, {"Name", &StringAbbrev
}},
147 {COMMENT_DIRECTION
, {"Direction", &StringAbbrev
}},
148 {COMMENT_PARAMNAME
, {"ParamName", &StringAbbrev
}},
149 {COMMENT_CLOSENAME
, {"CloseName", &StringAbbrev
}},
150 {COMMENT_SELFCLOSING
, {"SelfClosing", &BoolAbbrev
}},
151 {COMMENT_EXPLICIT
, {"Explicit", &BoolAbbrev
}},
152 {COMMENT_ATTRKEY
, {"AttrKey", &StringAbbrev
}},
153 {COMMENT_ATTRVAL
, {"AttrVal", &StringAbbrev
}},
154 {COMMENT_ARG
, {"Arg", &StringAbbrev
}},
155 {FIELD_TYPE_NAME
, {"Name", &StringAbbrev
}},
156 {FIELD_DEFAULT_VALUE
, {"DefaultValue", &StringAbbrev
}},
157 {MEMBER_TYPE_NAME
, {"Name", &StringAbbrev
}},
158 {MEMBER_TYPE_ACCESS
, {"Access", &IntAbbrev
}},
159 {NAMESPACE_USR
, {"USR", &SymbolIDAbbrev
}},
160 {NAMESPACE_NAME
, {"Name", &StringAbbrev
}},
161 {NAMESPACE_PATH
, {"Path", &StringAbbrev
}},
162 {ENUM_USR
, {"USR", &SymbolIDAbbrev
}},
163 {ENUM_NAME
, {"Name", &StringAbbrev
}},
164 {ENUM_DEFLOCATION
, {"DefLocation", &LocationAbbrev
}},
165 {ENUM_LOCATION
, {"Location", &LocationAbbrev
}},
166 {ENUM_SCOPED
, {"Scoped", &BoolAbbrev
}},
167 {ENUM_VALUE_NAME
, {"Name", &StringAbbrev
}},
168 {ENUM_VALUE_VALUE
, {"Value", &StringAbbrev
}},
169 {ENUM_VALUE_EXPR
, {"Expr", &StringAbbrev
}},
170 {RECORD_USR
, {"USR", &SymbolIDAbbrev
}},
171 {RECORD_NAME
, {"Name", &StringAbbrev
}},
172 {RECORD_PATH
, {"Path", &StringAbbrev
}},
173 {RECORD_DEFLOCATION
, {"DefLocation", &LocationAbbrev
}},
174 {RECORD_LOCATION
, {"Location", &LocationAbbrev
}},
175 {RECORD_TAG_TYPE
, {"TagType", &IntAbbrev
}},
176 {RECORD_IS_TYPE_DEF
, {"IsTypeDef", &BoolAbbrev
}},
177 {BASE_RECORD_USR
, {"USR", &SymbolIDAbbrev
}},
178 {BASE_RECORD_NAME
, {"Name", &StringAbbrev
}},
179 {BASE_RECORD_PATH
, {"Path", &StringAbbrev
}},
180 {BASE_RECORD_TAG_TYPE
, {"TagType", &IntAbbrev
}},
181 {BASE_RECORD_IS_VIRTUAL
, {"IsVirtual", &BoolAbbrev
}},
182 {BASE_RECORD_ACCESS
, {"Access", &IntAbbrev
}},
183 {BASE_RECORD_IS_PARENT
, {"IsParent", &BoolAbbrev
}},
184 {FUNCTION_USR
, {"USR", &SymbolIDAbbrev
}},
185 {FUNCTION_NAME
, {"Name", &StringAbbrev
}},
186 {FUNCTION_DEFLOCATION
, {"DefLocation", &LocationAbbrev
}},
187 {FUNCTION_LOCATION
, {"Location", &LocationAbbrev
}},
188 {FUNCTION_ACCESS
, {"Access", &IntAbbrev
}},
189 {FUNCTION_IS_METHOD
, {"IsMethod", &BoolAbbrev
}},
190 {REFERENCE_USR
, {"USR", &SymbolIDAbbrev
}},
191 {REFERENCE_NAME
, {"Name", &StringAbbrev
}},
192 {REFERENCE_QUAL_NAME
, {"QualName", &StringAbbrev
}},
193 {REFERENCE_TYPE
, {"RefType", &IntAbbrev
}},
194 {REFERENCE_PATH
, {"Path", &StringAbbrev
}},
195 {REFERENCE_FIELD
, {"Field", &IntAbbrev
}},
196 {TEMPLATE_PARAM_CONTENTS
, {"Contents", &StringAbbrev
}},
197 {TEMPLATE_SPECIALIZATION_OF
, {"SpecializationOf", &SymbolIDAbbrev
}},
198 {TYPEDEF_USR
, {"USR", &SymbolIDAbbrev
}},
199 {TYPEDEF_NAME
, {"Name", &StringAbbrev
}},
200 {TYPEDEF_DEFLOCATION
, {"DefLocation", &LocationAbbrev
}},
201 {TYPEDEF_IS_USING
, {"IsUsing", &BoolAbbrev
}}};
202 assert(Inits
.size() == RecordIdCount
);
203 for (const auto &Init
: Inits
) {
204 RecordIdNameMap
[Init
.first
] = Init
.second
;
205 assert((Init
.second
.Name
.size() + 1) <= BitCodeConstants::RecordSize
);
207 assert(RecordIdNameMap
.size() == RecordIdCount
);
208 return RecordIdNameMap
;
211 static const std::vector
<std::pair
<BlockId
, std::vector
<RecordId
>>>
214 {BI_VERSION_BLOCK_ID
, {VERSION
}},
216 {BI_COMMENT_BLOCK_ID
,
217 {COMMENT_KIND
, COMMENT_TEXT
, COMMENT_NAME
, COMMENT_DIRECTION
,
218 COMMENT_PARAMNAME
, COMMENT_CLOSENAME
, COMMENT_SELFCLOSING
,
219 COMMENT_EXPLICIT
, COMMENT_ATTRKEY
, COMMENT_ATTRVAL
, COMMENT_ARG
}},
221 {BI_TYPE_BLOCK_ID
, {}},
223 {BI_FIELD_TYPE_BLOCK_ID
, {FIELD_TYPE_NAME
, FIELD_DEFAULT_VALUE
}},
225 {BI_MEMBER_TYPE_BLOCK_ID
, {MEMBER_TYPE_NAME
, MEMBER_TYPE_ACCESS
}},
228 {ENUM_USR
, ENUM_NAME
, ENUM_DEFLOCATION
, ENUM_LOCATION
, ENUM_SCOPED
}},
230 {BI_ENUM_VALUE_BLOCK_ID
,
231 {ENUM_VALUE_NAME
, ENUM_VALUE_VALUE
, ENUM_VALUE_EXPR
}},
233 {BI_TYPEDEF_BLOCK_ID
,
234 {TYPEDEF_USR
, TYPEDEF_NAME
, TYPEDEF_DEFLOCATION
, TYPEDEF_IS_USING
}},
236 {BI_NAMESPACE_BLOCK_ID
,
237 {NAMESPACE_USR
, NAMESPACE_NAME
, NAMESPACE_PATH
}},
240 {RECORD_USR
, RECORD_NAME
, RECORD_PATH
, RECORD_DEFLOCATION
,
241 RECORD_LOCATION
, RECORD_TAG_TYPE
, RECORD_IS_TYPE_DEF
}},
243 {BI_BASE_RECORD_BLOCK_ID
,
244 {BASE_RECORD_USR
, BASE_RECORD_NAME
, BASE_RECORD_PATH
,
245 BASE_RECORD_TAG_TYPE
, BASE_RECORD_IS_VIRTUAL
, BASE_RECORD_ACCESS
,
246 BASE_RECORD_IS_PARENT
}},
248 {BI_FUNCTION_BLOCK_ID
,
249 {FUNCTION_USR
, FUNCTION_NAME
, FUNCTION_DEFLOCATION
, FUNCTION_LOCATION
,
250 FUNCTION_ACCESS
, FUNCTION_IS_METHOD
}},
252 {BI_REFERENCE_BLOCK_ID
,
253 {REFERENCE_USR
, REFERENCE_NAME
, REFERENCE_QUAL_NAME
, REFERENCE_TYPE
,
254 REFERENCE_PATH
, REFERENCE_FIELD
}},
256 {BI_TEMPLATE_BLOCK_ID
, {}},
257 {BI_TEMPLATE_PARAM_BLOCK_ID
, {TEMPLATE_PARAM_CONTENTS
}},
258 {BI_TEMPLATE_SPECIALIZATION_BLOCK_ID
, {TEMPLATE_SPECIALIZATION_OF
}}};
262 constexpr unsigned char BitCodeConstants::Signature
[];
264 void ClangDocBitcodeWriter::AbbreviationMap::add(RecordId RID
,
266 assert(RecordIdNameMap
[RID
] && "Unknown RecordId.");
267 assert(!Abbrevs
.contains(RID
) && "Abbreviation already added.");
268 Abbrevs
[RID
] = AbbrevID
;
271 unsigned ClangDocBitcodeWriter::AbbreviationMap::get(RecordId RID
) const {
272 assert(RecordIdNameMap
[RID
] && "Unknown RecordId.");
273 assert(Abbrevs
.contains(RID
) && "Unknown abbreviation.");
274 return Abbrevs
.lookup(RID
);
277 // Validation and Overview Blocks
279 /// Emits the magic number header to check that its the right format,
280 /// in this case, 'DOCS'.
281 void ClangDocBitcodeWriter::emitHeader() {
282 for (char C
: BitCodeConstants::Signature
)
283 Stream
.Emit((unsigned)C
, BitCodeConstants::SignatureBitSize
);
286 void ClangDocBitcodeWriter::emitVersionBlock() {
287 StreamSubBlockGuard
Block(Stream
, BI_VERSION_BLOCK_ID
);
288 emitRecord(VersionNumber
, VERSION
);
291 /// Emits a block ID and the block name to the BLOCKINFO block.
292 void ClangDocBitcodeWriter::emitBlockID(BlockId BID
) {
293 const auto &BlockIdName
= BlockIdNameMap
[BID
];
294 assert(BlockIdName
.data() && BlockIdName
.size() && "Unknown BlockId.");
297 Record
.push_back(BID
);
298 Stream
.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID
, Record
);
299 Stream
.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME
,
300 ArrayRef
<unsigned char>(BlockIdName
.bytes_begin(),
301 BlockIdName
.bytes_end()));
304 /// Emits a record name to the BLOCKINFO block.
305 void ClangDocBitcodeWriter::emitRecordID(RecordId ID
) {
306 assert(RecordIdNameMap
[ID
] && "Unknown RecordId.");
308 Record
.append(RecordIdNameMap
[ID
].Name
.begin(),
309 RecordIdNameMap
[ID
].Name
.end());
310 Stream
.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME
, Record
);
315 void ClangDocBitcodeWriter::emitAbbrev(RecordId ID
, BlockId Block
) {
316 assert(RecordIdNameMap
[ID
] && "Unknown abbreviation.");
317 auto Abbrev
= std::make_shared
<llvm::BitCodeAbbrev
>();
318 Abbrev
->Add(llvm::BitCodeAbbrevOp(ID
));
319 RecordIdNameMap
[ID
].Abbrev(Abbrev
);
320 Abbrevs
.add(ID
, Stream
.EmitBlockInfoAbbrev(Block
, std::move(Abbrev
)));
325 void ClangDocBitcodeWriter::emitRecord(const SymbolID
&Sym
, RecordId ID
) {
326 assert(RecordIdNameMap
[ID
] && "Unknown RecordId.");
327 assert(RecordIdNameMap
[ID
].Abbrev
== &SymbolIDAbbrev
&&
328 "Abbrev type mismatch.");
329 if (!prepRecordData(ID
, Sym
!= EmptySID
))
331 assert(Sym
.size() == 20);
332 Record
.push_back(Sym
.size());
333 Record
.append(Sym
.begin(), Sym
.end());
334 Stream
.EmitRecordWithAbbrev(Abbrevs
.get(ID
), Record
);
337 void ClangDocBitcodeWriter::emitRecord(llvm::StringRef Str
, RecordId ID
) {
338 assert(RecordIdNameMap
[ID
] && "Unknown RecordId.");
339 assert(RecordIdNameMap
[ID
].Abbrev
== &StringAbbrev
&&
340 "Abbrev type mismatch.");
341 if (!prepRecordData(ID
, !Str
.empty()))
343 assert(Str
.size() < (1U << BitCodeConstants::StringLengthSize
));
344 Record
.push_back(Str
.size());
345 Stream
.EmitRecordWithBlob(Abbrevs
.get(ID
), Record
, Str
);
348 void ClangDocBitcodeWriter::emitRecord(const Location
&Loc
, RecordId ID
) {
349 assert(RecordIdNameMap
[ID
] && "Unknown RecordId.");
350 assert(RecordIdNameMap
[ID
].Abbrev
== &LocationAbbrev
&&
351 "Abbrev type mismatch.");
352 if (!prepRecordData(ID
, true))
354 // FIXME: Assert that the line number is of the appropriate size.
355 Record
.push_back(Loc
.LineNumber
);
356 assert(Loc
.Filename
.size() < (1U << BitCodeConstants::StringLengthSize
));
357 Record
.push_back(Loc
.IsFileInRootDir
);
358 Record
.push_back(Loc
.Filename
.size());
359 Stream
.EmitRecordWithBlob(Abbrevs
.get(ID
), Record
, Loc
.Filename
);
362 void ClangDocBitcodeWriter::emitRecord(bool Val
, RecordId ID
) {
363 assert(RecordIdNameMap
[ID
] && "Unknown RecordId.");
364 assert(RecordIdNameMap
[ID
].Abbrev
== &BoolAbbrev
&& "Abbrev type mismatch.");
365 if (!prepRecordData(ID
, Val
))
367 Record
.push_back(Val
);
368 Stream
.EmitRecordWithAbbrev(Abbrevs
.get(ID
), Record
);
371 void ClangDocBitcodeWriter::emitRecord(int Val
, RecordId ID
) {
372 assert(RecordIdNameMap
[ID
] && "Unknown RecordId.");
373 assert(RecordIdNameMap
[ID
].Abbrev
== &IntAbbrev
&& "Abbrev type mismatch.");
374 if (!prepRecordData(ID
, Val
))
376 // FIXME: Assert that the integer is of the appropriate size.
377 Record
.push_back(Val
);
378 Stream
.EmitRecordWithAbbrev(Abbrevs
.get(ID
), Record
);
381 void ClangDocBitcodeWriter::emitRecord(unsigned Val
, RecordId ID
) {
382 assert(RecordIdNameMap
[ID
] && "Unknown RecordId.");
383 assert(RecordIdNameMap
[ID
].Abbrev
== &IntAbbrev
&& "Abbrev type mismatch.");
384 if (!prepRecordData(ID
, Val
))
386 assert(Val
< (1U << BitCodeConstants::IntSize
));
387 Record
.push_back(Val
);
388 Stream
.EmitRecordWithAbbrev(Abbrevs
.get(ID
), Record
);
391 void ClangDocBitcodeWriter::emitRecord(const TemplateInfo
&Templ
) {}
393 bool ClangDocBitcodeWriter::prepRecordData(RecordId ID
, bool ShouldEmit
) {
394 assert(RecordIdNameMap
[ID
] && "Unknown RecordId.");
398 Record
.push_back(ID
);
404 void ClangDocBitcodeWriter::emitBlockInfoBlock() {
405 Stream
.EnterBlockInfoBlock();
406 for (const auto &Block
: RecordsByBlock
) {
407 assert(Block
.second
.size() < (1U << BitCodeConstants::SubblockIDSize
));
408 emitBlockInfo(Block
.first
, Block
.second
);
413 void ClangDocBitcodeWriter::emitBlockInfo(BlockId BID
,
414 const std::vector
<RecordId
> &RIDs
) {
415 assert(RIDs
.size() < (1U << BitCodeConstants::SubblockIDSize
));
417 for (RecordId RID
: RIDs
) {
419 emitAbbrev(RID
, BID
);
425 void ClangDocBitcodeWriter::emitBlock(const Reference
&R
, FieldId Field
) {
426 if (R
.USR
== EmptySID
&& R
.Name
.empty())
428 StreamSubBlockGuard
Block(Stream
, BI_REFERENCE_BLOCK_ID
);
429 emitRecord(R
.USR
, REFERENCE_USR
);
430 emitRecord(R
.Name
, REFERENCE_NAME
);
431 emitRecord(R
.QualName
, REFERENCE_QUAL_NAME
);
432 emitRecord((unsigned)R
.RefType
, REFERENCE_TYPE
);
433 emitRecord(R
.Path
, REFERENCE_PATH
);
434 emitRecord((unsigned)Field
, REFERENCE_FIELD
);
437 void ClangDocBitcodeWriter::emitBlock(const TypeInfo
&T
) {
438 StreamSubBlockGuard
Block(Stream
, BI_TYPE_BLOCK_ID
);
439 emitBlock(T
.Type
, FieldId::F_type
);
442 void ClangDocBitcodeWriter::emitBlock(const TypedefInfo
&T
) {
443 StreamSubBlockGuard
Block(Stream
, BI_TYPEDEF_BLOCK_ID
);
444 emitRecord(T
.USR
, TYPEDEF_USR
);
445 emitRecord(T
.Name
, TYPEDEF_NAME
);
446 for (const auto &N
: T
.Namespace
)
447 emitBlock(N
, FieldId::F_namespace
);
448 for (const auto &CI
: T
.Description
)
451 emitRecord(*T
.DefLoc
, TYPEDEF_DEFLOCATION
);
452 emitRecord(T
.IsUsing
, TYPEDEF_IS_USING
);
453 emitBlock(T
.Underlying
);
456 void ClangDocBitcodeWriter::emitBlock(const FieldTypeInfo
&T
) {
457 StreamSubBlockGuard
Block(Stream
, BI_FIELD_TYPE_BLOCK_ID
);
458 emitBlock(T
.Type
, FieldId::F_type
);
459 emitRecord(T
.Name
, FIELD_TYPE_NAME
);
460 emitRecord(T
.DefaultValue
, FIELD_DEFAULT_VALUE
);
463 void ClangDocBitcodeWriter::emitBlock(const MemberTypeInfo
&T
) {
464 StreamSubBlockGuard
Block(Stream
, BI_MEMBER_TYPE_BLOCK_ID
);
465 emitBlock(T
.Type
, FieldId::F_type
);
466 emitRecord(T
.Name
, MEMBER_TYPE_NAME
);
467 emitRecord(T
.Access
, MEMBER_TYPE_ACCESS
);
468 for (const auto &CI
: T
.Description
)
472 void ClangDocBitcodeWriter::emitBlock(const CommentInfo
&I
) {
473 StreamSubBlockGuard
Block(Stream
, BI_COMMENT_BLOCK_ID
);
474 for (const auto &L
: std::vector
<std::pair
<llvm::StringRef
, RecordId
>>{
475 {I
.Kind
, COMMENT_KIND
},
476 {I
.Text
, COMMENT_TEXT
},
477 {I
.Name
, COMMENT_NAME
},
478 {I
.Direction
, COMMENT_DIRECTION
},
479 {I
.ParamName
, COMMENT_PARAMNAME
},
480 {I
.CloseName
, COMMENT_CLOSENAME
}})
481 emitRecord(L
.first
, L
.second
);
482 emitRecord(I
.SelfClosing
, COMMENT_SELFCLOSING
);
483 emitRecord(I
.Explicit
, COMMENT_EXPLICIT
);
484 for (const auto &A
: I
.AttrKeys
)
485 emitRecord(A
, COMMENT_ATTRKEY
);
486 for (const auto &A
: I
.AttrValues
)
487 emitRecord(A
, COMMENT_ATTRVAL
);
488 for (const auto &A
: I
.Args
)
489 emitRecord(A
, COMMENT_ARG
);
490 for (const auto &C
: I
.Children
)
494 void ClangDocBitcodeWriter::emitBlock(const NamespaceInfo
&I
) {
495 StreamSubBlockGuard
Block(Stream
, BI_NAMESPACE_BLOCK_ID
);
496 emitRecord(I
.USR
, NAMESPACE_USR
);
497 emitRecord(I
.Name
, NAMESPACE_NAME
);
498 emitRecord(I
.Path
, NAMESPACE_PATH
);
499 for (const auto &N
: I
.Namespace
)
500 emitBlock(N
, FieldId::F_namespace
);
501 for (const auto &CI
: I
.Description
)
503 for (const auto &C
: I
.Children
.Namespaces
)
504 emitBlock(C
, FieldId::F_child_namespace
);
505 for (const auto &C
: I
.Children
.Records
)
506 emitBlock(C
, FieldId::F_child_record
);
507 for (const auto &C
: I
.Children
.Functions
)
509 for (const auto &C
: I
.Children
.Enums
)
511 for (const auto &C
: I
.Children
.Typedefs
)
515 void ClangDocBitcodeWriter::emitBlock(const EnumInfo
&I
) {
516 StreamSubBlockGuard
Block(Stream
, BI_ENUM_BLOCK_ID
);
517 emitRecord(I
.USR
, ENUM_USR
);
518 emitRecord(I
.Name
, ENUM_NAME
);
519 for (const auto &N
: I
.Namespace
)
520 emitBlock(N
, FieldId::F_namespace
);
521 for (const auto &CI
: I
.Description
)
524 emitRecord(*I
.DefLoc
, ENUM_DEFLOCATION
);
525 for (const auto &L
: I
.Loc
)
526 emitRecord(L
, ENUM_LOCATION
);
527 emitRecord(I
.Scoped
, ENUM_SCOPED
);
529 emitBlock(*I
.BaseType
);
530 for (const auto &N
: I
.Members
)
534 void ClangDocBitcodeWriter::emitBlock(const EnumValueInfo
&I
) {
535 StreamSubBlockGuard
Block(Stream
, BI_ENUM_VALUE_BLOCK_ID
);
536 emitRecord(I
.Name
, ENUM_VALUE_NAME
);
537 emitRecord(I
.Value
, ENUM_VALUE_VALUE
);
538 emitRecord(I
.ValueExpr
, ENUM_VALUE_EXPR
);
541 void ClangDocBitcodeWriter::emitBlock(const RecordInfo
&I
) {
542 StreamSubBlockGuard
Block(Stream
, BI_RECORD_BLOCK_ID
);
543 emitRecord(I
.USR
, RECORD_USR
);
544 emitRecord(I
.Name
, RECORD_NAME
);
545 emitRecord(I
.Path
, RECORD_PATH
);
546 for (const auto &N
: I
.Namespace
)
547 emitBlock(N
, FieldId::F_namespace
);
548 for (const auto &CI
: I
.Description
)
551 emitRecord(*I
.DefLoc
, RECORD_DEFLOCATION
);
552 for (const auto &L
: I
.Loc
)
553 emitRecord(L
, RECORD_LOCATION
);
554 emitRecord(I
.TagType
, RECORD_TAG_TYPE
);
555 emitRecord(I
.IsTypeDef
, RECORD_IS_TYPE_DEF
);
556 for (const auto &N
: I
.Members
)
558 for (const auto &P
: I
.Parents
)
559 emitBlock(P
, FieldId::F_parent
);
560 for (const auto &P
: I
.VirtualParents
)
561 emitBlock(P
, FieldId::F_vparent
);
562 for (const auto &PB
: I
.Bases
)
564 for (const auto &C
: I
.Children
.Records
)
565 emitBlock(C
, FieldId::F_child_record
);
566 for (const auto &C
: I
.Children
.Functions
)
568 for (const auto &C
: I
.Children
.Enums
)
570 for (const auto &C
: I
.Children
.Typedefs
)
573 emitBlock(*I
.Template
);
576 void ClangDocBitcodeWriter::emitBlock(const BaseRecordInfo
&I
) {
577 StreamSubBlockGuard
Block(Stream
, BI_BASE_RECORD_BLOCK_ID
);
578 emitRecord(I
.USR
, BASE_RECORD_USR
);
579 emitRecord(I
.Name
, BASE_RECORD_NAME
);
580 emitRecord(I
.Path
, BASE_RECORD_PATH
);
581 emitRecord(I
.TagType
, BASE_RECORD_TAG_TYPE
);
582 emitRecord(I
.IsVirtual
, BASE_RECORD_IS_VIRTUAL
);
583 emitRecord(I
.Access
, BASE_RECORD_ACCESS
);
584 emitRecord(I
.IsParent
, BASE_RECORD_IS_PARENT
);
585 for (const auto &M
: I
.Members
)
587 for (const auto &C
: I
.Children
.Functions
)
591 void ClangDocBitcodeWriter::emitBlock(const FunctionInfo
&I
) {
592 StreamSubBlockGuard
Block(Stream
, BI_FUNCTION_BLOCK_ID
);
593 emitRecord(I
.USR
, FUNCTION_USR
);
594 emitRecord(I
.Name
, FUNCTION_NAME
);
595 for (const auto &N
: I
.Namespace
)
596 emitBlock(N
, FieldId::F_namespace
);
597 for (const auto &CI
: I
.Description
)
599 emitRecord(I
.Access
, FUNCTION_ACCESS
);
600 emitRecord(I
.IsMethod
, FUNCTION_IS_METHOD
);
602 emitRecord(*I
.DefLoc
, FUNCTION_DEFLOCATION
);
603 for (const auto &L
: I
.Loc
)
604 emitRecord(L
, FUNCTION_LOCATION
);
605 emitBlock(I
.Parent
, FieldId::F_parent
);
606 emitBlock(I
.ReturnType
);
607 for (const auto &N
: I
.Params
)
610 emitBlock(*I
.Template
);
613 void ClangDocBitcodeWriter::emitBlock(const TemplateInfo
&T
) {
614 StreamSubBlockGuard
Block(Stream
, BI_TEMPLATE_BLOCK_ID
);
615 for (const auto &P
: T
.Params
)
617 if (T
.Specialization
)
618 emitBlock(*T
.Specialization
);
621 void ClangDocBitcodeWriter::emitBlock(const TemplateSpecializationInfo
&T
) {
622 StreamSubBlockGuard
Block(Stream
, BI_TEMPLATE_SPECIALIZATION_BLOCK_ID
);
623 emitRecord(T
.SpecializationOf
, TEMPLATE_SPECIALIZATION_OF
);
624 for (const auto &P
: T
.Params
)
628 void ClangDocBitcodeWriter::emitBlock(const TemplateParamInfo
&T
) {
629 StreamSubBlockGuard
Block(Stream
, BI_TEMPLATE_PARAM_BLOCK_ID
);
630 emitRecord(T
.Contents
, TEMPLATE_PARAM_CONTENTS
);
633 bool ClangDocBitcodeWriter::dispatchInfoForWrite(Info
*I
) {
635 case InfoType::IT_namespace
:
636 emitBlock(*static_cast<clang::doc::NamespaceInfo
*>(I
));
638 case InfoType::IT_record
:
639 emitBlock(*static_cast<clang::doc::RecordInfo
*>(I
));
641 case InfoType::IT_enum
:
642 emitBlock(*static_cast<clang::doc::EnumInfo
*>(I
));
644 case InfoType::IT_function
:
645 emitBlock(*static_cast<clang::doc::FunctionInfo
*>(I
));
647 case InfoType::IT_typedef
:
648 emitBlock(*static_cast<clang::doc::TypedefInfo
*>(I
));
651 llvm::errs() << "Unexpected info, unable to write.\n";