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