1 //===-- BitcodeWriter.h - 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 // This file implements a writer for serializing the clang-doc internal 10 // representation to LLVM bitcode. The writer takes in a stream and emits the 11 // generated bitcode to that stream. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_BITCODEWRITER_H 16 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_BITCODEWRITER_H 17 18 #include "Representation.h" 19 #include "clang/AST/AST.h" 20 #include "llvm/ADT/DenseMap.h" 21 #include "llvm/ADT/SmallVector.h" 22 #include "llvm/ADT/StringRef.h" 23 #include "llvm/Bitstream/BitstreamWriter.h" 24 #include <initializer_list> 25 #include <vector> 26 27 namespace clang { 28 namespace doc { 29 30 // Current version number of clang-doc bitcode. 31 // Should be bumped when removing or changing BlockIds, RecordIds, or 32 // BitCodeConstants, though they can be added without breaking it. 33 static const unsigned VersionNumber = 3; 34 35 struct BitCodeConstants { 36 static constexpr unsigned RecordSize = 32U; 37 static constexpr unsigned SignatureBitSize = 8U; 38 static constexpr unsigned SubblockIDSize = 4U; 39 static constexpr unsigned BoolSize = 1U; 40 static constexpr unsigned IntSize = 16U; 41 static constexpr unsigned StringLengthSize = 16U; 42 static constexpr unsigned FilenameLengthSize = 16U; 43 static constexpr unsigned LineNumberSize = 32U; 44 static constexpr unsigned ReferenceTypeSize = 8U; 45 static constexpr unsigned USRLengthSize = 6U; 46 static constexpr unsigned USRBitLengthSize = 8U; 47 static constexpr unsigned char Signature[4] = {'D', 'O', 'C', 'S'}; 48 static constexpr int USRHashSize = 20; 49 }; 50 51 // New Ids need to be added to both the enum here and the relevant IdNameMap in 52 // the implementation file. 53 enum BlockId { 54 BI_VERSION_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID, 55 BI_NAMESPACE_BLOCK_ID, 56 BI_ENUM_BLOCK_ID, 57 BI_ENUM_VALUE_BLOCK_ID, 58 BI_TYPE_BLOCK_ID, 59 BI_FIELD_TYPE_BLOCK_ID, 60 BI_MEMBER_TYPE_BLOCK_ID, 61 BI_RECORD_BLOCK_ID, 62 BI_BASE_RECORD_BLOCK_ID, 63 BI_FUNCTION_BLOCK_ID, 64 BI_COMMENT_BLOCK_ID, 65 BI_REFERENCE_BLOCK_ID, 66 BI_TEMPLATE_BLOCK_ID, 67 BI_TEMPLATE_SPECIALIZATION_BLOCK_ID, 68 BI_TEMPLATE_PARAM_BLOCK_ID, 69 BI_TYPEDEF_BLOCK_ID, 70 BI_LAST, 71 BI_FIRST = BI_VERSION_BLOCK_ID 72 }; 73 74 // New Ids need to be added to the enum here, and to the relevant IdNameMap and 75 // initialization list in the implementation file. 76 enum RecordId { 77 VERSION = 1, 78 FUNCTION_USR, 79 FUNCTION_NAME, 80 FUNCTION_DEFLOCATION, 81 FUNCTION_LOCATION, 82 FUNCTION_ACCESS, 83 FUNCTION_IS_METHOD, 84 COMMENT_KIND, 85 COMMENT_TEXT, 86 COMMENT_NAME, 87 COMMENT_DIRECTION, 88 COMMENT_PARAMNAME, 89 COMMENT_CLOSENAME, 90 COMMENT_SELFCLOSING, 91 COMMENT_EXPLICIT, 92 COMMENT_ATTRKEY, 93 COMMENT_ATTRVAL, 94 COMMENT_ARG, 95 FIELD_TYPE_NAME, 96 FIELD_DEFAULT_VALUE, 97 MEMBER_TYPE_NAME, 98 MEMBER_TYPE_ACCESS, 99 NAMESPACE_USR, 100 NAMESPACE_NAME, 101 NAMESPACE_PATH, 102 ENUM_USR, 103 ENUM_NAME, 104 ENUM_DEFLOCATION, 105 ENUM_LOCATION, 106 ENUM_SCOPED, 107 ENUM_VALUE_NAME, 108 ENUM_VALUE_VALUE, 109 ENUM_VALUE_EXPR, 110 RECORD_USR, 111 RECORD_NAME, 112 RECORD_PATH, 113 RECORD_DEFLOCATION, 114 RECORD_LOCATION, 115 RECORD_TAG_TYPE, 116 RECORD_IS_TYPE_DEF, 117 BASE_RECORD_USR, 118 BASE_RECORD_NAME, 119 BASE_RECORD_PATH, 120 BASE_RECORD_TAG_TYPE, 121 BASE_RECORD_IS_VIRTUAL, 122 BASE_RECORD_ACCESS, 123 BASE_RECORD_IS_PARENT, 124 REFERENCE_USR, 125 REFERENCE_NAME, 126 REFERENCE_QUAL_NAME, 127 REFERENCE_TYPE, 128 REFERENCE_PATH, 129 REFERENCE_FIELD, 130 TEMPLATE_PARAM_CONTENTS, 131 TEMPLATE_SPECIALIZATION_OF, 132 TYPEDEF_USR, 133 TYPEDEF_NAME, 134 TYPEDEF_DEFLOCATION, 135 TYPEDEF_IS_USING, 136 RI_LAST, 137 RI_FIRST = VERSION 138 }; 139 140 static constexpr unsigned BlockIdCount = BI_LAST - BI_FIRST; 141 static constexpr unsigned RecordIdCount = RI_LAST - RI_FIRST; 142 143 // Identifiers for differentiating between subblocks 144 enum class FieldId { 145 F_default, 146 F_namespace, 147 F_parent, 148 F_vparent, 149 F_type, 150 F_child_namespace, 151 F_child_record 152 }; 153 154 class ClangDocBitcodeWriter { 155 public: ClangDocBitcodeWriter(llvm::BitstreamWriter & Stream)156 ClangDocBitcodeWriter(llvm::BitstreamWriter &Stream) : Stream(Stream) { 157 emitHeader(); 158 emitBlockInfoBlock(); 159 emitVersionBlock(); 160 } 161 162 // Write a specific info to a bitcode stream. 163 bool dispatchInfoForWrite(Info *I); 164 165 // Block emission of different info types. 166 void emitBlock(const NamespaceInfo &I); 167 void emitBlock(const RecordInfo &I); 168 void emitBlock(const BaseRecordInfo &I); 169 void emitBlock(const FunctionInfo &I); 170 void emitBlock(const EnumInfo &I); 171 void emitBlock(const EnumValueInfo &I); 172 void emitBlock(const TypeInfo &B); 173 void emitBlock(const TypedefInfo &B); 174 void emitBlock(const FieldTypeInfo &B); 175 void emitBlock(const MemberTypeInfo &T); 176 void emitBlock(const CommentInfo &B); 177 void emitBlock(const TemplateInfo &T); 178 void emitBlock(const TemplateSpecializationInfo &T); 179 void emitBlock(const TemplateParamInfo &T); 180 void emitBlock(const Reference &B, FieldId F); 181 182 private: 183 class AbbreviationMap { 184 llvm::DenseMap<unsigned, unsigned> Abbrevs; 185 186 public: AbbreviationMap()187 AbbreviationMap() : Abbrevs(RecordIdCount) {} 188 189 void add(RecordId RID, unsigned AbbrevID); 190 unsigned get(RecordId RID) const; 191 }; 192 193 class StreamSubBlockGuard { 194 llvm::BitstreamWriter &Stream; 195 196 public: StreamSubBlockGuard(llvm::BitstreamWriter & Stream_,BlockId ID)197 StreamSubBlockGuard(llvm::BitstreamWriter &Stream_, BlockId ID) 198 : Stream(Stream_) { 199 // NOTE: SubBlockIDSize could theoretically be calculated on the fly, 200 // based on the initialization list of records in each block. 201 Stream.EnterSubblock(ID, BitCodeConstants::SubblockIDSize); 202 } 203 204 StreamSubBlockGuard(const StreamSubBlockGuard &) = delete; 205 StreamSubBlockGuard &operator=(const StreamSubBlockGuard &) = delete; 206 ~StreamSubBlockGuard()207 ~StreamSubBlockGuard() { Stream.ExitBlock(); } 208 }; 209 210 // Emission of validation and overview blocks. 211 void emitHeader(); 212 void emitVersionBlock(); 213 void emitRecordID(RecordId ID); 214 void emitBlockID(BlockId ID); 215 void emitBlockInfoBlock(); 216 void emitBlockInfo(BlockId BID, const std::vector<RecordId> &RIDs); 217 218 // Emission of individual record types. 219 void emitRecord(StringRef Str, RecordId ID); 220 void emitRecord(const SymbolID &Str, RecordId ID); 221 void emitRecord(const Location &Loc, RecordId ID); 222 void emitRecord(const Reference &Ref, RecordId ID); 223 void emitRecord(bool Value, RecordId ID); 224 void emitRecord(int Value, RecordId ID); 225 void emitRecord(unsigned Value, RecordId ID); 226 void emitRecord(const TemplateInfo &Templ); 227 bool prepRecordData(RecordId ID, bool ShouldEmit = true); 228 229 // Emission of appropriate abbreviation type. 230 void emitAbbrev(RecordId ID, BlockId Block); 231 232 // Static size is the maximum length of the block/record names we're pushing 233 // to this + 1. Longest is currently `MemberTypeBlock` at 15 chars. 234 SmallVector<uint32_t, BitCodeConstants::RecordSize> Record; 235 llvm::BitstreamWriter &Stream; 236 AbbreviationMap Abbrevs; 237 }; 238 239 } // namespace doc 240 } // namespace clang 241 242 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_BITCODEWRITER_H 243