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_TYPE_BLOCK_ID, 58 BI_FIELD_TYPE_BLOCK_ID, 59 BI_MEMBER_TYPE_BLOCK_ID, 60 BI_RECORD_BLOCK_ID, 61 BI_BASE_RECORD_BLOCK_ID, 62 BI_FUNCTION_BLOCK_ID, 63 BI_COMMENT_BLOCK_ID, 64 BI_REFERENCE_BLOCK_ID, 65 BI_LAST, 66 BI_FIRST = BI_VERSION_BLOCK_ID 67 }; 68 69 // New Ids need to be added to the enum here, and to the relevant IdNameMap and 70 // initialization list in the implementation file. 71 enum RecordId { 72 VERSION = 1, 73 FUNCTION_USR, 74 FUNCTION_NAME, 75 FUNCTION_DEFLOCATION, 76 FUNCTION_LOCATION, 77 FUNCTION_ACCESS, 78 FUNCTION_IS_METHOD, 79 COMMENT_KIND, 80 COMMENT_TEXT, 81 COMMENT_NAME, 82 COMMENT_DIRECTION, 83 COMMENT_PARAMNAME, 84 COMMENT_CLOSENAME, 85 COMMENT_SELFCLOSING, 86 COMMENT_EXPLICIT, 87 COMMENT_ATTRKEY, 88 COMMENT_ATTRVAL, 89 COMMENT_ARG, 90 FIELD_TYPE_NAME, 91 MEMBER_TYPE_NAME, 92 MEMBER_TYPE_ACCESS, 93 NAMESPACE_USR, 94 NAMESPACE_NAME, 95 NAMESPACE_PATH, 96 ENUM_USR, 97 ENUM_NAME, 98 ENUM_DEFLOCATION, 99 ENUM_LOCATION, 100 ENUM_MEMBER, 101 ENUM_SCOPED, 102 RECORD_USR, 103 RECORD_NAME, 104 RECORD_PATH, 105 RECORD_DEFLOCATION, 106 RECORD_LOCATION, 107 RECORD_TAG_TYPE, 108 RECORD_IS_TYPE_DEF, 109 BASE_RECORD_USR, 110 BASE_RECORD_NAME, 111 BASE_RECORD_PATH, 112 BASE_RECORD_TAG_TYPE, 113 BASE_RECORD_IS_VIRTUAL, 114 BASE_RECORD_ACCESS, 115 BASE_RECORD_IS_PARENT, 116 REFERENCE_USR, 117 REFERENCE_NAME, 118 REFERENCE_TYPE, 119 REFERENCE_PATH, 120 REFERENCE_IS_IN_GLOBAL_NAMESPACE, 121 REFERENCE_FIELD, 122 RI_LAST, 123 RI_FIRST = VERSION 124 }; 125 126 static constexpr unsigned BlockIdCount = BI_LAST - BI_FIRST; 127 static constexpr unsigned RecordIdCount = RI_LAST - RI_FIRST; 128 129 // Identifiers for differentiating between subblocks 130 enum class FieldId { 131 F_default, 132 F_namespace, 133 F_parent, 134 F_vparent, 135 F_type, 136 F_child_namespace, 137 F_child_record 138 }; 139 140 class ClangDocBitcodeWriter { 141 public: ClangDocBitcodeWriter(llvm::BitstreamWriter & Stream)142 ClangDocBitcodeWriter(llvm::BitstreamWriter &Stream) : Stream(Stream) { 143 emitHeader(); 144 emitBlockInfoBlock(); 145 emitVersionBlock(); 146 } 147 148 // Write a specific info to a bitcode stream. 149 bool dispatchInfoForWrite(Info *I); 150 151 // Block emission of different info types. 152 void emitBlock(const NamespaceInfo &I); 153 void emitBlock(const RecordInfo &I); 154 void emitBlock(const BaseRecordInfo &I); 155 void emitBlock(const FunctionInfo &I); 156 void emitBlock(const EnumInfo &I); 157 void emitBlock(const TypeInfo &B); 158 void emitBlock(const FieldTypeInfo &B); 159 void emitBlock(const MemberTypeInfo &B); 160 void emitBlock(const CommentInfo &B); 161 void emitBlock(const Reference &B, FieldId F); 162 163 private: 164 class AbbreviationMap { 165 llvm::DenseMap<unsigned, unsigned> Abbrevs; 166 167 public: AbbreviationMap()168 AbbreviationMap() : Abbrevs(RecordIdCount) {} 169 170 void add(RecordId RID, unsigned AbbrevID); 171 unsigned get(RecordId RID) const; 172 }; 173 174 class StreamSubBlockGuard { 175 llvm::BitstreamWriter &Stream; 176 177 public: StreamSubBlockGuard(llvm::BitstreamWriter & Stream_,BlockId ID)178 StreamSubBlockGuard(llvm::BitstreamWriter &Stream_, BlockId ID) 179 : Stream(Stream_) { 180 // NOTE: SubBlockIDSize could theoretically be calculated on the fly, 181 // based on the initialization list of records in each block. 182 Stream.EnterSubblock(ID, BitCodeConstants::SubblockIDSize); 183 } 184 185 StreamSubBlockGuard(const StreamSubBlockGuard &) = delete; 186 StreamSubBlockGuard &operator=(const StreamSubBlockGuard &) = delete; 187 ~StreamSubBlockGuard()188 ~StreamSubBlockGuard() { Stream.ExitBlock(); } 189 }; 190 191 // Emission of validation and overview blocks. 192 void emitHeader(); 193 void emitVersionBlock(); 194 void emitRecordID(RecordId ID); 195 void emitBlockID(BlockId ID); 196 void emitBlockInfoBlock(); 197 void emitBlockInfo(BlockId BID, const std::vector<RecordId> &RIDs); 198 199 // Emission of individual record types. 200 void emitRecord(StringRef Str, RecordId ID); 201 void emitRecord(const SymbolID &Str, RecordId ID); 202 void emitRecord(const Location &Loc, RecordId ID); 203 void emitRecord(const Reference &Ref, RecordId ID); 204 void emitRecord(bool Value, RecordId ID); 205 void emitRecord(int Value, RecordId ID); 206 void emitRecord(unsigned Value, RecordId ID); 207 bool prepRecordData(RecordId ID, bool ShouldEmit = true); 208 209 // Emission of appropriate abbreviation type. 210 void emitAbbrev(RecordId ID, BlockId Block); 211 212 // Static size is the maximum length of the block/record names we're pushing 213 // to this + 1. Longest is currently `MemberTypeBlock` at 15 chars. 214 SmallVector<uint32_t, BitCodeConstants::RecordSize> Record; 215 llvm::BitstreamWriter &Stream; 216 AbbreviationMap Abbrevs; 217 }; 218 219 } // namespace doc 220 } // namespace clang 221 222 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_BITCODEWRITER_H 223