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