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