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. Fixed-size integer (length of the following string (filename)) 81 llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed, 82 BitCodeConstants::StringLengthSize), 83 // 2. The string blob 84 llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)}); 85 } 86 87 struct RecordIdDsc { 88 llvm::StringRef Name; 89 AbbrevDsc Abbrev = nullptr; 90 91 RecordIdDsc() = default; 92 RecordIdDsc(llvm::StringRef Name, AbbrevDsc Abbrev) 93 : Name(Name), Abbrev(Abbrev) {} 94 95 // Is this 'description' valid? 96 operator bool() const { 97 return Abbrev != nullptr && Name.data() != nullptr && !Name.empty(); 98 } 99 }; 100 101 static const llvm::IndexedMap<llvm::StringRef, BlockIdToIndexFunctor> 102 BlockIdNameMap = []() { 103 llvm::IndexedMap<llvm::StringRef, BlockIdToIndexFunctor> BlockIdNameMap; 104 BlockIdNameMap.resize(BlockIdCount); 105 106 // There is no init-list constructor for the IndexedMap, so have to 107 // improvise 108 static const std::vector<std::pair<BlockId, const char *const>> Inits = { 109 {BI_VERSION_BLOCK_ID, "VersionBlock"}, 110 {BI_NAMESPACE_BLOCK_ID, "NamespaceBlock"}, 111 {BI_ENUM_BLOCK_ID, "EnumBlock"}, 112 {BI_TYPE_BLOCK_ID, "TypeBlock"}, 113 {BI_FIELD_TYPE_BLOCK_ID, "FieldTypeBlock"}, 114 {BI_MEMBER_TYPE_BLOCK_ID, "MemberTypeBlock"}, 115 {BI_RECORD_BLOCK_ID, "RecordBlock"}, 116 {BI_FUNCTION_BLOCK_ID, "FunctionBlock"}, 117 {BI_COMMENT_BLOCK_ID, "CommentBlock"}, 118 {BI_REFERENCE_BLOCK_ID, "ReferenceBlock"}}; 119 assert(Inits.size() == BlockIdCount); 120 for (const auto &Init : Inits) 121 BlockIdNameMap[Init.first] = Init.second; 122 assert(BlockIdNameMap.size() == BlockIdCount); 123 return BlockIdNameMap; 124 }(); 125 126 static const llvm::IndexedMap<RecordIdDsc, RecordIdToIndexFunctor> 127 RecordIdNameMap = []() { 128 llvm::IndexedMap<RecordIdDsc, RecordIdToIndexFunctor> RecordIdNameMap; 129 RecordIdNameMap.resize(RecordIdCount); 130 131 // There is no init-list constructor for the IndexedMap, so have to 132 // improvise 133 static const std::vector<std::pair<RecordId, RecordIdDsc>> Inits = { 134 {VERSION, {"Version", &IntAbbrev}}, 135 {COMMENT_KIND, {"Kind", &StringAbbrev}}, 136 {COMMENT_TEXT, {"Text", &StringAbbrev}}, 137 {COMMENT_NAME, {"Name", &StringAbbrev}}, 138 {COMMENT_DIRECTION, {"Direction", &StringAbbrev}}, 139 {COMMENT_PARAMNAME, {"ParamName", &StringAbbrev}}, 140 {COMMENT_CLOSENAME, {"CloseName", &StringAbbrev}}, 141 {COMMENT_SELFCLOSING, {"SelfClosing", &BoolAbbrev}}, 142 {COMMENT_EXPLICIT, {"Explicit", &BoolAbbrev}}, 143 {COMMENT_ATTRKEY, {"AttrKey", &StringAbbrev}}, 144 {COMMENT_ATTRVAL, {"AttrVal", &StringAbbrev}}, 145 {COMMENT_ARG, {"Arg", &StringAbbrev}}, 146 {FIELD_TYPE_NAME, {"Name", &StringAbbrev}}, 147 {MEMBER_TYPE_NAME, {"Name", &StringAbbrev}}, 148 {MEMBER_TYPE_ACCESS, {"Access", &IntAbbrev}}, 149 {NAMESPACE_USR, {"USR", &SymbolIDAbbrev}}, 150 {NAMESPACE_NAME, {"Name", &StringAbbrev}}, 151 {ENUM_USR, {"USR", &SymbolIDAbbrev}}, 152 {ENUM_NAME, {"Name", &StringAbbrev}}, 153 {ENUM_DEFLOCATION, {"DefLocation", &LocationAbbrev}}, 154 {ENUM_LOCATION, {"Location", &LocationAbbrev}}, 155 {ENUM_MEMBER, {"Member", &StringAbbrev}}, 156 {ENUM_SCOPED, {"Scoped", &BoolAbbrev}}, 157 {RECORD_USR, {"USR", &SymbolIDAbbrev}}, 158 {RECORD_NAME, {"Name", &StringAbbrev}}, 159 {RECORD_DEFLOCATION, {"DefLocation", &LocationAbbrev}}, 160 {RECORD_LOCATION, {"Location", &LocationAbbrev}}, 161 {RECORD_TAG_TYPE, {"TagType", &IntAbbrev}}, 162 {FUNCTION_USR, {"USR", &SymbolIDAbbrev}}, 163 {FUNCTION_NAME, {"Name", &StringAbbrev}}, 164 {FUNCTION_DEFLOCATION, {"DefLocation", &LocationAbbrev}}, 165 {FUNCTION_LOCATION, {"Location", &LocationAbbrev}}, 166 {FUNCTION_ACCESS, {"Access", &IntAbbrev}}, 167 {FUNCTION_IS_METHOD, {"IsMethod", &BoolAbbrev}}, 168 {REFERENCE_USR, {"USR", &SymbolIDAbbrev}}, 169 {REFERENCE_NAME, {"Name", &StringAbbrev}}, 170 {REFERENCE_TYPE, {"RefType", &IntAbbrev}}, 171 {REFERENCE_FIELD, {"Field", &IntAbbrev}}}; 172 assert(Inits.size() == RecordIdCount); 173 for (const auto &Init : Inits) { 174 RecordIdNameMap[Init.first] = Init.second; 175 assert((Init.second.Name.size() + 1) <= BitCodeConstants::RecordSize); 176 } 177 assert(RecordIdNameMap.size() == RecordIdCount); 178 return RecordIdNameMap; 179 }(); 180 181 static const std::vector<std::pair<BlockId, std::vector<RecordId>>> 182 RecordsByBlock{ 183 // Version Block 184 {BI_VERSION_BLOCK_ID, {VERSION}}, 185 // Comment Block 186 {BI_COMMENT_BLOCK_ID, 187 {COMMENT_KIND, COMMENT_TEXT, COMMENT_NAME, COMMENT_DIRECTION, 188 COMMENT_PARAMNAME, COMMENT_CLOSENAME, COMMENT_SELFCLOSING, 189 COMMENT_EXPLICIT, COMMENT_ATTRKEY, COMMENT_ATTRVAL, COMMENT_ARG}}, 190 // Type Block 191 {BI_TYPE_BLOCK_ID, {}}, 192 // FieldType Block 193 {BI_FIELD_TYPE_BLOCK_ID, {FIELD_TYPE_NAME}}, 194 // MemberType Block 195 {BI_MEMBER_TYPE_BLOCK_ID, {MEMBER_TYPE_NAME, MEMBER_TYPE_ACCESS}}, 196 // Enum Block 197 {BI_ENUM_BLOCK_ID, 198 {ENUM_USR, ENUM_NAME, ENUM_DEFLOCATION, ENUM_LOCATION, ENUM_MEMBER, 199 ENUM_SCOPED}}, 200 // Namespace Block 201 {BI_NAMESPACE_BLOCK_ID, {NAMESPACE_USR, NAMESPACE_NAME}}, 202 // Record Block 203 {BI_RECORD_BLOCK_ID, 204 {RECORD_USR, RECORD_NAME, RECORD_DEFLOCATION, RECORD_LOCATION, 205 RECORD_TAG_TYPE}}, 206 // Function Block 207 {BI_FUNCTION_BLOCK_ID, 208 {FUNCTION_USR, FUNCTION_NAME, FUNCTION_DEFLOCATION, FUNCTION_LOCATION, 209 FUNCTION_ACCESS, FUNCTION_IS_METHOD}}, 210 // Reference Block 211 {BI_REFERENCE_BLOCK_ID, 212 {REFERENCE_USR, REFERENCE_NAME, REFERENCE_TYPE, REFERENCE_FIELD}}}; 213 214 // AbbreviationMap 215 216 constexpr char BitCodeConstants::Signature[]; 217 218 void ClangDocBitcodeWriter::AbbreviationMap::add(RecordId RID, 219 unsigned AbbrevID) { 220 assert(RecordIdNameMap[RID] && "Unknown RecordId."); 221 assert(Abbrevs.find(RID) == Abbrevs.end() && "Abbreviation already added."); 222 Abbrevs[RID] = AbbrevID; 223 } 224 225 unsigned ClangDocBitcodeWriter::AbbreviationMap::get(RecordId RID) const { 226 assert(RecordIdNameMap[RID] && "Unknown RecordId."); 227 assert(Abbrevs.find(RID) != Abbrevs.end() && "Unknown abbreviation."); 228 return Abbrevs.lookup(RID); 229 } 230 231 // Validation and Overview Blocks 232 233 /// \brief Emits the magic number header to check that its the right format, 234 /// in this case, 'DOCS'. 235 void ClangDocBitcodeWriter::emitHeader() { 236 for (char C : BitCodeConstants::Signature) 237 Stream.Emit((unsigned)C, BitCodeConstants::SignatureBitSize); 238 } 239 240 void ClangDocBitcodeWriter::emitVersionBlock() { 241 StreamSubBlockGuard Block(Stream, BI_VERSION_BLOCK_ID); 242 emitRecord(VersionNumber, VERSION); 243 } 244 245 /// \brief Emits a block ID and the block name to the BLOCKINFO block. 246 void ClangDocBitcodeWriter::emitBlockID(BlockId BID) { 247 const auto &BlockIdName = BlockIdNameMap[BID]; 248 assert(BlockIdName.data() && BlockIdName.size() && "Unknown BlockId."); 249 250 Record.clear(); 251 Record.push_back(BID); 252 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record); 253 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, 254 ArrayRef<unsigned char>(BlockIdName.bytes_begin(), 255 BlockIdName.bytes_end())); 256 } 257 258 /// \brief Emits a record name to the BLOCKINFO block. 259 void ClangDocBitcodeWriter::emitRecordID(RecordId ID) { 260 assert(RecordIdNameMap[ID] && "Unknown RecordId."); 261 prepRecordData(ID); 262 Record.append(RecordIdNameMap[ID].Name.begin(), 263 RecordIdNameMap[ID].Name.end()); 264 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record); 265 } 266 267 // Abbreviations 268 269 void ClangDocBitcodeWriter::emitAbbrev(RecordId ID, BlockId Block) { 270 assert(RecordIdNameMap[ID] && "Unknown abbreviation."); 271 auto Abbrev = std::make_shared<llvm::BitCodeAbbrev>(); 272 Abbrev->Add(llvm::BitCodeAbbrevOp(ID)); 273 RecordIdNameMap[ID].Abbrev(Abbrev); 274 Abbrevs.add(ID, Stream.EmitBlockInfoAbbrev(Block, std::move(Abbrev))); 275 } 276 277 // Records 278 279 void ClangDocBitcodeWriter::emitRecord(const SymbolID &Sym, RecordId ID) { 280 assert(RecordIdNameMap[ID] && "Unknown RecordId."); 281 assert(RecordIdNameMap[ID].Abbrev == &SymbolIDAbbrev && 282 "Abbrev type mismatch."); 283 if (!prepRecordData(ID, Sym != EmptySID)) 284 return; 285 assert(Sym.size() == 20); 286 Record.push_back(Sym.size()); 287 Record.append(Sym.begin(), Sym.end()); 288 Stream.EmitRecordWithAbbrev(Abbrevs.get(ID), Record); 289 } 290 291 void ClangDocBitcodeWriter::emitRecord(llvm::StringRef Str, RecordId ID) { 292 assert(RecordIdNameMap[ID] && "Unknown RecordId."); 293 assert(RecordIdNameMap[ID].Abbrev == &StringAbbrev && 294 "Abbrev type mismatch."); 295 if (!prepRecordData(ID, !Str.empty())) 296 return; 297 assert(Str.size() < (1U << BitCodeConstants::StringLengthSize)); 298 Record.push_back(Str.size()); 299 Stream.EmitRecordWithBlob(Abbrevs.get(ID), Record, Str); 300 } 301 302 void ClangDocBitcodeWriter::emitRecord(const Location &Loc, RecordId ID) { 303 assert(RecordIdNameMap[ID] && "Unknown RecordId."); 304 assert(RecordIdNameMap[ID].Abbrev == &LocationAbbrev && 305 "Abbrev type mismatch."); 306 if (!prepRecordData(ID, true)) 307 return; 308 // FIXME: Assert that the line number is of the appropriate size. 309 Record.push_back(Loc.LineNumber); 310 assert(Loc.Filename.size() < (1U << BitCodeConstants::StringLengthSize)); 311 Record.push_back(Loc.Filename.size()); 312 Stream.EmitRecordWithBlob(Abbrevs.get(ID), Record, Loc.Filename); 313 } 314 315 void ClangDocBitcodeWriter::emitRecord(bool Val, RecordId ID) { 316 assert(RecordIdNameMap[ID] && "Unknown RecordId."); 317 assert(RecordIdNameMap[ID].Abbrev == &BoolAbbrev && "Abbrev type mismatch."); 318 if (!prepRecordData(ID, Val)) 319 return; 320 Record.push_back(Val); 321 Stream.EmitRecordWithAbbrev(Abbrevs.get(ID), Record); 322 } 323 324 void ClangDocBitcodeWriter::emitRecord(int Val, RecordId ID) { 325 assert(RecordIdNameMap[ID] && "Unknown RecordId."); 326 assert(RecordIdNameMap[ID].Abbrev == &IntAbbrev && "Abbrev type mismatch."); 327 if (!prepRecordData(ID, Val)) 328 return; 329 // FIXME: Assert that the integer is of the appropriate size. 330 Record.push_back(Val); 331 Stream.EmitRecordWithAbbrev(Abbrevs.get(ID), Record); 332 } 333 334 void ClangDocBitcodeWriter::emitRecord(unsigned Val, RecordId ID) { 335 assert(RecordIdNameMap[ID] && "Unknown RecordId."); 336 assert(RecordIdNameMap[ID].Abbrev == &IntAbbrev && "Abbrev type mismatch."); 337 if (!prepRecordData(ID, Val)) 338 return; 339 assert(Val < (1U << BitCodeConstants::IntSize)); 340 Record.push_back(Val); 341 Stream.EmitRecordWithAbbrev(Abbrevs.get(ID), Record); 342 } 343 344 bool ClangDocBitcodeWriter::prepRecordData(RecordId ID, bool ShouldEmit) { 345 assert(RecordIdNameMap[ID] && "Unknown RecordId."); 346 if (!ShouldEmit) 347 return false; 348 Record.clear(); 349 Record.push_back(ID); 350 return true; 351 } 352 353 // BlockInfo Block 354 355 void ClangDocBitcodeWriter::emitBlockInfoBlock() { 356 Stream.EnterBlockInfoBlock(); 357 for (const auto &Block : RecordsByBlock) { 358 assert(Block.second.size() < (1U << BitCodeConstants::SubblockIDSize)); 359 emitBlockInfo(Block.first, Block.second); 360 } 361 Stream.ExitBlock(); 362 } 363 364 void ClangDocBitcodeWriter::emitBlockInfo(BlockId BID, 365 const std::vector<RecordId> &RIDs) { 366 assert(RIDs.size() < (1U << BitCodeConstants::SubblockIDSize)); 367 emitBlockID(BID); 368 for (RecordId RID : RIDs) { 369 emitRecordID(RID); 370 emitAbbrev(RID, BID); 371 } 372 } 373 374 // Block emission 375 376 void ClangDocBitcodeWriter::emitBlock(const Reference &R, FieldId Field) { 377 if (R.USR == EmptySID && R.Name.empty()) 378 return; 379 StreamSubBlockGuard Block(Stream, BI_REFERENCE_BLOCK_ID); 380 emitRecord(R.USR, REFERENCE_USR); 381 emitRecord(R.Name, REFERENCE_NAME); 382 emitRecord((unsigned)R.RefType, REFERENCE_TYPE); 383 emitRecord((unsigned)Field, REFERENCE_FIELD); 384 } 385 386 void ClangDocBitcodeWriter::emitBlock(const TypeInfo &T) { 387 StreamSubBlockGuard Block(Stream, BI_TYPE_BLOCK_ID); 388 emitBlock(T.Type, FieldId::F_type); 389 } 390 391 void ClangDocBitcodeWriter::emitBlock(const FieldTypeInfo &T) { 392 StreamSubBlockGuard Block(Stream, BI_FIELD_TYPE_BLOCK_ID); 393 emitBlock(T.Type, FieldId::F_type); 394 emitRecord(T.Name, FIELD_TYPE_NAME); 395 } 396 397 void ClangDocBitcodeWriter::emitBlock(const MemberTypeInfo &T) { 398 StreamSubBlockGuard Block(Stream, BI_MEMBER_TYPE_BLOCK_ID); 399 emitBlock(T.Type, FieldId::F_type); 400 emitRecord(T.Name, MEMBER_TYPE_NAME); 401 emitRecord(T.Access, MEMBER_TYPE_ACCESS); 402 } 403 404 void ClangDocBitcodeWriter::emitBlock(const CommentInfo &I) { 405 StreamSubBlockGuard Block(Stream, BI_COMMENT_BLOCK_ID); 406 for (const auto &L : std::vector<std::pair<llvm::StringRef, RecordId>>{ 407 {I.Kind, COMMENT_KIND}, 408 {I.Text, COMMENT_TEXT}, 409 {I.Name, COMMENT_NAME}, 410 {I.Direction, COMMENT_DIRECTION}, 411 {I.ParamName, COMMENT_PARAMNAME}, 412 {I.CloseName, COMMENT_CLOSENAME}}) 413 emitRecord(L.first, L.second); 414 emitRecord(I.SelfClosing, COMMENT_SELFCLOSING); 415 emitRecord(I.Explicit, COMMENT_EXPLICIT); 416 for (const auto &A : I.AttrKeys) 417 emitRecord(A, COMMENT_ATTRKEY); 418 for (const auto &A : I.AttrValues) 419 emitRecord(A, COMMENT_ATTRVAL); 420 for (const auto &A : I.Args) 421 emitRecord(A, COMMENT_ARG); 422 for (const auto &C : I.Children) 423 emitBlock(*C); 424 } 425 426 void ClangDocBitcodeWriter::emitBlock(const NamespaceInfo &I) { 427 StreamSubBlockGuard Block(Stream, BI_NAMESPACE_BLOCK_ID); 428 emitRecord(I.USR, NAMESPACE_USR); 429 emitRecord(I.Name, NAMESPACE_NAME); 430 for (const auto &N : I.Namespace) 431 emitBlock(N, FieldId::F_namespace); 432 for (const auto &CI : I.Description) 433 emitBlock(CI); 434 for (const auto &C : I.ChildNamespaces) 435 emitBlock(C, FieldId::F_child_namespace); 436 for (const auto &C : I.ChildRecords) 437 emitBlock(C, FieldId::F_child_record); 438 for (const auto &C : I.ChildFunctions) 439 emitBlock(C); 440 for (const auto &C : I.ChildEnums) 441 emitBlock(C); 442 } 443 444 void ClangDocBitcodeWriter::emitBlock(const EnumInfo &I) { 445 StreamSubBlockGuard Block(Stream, BI_ENUM_BLOCK_ID); 446 emitRecord(I.USR, ENUM_USR); 447 emitRecord(I.Name, ENUM_NAME); 448 for (const auto &N : I.Namespace) 449 emitBlock(N, FieldId::F_namespace); 450 for (const auto &CI : I.Description) 451 emitBlock(CI); 452 if (I.DefLoc) 453 emitRecord(I.DefLoc.getValue(), ENUM_DEFLOCATION); 454 for (const auto &L : I.Loc) 455 emitRecord(L, ENUM_LOCATION); 456 emitRecord(I.Scoped, ENUM_SCOPED); 457 for (const auto &N : I.Members) 458 emitRecord(N, ENUM_MEMBER); 459 } 460 461 void ClangDocBitcodeWriter::emitBlock(const RecordInfo &I) { 462 StreamSubBlockGuard Block(Stream, BI_RECORD_BLOCK_ID); 463 emitRecord(I.USR, RECORD_USR); 464 emitRecord(I.Name, RECORD_NAME); 465 for (const auto &N : I.Namespace) 466 emitBlock(N, FieldId::F_namespace); 467 for (const auto &CI : I.Description) 468 emitBlock(CI); 469 if (I.DefLoc) 470 emitRecord(I.DefLoc.getValue(), RECORD_DEFLOCATION); 471 for (const auto &L : I.Loc) 472 emitRecord(L, RECORD_LOCATION); 473 emitRecord(I.TagType, RECORD_TAG_TYPE); 474 for (const auto &N : I.Members) 475 emitBlock(N); 476 for (const auto &P : I.Parents) 477 emitBlock(P, FieldId::F_parent); 478 for (const auto &P : I.VirtualParents) 479 emitBlock(P, FieldId::F_vparent); 480 for (const auto &C : I.ChildRecords) 481 emitBlock(C, FieldId::F_child_record); 482 for (const auto &C : I.ChildFunctions) 483 emitBlock(C); 484 for (const auto &C : I.ChildEnums) 485 emitBlock(C); 486 } 487 488 void ClangDocBitcodeWriter::emitBlock(const FunctionInfo &I) { 489 StreamSubBlockGuard Block(Stream, BI_FUNCTION_BLOCK_ID); 490 emitRecord(I.USR, FUNCTION_USR); 491 emitRecord(I.Name, FUNCTION_NAME); 492 for (const auto &N : I.Namespace) 493 emitBlock(N, FieldId::F_namespace); 494 for (const auto &CI : I.Description) 495 emitBlock(CI); 496 emitRecord(I.IsMethod, FUNCTION_IS_METHOD); 497 if (I.DefLoc) 498 emitRecord(I.DefLoc.getValue(), FUNCTION_DEFLOCATION); 499 for (const auto &L : I.Loc) 500 emitRecord(L, FUNCTION_LOCATION); 501 emitBlock(I.Parent, FieldId::F_parent); 502 emitBlock(I.ReturnType); 503 for (const auto &N : I.Params) 504 emitBlock(N); 505 } 506 507 bool ClangDocBitcodeWriter::dispatchInfoForWrite(Info *I) { 508 switch (I->IT) { 509 case InfoType::IT_namespace: 510 emitBlock(*static_cast<clang::doc::NamespaceInfo *>(I)); 511 break; 512 case InfoType::IT_record: 513 emitBlock(*static_cast<clang::doc::RecordInfo *>(I)); 514 break; 515 case InfoType::IT_enum: 516 emitBlock(*static_cast<clang::doc::EnumInfo *>(I)); 517 break; 518 case InfoType::IT_function: 519 emitBlock(*static_cast<clang::doc::FunctionInfo *>(I)); 520 break; 521 default: 522 llvm::errs() << "Unexpected info, unable to write.\n"; 523 return true; 524 } 525 return false; 526 } 527 528 } // namespace doc 529 } // namespace clang 530