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(Op); 37 } 38 39 static void BoolAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) { 40 AbbrevGen(Abbrev, 41 {// 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 {// 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 {// 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 {// 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 {// 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(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(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(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::emitHeader() { 282 for (char C : BitCodeConstants::Signature) 283 Stream.Emit((unsigned)C, BitCodeConstants::SignatureBitSize); 284 } 285 286 void ClangDocBitcodeWriter::emitVersionBlock() { 287 StreamSubBlockGuard Block(Stream, BI_VERSION_BLOCK_ID); 288 emitRecord(VersionNumber, 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(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())); 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(RecordIdNameMap[ID].Name.begin(), 309 RecordIdNameMap[ID].Name.end()); 310 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, 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(llvm::BitCodeAbbrevOp(ID)); 319 RecordIdNameMap[ID].Abbrev(Abbrev); 320 Abbrevs.add(ID, Stream.EmitBlockInfoAbbrev(Block, 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, Sym != EmptySID)) 330 return; 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); 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, !Str.empty())) 342 return; 343 assert(Str.size() < (1U << BitCodeConstants::StringLengthSize)); 344 Record.push_back(Str.size()); 345 Stream.EmitRecordWithBlob(Abbrevs.get(ID), Record, 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, true)) 353 return; 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); 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, Val)) 366 return; 367 Record.push_back(Val); 368 Stream.EmitRecordWithAbbrev(Abbrevs.get(ID), 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, Val)) 375 return; 376 // FIXME: Assert that the integer is of the appropriate size. 377 Record.push_back(Val); 378 Stream.EmitRecordWithAbbrev(Abbrevs.get(ID), 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, Val)) 385 return; 386 assert(Val < (1U << BitCodeConstants::IntSize)); 387 Record.push_back(Val); 388 Stream.EmitRecordWithAbbrev(Abbrevs.get(ID), 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(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(Block.first, 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(RID); 419 emitAbbrev(RID, 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(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); 435 } 436 437 void ClangDocBitcodeWriter::emitBlock(const TypeInfo &T) { 438 StreamSubBlockGuard Block(Stream, BI_TYPE_BLOCK_ID); 439 emitBlock(T.Type, FieldId::F_type); 440 } 441 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) 449 emitBlock(CI); 450 if (T.DefLoc) 451 emitRecord(*T.DefLoc, TYPEDEF_DEFLOCATION); 452 emitRecord(T.IsUsing, TYPEDEF_IS_USING); 453 emitBlock(T.Underlying); 454 } 455 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); 461 } 462 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) 469 emitBlock(CI); 470 } 471 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) 491 emitBlock(*C); 492 } 493 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) 502 emitBlock(CI); 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) 508 emitBlock(C); 509 for (const auto &C : I.Children.Enums) 510 emitBlock(C); 511 for (const auto &C : I.Children.Typedefs) 512 emitBlock(C); 513 } 514 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) 522 emitBlock(CI); 523 if (I.DefLoc) 524 emitRecord(*I.DefLoc, ENUM_DEFLOCATION); 525 for (const auto &L : I.Loc) 526 emitRecord(L, ENUM_LOCATION); 527 emitRecord(I.Scoped, ENUM_SCOPED); 528 if (I.BaseType) 529 emitBlock(*I.BaseType); 530 for (const auto &N : I.Members) 531 emitBlock(N); 532 } 533 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); 539 for (const auto &CI : I.Description) 540 emitBlock(CI); 541 } 542 543 void ClangDocBitcodeWriter::emitBlock(const RecordInfo &I) { 544 StreamSubBlockGuard Block(Stream, BI_RECORD_BLOCK_ID); 545 emitRecord(I.USR, RECORD_USR); 546 emitRecord(I.Name, RECORD_NAME); 547 emitRecord(I.Path, RECORD_PATH); 548 for (const auto &N : I.Namespace) 549 emitBlock(N, FieldId::F_namespace); 550 for (const auto &CI : I.Description) 551 emitBlock(CI); 552 if (I.DefLoc) 553 emitRecord(*I.DefLoc, RECORD_DEFLOCATION); 554 for (const auto &L : I.Loc) 555 emitRecord(L, RECORD_LOCATION); 556 emitRecord(llvm::to_underlying(I.TagType), RECORD_TAG_TYPE); 557 emitRecord(I.IsTypeDef, RECORD_IS_TYPE_DEF); 558 for (const auto &N : I.Members) 559 emitBlock(N); 560 for (const auto &P : I.Parents) 561 emitBlock(P, FieldId::F_parent); 562 for (const auto &P : I.VirtualParents) 563 emitBlock(P, FieldId::F_vparent); 564 for (const auto &PB : I.Bases) 565 emitBlock(PB); 566 for (const auto &C : I.Children.Records) 567 emitBlock(C, FieldId::F_child_record); 568 for (const auto &C : I.Children.Functions) 569 emitBlock(C); 570 for (const auto &C : I.Children.Enums) 571 emitBlock(C); 572 for (const auto &C : I.Children.Typedefs) 573 emitBlock(C); 574 if (I.Template) 575 emitBlock(*I.Template); 576 } 577 578 void ClangDocBitcodeWriter::emitBlock(const BaseRecordInfo &I) { 579 StreamSubBlockGuard Block(Stream, BI_BASE_RECORD_BLOCK_ID); 580 emitRecord(I.USR, BASE_RECORD_USR); 581 emitRecord(I.Name, BASE_RECORD_NAME); 582 emitRecord(I.Path, BASE_RECORD_PATH); 583 emitRecord(llvm::to_underlying(I.TagType), BASE_RECORD_TAG_TYPE); 584 emitRecord(I.IsVirtual, BASE_RECORD_IS_VIRTUAL); 585 emitRecord(I.Access, BASE_RECORD_ACCESS); 586 emitRecord(I.IsParent, BASE_RECORD_IS_PARENT); 587 for (const auto &M : I.Members) 588 emitBlock(M); 589 for (const auto &C : I.Children.Functions) 590 emitBlock(C); 591 } 592 593 void ClangDocBitcodeWriter::emitBlock(const FunctionInfo &I) { 594 StreamSubBlockGuard Block(Stream, BI_FUNCTION_BLOCK_ID); 595 emitRecord(I.USR, FUNCTION_USR); 596 emitRecord(I.Name, FUNCTION_NAME); 597 for (const auto &N : I.Namespace) 598 emitBlock(N, FieldId::F_namespace); 599 for (const auto &CI : I.Description) 600 emitBlock(CI); 601 emitRecord(I.Access, FUNCTION_ACCESS); 602 emitRecord(I.IsMethod, FUNCTION_IS_METHOD); 603 if (I.DefLoc) 604 emitRecord(*I.DefLoc, FUNCTION_DEFLOCATION); 605 for (const auto &L : I.Loc) 606 emitRecord(L, FUNCTION_LOCATION); 607 emitBlock(I.Parent, FieldId::F_parent); 608 emitBlock(I.ReturnType); 609 for (const auto &N : I.Params) 610 emitBlock(N); 611 if (I.Template) 612 emitBlock(*I.Template); 613 } 614 615 void ClangDocBitcodeWriter::emitBlock(const TemplateInfo &T) { 616 StreamSubBlockGuard Block(Stream, BI_TEMPLATE_BLOCK_ID); 617 for (const auto &P : T.Params) 618 emitBlock(P); 619 if (T.Specialization) 620 emitBlock(*T.Specialization); 621 } 622 623 void ClangDocBitcodeWriter::emitBlock(const TemplateSpecializationInfo &T) { 624 StreamSubBlockGuard Block(Stream, BI_TEMPLATE_SPECIALIZATION_BLOCK_ID); 625 emitRecord(T.SpecializationOf, TEMPLATE_SPECIALIZATION_OF); 626 for (const auto &P : T.Params) 627 emitBlock(P); 628 } 629 630 void ClangDocBitcodeWriter::emitBlock(const TemplateParamInfo &T) { 631 StreamSubBlockGuard Block(Stream, BI_TEMPLATE_PARAM_BLOCK_ID); 632 emitRecord(T.Contents, TEMPLATE_PARAM_CONTENTS); 633 } 634 635 bool ClangDocBitcodeWriter::dispatchInfoForWrite(Info *I) { 636 switch (I->IT) { 637 case InfoType::IT_namespace: 638 emitBlock(*static_cast<clang::doc::NamespaceInfo *>(I)); 639 break; 640 case InfoType::IT_record: 641 emitBlock(*static_cast<clang::doc::RecordInfo *>(I)); 642 break; 643 case InfoType::IT_enum: 644 emitBlock(*static_cast<clang::doc::EnumInfo *>(I)); 645 break; 646 case InfoType::IT_function: 647 emitBlock(*static_cast<clang::doc::FunctionInfo *>(I)); 648 break; 649 case InfoType::IT_typedef: 650 emitBlock(*static_cast<clang::doc::TypedefInfo *>(I)); 651 break; 652 default: 653 llvm::errs() << "Unexpected info, unable to write.\n"; 654 return true; 655 } 656 return false; 657 } 658 659 } // namespace doc 660 } // namespace clang 661