1 | //===-- BitcodeWriter.cpp - ClangDoc Bitcode Writer ------------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "BitcodeWriter.h" |
10 | #include "llvm/ADT/IndexedMap.h" |
11 | #include <initializer_list> |
12 | |
13 | namespace clang { |
14 | namespace doc { |
15 | |
16 | // Empty SymbolID for comparison, so we don't have to construct one every time. |
17 | static const SymbolID EmptySID = SymbolID(); |
18 | |
19 | // Since id enums are not zero-indexed, we need to transform the given id into |
20 | // its associated index. |
21 | struct BlockIdToIndexFunctor { |
22 | using argument_type = unsigned; |
23 | unsigned operator()(unsigned ID) const { return ID - BI_FIRST; } |
24 | }; |
25 | |
26 | struct RecordIdToIndexFunctor { |
27 | using argument_type = unsigned; |
28 | unsigned operator()(unsigned ID) const { return ID - RI_FIRST; } |
29 | }; |
30 | |
31 | using AbbrevDsc = void (*)(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev); |
32 | |
33 | static void AbbrevGen(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev, |
34 | const std::initializer_list<llvm::BitCodeAbbrevOp> Ops) { |
35 | for (const auto &Op : Ops) |
36 | Abbrev->Add(OpInfo: Op); |
37 | } |
38 | |
39 | static void BoolAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) { |
40 | AbbrevGen(Abbrev, |
41 | Ops: {// 0. Boolean |
42 | llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed, |
43 | BitCodeConstants::BoolSize)}); |
44 | } |
45 | |
46 | static void IntAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) { |
47 | AbbrevGen(Abbrev, |
48 | Ops: {// 0. Fixed-size integer |
49 | llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed, |
50 | BitCodeConstants::IntSize)}); |
51 | } |
52 | |
53 | static void SymbolIDAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) { |
54 | AbbrevGen(Abbrev, |
55 | Ops: {// 0. Fixed-size integer (length of the sha1'd USR) |
56 | llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed, |
57 | BitCodeConstants::USRLengthSize), |
58 | // 1. Fixed-size array of Char6 (USR) |
59 | llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Array), |
60 | llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed, |
61 | BitCodeConstants::USRBitLengthSize)}); |
62 | } |
63 | |
64 | static void StringAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) { |
65 | AbbrevGen(Abbrev, |
66 | Ops: {// 0. Fixed-size integer (length of the following string) |
67 | llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed, |
68 | BitCodeConstants::StringLengthSize), |
69 | // 1. The string blob |
70 | llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)}); |
71 | } |
72 | |
73 | // Assumes that the file will not have more than 65535 lines. |
74 | static void LocationAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) { |
75 | AbbrevGen( |
76 | Abbrev, |
77 | Ops: {// 0. Fixed-size integer (line number) |
78 | llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed, |
79 | BitCodeConstants::LineNumberSize), |
80 | // 1. Boolean (IsFileInRootDir) |
81 | llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed, |
82 | BitCodeConstants::BoolSize), |
83 | // 2. Fixed-size integer (length of the following string (filename)) |
84 | llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed, |
85 | BitCodeConstants::StringLengthSize), |
86 | // 3. The string blob |
87 | llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)}); |
88 | } |
89 | |
90 | struct RecordIdDsc { |
91 | llvm::StringRef Name; |
92 | AbbrevDsc Abbrev = nullptr; |
93 | |
94 | RecordIdDsc() = default; |
95 | RecordIdDsc(llvm::StringRef Name, AbbrevDsc Abbrev) |
96 | : Name(Name), Abbrev(Abbrev) {} |
97 | |
98 | // Is this 'description' valid? |
99 | operator bool() const { |
100 | return Abbrev != nullptr && Name.data() != nullptr && !Name.empty(); |
101 | } |
102 | }; |
103 | |
104 | static const llvm::IndexedMap<llvm::StringRef, BlockIdToIndexFunctor> |
105 | BlockIdNameMap = []() { |
106 | llvm::IndexedMap<llvm::StringRef, BlockIdToIndexFunctor> BlockIdNameMap; |
107 | BlockIdNameMap.resize(s: BlockIdCount); |
108 | |
109 | // There is no init-list constructor for the IndexedMap, so have to |
110 | // improvise |
111 | static const std::vector<std::pair<BlockId, const char *const>> Inits = { |
112 | {BI_VERSION_BLOCK_ID, "VersionBlock" }, |
113 | {BI_NAMESPACE_BLOCK_ID, "NamespaceBlock" }, |
114 | {BI_ENUM_BLOCK_ID, "EnumBlock" }, |
115 | {BI_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; |
133 | }(); |
134 | |
135 | static const llvm::IndexedMap<RecordIdDsc, RecordIdToIndexFunctor> |
136 | RecordIdNameMap = []() { |
137 | llvm::IndexedMap<RecordIdDsc, RecordIdToIndexFunctor> RecordIdNameMap; |
138 | RecordIdNameMap.resize(s: RecordIdCount); |
139 | |
140 | // There is no init-list constructor for the IndexedMap, so have to |
141 | // improvise |
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); |
206 | } |
207 | assert(RecordIdNameMap.size() == RecordIdCount); |
208 | return RecordIdNameMap; |
209 | }(); |
210 | |
211 | static const std::vector<std::pair<BlockId, std::vector<RecordId>>> |
212 | RecordsByBlock{ |
213 | // Version Block |
214 | {BI_VERSION_BLOCK_ID, {VERSION}}, |
215 | // Comment Block |
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}}, |
220 | // Type Block |
221 | {BI_TYPE_BLOCK_ID, {}}, |
222 | // FieldType Block |
223 | {BI_FIELD_TYPE_BLOCK_ID, {FIELD_TYPE_NAME, FIELD_DEFAULT_VALUE}}, |
224 | // MemberType Block |
225 | {BI_MEMBER_TYPE_BLOCK_ID, {MEMBER_TYPE_NAME, MEMBER_TYPE_ACCESS}}, |
226 | // Enum Block |
227 | {BI_ENUM_BLOCK_ID, |
228 | {ENUM_USR, ENUM_NAME, ENUM_DEFLOCATION, ENUM_LOCATION, ENUM_SCOPED}}, |
229 | // Enum Value Block |
230 | {BI_ENUM_VALUE_BLOCK_ID, |
231 | {ENUM_VALUE_NAME, ENUM_VALUE_VALUE, ENUM_VALUE_EXPR}}, |
232 | // Typedef Block |
233 | {BI_TYPEDEF_BLOCK_ID, |
234 | {TYPEDEF_USR, TYPEDEF_NAME, TYPEDEF_DEFLOCATION, TYPEDEF_IS_USING}}, |
235 | // Namespace Block |
236 | {BI_NAMESPACE_BLOCK_ID, |
237 | {NAMESPACE_USR, NAMESPACE_NAME, NAMESPACE_PATH}}, |
238 | // Record Block |
239 | {BI_RECORD_BLOCK_ID, |
240 | {RECORD_USR, RECORD_NAME, RECORD_PATH, RECORD_DEFLOCATION, |
241 | RECORD_LOCATION, RECORD_TAG_TYPE, RECORD_IS_TYPE_DEF}}, |
242 | // BaseRecord Block |
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}}, |
247 | // Function Block |
248 | {BI_FUNCTION_BLOCK_ID, |
249 | {FUNCTION_USR, FUNCTION_NAME, FUNCTION_DEFLOCATION, FUNCTION_LOCATION, |
250 | FUNCTION_ACCESS, FUNCTION_IS_METHOD}}, |
251 | // Reference Block |
252 | {BI_REFERENCE_BLOCK_ID, |
253 | {REFERENCE_USR, REFERENCE_NAME, REFERENCE_QUAL_NAME, REFERENCE_TYPE, |
254 | REFERENCE_PATH, REFERENCE_FIELD}}, |
255 | // Template Blocks. |
256 | {BI_TEMPLATE_BLOCK_ID, {}}, |
257 | {BI_TEMPLATE_PARAM_BLOCK_ID, {TEMPLATE_PARAM_CONTENTS}}, |
258 | {BI_TEMPLATE_SPECIALIZATION_BLOCK_ID, {TEMPLATE_SPECIALIZATION_OF}}}; |
259 | |
260 | // AbbreviationMap |
261 | |
262 | constexpr unsigned char BitCodeConstants::Signature[]; |
263 | |
264 | void ClangDocBitcodeWriter::AbbreviationMap::add(RecordId RID, |
265 | unsigned AbbrevID) { |
266 | assert(RecordIdNameMap[RID] && "Unknown RecordId." ); |
267 | assert(!Abbrevs.contains(RID) && "Abbreviation already added." ); |
268 | Abbrevs[RID] = AbbrevID; |
269 | } |
270 | |
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(Val: RID); |
275 | } |
276 | |
277 | // Validation and Overview Blocks |
278 | |
279 | /// Emits the magic number header to check that its the right format, |
280 | /// in this case, 'DOCS'. |
281 | void ClangDocBitcodeWriter::() { |
282 | for (char C : BitCodeConstants::Signature) |
283 | Stream.Emit(Val: (unsigned)C, NumBits: BitCodeConstants::SignatureBitSize); |
284 | } |
285 | |
286 | void ClangDocBitcodeWriter::emitVersionBlock() { |
287 | StreamSubBlockGuard Block(Stream, BI_VERSION_BLOCK_ID); |
288 | emitRecord(Value: VersionNumber, ID: VERSION); |
289 | } |
290 | |
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." ); |
295 | |
296 | Record.clear(); |
297 | Record.push_back(Elt: BID); |
298 | Stream.EmitRecord(Code: llvm::bitc::BLOCKINFO_CODE_SETBID, Vals: Record); |
299 | Stream.EmitRecord(Code: llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, |
300 | Vals: ArrayRef<unsigned char>(BlockIdName.bytes_begin(), |
301 | BlockIdName.bytes_end())); |
302 | } |
303 | |
304 | /// Emits a record name to the BLOCKINFO block. |
305 | void ClangDocBitcodeWriter::emitRecordID(RecordId ID) { |
306 | assert(RecordIdNameMap[ID] && "Unknown RecordId." ); |
307 | prepRecordData(ID); |
308 | Record.append(in_start: RecordIdNameMap[ID].Name.begin(), |
309 | in_end: RecordIdNameMap[ID].Name.end()); |
310 | Stream.EmitRecord(Code: llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Vals: Record); |
311 | } |
312 | |
313 | // Abbreviations |
314 | |
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(OpInfo: llvm::BitCodeAbbrevOp(ID)); |
319 | RecordIdNameMap[ID].Abbrev(Abbrev); |
320 | Abbrevs.add(RID: ID, AbbrevID: Stream.EmitBlockInfoAbbrev(BlockID: Block, Abbv: std::move(Abbrev))); |
321 | } |
322 | |
323 | // Records |
324 | |
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, ShouldEmit: Sym != EmptySID)) |
330 | return; |
331 | assert(Sym.size() == 20); |
332 | Record.push_back(Elt: Sym.size()); |
333 | Record.append(in_start: Sym.begin(), in_end: Sym.end()); |
334 | Stream.EmitRecordWithAbbrev(Abbrev: Abbrevs.get(RID: ID), Vals: Record); |
335 | } |
336 | |
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, ShouldEmit: !Str.empty())) |
342 | return; |
343 | assert(Str.size() < (1U << BitCodeConstants::StringLengthSize)); |
344 | Record.push_back(Elt: Str.size()); |
345 | Stream.EmitRecordWithBlob(Abbrev: Abbrevs.get(RID: ID), Vals: Record, Blob: Str); |
346 | } |
347 | |
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, ShouldEmit: true)) |
353 | return; |
354 | // FIXME: Assert that the line number is of the appropriate size. |
355 | Record.push_back(Elt: Loc.LineNumber); |
356 | assert(Loc.Filename.size() < (1U << BitCodeConstants::StringLengthSize)); |
357 | Record.push_back(Elt: Loc.IsFileInRootDir); |
358 | Record.push_back(Elt: Loc.Filename.size()); |
359 | Stream.EmitRecordWithBlob(Abbrev: Abbrevs.get(RID: ID), Vals: Record, Blob: Loc.Filename); |
360 | } |
361 | |
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, ShouldEmit: Val)) |
366 | return; |
367 | Record.push_back(Elt: Val); |
368 | Stream.EmitRecordWithAbbrev(Abbrev: Abbrevs.get(RID: ID), Vals: Record); |
369 | } |
370 | |
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, ShouldEmit: Val)) |
375 | return; |
376 | // FIXME: Assert that the integer is of the appropriate size. |
377 | Record.push_back(Elt: Val); |
378 | Stream.EmitRecordWithAbbrev(Abbrev: Abbrevs.get(RID: ID), Vals: Record); |
379 | } |
380 | |
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, ShouldEmit: Val)) |
385 | return; |
386 | assert(Val < (1U << BitCodeConstants::IntSize)); |
387 | Record.push_back(Elt: Val); |
388 | Stream.EmitRecordWithAbbrev(Abbrev: Abbrevs.get(RID: ID), Vals: Record); |
389 | } |
390 | |
391 | void ClangDocBitcodeWriter::emitRecord(const TemplateInfo &Templ) {} |
392 | |
393 | bool ClangDocBitcodeWriter::prepRecordData(RecordId ID, bool ShouldEmit) { |
394 | assert(RecordIdNameMap[ID] && "Unknown RecordId." ); |
395 | if (!ShouldEmit) |
396 | return false; |
397 | Record.clear(); |
398 | Record.push_back(Elt: ID); |
399 | return true; |
400 | } |
401 | |
402 | // BlockInfo Block |
403 | |
404 | void ClangDocBitcodeWriter::emitBlockInfoBlock() { |
405 | Stream.EnterBlockInfoBlock(); |
406 | for (const auto &Block : RecordsByBlock) { |
407 | assert(Block.second.size() < (1U << BitCodeConstants::SubblockIDSize)); |
408 | emitBlockInfo(BID: Block.first, RIDs: Block.second); |
409 | } |
410 | Stream.ExitBlock(); |
411 | } |
412 | |
413 | void ClangDocBitcodeWriter::emitBlockInfo(BlockId BID, |
414 | const std::vector<RecordId> &RIDs) { |
415 | assert(RIDs.size() < (1U << BitCodeConstants::SubblockIDSize)); |
416 | emitBlockID(BID); |
417 | for (RecordId RID : RIDs) { |
418 | emitRecordID(ID: RID); |
419 | emitAbbrev(ID: RID, Block: BID); |
420 | } |
421 | } |
422 | |
423 | // Block emission |
424 | |
425 | void ClangDocBitcodeWriter::emitBlock(const Reference &R, FieldId Field) { |
426 | if (R.USR == EmptySID && R.Name.empty()) |
427 | return; |
428 | StreamSubBlockGuard Block(Stream, BI_REFERENCE_BLOCK_ID); |
429 | emitRecord(Sym: R.USR, ID: REFERENCE_USR); |
430 | emitRecord(Str: R.Name, ID: REFERENCE_NAME); |
431 | emitRecord(Str: R.QualName, ID: REFERENCE_QUAL_NAME); |
432 | emitRecord(Val: (unsigned)R.RefType, ID: REFERENCE_TYPE); |
433 | emitRecord(Str: R.Path, ID: REFERENCE_PATH); |
434 | emitRecord(Val: (unsigned)Field, ID: REFERENCE_FIELD); |
435 | } |
436 | |
437 | void ClangDocBitcodeWriter::emitBlock(const TypeInfo &T) { |
438 | StreamSubBlockGuard Block(Stream, BI_TYPE_BLOCK_ID); |
439 | emitBlock(R: T.Type, Field: FieldId::F_type); |
440 | } |
441 | |
442 | void ClangDocBitcodeWriter::emitBlock(const TypedefInfo &T) { |
443 | StreamSubBlockGuard Block(Stream, BI_TYPEDEF_BLOCK_ID); |
444 | emitRecord(Sym: T.USR, ID: TYPEDEF_USR); |
445 | emitRecord(Str: T.Name, ID: TYPEDEF_NAME); |
446 | for (const auto &N : T.Namespace) |
447 | emitBlock(R: N, Field: FieldId::F_namespace); |
448 | for (const auto &CI : T.Description) |
449 | emitBlock(B: CI); |
450 | if (T.DefLoc) |
451 | emitRecord(Loc: *T.DefLoc, ID: TYPEDEF_DEFLOCATION); |
452 | emitRecord(Val: T.IsUsing, ID: TYPEDEF_IS_USING); |
453 | emitBlock(T: T.Underlying); |
454 | } |
455 | |
456 | void ClangDocBitcodeWriter::emitBlock(const FieldTypeInfo &T) { |
457 | StreamSubBlockGuard Block(Stream, BI_FIELD_TYPE_BLOCK_ID); |
458 | emitBlock(R: T.Type, Field: FieldId::F_type); |
459 | emitRecord(Str: T.Name, ID: FIELD_TYPE_NAME); |
460 | emitRecord(Str: T.DefaultValue, ID: FIELD_DEFAULT_VALUE); |
461 | } |
462 | |
463 | void ClangDocBitcodeWriter::emitBlock(const MemberTypeInfo &T) { |
464 | StreamSubBlockGuard Block(Stream, BI_MEMBER_TYPE_BLOCK_ID); |
465 | emitBlock(R: T.Type, Field: FieldId::F_type); |
466 | emitRecord(Str: T.Name, ID: MEMBER_TYPE_NAME); |
467 | emitRecord(Val: T.Access, ID: MEMBER_TYPE_ACCESS); |
468 | for (const auto &CI : T.Description) |
469 | emitBlock(B: CI); |
470 | } |
471 | |
472 | void ClangDocBitcodeWriter::(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(Str: L.first, ID: L.second); |
482 | emitRecord(Val: I.SelfClosing, ID: COMMENT_SELFCLOSING); |
483 | emitRecord(Val: I.Explicit, ID: COMMENT_EXPLICIT); |
484 | for (const auto &A : I.AttrKeys) |
485 | emitRecord(Str: A, ID: COMMENT_ATTRKEY); |
486 | for (const auto &A : I.AttrValues) |
487 | emitRecord(Str: A, ID: COMMENT_ATTRVAL); |
488 | for (const auto &A : I.Args) |
489 | emitRecord(Str: A, ID: COMMENT_ARG); |
490 | for (const auto &C : I.Children) |
491 | emitBlock(I: *C); |
492 | } |
493 | |
494 | void ClangDocBitcodeWriter::emitBlock(const NamespaceInfo &I) { |
495 | StreamSubBlockGuard Block(Stream, BI_NAMESPACE_BLOCK_ID); |
496 | emitRecord(Sym: I.USR, ID: NAMESPACE_USR); |
497 | emitRecord(Str: I.Name, ID: NAMESPACE_NAME); |
498 | emitRecord(Str: I.Path, ID: NAMESPACE_PATH); |
499 | for (const auto &N : I.Namespace) |
500 | emitBlock(R: N, Field: FieldId::F_namespace); |
501 | for (const auto &CI : I.Description) |
502 | emitBlock(I: CI); |
503 | for (const auto &C : I.Children.Namespaces) |
504 | emitBlock(R: C, Field: FieldId::F_child_namespace); |
505 | for (const auto &C : I.Children.Records) |
506 | emitBlock(R: C, Field: FieldId::F_child_record); |
507 | for (const auto &C : I.Children.Functions) |
508 | emitBlock(I: C); |
509 | for (const auto &C : I.Children.Enums) |
510 | emitBlock(I: C); |
511 | for (const auto &C : I.Children.Typedefs) |
512 | emitBlock(T: C); |
513 | } |
514 | |
515 | void ClangDocBitcodeWriter::emitBlock(const EnumInfo &I) { |
516 | StreamSubBlockGuard Block(Stream, BI_ENUM_BLOCK_ID); |
517 | emitRecord(Sym: I.USR, ID: ENUM_USR); |
518 | emitRecord(Str: I.Name, ID: ENUM_NAME); |
519 | for (const auto &N : I.Namespace) |
520 | emitBlock(R: N, Field: FieldId::F_namespace); |
521 | for (const auto &CI : I.Description) |
522 | emitBlock(I: CI); |
523 | if (I.DefLoc) |
524 | emitRecord(Loc: *I.DefLoc, ID: ENUM_DEFLOCATION); |
525 | for (const auto &L : I.Loc) |
526 | emitRecord(Loc: L, ID: ENUM_LOCATION); |
527 | emitRecord(Val: I.Scoped, ID: ENUM_SCOPED); |
528 | if (I.BaseType) |
529 | emitBlock(T: *I.BaseType); |
530 | for (const auto &N : I.Members) |
531 | emitBlock(I: N); |
532 | } |
533 | |
534 | void ClangDocBitcodeWriter::emitBlock(const EnumValueInfo &I) { |
535 | StreamSubBlockGuard Block(Stream, BI_ENUM_VALUE_BLOCK_ID); |
536 | emitRecord(Str: I.Name, ID: ENUM_VALUE_NAME); |
537 | emitRecord(Str: I.Value, ID: ENUM_VALUE_VALUE); |
538 | emitRecord(Str: I.ValueExpr, ID: ENUM_VALUE_EXPR); |
539 | } |
540 | |
541 | void ClangDocBitcodeWriter::emitBlock(const RecordInfo &I) { |
542 | StreamSubBlockGuard Block(Stream, BI_RECORD_BLOCK_ID); |
543 | emitRecord(Sym: I.USR, ID: RECORD_USR); |
544 | emitRecord(Str: I.Name, ID: RECORD_NAME); |
545 | emitRecord(Str: I.Path, ID: RECORD_PATH); |
546 | for (const auto &N : I.Namespace) |
547 | emitBlock(R: N, Field: FieldId::F_namespace); |
548 | for (const auto &CI : I.Description) |
549 | emitBlock(I: CI); |
550 | if (I.DefLoc) |
551 | emitRecord(Loc: *I.DefLoc, ID: RECORD_DEFLOCATION); |
552 | for (const auto &L : I.Loc) |
553 | emitRecord(Loc: L, ID: RECORD_LOCATION); |
554 | emitRecord(Val: llvm::to_underlying(E: I.TagType), ID: RECORD_TAG_TYPE); |
555 | emitRecord(Val: I.IsTypeDef, ID: RECORD_IS_TYPE_DEF); |
556 | for (const auto &N : I.Members) |
557 | emitBlock(T: N); |
558 | for (const auto &P : I.Parents) |
559 | emitBlock(R: P, Field: FieldId::F_parent); |
560 | for (const auto &P : I.VirtualParents) |
561 | emitBlock(R: P, Field: FieldId::F_vparent); |
562 | for (const auto &PB : I.Bases) |
563 | emitBlock(I: PB); |
564 | for (const auto &C : I.Children.Records) |
565 | emitBlock(R: C, Field: FieldId::F_child_record); |
566 | for (const auto &C : I.Children.Functions) |
567 | emitBlock(I: C); |
568 | for (const auto &C : I.Children.Enums) |
569 | emitBlock(I: C); |
570 | for (const auto &C : I.Children.Typedefs) |
571 | emitBlock(T: C); |
572 | if (I.Template) |
573 | emitBlock(T: *I.Template); |
574 | } |
575 | |
576 | void ClangDocBitcodeWriter::emitBlock(const BaseRecordInfo &I) { |
577 | StreamSubBlockGuard Block(Stream, BI_BASE_RECORD_BLOCK_ID); |
578 | emitRecord(Sym: I.USR, ID: BASE_RECORD_USR); |
579 | emitRecord(Str: I.Name, ID: BASE_RECORD_NAME); |
580 | emitRecord(Str: I.Path, ID: BASE_RECORD_PATH); |
581 | emitRecord(Val: llvm::to_underlying(E: I.TagType), ID: BASE_RECORD_TAG_TYPE); |
582 | emitRecord(Val: I.IsVirtual, ID: BASE_RECORD_IS_VIRTUAL); |
583 | emitRecord(Val: I.Access, ID: BASE_RECORD_ACCESS); |
584 | emitRecord(Val: I.IsParent, ID: BASE_RECORD_IS_PARENT); |
585 | for (const auto &M : I.Members) |
586 | emitBlock(T: M); |
587 | for (const auto &C : I.Children.Functions) |
588 | emitBlock(I: C); |
589 | } |
590 | |
591 | void ClangDocBitcodeWriter::emitBlock(const FunctionInfo &I) { |
592 | StreamSubBlockGuard Block(Stream, BI_FUNCTION_BLOCK_ID); |
593 | emitRecord(Sym: I.USR, ID: FUNCTION_USR); |
594 | emitRecord(Str: I.Name, ID: FUNCTION_NAME); |
595 | for (const auto &N : I.Namespace) |
596 | emitBlock(R: N, Field: FieldId::F_namespace); |
597 | for (const auto &CI : I.Description) |
598 | emitBlock(I: CI); |
599 | emitRecord(Val: I.Access, ID: FUNCTION_ACCESS); |
600 | emitRecord(Val: I.IsMethod, ID: FUNCTION_IS_METHOD); |
601 | if (I.DefLoc) |
602 | emitRecord(Loc: *I.DefLoc, ID: FUNCTION_DEFLOCATION); |
603 | for (const auto &L : I.Loc) |
604 | emitRecord(Loc: L, ID: FUNCTION_LOCATION); |
605 | emitBlock(R: I.Parent, Field: FieldId::F_parent); |
606 | emitBlock(T: I.ReturnType); |
607 | for (const auto &N : I.Params) |
608 | emitBlock(T: N); |
609 | if (I.Template) |
610 | emitBlock(T: *I.Template); |
611 | } |
612 | |
613 | void ClangDocBitcodeWriter::emitBlock(const TemplateInfo &T) { |
614 | StreamSubBlockGuard Block(Stream, BI_TEMPLATE_BLOCK_ID); |
615 | for (const auto &P : T.Params) |
616 | emitBlock(T: P); |
617 | if (T.Specialization) |
618 | emitBlock(T: *T.Specialization); |
619 | } |
620 | |
621 | void ClangDocBitcodeWriter::emitBlock(const TemplateSpecializationInfo &T) { |
622 | StreamSubBlockGuard Block(Stream, BI_TEMPLATE_SPECIALIZATION_BLOCK_ID); |
623 | emitRecord(Sym: T.SpecializationOf, ID: TEMPLATE_SPECIALIZATION_OF); |
624 | for (const auto &P : T.Params) |
625 | emitBlock(T: P); |
626 | } |
627 | |
628 | void ClangDocBitcodeWriter::emitBlock(const TemplateParamInfo &T) { |
629 | StreamSubBlockGuard Block(Stream, BI_TEMPLATE_PARAM_BLOCK_ID); |
630 | emitRecord(Str: T.Contents, ID: TEMPLATE_PARAM_CONTENTS); |
631 | } |
632 | |
633 | bool ClangDocBitcodeWriter::dispatchInfoForWrite(Info *I) { |
634 | switch (I->IT) { |
635 | case InfoType::IT_namespace: |
636 | emitBlock(I: *static_cast<clang::doc::NamespaceInfo *>(I)); |
637 | break; |
638 | case InfoType::IT_record: |
639 | emitBlock(I: *static_cast<clang::doc::RecordInfo *>(I)); |
640 | break; |
641 | case InfoType::IT_enum: |
642 | emitBlock(I: *static_cast<clang::doc::EnumInfo *>(I)); |
643 | break; |
644 | case InfoType::IT_function: |
645 | emitBlock(I: *static_cast<clang::doc::FunctionInfo *>(I)); |
646 | break; |
647 | case InfoType::IT_typedef: |
648 | emitBlock(T: *static_cast<clang::doc::TypedefInfo *>(I)); |
649 | break; |
650 | default: |
651 | llvm::errs() << "Unexpected info, unable to write.\n" ; |
652 | return true; |
653 | } |
654 | return false; |
655 | } |
656 | |
657 | } // namespace doc |
658 | } // namespace clang |
659 | |