780 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "BitcodeWriter.h"10#include "llvm/ADT/IndexedMap.h"11#include <initializer_list>12 13namespace clang {14namespace doc {15 16// Empty SymbolID for comparison, so we don't have to construct one every time.17static const SymbolID EmptySID = SymbolID();18 19// Since id enums are not zero-indexed, we need to transform the given id into20// its associated index.21struct BlockIdToIndexFunctor {22 using argument_type = unsigned;23 unsigned operator()(unsigned ID) const { return ID - BI_FIRST; }24};25 26struct RecordIdToIndexFunctor {27 using argument_type = unsigned;28 unsigned operator()(unsigned ID) const { return ID - RI_FIRST; }29};30 31using AbbrevDsc = void (*)(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev);32 33static void34generateAbbrev(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 40static void genBoolAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {41 generateAbbrev(Abbrev,42 {// 0. Boolean43 llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,44 BitCodeConstants::BoolSize)});45}46 47static void genIntAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {48 generateAbbrev(Abbrev,49 {// 0. Fixed-size integer50 llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,51 BitCodeConstants::IntSize)});52}53 54static void genSymbolIdAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {55 generateAbbrev(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 65static void genStringAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {66 generateAbbrev(Abbrev,67 {// 0. Fixed-size integer (length of the following string)68 llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,69 BitCodeConstants::StringLengthSize),70 // 1. The string blob71 llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)});72}73 74// Assumes that the file will not have more than 65535 lines.75static void genLocationAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {76 generateAbbrev(77 Abbrev,78 {// 0. Fixed-size integer (line number)79 llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,80 BitCodeConstants::LineNumberSize),81 // 1. Fixed-size integer (start line number)82 llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,83 BitCodeConstants::LineNumberSize),84 // 2. Boolean (IsFileInRootDir)85 llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,86 BitCodeConstants::BoolSize),87 // 3. Fixed-size integer (length of the following string (filename))88 llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,89 BitCodeConstants::StringLengthSize),90 // 4. The string blob91 llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)});92}93 94struct RecordIdDsc {95 llvm::StringRef Name;96 AbbrevDsc Abbrev = nullptr;97 98 RecordIdDsc() = default;99 RecordIdDsc(llvm::StringRef Name, AbbrevDsc Abbrev)100 : Name(Name), Abbrev(Abbrev) {}101 102 // Is this 'description' valid?103 operator bool() const {104 return Abbrev != nullptr && Name.data() != nullptr && !Name.empty();105 }106};107 108static const llvm::IndexedMap<llvm::StringRef, BlockIdToIndexFunctor>109 BlockIdNameMap = []() {110 llvm::IndexedMap<llvm::StringRef, BlockIdToIndexFunctor> BlockIdNameMap;111 BlockIdNameMap.resize(BlockIdCount);112 113 // There is no init-list constructor for the IndexedMap, so have to114 // improvise115 static const std::vector<std::pair<BlockId, const char *const>> Inits = {116 {BI_VERSION_BLOCK_ID, "VersionBlock"},117 {BI_NAMESPACE_BLOCK_ID, "NamespaceBlock"},118 {BI_ENUM_BLOCK_ID, "EnumBlock"},119 {BI_ENUM_VALUE_BLOCK_ID, "EnumValueBlock"},120 {BI_TYPEDEF_BLOCK_ID, "TypedefBlock"},121 {BI_TYPE_BLOCK_ID, "TypeBlock"},122 {BI_FIELD_TYPE_BLOCK_ID, "FieldTypeBlock"},123 {BI_MEMBER_TYPE_BLOCK_ID, "MemberTypeBlock"},124 {BI_RECORD_BLOCK_ID, "RecordBlock"},125 {BI_BASE_RECORD_BLOCK_ID, "BaseRecordBlock"},126 {BI_FUNCTION_BLOCK_ID, "FunctionBlock"},127 {BI_COMMENT_BLOCK_ID, "CommentBlock"},128 {BI_REFERENCE_BLOCK_ID, "ReferenceBlock"},129 {BI_TEMPLATE_BLOCK_ID, "TemplateBlock"},130 {BI_TEMPLATE_SPECIALIZATION_BLOCK_ID, "TemplateSpecializationBlock"},131 {BI_TEMPLATE_PARAM_BLOCK_ID, "TemplateParamBlock"},132 {BI_CONSTRAINT_BLOCK_ID, "ConstraintBlock"},133 {BI_CONCEPT_BLOCK_ID, "ConceptBlock"},134 {BI_VAR_BLOCK_ID, "VarBlock"},135 {BI_FRIEND_BLOCK_ID, "FriendBlock"}};136 assert(Inits.size() == BlockIdCount);137 for (const auto &Init : Inits)138 BlockIdNameMap[Init.first] = Init.second;139 assert(BlockIdNameMap.size() == BlockIdCount);140 return BlockIdNameMap;141 }();142 143static const llvm::IndexedMap<RecordIdDsc, RecordIdToIndexFunctor>144 RecordIdNameMap = []() {145 llvm::IndexedMap<RecordIdDsc, RecordIdToIndexFunctor> RecordIdNameMap;146 RecordIdNameMap.resize(RecordIdCount);147 148 // There is no init-list constructor for the IndexedMap, so have to149 // improvise150 static const std::vector<std::pair<RecordId, RecordIdDsc>> Inits = {151 {VERSION, {"Version", &genIntAbbrev}},152 {COMMENT_KIND, {"Kind", &genStringAbbrev}},153 {COMMENT_TEXT, {"Text", &genStringAbbrev}},154 {COMMENT_NAME, {"Name", &genStringAbbrev}},155 {COMMENT_DIRECTION, {"Direction", &genStringAbbrev}},156 {COMMENT_PARAMNAME, {"ParamName", &genStringAbbrev}},157 {COMMENT_CLOSENAME, {"CloseName", &genStringAbbrev}},158 {COMMENT_SELFCLOSING, {"SelfClosing", &genBoolAbbrev}},159 {COMMENT_EXPLICIT, {"Explicit", &genBoolAbbrev}},160 {COMMENT_ATTRKEY, {"AttrKey", &genStringAbbrev}},161 {COMMENT_ATTRVAL, {"AttrVal", &genStringAbbrev}},162 {COMMENT_ARG, {"Arg", &genStringAbbrev}},163 {FIELD_TYPE_NAME, {"Name", &genStringAbbrev}},164 {FIELD_DEFAULT_VALUE, {"DefaultValue", &genStringAbbrev}},165 {FIELD_TYPE_IS_BUILTIN, {"IsBuiltin", &genBoolAbbrev}},166 {FIELD_TYPE_IS_TEMPLATE, {"IsTemplate", &genBoolAbbrev}},167 {MEMBER_TYPE_NAME, {"Name", &genStringAbbrev}},168 {MEMBER_TYPE_ACCESS, {"Access", &genIntAbbrev}},169 {MEMBER_TYPE_IS_STATIC, {"IsStatic", &genBoolAbbrev}},170 {MEMBER_TYPE_IS_BUILTIN, {"IsBuiltin", &genBoolAbbrev}},171 {MEMBER_TYPE_IS_TEMPLATE, {"IsTemplate", &genBoolAbbrev}},172 {TYPE_IS_BUILTIN, {"IsBuiltin", &genBoolAbbrev}},173 {TYPE_IS_TEMPLATE, {"IsTemplate", &genBoolAbbrev}},174 {NAMESPACE_USR, {"USR", &genSymbolIdAbbrev}},175 {NAMESPACE_NAME, {"Name", &genStringAbbrev}},176 {NAMESPACE_PATH, {"Path", &genStringAbbrev}},177 {ENUM_USR, {"USR", &genSymbolIdAbbrev}},178 {ENUM_NAME, {"Name", &genStringAbbrev}},179 {ENUM_DEFLOCATION, {"DefLocation", &genLocationAbbrev}},180 {ENUM_LOCATION, {"Location", &genLocationAbbrev}},181 {ENUM_SCOPED, {"Scoped", &genBoolAbbrev}},182 {ENUM_VALUE_NAME, {"Name", &genStringAbbrev}},183 {ENUM_VALUE_VALUE, {"Value", &genStringAbbrev}},184 {ENUM_VALUE_EXPR, {"Expr", &genStringAbbrev}},185 {RECORD_USR, {"USR", &genSymbolIdAbbrev}},186 {RECORD_NAME, {"Name", &genStringAbbrev}},187 {RECORD_PATH, {"Path", &genStringAbbrev}},188 {RECORD_DEFLOCATION, {"DefLocation", &genLocationAbbrev}},189 {RECORD_LOCATION, {"Location", &genLocationAbbrev}},190 {RECORD_TAG_TYPE, {"TagType", &genIntAbbrev}},191 {RECORD_IS_TYPE_DEF, {"IsTypeDef", &genBoolAbbrev}},192 {RECORD_MANGLED_NAME, {"MangledName", &genStringAbbrev}},193 {BASE_RECORD_USR, {"USR", &genSymbolIdAbbrev}},194 {BASE_RECORD_NAME, {"Name", &genStringAbbrev}},195 {BASE_RECORD_PATH, {"Path", &genStringAbbrev}},196 {BASE_RECORD_TAG_TYPE, {"TagType", &genIntAbbrev}},197 {BASE_RECORD_IS_VIRTUAL, {"IsVirtual", &genBoolAbbrev}},198 {BASE_RECORD_ACCESS, {"Access", &genIntAbbrev}},199 {BASE_RECORD_IS_PARENT, {"IsParent", &genBoolAbbrev}},200 {FUNCTION_USR, {"USR", &genSymbolIdAbbrev}},201 {FUNCTION_NAME, {"Name", &genStringAbbrev}},202 {FUNCTION_DEFLOCATION, {"DefLocation", &genLocationAbbrev}},203 {FUNCTION_LOCATION, {"Location", &genLocationAbbrev}},204 {FUNCTION_ACCESS, {"Access", &genIntAbbrev}},205 {FUNCTION_IS_METHOD, {"IsMethod", &genBoolAbbrev}},206 {FUNCTION_IS_STATIC, {"IsStatic", &genBoolAbbrev}},207 {REFERENCE_USR, {"USR", &genSymbolIdAbbrev}},208 {REFERENCE_NAME, {"Name", &genStringAbbrev}},209 {REFERENCE_QUAL_NAME, {"QualName", &genStringAbbrev}},210 {REFERENCE_TYPE, {"RefType", &genIntAbbrev}},211 {REFERENCE_PATH, {"Path", &genStringAbbrev}},212 {REFERENCE_FIELD, {"Field", &genIntAbbrev}},213 {REFERENCE_FILE, {"File", &genStringAbbrev}},214 {TEMPLATE_PARAM_CONTENTS, {"Contents", &genStringAbbrev}},215 {TEMPLATE_SPECIALIZATION_OF,216 {"SpecializationOf", &genSymbolIdAbbrev}},217 {TYPEDEF_USR, {"USR", &genSymbolIdAbbrev}},218 {TYPEDEF_NAME, {"Name", &genStringAbbrev}},219 {TYPEDEF_DEFLOCATION, {"DefLocation", &genLocationAbbrev}},220 {TYPEDEF_IS_USING, {"IsUsing", &genBoolAbbrev}},221 {CONCEPT_USR, {"USR", &genSymbolIdAbbrev}},222 {CONCEPT_NAME, {"Name", &genStringAbbrev}},223 {CONCEPT_IS_TYPE, {"IsType", &genBoolAbbrev}},224 {CONCEPT_CONSTRAINT_EXPRESSION,225 {"ConstraintExpression", &genStringAbbrev}},226 {CONSTRAINT_EXPRESSION, {"Expression", &genStringAbbrev}},227 {VAR_USR, {"USR", &genSymbolIdAbbrev}},228 {VAR_NAME, {"Name", &genStringAbbrev}},229 {VAR_DEFLOCATION, {"DefLocation", &genLocationAbbrev}},230 {VAR_IS_STATIC, {"IsStatic", &genBoolAbbrev}},231 {FRIEND_IS_CLASS, {"IsClass", &genBoolAbbrev}}};232 233 assert(Inits.size() == RecordIdCount);234 for (const auto &Init : Inits) {235 RecordIdNameMap[Init.first] = Init.second;236 assert((Init.second.Name.size() + 1) <= BitCodeConstants::RecordSize);237 }238 assert(RecordIdNameMap.size() == RecordIdCount);239 return RecordIdNameMap;240 }();241 242static const std::vector<std::pair<BlockId, std::vector<RecordId>>>243 RecordsByBlock{244 // Version Block245 {BI_VERSION_BLOCK_ID, {VERSION}},246 // Comment Block247 {BI_COMMENT_BLOCK_ID,248 {COMMENT_KIND, COMMENT_TEXT, COMMENT_NAME, COMMENT_DIRECTION,249 COMMENT_PARAMNAME, COMMENT_CLOSENAME, COMMENT_SELFCLOSING,250 COMMENT_EXPLICIT, COMMENT_ATTRKEY, COMMENT_ATTRVAL, COMMENT_ARG}},251 // Type Block252 {BI_TYPE_BLOCK_ID, {TYPE_IS_BUILTIN, TYPE_IS_TEMPLATE}},253 // FieldType Block254 {BI_FIELD_TYPE_BLOCK_ID,255 {FIELD_TYPE_NAME, FIELD_DEFAULT_VALUE, FIELD_TYPE_IS_BUILTIN,256 FIELD_TYPE_IS_TEMPLATE}},257 // MemberType Block258 {BI_MEMBER_TYPE_BLOCK_ID,259 {MEMBER_TYPE_NAME, MEMBER_TYPE_ACCESS, MEMBER_TYPE_IS_STATIC,260 MEMBER_TYPE_IS_BUILTIN, MEMBER_TYPE_IS_TEMPLATE}},261 // Enum Block262 {BI_ENUM_BLOCK_ID,263 {ENUM_USR, ENUM_NAME, ENUM_DEFLOCATION, ENUM_LOCATION, ENUM_SCOPED}},264 // Enum Value Block265 {BI_ENUM_VALUE_BLOCK_ID,266 {ENUM_VALUE_NAME, ENUM_VALUE_VALUE, ENUM_VALUE_EXPR}},267 // Typedef Block268 {BI_TYPEDEF_BLOCK_ID,269 {TYPEDEF_USR, TYPEDEF_NAME, TYPEDEF_DEFLOCATION, TYPEDEF_IS_USING}},270 // Namespace Block271 {BI_NAMESPACE_BLOCK_ID,272 {NAMESPACE_USR, NAMESPACE_NAME, NAMESPACE_PATH}},273 // Record Block274 {BI_RECORD_BLOCK_ID,275 {RECORD_USR, RECORD_NAME, RECORD_PATH, RECORD_DEFLOCATION,276 RECORD_LOCATION, RECORD_TAG_TYPE, RECORD_IS_TYPE_DEF,277 RECORD_MANGLED_NAME}},278 // BaseRecord Block279 {BI_BASE_RECORD_BLOCK_ID,280 {BASE_RECORD_USR, BASE_RECORD_NAME, BASE_RECORD_PATH,281 BASE_RECORD_TAG_TYPE, BASE_RECORD_IS_VIRTUAL, BASE_RECORD_ACCESS,282 BASE_RECORD_IS_PARENT}},283 // Function Block284 {BI_FUNCTION_BLOCK_ID,285 {FUNCTION_USR, FUNCTION_NAME, FUNCTION_DEFLOCATION, FUNCTION_LOCATION,286 FUNCTION_ACCESS, FUNCTION_IS_METHOD, FUNCTION_IS_STATIC}},287 // Reference Block288 {BI_REFERENCE_BLOCK_ID,289 {REFERENCE_USR, REFERENCE_NAME, REFERENCE_QUAL_NAME, REFERENCE_TYPE,290 REFERENCE_PATH, REFERENCE_FIELD, REFERENCE_FILE}},291 // Template Blocks.292 {BI_TEMPLATE_BLOCK_ID, {}},293 {BI_TEMPLATE_PARAM_BLOCK_ID, {TEMPLATE_PARAM_CONTENTS}},294 {BI_TEMPLATE_SPECIALIZATION_BLOCK_ID, {TEMPLATE_SPECIALIZATION_OF}},295 // Concept Block296 {BI_CONCEPT_BLOCK_ID,297 {CONCEPT_USR, CONCEPT_NAME, CONCEPT_IS_TYPE,298 CONCEPT_CONSTRAINT_EXPRESSION}},299 // Constraint Block300 {BI_CONSTRAINT_BLOCK_ID, {CONSTRAINT_EXPRESSION}},301 {BI_VAR_BLOCK_ID, {VAR_NAME, VAR_USR, VAR_DEFLOCATION, VAR_IS_STATIC}},302 {BI_FRIEND_BLOCK_ID, {FRIEND_IS_CLASS}}};303 304// AbbreviationMap305 306void ClangDocBitcodeWriter::AbbreviationMap::add(RecordId RID,307 unsigned AbbrevID) {308 assert(RecordIdNameMap[RID] && "Unknown RecordId.");309 assert(!Abbrevs.contains(RID) && "Abbreviation already added.");310 Abbrevs[RID] = AbbrevID;311}312 313unsigned ClangDocBitcodeWriter::AbbreviationMap::get(RecordId RID) const {314 assert(RecordIdNameMap[RID] && "Unknown RecordId.");315 assert(Abbrevs.contains(RID) && "Unknown abbreviation.");316 return Abbrevs.lookup(RID);317}318 319// Validation and Overview Blocks320 321/// Emits the magic number header to check that its the right format,322/// in this case, 'DOCS'.323void ClangDocBitcodeWriter::emitHeader() {324 for (char C : BitCodeConstants::Signature)325 Stream.Emit((unsigned)C, BitCodeConstants::SignatureBitSize);326}327 328void ClangDocBitcodeWriter::emitVersionBlock() {329 StreamSubBlockGuard Block(Stream, BI_VERSION_BLOCK_ID);330 emitRecord(VersionNumber, VERSION);331}332 333/// Emits a block ID and the block name to the BLOCKINFO block.334void ClangDocBitcodeWriter::emitBlockID(BlockId BID) {335 const auto &BlockIdName = BlockIdNameMap[BID];336 assert(BlockIdName.data() && BlockIdName.size() && "Unknown BlockId.");337 338 Record.clear();339 Record.push_back(BID);340 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record);341 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME,342 ArrayRef<unsigned char>(BlockIdName.bytes_begin(),343 BlockIdName.bytes_end()));344}345 346/// Emits a record name to the BLOCKINFO block.347void ClangDocBitcodeWriter::emitRecordID(RecordId ID) {348 assert(RecordIdNameMap[ID] && "Unknown RecordId.");349 prepRecordData(ID);350 Record.append(RecordIdNameMap[ID].Name.begin(),351 RecordIdNameMap[ID].Name.end());352 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);353}354 355// Abbreviations356 357void ClangDocBitcodeWriter::emitAbbrev(RecordId ID, BlockId Block) {358 assert(RecordIdNameMap[ID] && "Unknown abbreviation.");359 auto Abbrev = std::make_shared<llvm::BitCodeAbbrev>();360 Abbrev->Add(llvm::BitCodeAbbrevOp(ID));361 RecordIdNameMap[ID].Abbrev(Abbrev);362 Abbrevs.add(ID, Stream.EmitBlockInfoAbbrev(Block, std::move(Abbrev)));363}364 365// Records366 367void ClangDocBitcodeWriter::emitRecord(const SymbolID &Sym, RecordId ID) {368 assert(RecordIdNameMap[ID] && "Unknown RecordId.");369 assert(RecordIdNameMap[ID].Abbrev == &genSymbolIdAbbrev &&370 "Abbrev type mismatch.");371 if (!prepRecordData(ID, Sym != EmptySID))372 return;373 assert(Sym.size() == 20);374 Record.push_back(Sym.size());375 Record.append(Sym.begin(), Sym.end());376 Stream.EmitRecordWithAbbrev(Abbrevs.get(ID), Record);377}378 379void ClangDocBitcodeWriter::emitRecord(llvm::StringRef Str, RecordId ID) {380 assert(RecordIdNameMap[ID] && "Unknown RecordId.");381 assert(RecordIdNameMap[ID].Abbrev == &genStringAbbrev &&382 "Abbrev type mismatch.");383 if (!prepRecordData(ID, !Str.empty()))384 return;385 assert(Str.size() < (1U << BitCodeConstants::StringLengthSize));386 Record.push_back(Str.size());387 Stream.EmitRecordWithBlob(Abbrevs.get(ID), Record, Str);388}389 390void ClangDocBitcodeWriter::emitRecord(const Location &Loc, RecordId ID) {391 assert(RecordIdNameMap[ID] && "Unknown RecordId.");392 assert(RecordIdNameMap[ID].Abbrev == &genLocationAbbrev &&393 "Abbrev type mismatch.");394 if (!prepRecordData(ID, true))395 return;396 // FIXME: Assert that the line number is of the appropriate size.397 Record.push_back(Loc.StartLineNumber);398 Record.push_back(Loc.EndLineNumber);399 assert(Loc.Filename.size() < (1U << BitCodeConstants::StringLengthSize));400 Record.push_back(Loc.IsFileInRootDir);401 Record.push_back(Loc.Filename.size());402 Stream.EmitRecordWithBlob(Abbrevs.get(ID), Record, Loc.Filename);403}404 405void ClangDocBitcodeWriter::emitRecord(bool Val, RecordId ID) {406 assert(RecordIdNameMap[ID] && "Unknown RecordId.");407 assert(RecordIdNameMap[ID].Abbrev == &genBoolAbbrev &&408 "Abbrev type mismatch.");409 if (!prepRecordData(ID, Val))410 return;411 Record.push_back(Val);412 Stream.EmitRecordWithAbbrev(Abbrevs.get(ID), Record);413}414 415void ClangDocBitcodeWriter::emitRecord(int Val, RecordId ID) {416 assert(RecordIdNameMap[ID] && "Unknown RecordId.");417 assert(RecordIdNameMap[ID].Abbrev == &genIntAbbrev &&418 "Abbrev type mismatch.");419 if (!prepRecordData(ID, Val))420 return;421 // FIXME: Assert that the integer is of the appropriate size.422 Record.push_back(Val);423 Stream.EmitRecordWithAbbrev(Abbrevs.get(ID), Record);424}425 426void ClangDocBitcodeWriter::emitRecord(unsigned Val, RecordId ID) {427 assert(RecordIdNameMap[ID] && "Unknown RecordId.");428 assert(RecordIdNameMap[ID].Abbrev == &genIntAbbrev &&429 "Abbrev type mismatch.");430 if (!prepRecordData(ID, Val))431 return;432 assert(Val < (1U << BitCodeConstants::IntSize));433 Record.push_back(Val);434 Stream.EmitRecordWithAbbrev(Abbrevs.get(ID), Record);435}436 437void ClangDocBitcodeWriter::emitRecord(const TemplateInfo &Templ) {}438 439bool ClangDocBitcodeWriter::prepRecordData(RecordId ID, bool ShouldEmit) {440 assert(RecordIdNameMap[ID] && "Unknown RecordId.");441 if (!ShouldEmit)442 return false;443 Record.clear();444 Record.push_back(ID);445 return true;446}447 448// BlockInfo Block449 450void ClangDocBitcodeWriter::emitBlockInfoBlock() {451 Stream.EnterBlockInfoBlock();452 for (const auto &Block : RecordsByBlock) {453 assert(Block.second.size() < (1U << BitCodeConstants::SubblockIDSize));454 emitBlockInfo(Block.first, Block.second);455 }456 Stream.ExitBlock();457}458 459void ClangDocBitcodeWriter::emitBlockInfo(BlockId BID,460 const std::vector<RecordId> &RIDs) {461 assert(RIDs.size() < (1U << BitCodeConstants::SubblockIDSize));462 emitBlockID(BID);463 for (RecordId RID : RIDs) {464 emitRecordID(RID);465 emitAbbrev(RID, BID);466 }467}468 469// Block emission470 471void ClangDocBitcodeWriter::emitBlock(const Reference &R, FieldId Field) {472 if (R.USR == EmptySID && R.Name.empty())473 return;474 StreamSubBlockGuard Block(Stream, BI_REFERENCE_BLOCK_ID);475 emitRecord(R.USR, REFERENCE_USR);476 emitRecord(R.Name, REFERENCE_NAME);477 emitRecord(R.QualName, REFERENCE_QUAL_NAME);478 emitRecord((unsigned)R.RefType, REFERENCE_TYPE);479 emitRecord(R.Path, REFERENCE_PATH);480 emitRecord((unsigned)Field, REFERENCE_FIELD);481 emitRecord(R.DocumentationFileName, REFERENCE_FILE);482}483 484void ClangDocBitcodeWriter::emitBlock(const FriendInfo &R) {485 StreamSubBlockGuard Block(Stream, BI_FRIEND_BLOCK_ID);486 emitBlock(R.Ref, FieldId::F_friend);487 emitRecord(R.IsClass, FRIEND_IS_CLASS);488 if (R.Template)489 emitBlock(*R.Template);490 if (R.Params)491 for (const auto &P : *R.Params)492 emitBlock(P);493 if (R.ReturnType)494 emitBlock(*R.ReturnType);495}496 497void ClangDocBitcodeWriter::emitBlock(const TypeInfo &T) {498 StreamSubBlockGuard Block(Stream, BI_TYPE_BLOCK_ID);499 emitBlock(T.Type, FieldId::F_type);500 emitRecord(T.IsBuiltIn, TYPE_IS_BUILTIN);501 emitRecord(T.IsTemplate, TYPE_IS_TEMPLATE);502}503 504void ClangDocBitcodeWriter::emitBlock(const TypedefInfo &T) {505 StreamSubBlockGuard Block(Stream, BI_TYPEDEF_BLOCK_ID);506 emitRecord(T.USR, TYPEDEF_USR);507 emitRecord(T.Name, TYPEDEF_NAME);508 for (const auto &N : T.Namespace)509 emitBlock(N, FieldId::F_namespace);510 for (const auto &CI : T.Description)511 emitBlock(CI);512 if (T.DefLoc)513 emitRecord(*T.DefLoc, TYPEDEF_DEFLOCATION);514 emitRecord(T.IsUsing, TYPEDEF_IS_USING);515 emitBlock(T.Underlying);516}517 518void ClangDocBitcodeWriter::emitBlock(const FieldTypeInfo &T) {519 StreamSubBlockGuard Block(Stream, BI_FIELD_TYPE_BLOCK_ID);520 emitBlock(T.Type, FieldId::F_type);521 emitRecord(T.Name, FIELD_TYPE_NAME);522 emitRecord(T.DefaultValue, FIELD_DEFAULT_VALUE);523 emitRecord(T.IsBuiltIn, FIELD_TYPE_IS_BUILTIN);524 emitRecord(T.IsTemplate, FIELD_TYPE_IS_TEMPLATE);525}526 527void ClangDocBitcodeWriter::emitBlock(const MemberTypeInfo &T) {528 StreamSubBlockGuard Block(Stream, BI_MEMBER_TYPE_BLOCK_ID);529 emitBlock(T.Type, FieldId::F_type);530 emitRecord(T.Name, MEMBER_TYPE_NAME);531 emitRecord(T.Access, MEMBER_TYPE_ACCESS);532 emitRecord(T.IsStatic, MEMBER_TYPE_IS_STATIC);533 emitRecord(T.IsBuiltIn, MEMBER_TYPE_IS_BUILTIN);534 emitRecord(T.IsTemplate, MEMBER_TYPE_IS_TEMPLATE);535 emitRecord(T.IsTemplate, MEMBER_TYPE_IS_TEMPLATE);536 for (const auto &CI : T.Description)537 emitBlock(CI);538}539 540void ClangDocBitcodeWriter::emitBlock(const CommentInfo &I) {541 StreamSubBlockGuard Block(Stream, BI_COMMENT_BLOCK_ID);542 // Handle Kind (enum) separately, since it is not a string.543 emitRecord(commentKindToString(I.Kind), COMMENT_KIND);544 for (const auto &L : std::vector<std::pair<llvm::StringRef, RecordId>>{545 {I.Text, COMMENT_TEXT},546 {I.Name, COMMENT_NAME},547 {I.Direction, COMMENT_DIRECTION},548 {I.ParamName, COMMENT_PARAMNAME},549 {I.CloseName, COMMENT_CLOSENAME}})550 emitRecord(L.first, L.second);551 emitRecord(I.SelfClosing, COMMENT_SELFCLOSING);552 emitRecord(I.Explicit, COMMENT_EXPLICIT);553 for (const auto &A : I.AttrKeys)554 emitRecord(A, COMMENT_ATTRKEY);555 for (const auto &A : I.AttrValues)556 emitRecord(A, COMMENT_ATTRVAL);557 for (const auto &A : I.Args)558 emitRecord(A, COMMENT_ARG);559 for (const auto &C : I.Children)560 emitBlock(*C);561}562 563void ClangDocBitcodeWriter::emitBlock(const NamespaceInfo &I) {564 StreamSubBlockGuard Block(Stream, BI_NAMESPACE_BLOCK_ID);565 emitRecord(I.USR, NAMESPACE_USR);566 emitRecord(I.Name, NAMESPACE_NAME);567 emitRecord(I.Path, NAMESPACE_PATH);568 for (const auto &N : I.Namespace)569 emitBlock(N, FieldId::F_namespace);570 for (const auto &CI : I.Description)571 emitBlock(CI);572 for (const auto &C : I.Children.Namespaces)573 emitBlock(C, FieldId::F_child_namespace);574 for (const auto &C : I.Children.Records)575 emitBlock(C, FieldId::F_child_record);576 for (const auto &C : I.Children.Functions)577 emitBlock(C);578 for (const auto &C : I.Children.Enums)579 emitBlock(C);580 for (const auto &C : I.Children.Typedefs)581 emitBlock(C);582 for (const auto &C : I.Children.Concepts)583 emitBlock(C);584 for (const auto &C : I.Children.Variables)585 emitBlock(C);586}587 588void ClangDocBitcodeWriter::emitBlock(const EnumInfo &I) {589 StreamSubBlockGuard Block(Stream, BI_ENUM_BLOCK_ID);590 emitRecord(I.USR, ENUM_USR);591 emitRecord(I.Name, ENUM_NAME);592 for (const auto &N : I.Namespace)593 emitBlock(N, FieldId::F_namespace);594 for (const auto &CI : I.Description)595 emitBlock(CI);596 if (I.DefLoc)597 emitRecord(*I.DefLoc, ENUM_DEFLOCATION);598 for (const auto &L : I.Loc)599 emitRecord(L, ENUM_LOCATION);600 emitRecord(I.Scoped, ENUM_SCOPED);601 if (I.BaseType)602 emitBlock(*I.BaseType);603 for (const auto &N : I.Members)604 emitBlock(N);605}606 607void ClangDocBitcodeWriter::emitBlock(const EnumValueInfo &I) {608 StreamSubBlockGuard Block(Stream, BI_ENUM_VALUE_BLOCK_ID);609 emitRecord(I.Name, ENUM_VALUE_NAME);610 emitRecord(I.Value, ENUM_VALUE_VALUE);611 emitRecord(I.ValueExpr, ENUM_VALUE_EXPR);612 for (const auto &CI : I.Description)613 emitBlock(CI);614}615 616void ClangDocBitcodeWriter::emitBlock(const RecordInfo &I) {617 StreamSubBlockGuard Block(Stream, BI_RECORD_BLOCK_ID);618 emitRecord(I.USR, RECORD_USR);619 emitRecord(I.Name, RECORD_NAME);620 emitRecord(I.Path, RECORD_PATH);621 emitRecord(I.MangledName, RECORD_MANGLED_NAME);622 for (const auto &N : I.Namespace)623 emitBlock(N, FieldId::F_namespace);624 for (const auto &CI : I.Description)625 emitBlock(CI);626 if (I.DefLoc)627 emitRecord(*I.DefLoc, RECORD_DEFLOCATION);628 for (const auto &L : I.Loc)629 emitRecord(L, RECORD_LOCATION);630 emitRecord(llvm::to_underlying(I.TagType), RECORD_TAG_TYPE);631 emitRecord(I.IsTypeDef, RECORD_IS_TYPE_DEF);632 for (const auto &N : I.Members)633 emitBlock(N);634 for (const auto &P : I.Parents)635 emitBlock(P, FieldId::F_parent);636 for (const auto &P : I.VirtualParents)637 emitBlock(P, FieldId::F_vparent);638 for (const auto &PB : I.Bases)639 emitBlock(PB);640 for (const auto &C : I.Children.Records)641 emitBlock(C, FieldId::F_child_record);642 for (const auto &C : I.Children.Functions)643 emitBlock(C);644 for (const auto &C : I.Children.Enums)645 emitBlock(C);646 for (const auto &C : I.Children.Typedefs)647 emitBlock(C);648 if (I.Template)649 emitBlock(*I.Template);650 for (const auto &C : I.Friends)651 emitBlock(C);652}653 654void ClangDocBitcodeWriter::emitBlock(const BaseRecordInfo &I) {655 StreamSubBlockGuard Block(Stream, BI_BASE_RECORD_BLOCK_ID);656 emitRecord(I.USR, BASE_RECORD_USR);657 emitRecord(I.Name, BASE_RECORD_NAME);658 emitRecord(I.Path, BASE_RECORD_PATH);659 emitRecord(llvm::to_underlying(I.TagType), BASE_RECORD_TAG_TYPE);660 emitRecord(I.IsVirtual, BASE_RECORD_IS_VIRTUAL);661 emitRecord(I.Access, BASE_RECORD_ACCESS);662 emitRecord(I.IsParent, BASE_RECORD_IS_PARENT);663 for (const auto &M : I.Members)664 emitBlock(M);665 for (const auto &C : I.Children.Functions)666 emitBlock(C);667}668 669void ClangDocBitcodeWriter::emitBlock(const FunctionInfo &I) {670 StreamSubBlockGuard Block(Stream, BI_FUNCTION_BLOCK_ID);671 emitRecord(I.USR, FUNCTION_USR);672 emitRecord(I.Name, FUNCTION_NAME);673 for (const auto &N : I.Namespace)674 emitBlock(N, FieldId::F_namespace);675 for (const auto &CI : I.Description)676 emitBlock(CI);677 emitRecord(I.Access, FUNCTION_ACCESS);678 emitRecord(I.IsMethod, FUNCTION_IS_METHOD);679 emitRecord(I.IsStatic, FUNCTION_IS_STATIC);680 if (I.DefLoc)681 emitRecord(*I.DefLoc, FUNCTION_DEFLOCATION);682 for (const auto &L : I.Loc)683 emitRecord(L, FUNCTION_LOCATION);684 emitBlock(I.Parent, FieldId::F_parent);685 emitBlock(I.ReturnType);686 for (const auto &N : I.Params)687 emitBlock(N);688 if (I.Template)689 emitBlock(*I.Template);690}691 692void ClangDocBitcodeWriter::emitBlock(const ConceptInfo &I) {693 StreamSubBlockGuard Block(Stream, BI_CONCEPT_BLOCK_ID);694 emitRecord(I.USR, CONCEPT_USR);695 emitRecord(I.Name, CONCEPT_NAME);696 for (const auto &CI : I.Description)697 emitBlock(CI);698 emitRecord(I.IsType, CONCEPT_IS_TYPE);699 emitRecord(I.ConstraintExpression, CONCEPT_CONSTRAINT_EXPRESSION);700 emitBlock(I.Template);701}702 703void ClangDocBitcodeWriter::emitBlock(const TemplateInfo &T) {704 StreamSubBlockGuard Block(Stream, BI_TEMPLATE_BLOCK_ID);705 for (const auto &P : T.Params)706 emitBlock(P);707 if (T.Specialization)708 emitBlock(*T.Specialization);709 for (const auto &C : T.Constraints)710 emitBlock(C);711}712 713void ClangDocBitcodeWriter::emitBlock(const TemplateSpecializationInfo &T) {714 StreamSubBlockGuard Block(Stream, BI_TEMPLATE_SPECIALIZATION_BLOCK_ID);715 emitRecord(T.SpecializationOf, TEMPLATE_SPECIALIZATION_OF);716 for (const auto &P : T.Params)717 emitBlock(P);718}719 720void ClangDocBitcodeWriter::emitBlock(const TemplateParamInfo &T) {721 StreamSubBlockGuard Block(Stream, BI_TEMPLATE_PARAM_BLOCK_ID);722 emitRecord(T.Contents, TEMPLATE_PARAM_CONTENTS);723}724 725void ClangDocBitcodeWriter::emitBlock(const ConstraintInfo &C) {726 StreamSubBlockGuard Block(Stream, BI_CONSTRAINT_BLOCK_ID);727 emitRecord(C.ConstraintExpr, CONSTRAINT_EXPRESSION);728 emitBlock(C.ConceptRef, FieldId::F_concept);729}730 731void ClangDocBitcodeWriter::emitBlock(const VarInfo &I) {732 StreamSubBlockGuard Block(Stream, BI_VAR_BLOCK_ID);733 emitRecord(I.USR, VAR_USR);734 emitRecord(I.Name, VAR_NAME);735 for (const auto &N : I.Namespace)736 emitBlock(N, FieldId::F_namespace);737 for (const auto &CI : I.Description)738 emitBlock(CI);739 if (I.DefLoc)740 emitRecord(*I.DefLoc, VAR_DEFLOCATION);741 emitRecord(I.IsStatic, VAR_IS_STATIC);742 emitBlock(I.Type);743}744 745bool ClangDocBitcodeWriter::dispatchInfoForWrite(Info *I) {746 switch (I->IT) {747 case InfoType::IT_namespace:748 emitBlock(*static_cast<clang::doc::NamespaceInfo *>(I));749 break;750 case InfoType::IT_record:751 emitBlock(*static_cast<clang::doc::RecordInfo *>(I));752 break;753 case InfoType::IT_enum:754 emitBlock(*static_cast<clang::doc::EnumInfo *>(I));755 break;756 case InfoType::IT_function:757 emitBlock(*static_cast<clang::doc::FunctionInfo *>(I));758 break;759 case InfoType::IT_typedef:760 emitBlock(*static_cast<clang::doc::TypedefInfo *>(I));761 break;762 case InfoType::IT_concept:763 emitBlock(*static_cast<clang::doc::ConceptInfo *>(I));764 break;765 case InfoType::IT_variable:766 emitBlock(*static_cast<VarInfo *>(I));767 break;768 case InfoType::IT_friend:769 emitBlock(*static_cast<FriendInfo *>(I));770 break;771 case InfoType::IT_default:772 llvm::errs() << "Unexpected info, unable to write.\n";773 return true;774 }775 return false;776}777 778} // namespace doc779} // namespace clang780