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